mara's review: the theme override read as a hand-copied duplicate of colors.css's hex values instead of deriving from it. Restructured colors.css to declare each palette's 16 hex values exactly once (--mocha-baseNN, --latte-baseNN) and have every activation block (the default, the prefers-color-scheme media query, and two new :root[data-theme='light'|'dark'] blocks) just re-point the active --baseNN slot at one of those two raw palettes via var() - never a second copy of a hex value. theme-apply.ts simplifies to match: it now only toggles a data-theme attribute on <html>, same shape motion-apply.ts already had. No palette values live in JS at all anymore. Re-verified the override still genuinely outranks the media query with the new mechanism: same seed-localStorage-while-forcing-the- opposite-OS-preference test as before, both directions still render the stored override correctly.
38 lines
1.6 KiB
TypeScript
38 lines
1.6 KiB
TypeScript
// Applies the stored theme override (see `settings-storage.ts`) by
|
|
// setting `data-theme="light"|"dark"` on `<html>`, cleared when the
|
|
// override is "system" (letting the `prefers-color-scheme` media
|
|
// query in `@hive/shared/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, by re-pointing at the same `--mocha-baseNN` /
|
|
// `--latte-baseNN` custom properties its media-query block already
|
|
// uses. This file only ever toggles the attribute; the values come
|
|
// from colors.css, not a duplicate copy here.
|
|
import { useEffect } from 'preact/hooks';
|
|
import { useLocalSetting } from './settings-storage.js';
|
|
|
|
export type ThemeOverride = 'system' | 'light' | 'dark';
|
|
|
|
export const THEME_OVERRIDE_KEY = 'swarm-ui:theme-override';
|
|
|
|
export function useThemeOverride() {
|
|
return useLocalSetting<ThemeOverride>(THEME_OVERRIDE_KEY, 'system');
|
|
}
|
|
|
|
// Mounted once, high in the tree (`Shell`) — every route renders
|
|
// through one `<Shell>`, so one mount point applies the override
|
|
// regardless of which page is showing, 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(): void {
|
|
const [override] = useThemeOverride();
|
|
useEffect(() => {
|
|
const root = document.documentElement;
|
|
if (override === 'system') {
|
|
delete root.dataset.theme;
|
|
} else {
|
|
root.dataset.theme = override;
|
|
}
|
|
}, [override]);
|
|
}
|