-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy paththeme.ts
More file actions
84 lines (65 loc) · 2.53 KB
/
theme.ts
File metadata and controls
84 lines (65 loc) · 2.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
export const THEME_STORAGE_KEY = 'nullclaw_ui_theme';
export const EFFECTS_STORAGE_KEY = 'nullclaw_ui_effects';
export const SUPPORTED_THEMES = ['matrix', 'dracula', 'synthwave', 'amber', 'light'] as const;
export type ThemeName = (typeof SUPPORTED_THEMES)[number];
export const THEME_OPTIONS: Array<{ value: ThemeName; label: string }> = [
{ value: 'matrix', label: 'Matrix' },
{ value: 'dracula', label: 'Dracula' },
{ value: 'synthwave', label: 'Synthwave' },
{ value: 'amber', label: 'Amber' },
{ value: 'light', label: 'Light Mode' },
];
const THEME_CLASS_PREFIX = 'theme-';
const THEME_CLASS_NAMES = new Set(SUPPORTED_THEMES.map((theme) => `${THEME_CLASS_PREFIX}${theme}`));
function getStorage(): Storage | null {
if (typeof localStorage === 'undefined') return null;
return localStorage;
}
export function isThemeName(value: string): value is ThemeName {
return SUPPORTED_THEMES.includes(value as ThemeName);
}
export function coerceTheme(value: string, fallback: ThemeName = 'matrix'): ThemeName {
return isThemeName(value) ? value : fallback;
}
export function loadTheme(fallback: ThemeName = 'matrix'): ThemeName {
const storage = getStorage();
if (!storage) return fallback;
const storedTheme = storage.getItem(THEME_STORAGE_KEY);
if (!storedTheme) return fallback;
return coerceTheme(storedTheme, fallback);
}
export function saveTheme(theme: ThemeName) {
const storage = getStorage();
if (!storage) return;
storage.setItem(THEME_STORAGE_KEY, theme);
}
export function applyTheme(theme: ThemeName) {
if (typeof document === 'undefined') return;
for (const className of Array.from(document.body.classList)) {
if (THEME_CLASS_NAMES.has(className)) {
document.body.classList.remove(className);
}
}
document.body.classList.add(`${THEME_CLASS_PREFIX}${theme}`);
}
export function loadEffectsEnabled(fallback: boolean = false): boolean {
const storage = getStorage();
if (!storage) return fallback;
const stored = storage.getItem(EFFECTS_STORAGE_KEY);
if (stored === null) return fallback;
if (stored !== 'true' && stored !== 'false') return fallback;
return stored === 'true';
}
export function saveEffectsEnabled(enabled: boolean) {
const storage = getStorage();
if (!storage) return;
storage.setItem(EFFECTS_STORAGE_KEY, String(enabled));
}
export function applyEffectsEnabled(enabled: boolean) {
if (typeof document === 'undefined') return;
if (enabled) {
document.body.classList.remove('effects-disabled');
} else {
document.body.classList.add('effects-disabled');
}
}