aboutsummaryrefslogtreecommitdiffstats
path: root/frontend/src/components/shared/ThemeToggle.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/components/shared/ThemeToggle.tsx')
-rw-r--r--frontend/src/components/shared/ThemeToggle.tsx53
1 files changed, 43 insertions, 10 deletions
diff --git a/frontend/src/components/shared/ThemeToggle.tsx b/frontend/src/components/shared/ThemeToggle.tsx
index 679bbc5..b54bda9 100644
--- a/frontend/src/components/shared/ThemeToggle.tsx
+++ b/frontend/src/components/shared/ThemeToggle.tsx
@@ -1,36 +1,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 (theme === 'dark') {
- setTheme('light');
- } else {
- setTheme('dark');
- }
+ 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}
>
- {theme === 'dark' ? (
- <Sun className="h-[1.2rem] w-[1.2rem]" />
- ) : (
- <Moon className="h-[1.2rem] w-[1.2rem]" />
- )}
+ <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>
);
} \ No newline at end of file