fix(theme): persist one canonical preference
This commit is contained in:
@@ -1,19 +1,16 @@
|
||||
import { AUTH_USER_CHANGED_EVENT, getAuthUserKey } from "./auth";
|
||||
import { getAuthUserKey } from "./auth";
|
||||
|
||||
export type ThemeModePref = "system" | "light" | "dark";
|
||||
export type EffectiveThemeMode = "light" | "dark";
|
||||
|
||||
export const DEFAULT_THEME_MODE: ThemeModePref = "system";
|
||||
export const THEME_MODE_KEY = "jobtracker.themeMode";
|
||||
const THEME_KEY_PREFIX = "themeMode:";
|
||||
|
||||
export function getUserKeyFromToken(): string {
|
||||
return getAuthUserKey();
|
||||
}
|
||||
|
||||
function k(base: string) {
|
||||
return `${base}:${getUserKeyFromToken()}`;
|
||||
}
|
||||
|
||||
function readThemeMode(key: string): ThemeModePref | null {
|
||||
try {
|
||||
const raw = window.localStorage.getItem(key);
|
||||
@@ -24,19 +21,28 @@ function readThemeMode(key: string): ThemeModePref | null {
|
||||
}
|
||||
|
||||
export function getThemeModePref(): ThemeModePref {
|
||||
const savedMode = readThemeMode(THEME_MODE_KEY);
|
||||
if (savedMode) return savedMode;
|
||||
|
||||
// Migrate the former account-scoped values once. Theme is a browser UI
|
||||
// preference, so changing auth state must never change the visible scheme.
|
||||
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;
|
||||
const legacyMode = savedUserMode ?? (userKey !== "anon" ? readThemeMode(`${THEME_KEY_PREFIX}anon`) : null);
|
||||
if (legacyMode) {
|
||||
try {
|
||||
window.localStorage.setItem(THEME_MODE_KEY, legacyMode);
|
||||
} catch {
|
||||
// The migrated value still applies for this render when storage is unavailable.
|
||||
}
|
||||
return legacyMode;
|
||||
}
|
||||
return DEFAULT_THEME_MODE;
|
||||
}
|
||||
|
||||
export function setThemeModePref(v: ThemeModePref) {
|
||||
try {
|
||||
window.localStorage.setItem(k("themeMode"), v);
|
||||
window.localStorage.setItem(THEME_MODE_KEY, v);
|
||||
} catch {
|
||||
// Keep the in-memory selection even when storage is unavailable.
|
||||
}
|
||||
@@ -49,12 +55,10 @@ export function resolveEffectiveThemeMode(preference: ThemeModePref, systemPrefe
|
||||
|
||||
export function subscribeToThemePreferenceChanges(sync: () => void) {
|
||||
const onStorage = (event: StorageEvent) => {
|
||||
if (event.key === "authUserKey" || event.key?.startsWith(THEME_KEY_PREFIX)) sync();
|
||||
if (event.key === THEME_MODE_KEY) 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