aboutsummaryrefslogtreecommitdiffstats
path: root/frontend/src/components/shared/ThemeToggle.tsx
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>
  );
}