Files
opsxsql/frontend/src/hooks/useTheme.tsx
T
loganandClaude Opus 4.7 439155c92e Initial commit: SQL audit platform v0.1.0
FastAPI backend with auth, user, instance, ticket, query, dashboard APIs.
React + TypeScript frontend with mock data UI (10 pages).
SQLite + async SQLAlchemy, JWT auth, role-based access control.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 11:11:57 +08:00

62 lines
1.6 KiB
TypeScript

import { createContext, useContext, useState, useCallback, useMemo, useEffect } from 'react';
export type Theme = 'dark' | 'light';
interface ThemeContextType {
theme: Theme;
toggleTheme: () => void;
setTheme: (theme: Theme) => void;
isDark: boolean;
isLight: boolean;
}
const ThemeContext = createContext<ThemeContextType | null>(null);
function getInitialTheme(): Theme {
if (typeof window === 'undefined') return 'dark';
const stored = localStorage.getItem('dg-theme') as Theme | null;
if (stored === 'dark' || stored === 'light') return stored;
return 'dark';
}
function applyTheme(theme: Theme) {
document.documentElement.setAttribute('data-theme', theme);
}
export function ThemeProvider({ children }: { children: React.ReactNode }) {
const [theme, setThemeState] = useState<Theme>(getInitialTheme);
useEffect(() => {
applyTheme(theme);
}, [theme]);
const toggleTheme = useCallback(() => {
setThemeState(prev => {
const next = prev === 'dark' ? 'light' : 'dark';
localStorage.setItem('dg-theme', next);
return next;
});
}, []);
const setTheme = useCallback((t: Theme) => {
localStorage.setItem('dg-theme', t);
setThemeState(t);
}, []);
const value = useMemo(() => ({
theme,
toggleTheme,
setTheme,
isDark: theme === 'dark',
isLight: theme === 'light',
}), [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;
}