MCPcopy Create free account
hub / github.com/Oslonline/dithering-studio / AlgorithmSelect

Function AlgorithmSelect

src/components/panels/AlgorithmSelect.tsx:25–89  ·  view source on GitHub ↗
({
  pattern,
  setPattern,
  threshold,
  setThreshold,
  invert,
  setInvert,
  serpentine,
  setSerpentine,
  paletteId,
  groupByCategory = false,
  defaultOpen = true,
})

Source from the content-addressed store, hash-verified

23};
24
25const AlgorithmSelect: React.FC<AlgorithmSelectProps> = ({
26 pattern,
27 setPattern,
28 threshold,
29 setThreshold,
30 invert,
31 setInvert,
32 serpentine,
33 setSerpentine,
34 paletteId,
35 groupByCategory = false,
36 defaultOpen = true,
37}) => {
38 const { t } = useTranslation();
39 const [open, setOpen] = useState(defaultOpen);
40
41 const algoMetaMap: Record<number, { description: string; supportsThreshold: boolean; category: string; name: string }> = {};
42 for (const a of algorithms) { algoMetaMap[a.id] = { description: a.name, supportsThreshold: a.supportsThreshold, category: a.category, name: a.name }; }
43
44 const renderOptions = () => {
45 if (!groupByCategory) {
46 return algorithms.map(a => <option key={a.id} value={a.id}>{a.name}</option>);
47 }
48 const categoryOrder = ["Error Diffusion", "Ordered", "Other"];
49 const groups = getAlgorithmsByCategory();
50 return categoryOrder.map(cat => {
51 const list = groups[cat]; if (!list || !list.length) return null;
52 const labelKey = cat === 'Error Diffusion' ? 'tool.algorithmPanel.errorDiffusion' : cat === 'Ordered' ? 'tool.algorithmPanel.ordered' : 'tool.algorithmPanel.other';
53 return <optgroup key={cat} label={t(labelKey)}>{list.map(a => <option key={a.id} value={a.id}>{a.name}</option>)}</optgroup>;
54 });
55 };
56
57 return (
58 <div className="min-panel p-0">
59 <button type="button" onClick={() => setOpen(o => !o)} className="flex w-full items-center justify-between px-4 py-3 text-left font-mono text-[11px] tracking-wide text-gray-300 hover:bg-neutral-800/40 focus-visible:shadow-[var(--focus-ring)]" aria-expanded={open}>
60 <span className="flex items-center gap-2"><span>{open ? '▾' : '▸'}</span> {t('tool.algorithmPanel.title')}</span>
61 <span className="text-[10px] text-gray-500">#{pattern}</span>
62 </button>
63 {open && (
64 <div className="space-y-3 border-t border-neutral-800 px-4 pt-3 pb-4">
65 <div>
66 <label htmlFor="algo-select" className="sr-only">{t('tool.algorithmPanel.title')}</label>
67 <select id="algo-select" className="clean-input" value={pattern} onChange={(e) => setPattern(Number(e.target.value))}>
68 {renderOptions()}
69 </select>
70 </div>
71 {algoMetaMap[pattern]?.supportsThreshold && (
72 <div className="space-y-1">
73 <div className="flex items-center justify-between">
74 <span className="font-mono text-[10px] tracking-wide text-gray-400">{t('tool.algorithmPanel.threshold')}</span>
75 <span className="text-[10px] text-gray-500">{threshold}</span>
76 </div>
77 <input type="range" min={0} max={255} value={threshold} className="clean-range" onChange={(e) => setThreshold(Number(e.target.value))} aria-label={t('tool.algorithmPanel.threshold')} />
78 </div>
79 )}
80 <div className="grid grid-cols-2 gap-2">
81 <button type="button" onClick={() => !paletteId && setInvert(v => !v)} disabled={!!paletteId} className={`clean-btn justify-center text-[10px] ${invert ? 'border-emerald-600 text-emerald-400' : ''} ${paletteId ? 'cursor-not-allowed opacity-40' : ''}`}>{t('tool.algorithmPanel.invert')}</button>
82 <button type="button" onClick={() => setSerpentine(s => !s)} className={`clean-btn justify-center text-[10px] ${serpentine ? 'border-blue-600 text-blue-400' : ''}`}>{t('tool.algorithmPanel.serpentine')}</button>

Callers

nothing calls this directly

Calls 1

renderOptionsFunction · 0.70

Tested by

no test coverage detected