This commit is contained in:
2026-02-17 10:06:53 +00:00
parent 4cdd257735
commit 13e8866875
54 changed files with 2537 additions and 76 deletions
@@ -16,6 +16,7 @@ export type UserSettings = {
};
appearance: {
theme: string;
colorTheme: string;
};
languages: {
spoken: string[];
@@ -44,6 +45,7 @@ export const DEFAULT_SETTINGS: UserSettings = {
},
appearance: {
theme: 'light',
colorTheme: 'DuckPond',
},
languages: {
spoken: ['en'],
+36 -20
View File
@@ -1,32 +1,48 @@
import { useEffect, useRef } from 'react';
import { useEffect } from 'react';
import { useTheme } from '@/components/ui/ThemeProvider';
import { useSettings } from './useSettings';
import { DEFAULT_SETTINGS } from './types/user-settings';
const THEME_MODES: Record<string, 'light' | 'dark'> = {
DuckPond: 'light',
TokyoNight: 'dark',
CatppuccinLatte: 'light',
CatppuccinMocha: 'dark',
Everforest: 'dark',
Gruvbox: 'dark',
Kanagawa: 'dark',
MatteBlack: 'dark',
Nord: 'dark',
OsakaJade: 'dark',
Ristretto: 'dark',
RosePine: 'dark',
};
const BG_IMAGES: Record<string, string> = {
DuckPond: 'url(/static/landscape1.jpg)',
};
export const useThemeSync = () => {
const { settings, saveSettings } = useSettings();
const { settings } = useSettings();
const { setTheme } = useTheme();
const migrated = useRef(false);
useEffect(() => {
if (!settings) return;
const colorTheme = settings.appearance.colorTheme ?? 'DuckPond';
const root = document.documentElement;
// One-time migration: if settings are default and localStorage has a theme, save it
if (!migrated.current) {
migrated.current = true;
const lsTheme = localStorage.getItem('officer-theme');
if (
lsTheme &&
settings.appearance.theme === DEFAULT_SETTINGS.appearance.theme &&
lsTheme !== settings.appearance.theme
) {
const updated = { ...settings, appearance: { ...settings.appearance, theme: lsTheme } };
saveSettings(updated);
setTheme(lsTheme);
return;
}
// Set data attribute for CSS scoping (DuckPond uses :root as default)
if (colorTheme === 'DuckPond') {
root.removeAttribute('data-color-theme');
} else {
root.setAttribute('data-color-theme', colorTheme);
}
setTheme(settings.appearance.theme);
}, [settings?.appearance.theme]);
// Set light/dark class based on theme mode
const mode = THEME_MODES[colorTheme] ?? 'light';
setTheme(mode);
// Set background image
const bgImage = BG_IMAGES[colorTheme] ?? 'none';
root.style.setProperty('--page-bg-image', bgImage);
}, [settings?.appearance?.colorTheme]);
};