P1: - utils/storage.ts、theme.ts、validate.ts + index 统一出口 - request/store/useTheme 接入 storage;清零 confirm/alert - PipelineManager、TerminalAuditTab 拆分子模块(<700行红线) P2: - api/monitor、api/deploy 子目录化 - hooks/api 扩展:servers/pipelines/alerts/audit/sessionCommands - PipelineManager、AuditOperationsTab 接入 TanStack Query
55 lines
1.3 KiB
TypeScript
55 lines
1.3 KiB
TypeScript
import { createContext, useContext, useState, useCallback, useMemo, useEffect } from 'react';
|
|
import {
|
|
type Theme,
|
|
type ThemeOption,
|
|
THEME_OPTIONS,
|
|
getInitialTheme,
|
|
persistTheme,
|
|
applyThemeToDocument,
|
|
getNextTheme,
|
|
} from '@/utils/theme';
|
|
|
|
export type { Theme, ThemeOption };
|
|
export { THEME_OPTIONS };
|
|
|
|
interface ThemeContextType {
|
|
theme: Theme;
|
|
toggleTheme: () => void;
|
|
setTheme: (theme: Theme) => void;
|
|
}
|
|
|
|
const ThemeContext = createContext<ThemeContextType | null>(null);
|
|
|
|
export function ThemeProvider({ children }: { children: React.ReactNode }) {
|
|
const [theme, setThemeState] = useState<Theme>(getInitialTheme);
|
|
|
|
useEffect(() => {
|
|
applyThemeToDocument(theme);
|
|
}, [theme]);
|
|
|
|
const toggleTheme = useCallback(() => {
|
|
setThemeState((prev) => {
|
|
const next = getNextTheme(prev);
|
|
persistTheme(next);
|
|
return next;
|
|
});
|
|
}, []);
|
|
|
|
const setTheme = useCallback((t: Theme) => {
|
|
persistTheme(t);
|
|
setThemeState(t);
|
|
}, []);
|
|
|
|
const value = useMemo(
|
|
() => ({ theme, toggleTheme, setTheme }),
|
|
[theme, toggleTheme, setTheme],
|
|
);
|
|
|
|
return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
|
|
}
|
|
|
|
export function useTheme(): ThemeContextType {
|
|
const ctx = useContext(ThemeContext);
|
|
if (!ctx) throw new Error('useTheme must be used within ThemeProvider');
|
|
return ctx;
|
|
} |