Watch
0
0
Fork
You've already forked hyperhive
0
hyperhive/frontend/packages/swarm-ui/src/lib/theme-apply.ts
iris afe627e0a9 swarm-ui: derive theme override from colors.css instead of duplicating hex values
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.
2026-08-18 23:58:48 +02:00

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]);
}