Mercurial
view mrjunejune/src/index.js @ 256:30c2196d03d4
[site] Integrate Zenbu themes and components
Co-authored-by: Copilot <[email protected]>
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Tue, 04 Aug 2026 16:49:01 -0700 |
| parents | bcc76a156aea |
| children | 60a876c4587a |
line wrap: on
line source
const THEME_STORAGE_KEY = 'theme-preference'; const THEMES = ['auto', 'paper', 'ink', 'playful']; const THEME_LABELS = { auto: 'Auto', paper: 'Paper', ink: 'Ink', playful: 'Playful', }; function normalizeTheme(value) { if (value === 'light') return 'paper'; if (value === 'dark') return 'ink'; return THEMES.includes(value) ? value : 'auto'; } function getThemePreference() { return normalizeTheme(localStorage.getItem(THEME_STORAGE_KEY)); } function updateThemeColor() { const probe = document.createElement('span'); probe.style.background = 'var(--zen-color-canvas)'; document.body.append(probe); const color = getComputedStyle(probe).backgroundColor; probe.remove(); document.querySelector('meta[name="theme-color"]') ?.setAttribute('content', color); } function updateThemeControl(preference) { const toggle = document.querySelector('#themeToggle'); const label = document.querySelector('#themeName'); if (label) label.textContent = THEME_LABELS[preference]; toggle?.setAttribute( 'aria-label', `Change site theme. Current theme: ${THEME_LABELS[preference]}`, ); } function applyTheme(value, persist = false) { const preference = normalizeTheme(value); const root = document.documentElement; root.classList.remove('light-mode', 'dark', 'auto'); if (preference === 'auto') delete root.dataset.zenTheme; else root.dataset.zenTheme = preference; if (persist) localStorage.setItem(THEME_STORAGE_KEY, preference); updateThemeControl(preference); requestAnimationFrame(updateThemeColor); document.dispatchEvent(new CustomEvent('zen-theme-change', { detail: { theme: preference }, })); return preference; } const currentPreference = applyTheme(getThemePreference()); if (localStorage.getItem(THEME_STORAGE_KEY) !== currentPreference) { localStorage.setItem(THEME_STORAGE_KEY, currentPreference); } document.querySelector('#themeToggle')?.addEventListener('click', () => { const current = getThemePreference(); const next = THEMES[(THEMES.indexOf(current) + 1) % THEMES.length]; applyTheme(next, true); }); matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { if (getThemePreference() === 'auto') updateThemeColor(); }); window.MrJuneJuneTheme = Object.freeze({ apply: theme => applyTheme(theme, true), current: getThemePreference, themes: [...THEMES], });