fix(theme): make preference state deterministic
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
import { getAuthUserKey } from "./auth";
|
||||
import { AUTH_USER_CHANGED_EVENT, getAuthUserKey } from "./auth";
|
||||
|
||||
export type ThemeModePref = "system" | "light" | "dark";
|
||||
export type EffectiveThemeMode = "light" | "dark";
|
||||
|
||||
export const DEFAULT_THEME_MODE: ThemeModePref = "system";
|
||||
const THEME_KEY_PREFIX = "themeMode:";
|
||||
|
||||
export function getUserKeyFromToken(): string {
|
||||
return getAuthUserKey();
|
||||
@@ -10,12 +14,47 @@ function k(base: string) {
|
||||
return `${base}:${getUserKeyFromToken()}`;
|
||||
}
|
||||
|
||||
function readThemeMode(key: string): ThemeModePref | null {
|
||||
try {
|
||||
const raw = window.localStorage.getItem(key);
|
||||
return raw === "light" || raw === "dark" || raw === "system" ? raw : null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function getThemeModePref(): ThemeModePref {
|
||||
const raw = window.localStorage.getItem(k("themeMode"));
|
||||
if (raw === "light" || raw === "dark" || raw === "system") return raw;
|
||||
return "system";
|
||||
const userKey = getUserKeyFromToken();
|
||||
const savedUserMode = readThemeMode(`${THEME_KEY_PREFIX}${userKey}`);
|
||||
if (savedUserMode) return savedUserMode;
|
||||
if (userKey !== "anon") {
|
||||
const anonymousMode = readThemeMode(`${THEME_KEY_PREFIX}anon`);
|
||||
if (anonymousMode) return anonymousMode;
|
||||
}
|
||||
return DEFAULT_THEME_MODE;
|
||||
}
|
||||
|
||||
export function setThemeModePref(v: ThemeModePref) {
|
||||
window.localStorage.setItem(k("themeMode"), v);
|
||||
try {
|
||||
window.localStorage.setItem(k("themeMode"), v);
|
||||
} catch {
|
||||
// Keep the in-memory selection even when storage is unavailable.
|
||||
}
|
||||
}
|
||||
|
||||
export function resolveEffectiveThemeMode(preference: ThemeModePref, systemPrefersDark: boolean): EffectiveThemeMode {
|
||||
if (preference === "light" || preference === "dark") return preference;
|
||||
return systemPrefersDark ? "dark" : "light";
|
||||
}
|
||||
|
||||
export function subscribeToThemePreferenceChanges(sync: () => void) {
|
||||
const onStorage = (event: StorageEvent) => {
|
||||
if (event.key === "authUserKey" || event.key?.startsWith(THEME_KEY_PREFIX)) sync();
|
||||
};
|
||||
window.addEventListener(AUTH_USER_CHANGED_EVENT, sync);
|
||||
window.addEventListener("storage", onStorage);
|
||||
return () => {
|
||||
window.removeEventListener(AUTH_USER_CHANGED_EVENT, sync);
|
||||
window.removeEventListener("storage", onStorage);
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user