86 lines
2.3 KiB
TypeScript
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>
|
|
);
|
|
}
|