68 lines
1.6 KiB
TypeScript
68 lines
1.6 KiB
TypeScript
export const UI_THEME_STORAGE_KEY = "dashboard-ui-theme";
|
|
|
|
export type UiTheme = "dark" | "light";
|
|
|
|
type ReadableThemeStorage =
|
|
| { getItem(key: string): string | null }
|
|
| { get(key: string): string | undefined };
|
|
|
|
type WritableThemeStorage =
|
|
| { setItem(key: string, value: string): void }
|
|
| { set(key: string, value: string): unknown };
|
|
|
|
export function isUiTheme(value: unknown): value is UiTheme {
|
|
return value === "dark" || value === "light";
|
|
}
|
|
|
|
export function getNextUiTheme(theme: UiTheme): UiTheme {
|
|
return theme === "dark" ? "light" : "dark";
|
|
}
|
|
|
|
export function resolveInitialUiTheme(
|
|
storage?: ReadableThemeStorage | null,
|
|
fallback: UiTheme = "dark",
|
|
): UiTheme {
|
|
const stored = safeReadStoredTheme(storage);
|
|
|
|
return isUiTheme(stored) ? stored : fallback;
|
|
}
|
|
|
|
export function persistUiTheme(
|
|
theme: UiTheme,
|
|
storage?: WritableThemeStorage | null,
|
|
): void {
|
|
if (!storage) return;
|
|
|
|
try {
|
|
if ("setItem" in storage) {
|
|
storage.setItem(UI_THEME_STORAGE_KEY, theme);
|
|
return;
|
|
}
|
|
|
|
storage.set(UI_THEME_STORAGE_KEY, theme);
|
|
} catch {
|
|
// Browser storage may be blocked or quota-constrained.
|
|
}
|
|
}
|
|
|
|
function safeReadStoredTheme(
|
|
storage?: ReadableThemeStorage | null,
|
|
): string | undefined {
|
|
try {
|
|
return readStoredTheme(storage);
|
|
} catch {
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
function readStoredTheme(
|
|
storage?: ReadableThemeStorage | null,
|
|
): string | undefined {
|
|
if (!storage) return undefined;
|
|
|
|
if ("getItem" in storage) {
|
|
return storage.getItem(UI_THEME_STORAGE_KEY) ?? undefined;
|
|
}
|
|
|
|
return storage.get(UI_THEME_STORAGE_KEY);
|
|
}
|