'use client' import * as React from 'react' import { createContext, useContext, useEffect, useState, useCallback } from 'react' import { Sun, Moon, Monitor, ChevronDown } from 'lucide-react' import { Button } from '@/components/ui/button' import { cn } from '@/lib/utils' type Theme = 'light' | 'dark' | 'system' interface ThemeContextType { theme: Theme setTheme: (theme: Theme) => void resolvedTheme: 'light' | 'dark' } const ThemeContext = createContext(undefined) export function ThemeProvider({ children }: { children: React.ReactNode }) { const [theme, setTheme] = useState('system') const [resolvedTheme, setResolvedTheme] = useState<'light' | 'dark'>('dark') const [mounted, setMounted] = useState(false) // Initialize from localStorage useEffect(() => { const stored = localStorage.getItem('theme') as Theme | null if (stored) { setTheme(stored) } setMounted(true) }, []) // Apply theme to document useEffect(() => { if (!mounted) return const root = document.documentElement let resolved: 'light' | 'dark' if (theme === 'system') { resolved = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' } else { resolved = theme } setResolvedTheme(resolved) root.classList.remove('light', 'dark') root.classList.add(resolved) root.style.colorScheme = resolved localStorage.setItem('theme', theme) }, [theme, mounted]) // Listen for system theme changes useEffect(() => { if (!mounted || theme !== 'system') return const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)') const handleChange = () => { const resolved = mediaQuery.matches ? 'dark' : 'light' setResolvedTheme(resolved) document.documentElement.classList.remove('light', 'dark') document.documentElement.classList.add(resolved) document.documentElement.style.colorScheme = resolved } mediaQuery.addEventListener('change', handleChange) return () => mediaQuery.removeEventListener('change', handleChange) }, [theme, mounted]) const setThemeCallback = useCallback((newTheme: Theme) => { setTheme(newTheme) }, []) if (!mounted) { return ( {}, resolvedTheme: 'dark' }}> {children} ) } return ( {children} ) } export function useTheme() { const context = useContext(ThemeContext) if (!context) { throw new Error('useTheme must be used within a ThemeProvider') } return context } export function ThemeToggle() { const { theme, setTheme, resolvedTheme } = useTheme() const themes: { value: Theme; label: string; icon: React.ReactNode }[] = [ { value: 'light', label: 'Light', icon: }, { value: 'dark', label: 'Dark', icon: }, { value: 'system', label: 'System', icon: }, ] return (
{/* Tooltip */}
Theme: {theme.charAt(0).toUpperCase() + theme.slice(1)}
) }