Openstatus www.openstatus.dev
at 4c0f4c00a38753a5d0dfd7e7b7b7706dec6f1503 67 lines 1.8 kB view raw
1"use client"; 2 3import { useTheme } from "next-themes"; 4import type * as React from "react"; 5 6import { 7 Select, 8 SelectContent, 9 SelectItem, 10 SelectTrigger, 11 SelectValue, 12} from "@/components/ui/select"; 13import { cn } from "@/lib/utils"; 14import { Laptop, Moon, Sun } from "lucide-react"; 15import { useState } from "react"; 16import { useEffect } from "react"; 17 18export function ThemeToggle({ 19 className, 20 ...props 21}: React.ComponentProps<typeof SelectTrigger>) { 22 const { setTheme, theme } = useTheme(); 23 const [mounted, setMounted] = useState(false); 24 25 useEffect(() => { 26 setMounted(true); 27 }, []); 28 29 // NOTE: hydration error if we don't do this 30 if (!mounted) { 31 return ( 32 <Select> 33 <SelectTrigger className={cn("w-[180px]", className)} {...props}> 34 <SelectValue placeholder="Select theme" /> 35 </SelectTrigger> 36 </Select> 37 ); 38 } 39 40 return ( 41 <Select value={theme} onValueChange={setTheme}> 42 <SelectTrigger className={cn("w-[180px]", className)} {...props}> 43 <SelectValue defaultValue={theme} placeholder="Select theme" /> 44 </SelectTrigger> 45 <SelectContent> 46 <SelectItem value="light"> 47 <div className="flex items-center gap-2"> 48 <Sun className="h-4 w-4" /> 49 <span>Light</span> 50 </div> 51 </SelectItem> 52 <SelectItem value="dark"> 53 <div className="flex items-center gap-2"> 54 <Moon className="h-4 w-4" /> 55 <span>Dark</span> 56 </div> 57 </SelectItem> 58 <SelectItem value="system"> 59 <div className="flex items-center gap-2"> 60 <Laptop className="h-4 w-4" /> 61 <span>System</span> 62 </div> 63 </SelectItem> 64 </SelectContent> 65 </Select> 66 ); 67}