Openstatus
www.openstatus.dev
1"use client";
2
3import { cn } from "@/lib/utils";
4import { Laptop, Moon, Sun } from "lucide-react";
5import { useTheme } from "next-themes";
6import type * as React from "react";
7import { useEffect, useState } from "react";
8
9export function ThemeToggle({
10 className,
11 ...props
12}: React.ComponentProps<"div">) {
13 const { setTheme, theme } = useTheme();
14 const [mounted, setMounted] = useState(false);
15
16 useEffect(() => {
17 setMounted(true);
18 }, []);
19
20 if (!mounted) {
21 return (
22 <div
23 className={cn(
24 "flex items-center gap-px bg-border [&>*]:flex [&>*]:flex-1 [&>*]:items-center [&>*]:justify-center [&>*]:bg-background [&>*]:p-4",
25 className,
26 )}
27 {...props}
28 >
29 <div>
30 <Sun className="h-6 w-6" />
31 </div>
32 <div>
33 <Moon className="h-6 w-6" />
34 </div>
35 <div>
36 <Laptop className="h-6 w-6" />
37 </div>
38 </div>
39 );
40 }
41
42 return (
43 <div
44 className={cn(
45 "flex items-center gap-px bg-border [&>*]:flex [&>*]:flex-1 [&>*]:items-center [&>*]:justify-center [&>*]:bg-background [&>*]:p-4 [&>*]:hover:bg-muted [&>*]:data-[active=true]:bg-muted",
46 className,
47 )}
48 {...props}
49 >
50 <button
51 type="button"
52 data-active={theme === "light"}
53 onClick={() => setTheme("light")}
54 >
55 [light]
56 </button>
57 <button
58 type="button"
59 data-active={theme === "dark"}
60 onClick={() => setTheme("dark")}
61 >
62 [dark]
63 </button>
64 <button
65 type="button"
66 data-active={theme === "system"}
67 onClick={() => setTheme("system")}
68 >
69 [system]
70 </button>
71 </div>
72 );
73}