// CRITICAL 'use client'; import { useEffect } from 'react'; import { Moon, Sun, Monitor } from 'lucide-react'; import { motion, AnimatePresence } from 'framer-motion'; import { useAppStore } from '@/store'; type Theme = 'light' | 'dark' | 'system'; export function ThemeToggle() { const theme = useAppStore((state) => state.themeMode) as Theme; const setThemeMode = useAppStore((state) => state.setThemeMode); const resolvedTheme = useAppStore((state) => state.resolvedTheme); const setResolvedTheme = useAppStore((state) => state.setResolvedTheme); const isOpen = useAppStore((state) => state.themeMenuOpen); const setThemeMenuOpen = useAppStore((state) => state.setThemeMenuOpen); useEffect(() => { // Load saved theme preference const saved = localStorage.getItem('theme') as Theme | null; if (saved) { setThemeMode(saved); } // Determine initial resolved theme const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; const initialTheme = saved === 'system' ? systemTheme : (saved || systemTheme); setResolvedTheme(initialTheme); applyTheme(initialTheme); }, [setResolvedTheme, setThemeMode]); useEffect(() => { // Listen for system theme changes const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); const handleChange = (e: MediaQueryListEvent) => { if (theme === 'system') { const newTheme = e.matches ? 'dark' : 'light'; setResolvedTheme(newTheme); applyTheme(newTheme); } }; mediaQuery.addEventListener('change', handleChange); return () => mediaQuery.removeEventListener('change', handleChange); }, [setResolvedTheme, theme]); const applyTheme = (newTheme: 'light' | 'dark') => { const root = document.documentElement; if (newTheme === 'dark') { root.style.setProperty('--background', '#1a1a1a'); root.style.setProperty('--foreground', '#ededed'); root.style.setProperty('--card', '#242424'); root.style.setProperty('--card-foreground', '#ededed'); root.style.setProperty('--popover', '#242424'); root.style.setProperty('--popover-foreground', '#ededed'); root.style.setProperty('--primary', '#f3f4f6'); root.style.setProperty('--primary-foreground', '#1a1a1a'); root.style.setProperty('--secondary', '#2a2a2a'); root.style.setProperty('--secondary-foreground', '#ededed'); root.style.setProperty('--muted', '#2a2a2a'); root.style.setProperty('--muted-foreground', '#d4d4d4'); root.style.setProperty('--accent', '#2a2a2a'); root.style.setProperty('--accent-foreground', '#f3f4f6'); root.style.setProperty('--destructive', '#7f1d1d'); root.style.setProperty('--destructive-foreground', '#f3f4f6'); root.style.setProperty('--border', '#2a2a2a'); root.style.setProperty('--input', '#2a2a2a'); root.style.setProperty('--ring', '#52525b'); root.style.setProperty('--success', '#22c55e'); root.style.setProperty('--warning', '#eab308'); } else { root.style.setProperty('--background', '#ffffff'); root.style.setProperty('--foreground', '#171717'); root.style.setProperty('--card', '#f5f5f5'); root.style.setProperty('--card-foreground', '#171717'); root.style.setProperty('--popover', '#ffffff'); root.style.setProperty('--popover-foreground', '#171717'); root.style.setProperty('--primary', '#171717'); root.style.setProperty('--primary-foreground', '#fafafa'); root.style.setProperty('--secondary', '#e5e5e5'); root.style.setProperty('--secondary-foreground', '#171717'); root.style.setProperty('--muted', '#f5f5f5'); root.style.setProperty('--muted-foreground', '#737373'); root.style.setProperty('--accent', '#f5f5f5'); root.style.setProperty('--accent-foreground', '#171717'); root.style.setProperty('--destructive', '#dc2626'); root.style.setProperty('--destructive-foreground', '#fafafa'); root.style.setProperty('--border', '#e5e5e5'); root.style.setProperty('--input', '#e5e5e5'); root.style.setProperty('--ring', '#d4d4d8'); root.style.setProperty('--success', '#16a34a'); root.style.setProperty('--warning', '#ca8a04'); } }; const changeTheme = (newTheme: Theme) => { setThemeMode(newTheme); localStorage.setItem('theme', newTheme); setThemeMenuOpen(false); const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; const newResolvedTheme = newTheme === 'system' ? systemTheme : newTheme; setResolvedTheme(newResolvedTheme); applyTheme(newResolvedTheme); }; const themes: { value: Theme; icon: typeof Sun; label: string }[] = [ { value: 'light', icon: Sun, label: 'Light' }, { value: 'dark', icon: Moon, label: 'Dark' }, { value: 'system', icon: Monitor, label: 'System' }, ]; const CurrentIcon = theme === 'light' ? Sun : theme === 'dark' ? Moon : Monitor; return (
setThemeMenuOpen(!isOpen)} className="p-2 rounded-lg hover:bg-[var(--accent)] transition-colors text-[#b0a8a0] hover:text-[var(--foreground)]" title="Toggle theme" > {isOpen && ( <> {/* Backdrop */}
setThemeMenuOpen(false)} /> {/* Menu */}
{themes.map(({ value, icon: Icon, label }) => ( changeTheme(value)} className={`w-full flex items-center gap-3 px-3 py-2 rounded-lg text-sm transition-colors ${ theme === value ? 'bg-[var(--accent)] text-[var(--primary)]' : 'text-[#b0a8a0] hover:text-[var(--foreground)]' }`} > {label} {theme === value && ( )} ))}
)}
); }