Spaces:
Running
Running
'use client'; | |
import { useTheme } from 'next-themes'; | |
import { SunIcon, MoonIcon, MonitorIcon } from 'lucide-react'; | |
import { useCallback, useEffect, useState } from 'react'; | |
import { Select } from '../SettingsDialog'; | |
type Theme = 'dark' | 'light' | 'system'; | |
const ThemeSwitcher = ({ className }: { className?: string }) => { | |
const [mounted, setMounted] = useState(false); | |
const { theme, setTheme } = useTheme(); | |
const isTheme = useCallback((t: Theme) => t === theme, [theme]); | |
const handleThemeSwitch = (theme: Theme) => { | |
setTheme(theme); | |
}; | |
useEffect(() => { | |
setMounted(true); | |
}, []); | |
useEffect(() => { | |
if (isTheme('system')) { | |
const preferDarkScheme = window.matchMedia( | |
'(prefers-color-scheme: dark)', | |
); | |
const detectThemeChange = (event: MediaQueryListEvent) => { | |
const theme: Theme = event.matches ? 'dark' : 'light'; | |
setTheme(theme); | |
}; | |
preferDarkScheme.addEventListener('change', detectThemeChange); | |
return () => { | |
preferDarkScheme.removeEventListener('change', detectThemeChange); | |
}; | |
} | |
}, [isTheme, setTheme, theme]); | |
// Avoid Hydration Mismatch | |
if (!mounted) { | |
return null; | |
} | |
return ( | |
<Select | |
className={className} | |
value={theme} | |
onChange={(e) => handleThemeSwitch(e.target.value as Theme)} | |
options={[ | |
{ value: 'light', label: 'Light' }, | |
{ value: 'dark', label: 'Dark' }, | |
]} | |
/> | |
); | |
}; | |
export default ThemeSwitcher; | |