// Applies a stored theme override by setting `data-theme="light"|"dark"` // on ``, cleared when the override is "system" (letting the // `prefers-color-scheme` media query in `./colors.css` resume control). // No palette values live here — `colors.css`'s own // `:root[data-theme='light']` / `:root[data-theme='dark']` blocks are // what actually apply the colours. // // Callers own their own storage key (kept in their own small constant, // not derived here) so two pages never silently share one browser-local // setting by accident. `fallback` defaults to `'dark'`: `prefers-color- // scheme` has no real "unset" value the way `prefers-reduced-motion` // does, so a browser with no explicit dark-mode toggle reports `light` // — `'system'` as a default silently reads as light-by-default for most // first-time visitors (mara: "light mode seems to be default"). Still // fully overridable per caller if a page ever wants a different default. import { useEffect } from "preact/hooks"; import { useLocalSetting } from "./settings-storage.js"; export type ThemeOverride = "system" | "light" | "dark"; export function useThemeOverride( key: string, fallback: ThemeOverride = "dark", ) { return useLocalSetting(key, fallback); } // Mounted once, high in the tree — one mount point applies the override // regardless of what else is rendering, and `useLocalSetting`'s // same-tab subscription means `SettingsMenu` changing the value re-runs // this effect without either component needing to know about the other // directly. export function useApplyThemeOverride( key: string, fallback: ThemeOverride = "dark", ): void { const [override] = useThemeOverride(key, fallback); useEffect(() => { const root = document.documentElement; if (override === "system") { delete root.dataset.theme; } else { root.dataset.theme = override; } }, [override]); }