56 lines
1.6 KiB
TypeScript
56 lines
1.6 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { Moon, Sun } from "lucide-react";
|
|
import { useTheme } from "@/components/theme-provider";
|
|
import type { ThemeMode } from "@/lib/theme";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
interface ThemeToggleProps {
|
|
className?: string;
|
|
compact?: boolean;
|
|
}
|
|
|
|
export function ThemeToggle({ className, compact }: ThemeToggleProps) {
|
|
const { theme, setTheme } = useTheme();
|
|
const [mounted, setMounted] = useState(false);
|
|
|
|
useEffect(() => {
|
|
setMounted(true);
|
|
}, []);
|
|
|
|
return (
|
|
<div
|
|
className={cn(
|
|
"inline-flex rounded-lg border border-border bg-muted p-0.5",
|
|
className
|
|
)}
|
|
role="group"
|
|
aria-label="外觀模式"
|
|
>
|
|
{(["light", "dark"] as ThemeMode[]).map((mode) => {
|
|
const active = mounted && theme === mode;
|
|
const label = mode === "light" ? "淺色" : "深色";
|
|
const Icon = mode === "light" ? Sun : Moon;
|
|
return (
|
|
<button
|
|
key={mode}
|
|
type="button"
|
|
onClick={() => setTheme(mode)}
|
|
className={cn(
|
|
"inline-flex items-center justify-center gap-1.5 rounded-md text-[12px] font-medium transition-colors",
|
|
compact ? "h-8 px-2.5" : "h-9 px-3.5",
|
|
active
|
|
? "bg-card text-foreground shadow-sm"
|
|
: "text-muted-foreground hover:text-foreground"
|
|
)}
|
|
aria-pressed={active}
|
|
>
|
|
<Icon className="h-3.5 w-3.5" />
|
|
{!compact && label}
|
|
</button>
|
|
);
|
|
})}
|
|
</div>
|
|
);
|
|
} |