All checks were successful
Basil CI/CD Pipeline / Code Linting (push) Successful in 58s
Basil CI/CD Pipeline / Web Tests (push) Successful in 1m5s
Basil CI/CD Pipeline / Shared Package Tests (push) Successful in 1m0s
Basil CI/CD Pipeline / Security Scanning (push) Successful in 1m6s
Basil CI/CD Pipeline / API Tests (push) Successful in 2m44s
Basil CI/CD Pipeline / Build All Packages (push) Successful in 3m9s
Basil CI/CD Pipeline / E2E Tests (push) Has been skipped
Basil CI/CD Pipeline / Build & Push Docker Images (push) Successful in 5m5s
Basil CI/CD Pipeline / Trigger Deployment (push) Successful in 11s
Implemented a simple dark mode toggle that persists user preference across sessions. Changes: - Add CSS custom properties for light and dark themes in App.css - Create ThemeContext for global theme state management - Create ThemeToggle component with moon/sun icons - Update all color references to use CSS variables for theme support - Add localStorage persistence for theme preference - Include smooth transitions between themes The toggle appears in the header next to the user menu and allows instant switching between light and dark modes. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
54 lines
1.4 KiB
TypeScript
54 lines
1.4 KiB
TypeScript
import { createContext, useContext, useState, useEffect, ReactNode } from 'react';
|
|
|
|
type Theme = 'light' | 'dark';
|
|
|
|
interface ThemeContextType {
|
|
theme: Theme;
|
|
toggleTheme: () => void;
|
|
}
|
|
|
|
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
|
|
|
|
const THEME_STORAGE_KEY = 'basil_theme';
|
|
|
|
export function ThemeProvider({ children }: { children: ReactNode }) {
|
|
const [theme, setTheme] = useState<Theme>(() => {
|
|
// Load theme from localStorage safely
|
|
try {
|
|
const saved = localStorage.getItem(THEME_STORAGE_KEY);
|
|
return (saved === 'dark' ? 'dark' : 'light') as Theme;
|
|
} catch (e) {
|
|
return 'light';
|
|
}
|
|
});
|
|
|
|
useEffect(() => {
|
|
// Apply theme to document
|
|
document.documentElement.setAttribute('data-theme', theme);
|
|
// Save to localStorage safely
|
|
try {
|
|
localStorage.setItem(THEME_STORAGE_KEY, theme);
|
|
} catch (e) {
|
|
console.warn('Failed to save theme preference:', e);
|
|
}
|
|
}, [theme]);
|
|
|
|
const toggleTheme = () => {
|
|
setTheme(prev => prev === 'light' ? 'dark' : 'light');
|
|
};
|
|
|
|
return (
|
|
<ThemeContext.Provider value={{ theme, toggleTheme }}>
|
|
{children}
|
|
</ThemeContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function useTheme() {
|
|
const context = useContext(ThemeContext);
|
|
if (context === undefined) {
|
|
throw new Error('useTheme must be used within a ThemeProvider');
|
|
}
|
|
return context;
|
|
}
|