Added comprehensive theme switching system with two color palettes: **New Default Theme: Purple/Pink Gradient** - Primary: #8b52ff (vibrant purple) → #d194e6 (light purple) - Secondary: #ff7094 (pink) → #ffb3e4 (light pink) - Modern, energetic gradient aesthetic - Created purpleTheme.ts with full MUI theme configuration **High Contrast Theme: Warm Peach (Original)** - Renamed maternalTheme to highContrastTheme - Larger text sizes (7.5% increase for accessibility) - Stronger shadows and bolder fonts - Optimized for readability and accessibility **Theme Infrastructure:** 1. **ThemeContext** (contexts/ThemeContext.tsx) - Created theme context provider with useThemeContext hook - Theme modes: 'standard' (purple) | 'highContrast' (peach) - localStorage persistence with key: maternal_theme_preference - Prevents flash of wrong theme on load 2. **ThemeRegistry Updates** (components/ThemeRegistry.tsx) - Wrapped with ThemeContextProvider - Dynamic theme switching via useThemeContext - Maintains backward compatibility 3. **Settings Page Toggle** (app/settings/page.tsx) - Added theme switcher in Preferences section - Switch control with descriptive labels - Explains High Contrast benefits - Instant theme switching without reload 4. **CSS Variables** (app/globals.css) - Added --color-1 through --color-5 for purple gradient - Added --warm-1 through --warm-5 for peach palette - Available for custom styling **Features:** ✅ Instant theme switching (no page reload) ✅ Persistent preference across sessions ✅ Accessibility-focused high contrast mode ✅ Modern purple/pink gradient as default ✅ Smooth transitions between themes ✅ All existing components work with both themes **Files Created:** - contexts/ThemeContext.tsx - styles/themes/purpleTheme.ts - styles/themes/highContrastTheme.ts **Files Modified:** - components/ThemeRegistry.tsx - app/settings/page.tsx - app/globals.css Resolves: High Priority Feature #12 - Secondary Color Palette & Accessibility Toggle 🎉 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
66 lines
1.9 KiB
TypeScript
66 lines
1.9 KiB
TypeScript
'use client';
|
|
|
|
import { createContext, useContext, useState, useEffect, ReactNode } from 'react';
|
|
import { Theme } from '@mui/material/styles';
|
|
import { purpleTheme } from '@/styles/themes/purpleTheme';
|
|
import { highContrastTheme } from '@/styles/themes/highContrastTheme';
|
|
|
|
export type ThemeMode = 'standard' | 'highContrast';
|
|
|
|
interface ThemeContextType {
|
|
themeMode: ThemeMode;
|
|
toggleTheme: () => void;
|
|
setThemeMode: (mode: ThemeMode) => void;
|
|
currentTheme: Theme;
|
|
}
|
|
|
|
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
|
|
|
|
const THEME_STORAGE_KEY = 'maternal_theme_preference';
|
|
|
|
export function ThemeContextProvider({ children }: { children: ReactNode }) {
|
|
const [themeMode, setThemeModeState] = useState<ThemeMode>('standard');
|
|
const [mounted, setMounted] = useState(false);
|
|
|
|
// Load theme preference from localStorage on mount
|
|
useEffect(() => {
|
|
const savedTheme = localStorage.getItem(THEME_STORAGE_KEY) as ThemeMode | null;
|
|
if (savedTheme === 'highContrast' || savedTheme === 'standard') {
|
|
setThemeModeState(savedTheme);
|
|
}
|
|
setMounted(true);
|
|
}, []);
|
|
|
|
// Save theme preference to localStorage when it changes
|
|
const setThemeMode = (mode: ThemeMode) => {
|
|
setThemeModeState(mode);
|
|
localStorage.setItem(THEME_STORAGE_KEY, mode);
|
|
};
|
|
|
|
const toggleTheme = () => {
|
|
const newMode = themeMode === 'standard' ? 'highContrast' : 'standard';
|
|
setThemeMode(newMode);
|
|
};
|
|
|
|
const currentTheme = themeMode === 'highContrast' ? highContrastTheme : purpleTheme;
|
|
|
|
// Prevent flash of wrong theme
|
|
if (!mounted) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<ThemeContext.Provider value={{ themeMode, toggleTheme, setThemeMode, currentTheme }}>
|
|
{children}
|
|
</ThemeContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function useThemeContext() {
|
|
const context = useContext(ThemeContext);
|
|
if (context === undefined) {
|
|
throw new Error('useThemeContext must be used within a ThemeContextProvider');
|
|
}
|
|
return context;
|
|
}
|