'use client'; import { Button, type ButtonProps } from '@/components/ui/button'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; import { Skeleton } from '@/components/ui/skeleton'; import { MoonIcon, SunIcon } from 'lucide-react'; import { useTheme } from 'next-themes'; import { useCallback, useEffect, useState } from 'react'; /** * Props for the ThemeToggle component. */ interface ThemeToggleProps { /** The variant of the button. */ variant?: ButtonProps['variant']; /** The size of the button. */ size?: ButtonProps['size']; /** Additional CSS classes to apply to the button. */ className?: string; } /** * Mapping of button sizes to skeleton sizes. */ const skeletonSizes = { icon: 'h-10 w-10', default: 'h-10 w-16', sm: 'h-9 w-14', lg: 'h-11 w-20', } as const; /** * A component that allows users to toggle between different theme options. * @param props - The component props. * @returns A dropdown menu for theme selection. */ export function ThemeToggle({ variant = 'outline', size = 'icon', className }: ThemeToggleProps) { const { setTheme, resolvedTheme, themes } = useTheme(); const [mounted, setMounted] = useState(false); /** * Handles setting a new theme. * @param newTheme - The new theme to set. */ const handleSetTheme = useCallback( (newTheme: string) => { setTheme(newTheme); }, [setTheme] ); useEffect(() => { setMounted(true); }, []); if (!mounted) { const skeletonSize = skeletonSizes[size as keyof typeof skeletonSizes] || skeletonSizes.icon; return ; } return ( {themes.map((theme) => ( handleSetTheme(theme)} className="capitalize"> {theme} ))} ); }