blob: b54bda90f77f68f34b85ff799da7cf505181bcf8 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
'use client';
import { useState, useEffect } from 'react';
import { Moon, Sun } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { useTheme } from './ThemeProvider';
export function ThemeToggle() {
const { theme, setTheme } = useTheme();
const [isAnimating, setIsAnimating] = useState(false);
// Track initial mount to prevent animation on first render
const [isMounted, setIsMounted] = useState(false);
useEffect(() => {
setIsMounted(true);
}, []);
const toggleTheme = () => {
if (isAnimating) return;
setIsAnimating(true);
// Set new theme after a small delay for animation
const newTheme = theme === 'dark' ? 'light' : 'dark';
setTimeout(() => {
setTheme(newTheme);
setTimeout(() => {
setIsAnimating(false);
}, 300);
}, 200);
};
if (!isMounted) {
return (
<Button
variant="ghost"
size="icon"
className="opacity-0"
>
<Sun className="h-[1.2rem] w-[1.2rem]" />
</Button>
);
}
return (
<Button
variant="ghost"
size="icon"
onClick={toggleTheme}
className={`relative overflow-hidden hover:bg-muted/80 hover:text-foreground transition-all duration-300 ${isAnimating ? 'cursor-wait' : ''}`}
aria-label={
theme === 'dark'
? 'Switch to light theme'
: 'Switch to dark theme'
}
disabled={isAnimating}
>
<div className={`absolute inset-0 bg-primary/5 rounded-full transition-all duration-500 ${isAnimating ? 'scale-[5] opacity-0' : 'scale-0 opacity-0'}`}></div>
<div className="relative">
{theme === 'dark' ? (
<Sun className={`h-5 w-5 transition-all duration-300 ${isAnimating ? 'rotate-90 scale-50 opacity-0' : 'rotate-0 scale-100 opacity-100'}`} />
) : (
<Moon className={`h-5 w-5 transition-all duration-300 ${isAnimating ? 'rotate-90 scale-50 opacity-0' : 'rotate-0 scale-100 opacity-100'}`} />
)}
</div>
</Button>
);
}
|