83 lines
2.2 KiB
TypeScript
83 lines
2.2 KiB
TypeScript
"use client"
|
|
|
|
import { Moon, Sun } from "lucide-react"
|
|
import { useTheme } from "next-themes"
|
|
|
|
import { cn } from "@/lib/utils"
|
|
import { useEffect, useState } from "react"
|
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../ui/select"
|
|
|
|
const modes = ["light", "dark"] as const
|
|
const accents = ["zinc", "red", "rose", "orange", "green", "blue", "yellow", "violet", "default"] as const
|
|
|
|
const modeIcons = {
|
|
light: <Sun className="h-4 w-4" />,
|
|
dark: <Moon className="h-4 w-4" />,
|
|
}
|
|
|
|
export default function ModeToggle() {
|
|
const { setTheme, theme, resolvedTheme } = useTheme()
|
|
const [mode, setMode] = useState("dark")
|
|
const [accent, setAccent] = useState("violet")
|
|
|
|
useEffect(() => {
|
|
const parts = theme?.split("-")
|
|
if (parts?.length === 2) {
|
|
setMode(parts[0])
|
|
setAccent(parts[1])
|
|
}
|
|
}, [theme])
|
|
|
|
function updateTheme(newMode: string, newAccent: string) {
|
|
const fullTheme = `${newMode}-${newAccent}`
|
|
setTheme(fullTheme)
|
|
}
|
|
|
|
return (
|
|
<div className="flex gap-4 items-center">
|
|
<Select
|
|
value={mode}
|
|
onValueChange={(value) => {
|
|
setMode(value)
|
|
updateTheme(value, accent)
|
|
}}
|
|
>
|
|
<SelectTrigger className="w-[70px]">
|
|
<SelectValue
|
|
placeholder="Mode"
|
|
className="flex items-center gap-2"
|
|
/>
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{modes.map((m) => (
|
|
<SelectItem key={m} value={m}>
|
|
<span className="flex items-center gap-2">
|
|
{modeIcons[m]}
|
|
</span>
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
|
|
<Select
|
|
value={accent}
|
|
onValueChange={(value) => {
|
|
setAccent(value)
|
|
updateTheme(mode, value)
|
|
}}
|
|
>
|
|
<SelectTrigger className="w-[120px]">
|
|
<SelectValue placeholder="Accent" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{accents.map((a) => (
|
|
<SelectItem key={a} value={a} className={cn(`text-${a}-600`)}>
|
|
{a.charAt(0).toUpperCase() + a.slice(1)}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
)
|
|
}
|