import { useSyncExternalStore } from 'react' export type Theme = 'light' | 'dark' const STORAGE_KEY = 'kernel-theme' const listeners = new Set<() => void>() function readInitial(): Theme { const fromUrl = new URLSearchParams(window.location.search).get('theme') if (fromUrl === 'light' || fromUrl === 'dark') return fromUrl const stored = localStorage.getItem(STORAGE_KEY) if (stored === 'light' || stored === 'dark') return stored return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' } let current: Theme = 'light' function apply() { document.documentElement.classList.toggle('dark', current === 'dark') } /** Call once at app bootstrap, before first paint of themed UI. */ export function initTheme() { current = readInitial() apply() } export function getTheme(): Theme { return current } export function setTheme(theme: Theme) { current = theme localStorage.setItem(STORAGE_KEY, theme) apply() for (const listener of listeners) listener() } export function toggleTheme() { setTheme(current === 'dark' ? 'light' : 'dark') } /** Subscribe to light/dark changes; the palette store repaints on these. */ export function onThemeChange(listener: () => void): () => void { listeners.add(listener) return () => listeners.delete(listener) } function subscribe(listener: () => void) { listeners.add(listener) return () => listeners.delete(listener) } export function useTheme(): Theme { return useSyncExternalStore(subscribe, getTheme) }