/** * Theme runtime: mode (light/dark) + accent, applied as data attributes on * and persisted. localStorage for now; these become user-scope settings * rows once the DB layer lands (config-driven principle). */ export type ThemeMode = 'light' | 'dark' export const ACCENTS = ['teal', 'indigo', 'blue', 'emerald', 'violet', 'rose', 'amber'] as const export type Accent = (typeof ACCENTS)[number] /** Neutral ground. `warm` is the base (no attribute needed); the rest map to * `[data-palette=…]` overrides in tokens.css. Orthogonal to mode + accent. */ export const PALETTES = ['warm', 'slate', 'graphite', 'zinc'] as const export type Palette = (typeof PALETTES)[number] const MODE_KEY = 'ui.themeMode' const ACCENT_KEY = 'ui.accent' const PALETTE_KEY = 'ui.palette' export function getThemeMode(): ThemeMode { return localStorage.getItem(MODE_KEY) === 'dark' ? 'dark' : 'light' } export function getAccent(): Accent { const stored = localStorage.getItem(ACCENT_KEY) return (ACCENTS as readonly string[]).includes(stored ?? '') ? (stored as Accent) : 'teal' } export function getPalette(): Palette { const stored = localStorage.getItem(PALETTE_KEY) return (PALETTES as readonly string[]).includes(stored ?? '') ? (stored as Palette) : 'warm' } export function setThemeMode(mode: ThemeMode): void { localStorage.setItem(MODE_KEY, mode) document.documentElement.dataset['theme'] = mode } export function setAccent(accent: Accent): void { localStorage.setItem(ACCENT_KEY, accent) document.documentElement.dataset['accent'] = accent } export function setPalette(palette: Palette): void { localStorage.setItem(PALETTE_KEY, palette) document.documentElement.dataset['palette'] = palette } /** Call once before first render. */ export function initTheme(): void { document.documentElement.dataset['theme'] = getThemeMode() document.documentElement.dataset['accent'] = getAccent() document.documentElement.dataset['palette'] = getPalette() }