LLM_Comparison_Tool / frontend /src /components /ComparisonSelector.js
NeonClary
LLM Comparison Tool: deploy snapshot for Hugging Face Space (orphan history)
08b0543
import { useState } from 'react';
import { Cloud, ChevronDown, ChevronRight } from 'lucide-react';
export default function ComparisonSelector({ providers, selected, onSelectionChange }) {
const [expandedProviders, setExpandedProviders] = useState({});
const toggleExpand = (providerId) => {
setExpandedProviders(prev => ({ ...prev, [providerId]: !prev[providerId] }));
};
const toggleModel = (modelId) => {
if (selected.includes(modelId)) {
onSelectionChange(selected.filter(id => id !== modelId));
} else {
onSelectionChange([...selected, modelId]);
}
};
const toggleProvider = (provider) => {
const providerModelIds = provider.models.map(m => m.id);
const allSelected = providerModelIds.every(id => selected.includes(id));
if (allSelected) {
onSelectionChange(selected.filter(id => !providerModelIds.includes(id)));
} else {
const newIds = providerModelIds.filter(id => !selected.includes(id));
onSelectionChange([...selected, ...newIds]);
}
};
if (!providers.length) {
return (
<div className="selector-section">
<h3 className="selector-title"><Cloud size={16} /> Comparison Models</h3>
<p className="selector-hint">Configure API keys in .env to enable comparison providers</p>
</div>
);
}
return (
<div className="selector-section">
<h3 className="selector-title"><Cloud size={16} /> Comparison Models</h3>
<p className="selector-hint">Select models to compare against</p>
<div className="comparison-providers">
{[...providers].sort((a, b) => a.name.localeCompare(b.name)).map(provider => {
const providerModelIds = provider.models.map(m => m.id);
const allSelected = providerModelIds.every(id => selected.includes(id));
const selectedCount = providerModelIds.filter(id => selected.includes(id)).length;
const isExpanded = expandedProviders[provider.id] === true;
return (
<div key={provider.id} className="comparison-provider-group">
<div className="provider-group-header">
<label className="provider-group-checkbox" onClick={(e) => e.stopPropagation()}>
<input
type="checkbox"
checked={allSelected}
onChange={() => toggleProvider(provider)}
/>
</label>
<button className="provider-group-toggle" onClick={() => toggleExpand(provider.id)}>
<span className="provider-group-name">{provider.name}</span>
{selectedCount > 0 && <span className="provider-selected-count">{selectedCount}</span>}
{isExpanded ? <ChevronDown size={14} /> : <ChevronRight size={14} />}
</button>
</div>
{isExpanded && (
<div className="provider-model-list">
{provider.models.map(model => (
<label key={model.id} className={`comparison-model-item ${selected.includes(model.id) ? 'selected' : ''}`}>
<input
type="checkbox"
checked={selected.includes(model.id)}
onChange={() => toggleModel(model.id)}
/>
<span className="comparison-model-name">{model.name}</span>
</label>
))}
</div>
)}
</div>
);
})}
</div>
<style>{`
.comparison-providers {
display: flex;
flex-direction: column;
gap: 10px;
}
.comparison-provider-group {
border: 1px solid var(--border-primary);
border-radius: 8px;
overflow: hidden;
background: #E0EAFD;
}
:root[data-theme="dark"] .comparison-provider-group {
background: #1E2A40;
}
.provider-group-header {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
font-size: 13px;
border-bottom: 1px solid var(--border-muted);
}
.provider-group-checkbox {
display: flex;
align-items: center;
cursor: pointer;
}
.provider-group-checkbox input[type="checkbox"] {
accent-color: var(--accent-primary);
box-shadow: 0 1px 6px 1px rgba(0, 0, 0, 0.3);
border-radius: 3px;
}
.provider-group-toggle {
display: flex;
align-items: center;
gap: 6px;
flex: 1;
background: none;
border: none;
color: var(--text-primary);
font-size: 13px;
cursor: pointer;
padding: 0;
text-align: left;
}
.provider-group-toggle:hover {
opacity: 0.8;
}
.provider-selected-count {
font-size: 11px;
font-weight: 600;
color: var(--accent-primary);
background: var(--accent-light);
padding: 1px 6px;
border-radius: 10px;
margin-left: auto;
}
.provider-model-list {
padding: 4px;
}
.comparison-model-item {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 8px;
border-radius: 6px;
cursor: pointer;
transition: background 0.15s;
font-size: 13px;
}
.comparison-model-item:hover {
background: var(--card-hover);
}
.comparison-model-item.selected {
background: var(--accent-light);
}
.comparison-model-item input[type="checkbox"] {
accent-color: var(--accent-primary);
}
.provider-group-name {
font-weight: 600;
color: var(--text-primary);
font-size: 13px;
text-transform: uppercase;
}
.comparison-model-name {
color: var(--text-primary);
}
`}</style>
</div>
);
}