Spaces:
Sleeping
Sleeping
| import React, { createContext, useContext, useState, useEffect } from 'react'; | |
| type ThemeMode = 'light' | 'dark' | 'system'; | |
| interface ThemeContextType { | |
| themeMode: ThemeMode; | |
| isDarkMode: boolean; | |
| setThemeMode: (mode: ThemeMode) => void; | |
| toggleTheme: () => void; | |
| } | |
| const ThemeContext = createContext<ThemeContextType | undefined>(undefined); | |
| export const ThemeProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { | |
| // 从本地存储获取主题模式,默认为'system' | |
| const [themeMode, setThemeModeState] = useState<ThemeMode>(() => { | |
| const savedMode = localStorage.getItem('themeMode'); | |
| return (savedMode as ThemeMode) || 'system'; | |
| }); | |
| // 判断当前是否为深色模式 | |
| const [isDarkMode, setIsDarkMode] = useState<boolean>(false); | |
| // 当主题模式改变时,更新本地存储和文档根节点类名 | |
| useEffect(() => { | |
| localStorage.setItem('themeMode', themeMode); | |
| updateTheme(); | |
| }, [themeMode]); | |
| // 监听系统主题变化 | |
| useEffect(() => { | |
| const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); | |
| const handleChange = () => { | |
| if (themeMode === 'system') { | |
| updateTheme(); | |
| } | |
| }; | |
| mediaQuery.addEventListener('change', handleChange); | |
| updateTheme(); | |
| return () => mediaQuery.removeEventListener('change', handleChange); | |
| }, [themeMode]); | |
| // 更新主题 | |
| const updateTheme = () => { | |
| const isDark = | |
| themeMode === 'dark' || | |
| (themeMode === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches); | |
| setIsDarkMode(isDark); | |
| // 更新文档根节点的类名 | |
| if (isDark) { | |
| document.documentElement.classList.add('dark'); | |
| } else { | |
| document.documentElement.classList.remove('dark'); | |
| } | |
| }; | |
| // 设置主题模式 | |
| const setThemeMode = (mode: ThemeMode) => { | |
| setThemeModeState(mode); | |
| }; | |
| // 切换主题(仅在light/dark之间切换,不涉及system) | |
| const toggleTheme = () => { | |
| setThemeModeState(prev => (prev === 'dark' ? 'light' : 'dark')); | |
| }; | |
| const value = { | |
| themeMode, | |
| isDarkMode, | |
| setThemeMode, | |
| toggleTheme | |
| }; | |
| return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>; | |
| }; | |
| export const useTheme = () => { | |
| const context = useContext(ThemeContext); | |
| if (!context) { | |
| throw new Error('useTheme must be used within a ThemeProvider'); | |
| } | |
| return context; | |
| }; |