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

Function AlgorithmPanel

src/components/panels/AlgorithmPanel.tsx:19–103  ·  view source on GitHub ↗
({ pattern, setPattern, threshold, setThreshold, invert, setInvert, asciiRamp, setAsciiRamp })

Source from the content-addressed store, hash-verified

17}
18
19const AlgorithmPanel: React.FC<AlgorithmPanelProps> = ({ pattern, setPattern, threshold, setThreshold, invert, setInvert, asciiRamp, setAsciiRamp }) => {
20 const { t } = useTranslation();
21 const algoObj = algorithms.find(a=>a.id===pattern);
22 const isAscii = pattern === 25 || algoObj?.name.toLowerCase().includes('ascii');
23 const normalizedRamp = useMemo(()=>{
24 if (!asciiRamp) return DEFAULT_ASCII_RAMP; return Array.from(new Set(asciiRamp.split('').filter(ch=>ch !== '\n' && ch!=='\r'))).join('').slice(0,128);
25 },[asciiRamp]);
26
27 return (
28 <CollapsiblePanel
29 title={t(isAscii ? 'tool.algorithmPanel.titleAscii' : 'tool.algorithmPanel.title')}
30 subtitle={`#${pattern}`}
31 defaultOpen={true}
32 >
33 <div className="space-y-3">
34 <div>
35 <label htmlFor="algo-select" className="sr-only">{t('tool.algorithmPanel.title')}</label>
36 <select id="algo-select" className="clean-input" value={pattern} onChange={(e) => setPattern(Number(e.target.value))}>
37 {(() => {
38 const groups = getAlgorithmsByCategory();
39 const order: ("Error Diffusion"|"Ordered"|"Other")[] = ["Error Diffusion","Ordered","Other"];
40 return order.map(cat => {
41 const list = groups[cat]; if (!list) return null;
42 const labelKey = cat === 'Error Diffusion' ? 'tool.algorithmPanel.errorDiffusion' : cat === 'Ordered' ? 'tool.algorithmPanel.ordered' : 'tool.algorithmPanel.other';
43 return <optgroup key={cat} label={t(labelKey)}>{list.map(a => <option key={a.id} value={a.id}>{a.name}</option>)}</optgroup>;
44 });
45 })()}
46 </select>
47 </div>
48 {algorithms.find(a=>a.id===pattern)?.supportsThreshold && (
49 <div className="space-y-1">
50 <div className="flex items-center justify-between"><span className="font-mono text-[10px] tracking-wide text-gray-400">{t('tool.algorithmPanel.luminanceThreshold')}</span><span className="text-[10px] text-gray-500">{threshold}</span></div>
51 <input type="range" min={0} max={255} value={threshold} className="clean-range" onChange={(e) => setThreshold(Number(e.target.value))} aria-label={t('tool.algorithmPanel.luminanceThreshold')} />
52 </div>
53 )}
54 <div className="grid grid-cols-1 gap-2">
55 <button
56 type="button"
57 onClick={() => setInvert(v => !v)}
58 className={`clean-btn justify-center text-[10px] ${invert ? 'border-blue-600 text-blue-400' : ''}`}
59 >{t('tool.algorithmPanel.invert')}</button>
60 </div>
61 {isAscii && setAsciiRamp && (
62 <div className="space-y-2" data-section="ascii-ramp">
63 <div className="flex items-center justify-between">
64 <span className="font-mono text-[10px] tracking-wide text-gray-400">{t('tool.algorithmPanel.asciiRamp')}</span>
65 <span className="text-[9px] text-gray-500">{normalizedRamp.length} {t('tool.algorithmPanel.chars')}</span>
66 </div>
67 <textarea
68 value={asciiRamp || DEFAULT_ASCII_RAMP}
69 onChange={(e)=> {
70 const raw = e.target.value.replace(/\s+/g,' '); // collapse whitespace
71 const uniq = Array.from(new Set(raw.split(''))).join('');
72 setAsciiRamp(uniq.slice(0,128));
73 }}
74 rows={2}
75 className="clean-input !px-2 !py-1 font-mono text-[11px] resize-none"
76 aria-label={t('tool.algorithmPanel.asciiRamp')}

Callers

nothing calls this directly

Calls 2

getAlgorithmsByCategoryFunction · 0.90
orderRampDarkToLightFunction · 0.90

Tested by

no test coverage detected