52 lines
1.3 KiB
TypeScript
52 lines
1.3 KiB
TypeScript
'use client'
|
|
|
|
import { useEffect, useSyncExternalStore } from 'react'
|
|
import { Button } from '@/components/ui/button'
|
|
import { Moon, Sun } from 'lucide-react'
|
|
|
|
type Theme = 'light' | 'dark'
|
|
|
|
function getSnapshot(): Theme {
|
|
const saved = localStorage.getItem('theme')
|
|
if (saved === 'dark' || saved === 'light') return saved
|
|
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
|
|
}
|
|
|
|
function getServerSnapshot(): Theme {
|
|
return 'light'
|
|
}
|
|
|
|
function subscribe(cb: () => void): () => void {
|
|
window.addEventListener('storage', cb)
|
|
return () => window.removeEventListener('storage', cb)
|
|
}
|
|
|
|
export default function ThemeToggle() {
|
|
const theme = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot)
|
|
|
|
useEffect(() => {
|
|
document.documentElement.classList.toggle('dark', theme === 'dark')
|
|
}, [theme])
|
|
|
|
function toggleTheme() {
|
|
const next: Theme = theme === 'dark' ? 'light' : 'dark'
|
|
localStorage.setItem('theme', next)
|
|
window.dispatchEvent(new StorageEvent('storage', { key: 'theme', newValue: next }))
|
|
}
|
|
|
|
return (
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
onClick={toggleTheme}
|
|
suppressHydrationWarning
|
|
aria-label="Tema değiştir"
|
|
>
|
|
{theme === 'dark'
|
|
? <Sun className="size-4" />
|
|
: <Moon className="size-4" />}
|
|
</Button>
|
|
)
|
|
}
|
|
|