File size: 2,301 Bytes
557ab38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
70
71
72
73
74
75
/**
 * ThemeToggle — a moon/sun rendered as ink strokes, not a Material icon.
 * Deliberately hand-drawn feel: the moon has a slight crescent bite, the sun
 * has four short rays. Both drawn with strokeLinecap="round".
 */
import { motion } from "motion/react";

import { useTheme } from "@/hooks/useTheme";

export function ThemeToggle() {
  const { theme, toggle } = useTheme();
  const dark = theme === "dark";

  return (
    <button
      type="button"
      onClick={toggle}
      aria-label={`Switch to ${dark ? "light" : "dark"} mode`}
      className="group relative h-9 w-9 rounded-full border border-[var(--rule)] bg-[var(--surface)] transition-colors duration-500 ease-editorial hover:border-[var(--ink)]"
    >
      <motion.span
        key={theme}
        initial={{ rotate: -30, opacity: 0 }}
        animate={{ rotate: 0, opacity: 1 }}
        transition={{ duration: 0.5, ease: [0.16, 1, 0.3, 1] }}
        className="pointer-events-none absolute inset-0 flex items-center justify-center"
      >
        {dark ? <Moon /> : <Sun />}
      </motion.span>
    </button>
  );
}

function Sun() {
  return (
    <svg width="18" height="18" viewBox="0 0 20 20" fill="none" aria-hidden="true">
      <circle cx="10" cy="10" r="3.4" stroke="currentColor" strokeWidth="1.2" />
      {[0, 45, 90, 135, 180, 225, 270, 315].map((deg) => {
        const rad = (deg * Math.PI) / 180;
        const x1 = 10 + Math.cos(rad) * 6;
        const y1 = 10 + Math.sin(rad) * 6;
        const x2 = 10 + Math.cos(rad) * 7.8;
        const y2 = 10 + Math.sin(rad) * 7.8;
        return (
          <line
            key={deg}
            x1={x1}
            y1={y1}
            x2={x2}
            y2={y2}
            stroke="currentColor"
            strokeWidth="1.2"
            strokeLinecap="round"
          />
        );
      })}
    </svg>
  );
}

function Moon() {
  // A crescent drawn as one path — feels like a pen stroke, not an icon.
  return (
    <svg width="18" height="18" viewBox="0 0 20 20" fill="none" aria-hidden="true">
      <path
        d="M15 12.5A6 6 0 0 1 7.5 5c0-.5.06-.98.17-1.44A6 6 0 1 0 16.44 12.33c-.46.11-.94.17-1.44.17Z"
        stroke="currentColor"
        strokeWidth="1.2"
        strokeLinejoin="round"
        strokeLinecap="round"
      />
    </svg>
  );
}