86 lines
2.3 KiB
TypeScript

import { useState, useEffect } from 'react';
import { Sun, Moon, Monitor } from 'lucide-react';
import { Button } from '@/components/ui/button';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
type Theme = 'light' | 'dark' | 'system';
export default function ThemeToggle() {
const [theme, setTheme] = useState<Theme>('system');
useEffect(() => {
const stored = localStorage.getItem('theme') as Theme | null;
if (stored) {
setTheme(stored);
}
}, []);
useEffect(() => {
const root = document.documentElement;
function applyTheme(t: Theme) {
if (t === 'dark') {
root.classList.add('dark');
} else if (t === 'light') {
root.classList.remove('dark');
} else {
// system
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
root.classList.add('dark');
} else {
root.classList.remove('dark');
}
}
}
applyTheme(theme);
if (theme === 'system') {
localStorage.removeItem('theme');
const mq = window.matchMedia('(prefers-color-scheme: dark)');
const handler = () => applyTheme('system');
mq.addEventListener('change', handler);
return () => mq.removeEventListener('change', handler);
} else {
localStorage.setItem('theme', theme);
}
}, [theme]);
const icon = theme === 'dark' ? (
<Moon className="h-4 w-4" />
) : theme === 'light' ? (
<Sun className="h-4 w-4" />
) : (
<Monitor className="h-4 w-4" />
);
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" className="h-8 w-8" aria-label="Toggle theme">
{icon}
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => setTheme('light')}>
<Sun className="h-4 w-4" />
Light
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme('dark')}>
<Moon className="h-4 w-4" />
Dark
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme('system')}>
<Monitor className="h-4 w-4" />
System
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
}