70 lines
1.9 KiB
TypeScript
70 lines
1.9 KiB
TypeScript
'use client'
|
|
|
|
import { useEffect, useState } from 'react'
|
|
import { useTheme } from 'next-themes'
|
|
|
|
export function ThemeToggle() {
|
|
const [mounted, setMounted] = useState(false)
|
|
const { theme, setTheme } = useTheme()
|
|
const [isGlitching, setIsGlitching] = useState(false)
|
|
|
|
useEffect(() => {
|
|
setMounted(true)
|
|
}, [])
|
|
|
|
const toggleTheme = () => {
|
|
// Trigger glitch animation
|
|
setIsGlitching(true)
|
|
|
|
// Trigger screen flicker
|
|
document.body.classList.add('screen-flicker')
|
|
|
|
// Toggle theme
|
|
setTheme(theme === 'dark' ? 'light' : 'dark')
|
|
|
|
// Remove effects after animation
|
|
setTimeout(() => {
|
|
setIsGlitching(false)
|
|
document.body.classList.remove('screen-flicker')
|
|
}, 300)
|
|
}
|
|
|
|
if (!mounted) {
|
|
return (
|
|
<button className="font-mono text-xs text-slate-400 uppercase tracking-wider px-3 py-1 border-2 border-slate-700">
|
|
[...]
|
|
</button>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<button
|
|
onClick={toggleTheme}
|
|
className={`
|
|
relative font-mono text-xs uppercase tracking-wider
|
|
px-3 py-1 border-2 transition-all duration-300
|
|
${
|
|
theme === 'dark'
|
|
? 'text-cyan-400 border-cyan-900 hover:border-cyan-700 bg-cyan-950/20'
|
|
: 'text-emerald-600 border-emerald-700 hover:border-emerald-500 bg-emerald-50/50'
|
|
}
|
|
${isGlitching ? 'glitch-btn' : ''}
|
|
border-pulse overflow-hidden
|
|
`}
|
|
aria-label="Toggle theme"
|
|
>
|
|
<span className="relative z-10">{theme === 'dark' ? '[DARK MODE]' : '[LIGHT MODE]'}</span>
|
|
{isGlitching && (
|
|
<>
|
|
<span className="glitch-layer" aria-hidden="true">
|
|
{theme === 'dark' ? '[DARK MODE]' : '[LIGHT MODE]'}
|
|
</span>
|
|
<span className="glitch-layer" aria-hidden="true">
|
|
{theme === 'dark' ? '[DARK MODE]' : '[LIGHT MODE]'}
|
|
</span>
|
|
</>
|
|
)}
|
|
</button>
|
|
)
|
|
}
|