/** * Theme utilities for dark/light mode */ export type Theme = 'light' | 'dark'; /** * Get the current theme from localStorage or system preference */ export function getInitialTheme(): Theme { // Check localStorage first const savedTheme = localStorage.getItem('theme') as Theme; if (savedTheme) { return savedTheme; } // Check system preference if (window.matchMedia('(prefers-color-scheme: dark)').matches) { return 'dark'; } // Default to light return 'light'; } /** * Apply theme to document */ export function applyTheme(theme: Theme): void { const root = document.documentElement; if (theme === 'dark') { root.classList.add('dark'); } else { root.classList.remove('dark'); } // Save to localStorage localStorage.setItem('theme', theme); } /** * Initialize theme on page load */ export function initializeTheme(): void { const theme = getInitialTheme(); applyTheme(theme); } /** * Toggle between light and dark themes */ export function toggleTheme(): Theme { const currentTheme = getInitialTheme(); const newTheme = currentTheme === 'light' ? 'dark' : 'light'; applyTheme(newTheme); return newTheme; } /** * Listen for system theme changes */ export function watchSystemTheme(callback: (theme: Theme) => void): () => void { const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); const handleChange = (e: MediaQueryListEvent) => { // Only update if user hasn't set a preference in localStorage if (!localStorage.getItem('theme')) { const theme = e.matches ? 'dark' : 'light'; callback(theme); applyTheme(theme); } }; mediaQuery.addEventListener('change', handleChange); // Return cleanup function return () => mediaQuery.removeEventListener('change', handleChange); }