'use client'; import { useEffect, useState } from 'react'; import { ChevronsUpDownIcon, Monitor, Moon, Sun } from 'lucide-react'; import { useTheme } from 'next-themes'; import { DropdownMenu, DropdownMenuContent, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; import { Button } from '@/components/ui/button'; import { cn } from '@/lib/utils'; interface ThemeToggleProps { className?: string; compact?: boolean; menuSide?: 'top' | 'right' | 'bottom' | 'left'; menuAlign?: 'start' | 'center' | 'end'; } type ThemeMode = 'light' | 'dark' | 'system'; const THEME_OPTIONS: Array<{ value: ThemeMode; label: string; icon: typeof Sun; }> = [ { value: 'dark', label: 'Dark', icon: Moon }, { value: 'light', label: 'Light', icon: Sun }, { value: 'system', label: 'System', icon: Monitor }, ]; function isThemeMode(value: string | undefined): value is ThemeMode { return value === 'light' || value === 'dark' || value === 'system'; } function getThemeOption(theme: ThemeMode) { return ( THEME_OPTIONS.find((option) => option.value === theme) ?? THEME_OPTIONS[2] ); } export function ThemeToggle({ className, compact = false, menuSide = 'bottom', menuAlign = 'end', }: ThemeToggleProps) { const { setTheme, theme } = useTheme(); const [mounted, setMounted] = useState(false); const [fallbackTheme, setFallbackTheme] = useState('system'); useEffect(() => { setMounted(true); }, []); useEffect(() => { if (isThemeMode(theme)) { setFallbackTheme(theme); } }, [theme]); const activeTheme = mounted && isThemeMode(theme) ? theme : fallbackTheme; const activeOption = getThemeOption(activeTheme); const ActiveIcon = activeOption.icon; return ( { if (!isThemeMode(value)) return; setTheme(value); }} > {THEME_OPTIONS.map((option) => { const Icon = option.icon; return ( {option.label} ); })} ); }