/* ============================================================
CHAINUS — app root: theme / accent / aurora / motion / lang
============================================================ */
const ACCENTS = {
'Sapphire': '#163B7A',
'Navy': '#0E2C5F',
'Steel': '#536B8E',
'Indigo': '#293E8F',
};
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
"themeMode": "dark",
"accent": "#163B7A",
"aura": "subtle",
"motion": "lively"
}/*EDITMODE-END*/;
function systemTheme() {
return (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) ? 'light' : 'dark';
}
function App() {
const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
const [lang, setLang] = useState(() => (window.detectLang ? window.detectLang() : 'en'));
const [theme, setTheme] = useState(() => document.documentElement.getAttribute('data-theme') || 'dark');
const C = window.I18N[lang];
useReveal();
useEffect(() => {
const b = document.getElementById('boot');
if (b) { b.classList.add('gone'); setTimeout(() => b.remove(), 700); }
}, []);
/* theme: follow tweak mode (auto/dark/light); toggle persists a manual pick */
const applyTheme = (th) => {
document.documentElement.setAttribute('data-theme', th);
document.querySelector('meta[name="theme-color"]')?.setAttribute('content', th === 'light' ? '#E9ECF3' : '#050609');
setTheme(th);
};
useEffect(() => {
const mode = t.themeMode || 'auto';
if (mode === 'auto') {
applyTheme(systemTheme());
const mq = window.matchMedia('(prefers-color-scheme: light)');
const onCh = () => { if ((TWEAK_DEFAULTS && (t.themeMode || 'auto') === 'auto')) applyTheme(systemTheme()); };
mq.addEventListener && mq.addEventListener('change', onCh);
return () => mq.removeEventListener && mq.removeEventListener('change', onCh);
} else {
applyTheme(mode);
}
}, [t.themeMode]);
const onToggleTheme = () => {
const next = theme === 'dark' ? 'light' : 'dark';
try { localStorage.setItem('chainus_theme', next); } catch (e) {}
setTweak('themeMode', next);
applyTheme(next);
};
/* accent */
useEffect(() => {
const root = document.documentElement;
const v = (!t.accent || t.accent === '#5B7CFF' || t.accent === '#2997FF') ? '#163B7A' : t.accent;
root.style.setProperty('--brand', v);
root.style.setProperty('--brand-2', `color-mix(in oklab, ${v} 38%, #D8E0EC)`);
root.style.setProperty('--brand-hover', `color-mix(in oklab, ${v} 82%, black)`);
root.style.setProperty('--brand-active', `color-mix(in oklab, ${v} 70%, black)`);
}, [t.accent]);
useEffect(() => { document.documentElement.dataset.aura = t.aura || 'balanced'; }, [t.aura]);
useEffect(() => { document.documentElement.dataset.motion = t.motion || 'lively'; }, [t.motion]);
useEffect(() => {
document.documentElement.lang = lang === 'zh' ? 'zh-CN' : 'en';
document.documentElement.dataset.lang = lang;
document.body.dataset.lang = lang;
if (window.saveLang) window.saveLang(lang);
}, [lang]);
return (
setTweak('themeMode', v)}
/>
setTweak('accent', v)}
/>
setTweak('aura', v)}
/>
setTweak('motion', v)}
/>
setLang(v)}
/>
);
}
ReactDOM.createRoot(document.getElementById('root')).render();