为你的 Vite 应用添加暗黑模式。
暗黑模式
创建主题提供者
components/theme-provider.tsx
import { createContext, useContext, useEffect, useState } from "react"type Theme = "dark" | "light" | "system"type ThemeProviderProps = {children: React.ReactNodedefaultTheme?: ThemestorageKey?: string}type ThemeProviderState = {theme: ThemesetTheme: (theme: Theme) => void}const initialState: ThemeProviderState = {theme: "system",setTheme: () => null,}const ThemeProviderContext = createContext<ThemeProviderState>(initialState)export function ThemeProvider({children,defaultTheme = "system",storageKey = "vite-ui-theme",...props}: ThemeProviderProps) {const [theme, setTheme] = useState<Theme>(() => (localStorage.getItem(storageKey) as Theme) || defaultTheme)useEffect(() => {const root = window.document.documentElementroot.classList.remove("light", "dark")if (theme === "system") {const systemTheme = window.matchMedia("(prefers-color-scheme: dark)").matches? "dark": "light"root.classList.add(systemTheme)return}root.classList.add(theme)}, [theme])const value = {theme,setTheme: (theme: Theme) => {localStorage.setItem(storageKey, theme)setTheme(theme)},}return (<ThemeProviderContext.Provider {...props} value={value}>{children}</ThemeProviderContext.Provider>)}export const useTheme = () => {const context = useContext(ThemeProviderContext)if (context === undefined)throw new Error("useTheme 必须在 ThemeProvider 内部使用")return context}
包装你的根布局
将 ThemeProvider 添加到你的根布局。
App.tsx
import { ThemeProvider } from "@/components/theme-provider"function App() {return (<ThemeProvider defaultTheme="dark" storageKey="vite-ui-theme">{children}</ThemeProvider>)}export default App
添加模式切换
在你的站点上添加一个模式切换按钮,以在光明模式和暗黑模式之间切换。
components/mode-toggle.tsx
import { Moon, Sun } from "lucide-react"import { Button } from "@/components/ui/button"import {DropdownMenu,DropdownMenuContent,DropdownMenuItem,DropdownMenuTrigger,} from "@/components/ui/dropdown-menu"import { useTheme } from "@/components/theme-provider"export function ModeToggle() {const { setTheme } = useTheme()return (<DropdownMenu><DropdownMenuTrigger asChild><Button variant="outline" size="icon"><Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" /><Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" /><span className="sr-only">切换主题</span></Button></DropdownMenuTrigger><DropdownMenuContent align="end"><DropdownMenuItem onClick={() => setTheme("light")}>光明模式</DropdownMenuItem><DropdownMenuItem onClick={() => setTheme("dark")}>暗黑模式</DropdownMenuItem><DropdownMenuItem onClick={() => setTheme("system")}>系统模式</DropdownMenuItem></DropdownMenuContent></DropdownMenu>)}
