增加自动亮色/暗色主题切换 + 清理 pyc 文件
- 新建 store/theme.tsx: 亮色/暗色/跟随系统三种模式 - App.tsx: ThemeProvider + ConfigProvider 暗色算法 - MainLayout: 侧边栏主题切换按钮,Sider/Content 随主题变化 - 所有页面硬编码颜色替换为 antd token - AssignmentsPage: Tag 用预设颜色名适配暗色,未选中背景用 colorBgContainer - LoginPage: 暗色深色渐变背景 - 从 git 移除所有 __pycache__/*.pyc 文件 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
2f9b1a8eb2
commit
4522421293
@@ -0,0 +1,65 @@
|
||||
import { createContext, useContext, useState, useEffect, useCallback, type ReactNode } from 'react';
|
||||
|
||||
export type ThemeMode = 'light' | 'dark' | 'system';
|
||||
|
||||
const STORAGE_KEY = 'theme_mode';
|
||||
const DEFAULT_MODE: ThemeMode = 'system';
|
||||
|
||||
interface ThemeContextValue {
|
||||
mode: ThemeMode;
|
||||
isDark: boolean;
|
||||
setMode: (mode: ThemeMode) => void;
|
||||
toggle: () => void;
|
||||
}
|
||||
|
||||
const ThemeContext = createContext<ThemeContextValue>({
|
||||
mode: DEFAULT_MODE,
|
||||
isDark: false,
|
||||
setMode: () => {},
|
||||
toggle: () => {},
|
||||
});
|
||||
|
||||
export function ThemeProvider({ children }: { children: ReactNode }) {
|
||||
const [mode, setModeState] = useState<ThemeMode>(() => {
|
||||
const saved = localStorage.getItem(STORAGE_KEY);
|
||||
return (saved as ThemeMode) || DEFAULT_MODE;
|
||||
});
|
||||
|
||||
// 监听系统主题变化
|
||||
const [systemIsDark, setSystemIsDark] = useState(() =>
|
||||
window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const mql = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
const handler = (e: MediaQueryListEvent) => setSystemIsDark(e.matches);
|
||||
mql.addEventListener('change', handler);
|
||||
return () => mql.removeEventListener('change', handler);
|
||||
}, []);
|
||||
|
||||
const isDark = mode === 'dark' || (mode === 'system' && systemIsDark);
|
||||
|
||||
const setMode = useCallback((newMode: ThemeMode) => {
|
||||
setModeState(newMode);
|
||||
localStorage.setItem(STORAGE_KEY, newMode);
|
||||
}, []);
|
||||
|
||||
const toggle = useCallback(() => {
|
||||
setMode(isDark ? 'light' : 'dark');
|
||||
}, [isDark, setMode]);
|
||||
|
||||
// 同步到 HTML root,方便 CSS 使用
|
||||
useEffect(() => {
|
||||
document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
|
||||
}, [isDark]);
|
||||
|
||||
return (
|
||||
<ThemeContext.Provider value={{ mode, isDark, setMode, toggle }}>
|
||||
{children}
|
||||
</ThemeContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useTheme() {
|
||||
return useContext(ThemeContext);
|
||||
}
|
||||
Reference in New Issue
Block a user