| "use client"; |
|
|
| import { Moon, Sun } from "lucide-react"; |
| import { useEffect, useState } from "react"; |
|
|
| type Theme = "light" | "dark"; |
|
|
| const STORAGE_KEY = "image-theme"; |
|
|
| function resolveInitialTheme(): Theme { |
| if (typeof window === "undefined") { |
| return "light"; |
| } |
| const stored = window.localStorage.getItem(STORAGE_KEY); |
| if (stored === "light" || stored === "dark") { |
| return stored; |
| } |
| return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"; |
| } |
|
|
| function applyTheme(theme: Theme) { |
| document.documentElement.classList.toggle("dark", theme === "dark"); |
| document.documentElement.style.colorScheme = theme; |
| } |
|
|
| export function ThemeToggle() { |
| const [theme, setTheme] = useState<Theme>("light"); |
| const isDark = theme === "dark"; |
|
|
| useEffect(() => { |
| const nextTheme = resolveInitialTheme(); |
| setTheme(nextTheme); |
| applyTheme(nextTheme); |
| }, []); |
|
|
| const toggleTheme = () => { |
| const nextTheme: Theme = isDark ? "light" : "dark"; |
| window.localStorage.setItem(STORAGE_KEY, nextTheme); |
| setTheme(nextTheme); |
| applyTheme(nextTheme); |
| }; |
|
|
| return ( |
| <button |
| type="button" |
| aria-label={isDark ? "切换到浅色模式" : "切换到深色模式"} |
| title={isDark ? "浅色模式" : "深色模式"} |
| className="inline-flex size-8 shrink-0 items-center justify-center rounded-full border border-stone-200/80 bg-white/80 text-stone-500 shadow-sm transition hover:border-stone-300 hover:text-stone-900 dark:border-white/10 dark:bg-white/8 dark:text-stone-300 dark:hover:border-white/20 dark:hover:text-white" |
| onClick={toggleTheme} |
| > |
| {isDark ? <Sun className="size-4" /> : <Moon className="size-4" />} |
| </button> |
| ); |
| } |
|
|