/* eslint-disable */
// Renders model list, history list, bars, compare grid, theme & lang toggles, tweaks panel.
const { useEffect, useState, useRef } = React;
// ---------- 1. Model list ----------
function renderModels() {
const list = document.getElementById('modelList');
if (!list) return;
list.innerHTML = window.TOOLLY_MODELS.map(m => `
${m.name}
${m.free ? '
FREE' : ''}
${m.vendor}
${m.tags.map(t => `${t}`).join('')}
`).join('');
list.querySelectorAll('.model-card').forEach(el => {
el.addEventListener('click', () => {
if (window.TOOLLY_COMPARE_ACTIVE) {
el.classList.toggle('compare');
} else {
list.querySelectorAll('.model-card.selected').forEach(s => s.classList.remove('selected'));
el.classList.add('selected');
const m = window.TOOLLY_MODELS.find(x => x.id === el.dataset.id);
if (m) {
document.querySelector('.sm-name').textContent = m.name;
document.querySelector('.sm-avatar').className = `sm-avatar ${m.ava}`;
document.querySelector('.sm-avatar').textContent = m.initial;
document.querySelector('.selected-model-card .mname').textContent = m.name.split(' · ').pop();
document.querySelector('.selected-model-card .mvendor').textContent = `${m.vendor}`;
}
}
});
});
}
// ---------- 2. History ----------
function renderHistory() {
const el = document.getElementById('historyList');
if (!el) return;
el.innerHTML = window.TOOLLY_HISTORY.map(h => `
${h.time}
${h.model}
${h.ms} ms
${h.preset}
${h.status === 'ok' ? '✓' : '⚠'}
`).join('');
}
// ---------- 3. Sparkline bars ----------
function renderBars() {
const el = document.getElementById('bars');
if (!el) return;
const peak = Math.max(...window.TOOLLY_BARS);
el.innerHTML = window.TOOLLY_BARS.map(v => {
const h = Math.max(6, Math.round((v / peak) * 100));
const isPeak = v === peak;
return ``;
}).join('');
}
// ---------- 4. Compare grid ----------
function renderCompare() {
const el = document.getElementById('compareGrid');
if (!el) return;
el.innerHTML = window.TOOLLY_COMPARE.map(c => `
${c.initial}
${c.name}
${c.ms}ms
${c.body.replace(/\n/g, '
')}
`).join('');
}
// ---------- 5. Tabs (right pane + presets + compare toggle) ----------
function wireTabs() {
document.querySelectorAll('.rt').forEach(btn => {
btn.addEventListener('click', () => {
const tab = btn.dataset.tab;
document.querySelectorAll('.rt').forEach(b => b.classList.toggle('active', b === btn));
document.querySelectorAll('[data-tabbody]').forEach(b => {
b.classList.toggle('hidden', b.dataset.tabbody !== tab);
});
});
});
document.querySelectorAll('.preset-tabs .pt').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.preset-tabs .pt').forEach(b => b.classList.toggle('active', b === btn));
});
});
// 필터 칩
document.querySelectorAll('.filter-chips .chip').forEach(chip => {
chip.addEventListener('click', () => {
document.querySelectorAll('.filter-chips .chip').forEach(c => c.classList.remove('active'));
chip.classList.add('active');
if (typeof window.filterModels === 'function') window.filterModels();
});
});
const ct = document.getElementById('compareToggle');
if (ct) {
ct.addEventListener('click', () => {
const on = ct.classList.toggle('on');
window.TOOLLY_COMPARE_ACTIVE = on;
document.getElementById('singleMode').classList.toggle('hidden', on);
document.getElementById('compareMode').classList.toggle('hidden', !on);
document.querySelectorAll('.model-card.compare').forEach(m => m.classList.remove('compare'));
});
}
}
// ---------- 6. i18n ----------
function applyLang(lang) {
const dict = window.TOOLLY_I18N[lang] || {};
document.querySelectorAll('[data-i18n]').forEach(el => {
const k = el.dataset.i18n;
if (dict[k]) el.textContent = dict[k];
});
document.querySelectorAll('[data-i18n-ph]').forEach(el => {
const k = el.dataset.i18nPh;
if (dict[k]) el.placeholder = dict[k];
});
document.documentElement.lang = lang;
}
function wireLang() {
document.querySelectorAll('#langToggle button').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('#langToggle button').forEach(b => b.classList.toggle('active', b === btn));
applyLang(btn.dataset.lang);
});
});
}
// ---------- 7. Theme ----------
function applyTheme(t) {
document.documentElement.setAttribute('data-theme', t);
const btn = document.getElementById('themeToggle');
if (btn) {
btn.innerHTML = t === 'dark'
? ''
: '';
}
}
// ---------- 8. Tweaks panel ----------
const ACCENTS = [
{ id: 'amber', label: '앰버', l: 0.66, c: 0.155, h: 48, l2: 0.74, h2: 60 },
{ id: 'orange', label: '오렌지', l: 0.66, c: 0.18, h: 35, l2: 0.72, h2: 50 },
{ id: 'rose', label: '로즈', l: 0.66, c: 0.16, h: 15, l2: 0.74, h2: 25 },
{ id: 'green', label: '세이지', l: 0.62, c: 0.10, h: 145, l2: 0.70, h2: 160 },
{ id: 'blue', label: '블루', l: 0.60, c: 0.14, h: 240, l2: 0.68, h2: 220 },
{ id: 'plum', label: '플럼', l: 0.55, c: 0.15, h: 305, l2: 0.65, h2: 290 },
];
function applyAccent(id) {
const a = ACCENTS.find(x => x.id === id) || ACCENTS[0];
const r = document.documentElement.style;
r.setProperty('--accent', `oklch(${a.l} ${a.c} ${a.h})`);
r.setProperty('--accent-2', `oklch(${a.l2} ${a.c} ${a.h2})`);
r.setProperty('--accent-soft', `oklch(${(0.94 - 0.62*0)} ${a.c * 0.3} ${a.h})`);
r.setProperty('--accent-ink', `oklch(0.32 ${a.c * 0.7} ${a.h})`);
}
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
"accent": "amber",
"theme": "light",
"lang": "ko"
}/*EDITMODE-END*/;
function TweaksApp() {
const [t, setT] = window.useTweaks(TWEAK_DEFAULTS);
const { TweaksPanel, TweakSection, TweakRadio } = window;
useEffect(() => { applyAccent(t.accent); }, [t.accent]);
useEffect(() => { applyTheme(t.theme); }, [t.theme]);
useEffect(() => {
applyLang(t.lang);
document.querySelectorAll('#langToggle button').forEach(b => {
b.classList.toggle('active', b.dataset.lang === t.lang);
});
}, [t.lang]);
// sync top-bar buttons → tweak state
useEffect(() => {
const onLang = (e) => {
const b = e.target.closest('#langToggle button');
if (b) setT('lang', b.dataset.lang);
};
const onTheme = () => setT('theme', t.theme === 'dark' ? 'light' : 'dark');
document.getElementById('langToggle')?.addEventListener('click', onLang);
document.getElementById('themeToggle')?.addEventListener('click', onTheme);
return () => {
document.getElementById('langToggle')?.removeEventListener('click', onLang);
document.getElementById('themeToggle')?.removeEventListener('click', onTheme);
};
}, [t.theme]);
return (
{ACCENTS.map(a => (
))}
setT('theme', v)} options={['light','dark']} />
setT('lang', v)} options={['ko','en']} />
);
}
// ---------- INIT ----------
renderModels();
renderHistory();
renderBars();
renderCompare();
wireTabs();
wireLang();
applyLang('ko');
applyTheme('light');
// mount tweaks
const root = ReactDOM.createRoot(document.getElementById('tweaks-root'));
root.render();