feat: add dark/light theme toggle with system preference support (#18)

Add theme switching with three modes (system/light/dark) using Tailwind v4
class-based dark mode. Theme preference is persisted in localStorage and
defaults to the system's prefers-color-scheme. All components updated with
dark: variants for consistent dark mode rendering including SVG elements.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
shahondin1624
2026-03-12 12:54:04 +01:00
parent 79c14378a2
commit 60f3d8eeda
22 changed files with 418 additions and 181 deletions

View File

@@ -0,0 +1,86 @@
export type ThemeMode = 'light' | 'dark' | 'system';
const STORAGE_KEY = 'llm-multiverse-theme';
function createThemeStore() {
let mode: ThemeMode = $state('system');
let resolvedDark = $state(false);
function applyTheme(isDark: boolean) {
if (typeof document === 'undefined') return;
const root = document.documentElement;
// Add transition class for smooth switching
root.classList.add('theme-transition');
if (isDark) {
root.classList.add('dark');
} else {
root.classList.remove('dark');
}
// Remove transition class after animation completes
setTimeout(() => {
root.classList.remove('theme-transition');
}, 300);
}
function getSystemPreference(): boolean {
if (typeof window === 'undefined') return false;
return window.matchMedia('(prefers-color-scheme: dark)').matches;
}
function init() {
if (typeof window === 'undefined') return;
// Load saved preference
const saved = localStorage.getItem(STORAGE_KEY) as ThemeMode | null;
if (saved === 'light' || saved === 'dark' || saved === 'system') {
mode = saved;
} else {
mode = 'system';
}
// Listen for system preference changes
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
mediaQuery.addEventListener('change', (e) => {
if (mode === 'system') {
resolvedDark = e.matches;
applyTheme(resolvedDark);
}
});
// Apply initial theme
resolvedDark =
mode === 'dark' ? true : mode === 'light' ? false : getSystemPreference();
applyTheme(resolvedDark);
}
function setMode(newMode: ThemeMode) {
mode = newMode;
if (typeof window !== 'undefined') {
localStorage.setItem(STORAGE_KEY, newMode);
}
resolvedDark =
newMode === 'dark' ? true : newMode === 'light' ? false : getSystemPreference();
applyTheme(resolvedDark);
}
function cycle() {
const order: ThemeMode[] = ['system', 'light', 'dark'];
const idx = order.indexOf(mode);
const next = order[(idx + 1) % order.length];
setMode(next);
}
return {
get mode() {
return mode;
},
get isDark() {
return resolvedDark;
},
init,
setMode,
cycle
};
}
export const themeStore = createThemeStore();