import { useState } from 'react'; import { useTheme, COLOR_PALETTES } from '../../contexts/ThemeContext'; import type { AccentColor, BorderRadius, SidebarStyle, Density, FontFamily, ColorPalette } from '../../contexts/ThemeContext'; import { useTranslation } from '../../contexts/LanguageContext'; import { useAuth } from '../../contexts/AuthContext'; import { useSidebar } from '../../contexts/SidebarContext'; import type { SidebarMode } from '../../contexts/SidebarContext'; import { ChromePicker, HuePicker } from 'react-color'; import '../../styles/ThemeSettings.css'; type ThemeTab = 'colors' | 'appearance' | 'preview' | 'advanced'; type ColorPickerState = { isOpen: boolean; theme: 'light' | 'dark'; property: string; value: string; } | null; export default function ThemeSettings() { const [activeTab, setActiveTab] = useState('colors'); const { accentColor, borderRadius, sidebarStyle, density, fontFamily, colorPalette, setAccentColor, setBorderRadius, setSidebarStyle, setDensity, setFontFamily, setColorPalette, saveThemeToBackend } = useTheme(); const { t } = useTranslation(); const { user } = useAuth(); const { toggleMobileMenu, sidebarMode, setSidebarMode } = useSidebar(); const isAdmin = user?.is_superuser || false; const [tooltip, setTooltip] = useState<{ text: string; left: number; visible: boolean }>({ text: '', left: 0, visible: false, }); const handleTabMouseEnter = (text: string, e: React.MouseEvent) => { const rect = (e.currentTarget as HTMLElement).getBoundingClientRect(); setTooltip({ text, left: rect.left + rect.width / 2, visible: true, }); }; const handleTabMouseLeave = () => { setTooltip((prev) => ({ ...prev, visible: false })); }; // Handlers that save to backend after setting const handleAccentColorChange = async (color: AccentColor) => { setAccentColor(color); saveThemeToBackend({ accentColor: color }).catch(console.error); }; const handleBorderRadiusChange = async (radius: BorderRadius) => { setBorderRadius(radius); saveThemeToBackend({ borderRadius: radius }).catch(console.error); }; const handleSidebarStyleChange = async (style: SidebarStyle) => { setSidebarStyle(style); saveThemeToBackend({ sidebarStyle: style }).catch(console.error); }; const handleDensityChange = async (d: Density) => { setDensity(d); saveThemeToBackend({ density: d }).catch(console.error); }; const handleFontFamilyChange = async (font: FontFamily) => { setFontFamily(font); saveThemeToBackend({ fontFamily: font }).catch(console.error); }; const handleColorPaletteChange = async (palette: ColorPalette) => { setColorPalette(palette); saveThemeToBackend({ colorPalette: palette }).catch(console.error); }; // Advanced color states const [customColors, setCustomColors] = useState({ light: { bgMain: '#ffffff', bgCard: '#f9fafb', bgElevated: '#ffffff', textPrimary: '#111827', textSecondary: '#6b7280', border: '#e5e7eb', sidebarBg: '#1f2937', sidebarText: '#f9fafb' }, dark: { bgMain: '#0f172a', bgCard: '#1e293b', bgElevated: '#334155', textPrimary: '#f1f5f9', textSecondary: '#94a3b8', border: '#334155', sidebarBg: '#0c1222', sidebarText: '#f9fafb' } }); // Color picker popup state const [colorPickerState, setColorPickerState] = useState(null); const colors: { id: AccentColor; label: string; value: string; description: string }[] = [ { id: 'auto', label: t.theme.colors.auto, value: '#374151', description: t.theme.colors.autoDesc }, { id: 'blue', label: t.theme.colors.blue, value: '#3b82f6', description: t.theme.colors.blueDesc }, { id: 'purple', label: t.theme.colors.purple, value: '#8b5cf6', description: t.theme.colors.purpleDesc }, { id: 'green', label: t.theme.colors.green, value: '#10b981', description: t.theme.colors.greenDesc }, { id: 'orange', label: t.theme.colors.orange, value: '#f97316', description: t.theme.colors.orangeDesc }, { id: 'pink', label: t.theme.colors.pink, value: '#ec4899', description: t.theme.colors.pinkDesc }, { id: 'red', label: t.theme.colors.red, value: '#ef4444', description: t.theme.colors.redDesc }, { id: 'teal', label: t.theme.colors.teal, value: '#14b8a6', description: t.theme.colors.tealDesc }, { id: 'amber', label: t.theme.colors.amber, value: '#f59e0b', description: t.theme.colors.amberDesc }, { id: 'indigo', label: t.theme.colors.indigo, value: '#6366f1', description: t.theme.colors.indigoDesc }, { id: 'cyan', label: t.theme.colors.cyan, value: '#06b6d4', description: t.theme.colors.cyanDesc }, { id: 'rose', label: t.theme.colors.rose, value: '#f43f5e', description: t.theme.colors.roseDesc }, ]; const radii: { id: BorderRadius; label: string; description: string; preview: string }[] = [ { id: 'large', label: t.theme.radius.large, description: t.theme.radius.largeDesc, preview: '16px' }, { id: 'medium', label: t.theme.radius.medium, description: t.theme.radius.mediumDesc, preview: '8px' }, { id: 'small', label: t.theme.radius.small, description: t.theme.radius.smallDesc, preview: '4px' }, ]; const sidebarStyles: { id: SidebarStyle; label: string; description: string }[] = [ { id: 'default', label: t.theme.sidebarOptions.default, description: t.theme.sidebarOptions.defaultDesc }, { id: 'dark', label: t.theme.sidebarOptions.dark, description: t.theme.sidebarOptions.darkDesc }, { id: 'light', label: t.theme.sidebarOptions.light, description: t.theme.sidebarOptions.lightDesc }, ]; const sidebarModes: { id: SidebarMode; label: string; description: string }[] = [ { id: 'toggle', label: t.admin.sidebarModeToggle, description: t.admin.sidebarModeToggleDesc }, { id: 'dynamic', label: t.admin.sidebarModeDynamic, description: t.admin.sidebarModeDynamicDesc }, { id: 'collapsed', label: t.admin.sidebarModeCollapsed, description: t.admin.sidebarModeCollapsedDesc }, ]; const densities: { id: Density; label: string; description: string }[] = [ { id: 'compact', label: t.theme.densityOptions.compact, description: t.theme.densityOptions.compactDesc }, { id: 'comfortable', label: t.theme.densityOptions.comfortable, description: t.theme.densityOptions.comfortableDesc }, { id: 'spacious', label: t.theme.densityOptions.spacious, description: t.theme.densityOptions.spaciousDesc }, ]; const fonts: { id: FontFamily; label: string; description: string; fontStyle: string }[] = [ { id: 'sans', label: t.theme.fontOptions.system, description: t.theme.fontOptions.systemDesc, fontStyle: 'system-ui' }, { id: 'inter', label: t.theme.fontOptions.inter, description: t.theme.fontOptions.interDesc, fontStyle: 'Inter' }, { id: 'roboto', label: t.theme.fontOptions.roboto, description: t.theme.fontOptions.robotoDesc, fontStyle: 'Roboto' }, ]; const palettes: { id: ColorPalette; label: string; description: string }[] = [ { id: 'monochrome', label: t.theme.palettes.monochrome, description: t.theme.palettes.monochromeDesc }, { id: 'default', label: t.theme.palettes.default, description: t.theme.palettes.defaultDesc }, { id: 'monochromeBlue', label: t.theme.palettes.monochromeBlue, description: t.theme.palettes.monochromeBlueDesc }, { id: 'sepia', label: t.theme.palettes.sepia, description: t.theme.palettes.sepiaDesc }, { id: 'nord', label: t.theme.palettes.nord, description: t.theme.palettes.nordDesc }, { id: 'dracula', label: t.theme.palettes.dracula, description: t.theme.palettes.draculaDesc }, { id: 'solarized', label: t.theme.palettes.solarized, description: t.theme.palettes.solarizedDesc }, { id: 'github', label: t.theme.palettes.github, description: t.theme.palettes.githubDesc }, { id: 'ocean', label: t.theme.palettes.ocean, description: t.theme.palettes.oceanDesc }, { id: 'forest', label: t.theme.palettes.forest, description: t.theme.palettes.forestDesc }, { id: 'midnight', label: t.theme.palettes.midnight, description: t.theme.palettes.midnightDesc }, { id: 'sunset', label: t.theme.palettes.sunset, description: t.theme.palettes.sunsetDesc }, ]; // Helper component for color control const ColorControl = ({ theme, property, label, value }: { theme: 'light' | 'dark'; property: string; label: string; value: string }) => { return (
handleHexInput(theme, property, e.target.value)} className="color-hex-input" placeholder="#FFFFFF" maxLength={7} />
); }; // Color picker handlers const handleColorChange = (theme: 'light' | 'dark', property: string, value: string) => { setCustomColors(prev => ({ ...prev, [theme]: { ...prev[theme], [property]: value } })); // Apply to CSS variables immediately const root = document.documentElement; const varName = `--color-${property.replace(/([A-Z])/g, '-$1').toLowerCase()}`; root.style.setProperty(varName, value); }; const handleHexInput = (theme: 'light' | 'dark', property: string, value: string) => { // Validate hex color format const hexRegex = /^#?[0-9A-Fa-f]{6}$/; const formattedValue = value.startsWith('#') ? value : `#${value}`; if (hexRegex.test(formattedValue)) { handleColorChange(theme, property, formattedValue); } }; const resetToDefaults = () => { setCustomColors({ light: { bgMain: '#ffffff', bgCard: '#f9fafb', bgElevated: '#ffffff', textPrimary: '#111827', textSecondary: '#6b7280', border: '#e5e7eb', sidebarBg: '#1f2937', sidebarText: '#f9fafb' }, dark: { bgMain: '#0f172a', bgCard: '#1e293b', bgElevated: '#334155', textPrimary: '#f1f5f9', textSecondary: '#94a3b8', border: '#334155', sidebarBg: '#0c1222', sidebarText: '#f9fafb' } }); // Reset CSS variables const root = document.documentElement; root.style.removeProperty('--color-bg-main'); root.style.removeProperty('--color-bg-card'); root.style.removeProperty('--color-bg-elevated'); root.style.removeProperty('--color-text-primary'); root.style.removeProperty('--color-text-secondary'); root.style.removeProperty('--color-border'); root.style.removeProperty('--color-sidebar-bg'); root.style.removeProperty('--color-sidebar-text'); }; return (
{/* Tab Tooltip */} {tooltip.visible && (
{tooltip.text}
)} {/* Modern Tab Navigation */}
brush {t.theme.title}
{isAdmin && ( )}
{activeTab === 'colors' && (

{t.theme.accentColor}

{colors.map((color) => (
handleAccentColorChange(color.id)} >
{accentColor === color.id && ( check )}
{color.label} {color.description}
))}

{t.theme.colorPalette}

{palettes.map((palette) => { const paletteColors = COLOR_PALETTES[palette.id]; return (
handleColorPaletteChange(palette.id)} >
{colorPalette === palette.id && (
check
)}
{palette.label} {palette.description}
); })}
)} {activeTab === 'appearance' && (
{/* Border Radius Section */}

{t.theme.borderRadius}

{radii.map((radius) => (
handleBorderRadiusChange(radius.id)} >
{radius.label} {radius.description}
))}
{/* Sidebar Style Section */}

{t.theme.sidebarStyle}

{sidebarStyles.map((style) => (
handleSidebarStyleChange(style.id)} >
{style.label} {style.description}
))}
{/* Sidebar Mode Section */}

{t.admin.sidebarMode}

{sidebarModes.map((mode) => (
setSidebarMode(mode.id)} >
{mode.label} {mode.description}
))}
{/* Density Section */}

{t.theme.density}

{densities.map((d) => (
handleDensityChange(d.id)} >
{d.label} {d.description}
))}
{/* Font Family Section */}

{t.theme.fontFamily}

{fonts.map((f) => (
handleFontFamilyChange(f.id)} >
Aa
{f.label} {f.description}
))}
)} {activeTab === 'preview' && (

{t.theme.preview}

{t.theme.previewCard}

{t.theme.badge}

{t.theme.previewDescription}

{t.theme.sampleCard}

{t.dashboard.active}

{t.theme.sampleCardDesc}

142 {t.theme.totalItems}
89% {t.theme.successRate}
)} {activeTab === 'advanced' && isAdmin && (

{t.theme.advancedColors}

{/* Light Theme Colors */}

{t.theme.lightThemeColors}

{/* Dark Theme Colors */}

{t.theme.darkThemeColors}

)}
{/* Color Picker Popup */} {colorPickerState && (
setColorPickerState(null)} >
e.stopPropagation()} >

{t.theme.pickColor}

{colorPickerState.value.toUpperCase()} {t.theme.currentColor}
{ handleColorChange( colorPickerState.theme, colorPickerState.property, color.hex ); setColorPickerState({ ...colorPickerState, value: color.hex }); }} disableAlpha={true} />
{ handleColorChange( colorPickerState.theme, colorPickerState.property, color.hex ); setColorPickerState({ ...colorPickerState, value: color.hex }); }} width="100%" height="16px" />
)}
); }