41 lines
1.3 KiB
TypeScript
41 lines
1.3 KiB
TypeScript
/** 外观主题:浅色 / 深色 / 跟随系统。写到 html[data-theme] + localStorage,避免首屏闪白。 */
|
|
|
|
export type Appearance = "light" | "dark" | "system";
|
|
|
|
export const THEME_STORAGE_KEY = "yingqing-appearance";
|
|
|
|
export function normalizeAppearance(value: unknown): Appearance {
|
|
if (value === "light" || value === "dark" || value === "system") return value;
|
|
return "system";
|
|
}
|
|
|
|
export function resolveTheme(appearance: Appearance): "light" | "dark" {
|
|
if (appearance === "light" || appearance === "dark") return appearance;
|
|
if (typeof window !== "undefined" && window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
|
return "dark";
|
|
}
|
|
return "light";
|
|
}
|
|
|
|
export function applyTheme(appearance: Appearance | string | null | undefined) {
|
|
if (typeof document === "undefined") return;
|
|
const normalized = normalizeAppearance(appearance);
|
|
const theme = resolveTheme(normalized);
|
|
const root = document.documentElement;
|
|
root.setAttribute("data-theme", theme);
|
|
root.style.colorScheme = theme;
|
|
try {
|
|
localStorage.setItem(THEME_STORAGE_KEY, normalized);
|
|
} catch {
|
|
/* ignore quota / private mode */
|
|
}
|
|
}
|
|
|
|
export function readStoredAppearance(): Appearance {
|
|
try {
|
|
return normalizeAppearance(localStorage.getItem(THEME_STORAGE_KEY));
|
|
} catch {
|
|
return "system";
|
|
}
|
|
}
|