|
1 | 1 | import { useTheme } from "next-themes";
|
2 | 2 | import { cn } from "../lib/utils";
|
3 | 3 | import { SVGProps, useEffect, useRef, useState } from "react";
|
| 4 | +import { useIsMount } from "../hooks/useIsMount"; |
4 | 5 |
|
5 | 6 | export default function ThemeToggle() {
|
6 | 7 | const { theme, setTheme } = useTheme();
|
7 |
| - const [CurrentTheme, setCurrentTheme] = useState<string | undefined>(); |
8 |
| - useEffect(() => { |
9 |
| - setCurrentTheme(theme); |
10 |
| - }, [theme]); |
| 8 | + const isMount = useIsMount() |
| 9 | + |
| 10 | + if (!isMount) return null; |
11 | 11 |
|
12 |
| - function getClasses(isCurrentTheme: boolean) { |
13 |
| - return cn( |
14 |
| - "rounded-full p-2", |
15 |
| - isCurrentTheme |
16 |
| - ? "bg-primary text-primary-foreground" |
17 |
| - : "hover:bg-accent hover:text-accent-foreground" |
18 |
| - ); |
19 |
| - } |
20 | 12 | return (
|
21 | 13 | <div className="flex items-center gap-2 p-1 rounded-full border bg-background text-foreground w-fit">
|
22 |
| - <button |
23 |
| - onClick={() => setTheme("light")} |
24 |
| - aria-label="Toggle light theme" |
25 |
| - className={getClasses(CurrentTheme == "light")} |
26 |
| - > |
27 |
| - <SunIcon className="size-5" /> |
28 |
| - </button> |
29 |
| - <button |
30 |
| - onClick={() => setTheme("dark")} |
31 |
| - aria-label="Toggle dark theme" |
32 |
| - className={getClasses(CurrentTheme == "dark")} |
33 |
| - > |
34 |
| - <MoonIcon className="size-5" /> |
35 |
| - </button> |
36 |
| - <button |
37 |
| - onClick={() => setTheme("system")} |
38 |
| - aria-label="Toggle system theme" |
39 |
| - className={getClasses(CurrentTheme == "system")} |
40 |
| - > |
41 |
| - <MonitorIcon className="size-5" /> |
42 |
| - </button> |
| 14 | + {( |
| 15 | + [ |
| 16 | + ["light", SunIcon], |
| 17 | + ["dark", MoonIcon], |
| 18 | + ["system", MonitorIcon], |
| 19 | + ] as const |
| 20 | + ).map(([themeN, Icon]) => ( |
| 21 | + <button |
| 22 | + className={cn( |
| 23 | + "rounded-full p-2", |
| 24 | + theme == themeN |
| 25 | + ? "bg-primary text-primary-foreground" |
| 26 | + : "hover:bg-accent hover:text-accent-foreground" |
| 27 | + )} |
| 28 | + aria-selected={theme == themeN || undefined} |
| 29 | + onClick={() => setTheme(themeN)} |
| 30 | + aria-label={`set ${themeN} theme`} |
| 31 | + > |
| 32 | + <Icon className="size-5" /> |
| 33 | + </button> |
| 34 | + ))} |
43 | 35 | </div>
|
44 | 36 | );
|
45 | 37 | }
|
|
0 commit comments