feat(web/m7-362): theme preference + resolved-theme rune store
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
const STORAGE_KEY = 'minstrel:theme';
|
||||
|
||||
export type ThemePreference = 'dark' | 'light' | 'system';
|
||||
export type ResolvedTheme = 'dark' | 'light';
|
||||
|
||||
function readPref(): ThemePreference {
|
||||
if (typeof localStorage === 'undefined') return 'system';
|
||||
try {
|
||||
const v = localStorage.getItem(STORAGE_KEY);
|
||||
return v === 'dark' || v === 'light' || v === 'system' ? v : 'system';
|
||||
} catch {
|
||||
return 'system';
|
||||
}
|
||||
}
|
||||
|
||||
function systemResolved(): ResolvedTheme {
|
||||
if (typeof window === 'undefined' || !window.matchMedia) return 'dark';
|
||||
return window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
|
||||
}
|
||||
|
||||
function resolve(pref: ThemePreference): ResolvedTheme {
|
||||
return pref === 'system' ? systemResolved() : pref;
|
||||
}
|
||||
|
||||
function applyToDOM(resolved: ResolvedTheme): void {
|
||||
if (typeof document === 'undefined') return;
|
||||
document.documentElement.setAttribute('data-theme', resolved);
|
||||
}
|
||||
|
||||
let _theme = $state<ThemePreference>(readPref());
|
||||
let _resolved = $state<ResolvedTheme>(resolve(_theme));
|
||||
|
||||
export const theme = {
|
||||
get value(): ThemePreference {
|
||||
return _theme;
|
||||
}
|
||||
};
|
||||
|
||||
export const resolvedTheme = {
|
||||
get value(): ResolvedTheme {
|
||||
return _resolved;
|
||||
}
|
||||
};
|
||||
|
||||
export function setTheme(pref: ThemePreference): void {
|
||||
_theme = pref;
|
||||
_resolved = resolve(pref);
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
try { localStorage.setItem(STORAGE_KEY, pref); } catch { /* ignore quota / unavailable */ }
|
||||
}
|
||||
applyToDOM(_resolved);
|
||||
}
|
||||
|
||||
if (typeof window !== 'undefined' && window.matchMedia) {
|
||||
const mq = window.matchMedia('(prefers-color-scheme: light)');
|
||||
mq.addEventListener('change', () => {
|
||||
if (_theme === 'system') {
|
||||
_resolved = systemResolved();
|
||||
applyToDOM(_resolved);
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user