This commit is contained in:
Iliyan Angelov
2025-12-09 00:14:21 +02:00
parent b818d645a9
commit e43a95eafb
43 changed files with 2070 additions and 772 deletions

View File

@@ -7,25 +7,28 @@ import React, {
} from 'react';
import { themeService } from '../../features/system/services/systemSettingsService';
type ThemeColors = {
primary: string;
primaryLight: string;
primaryDark: string;
primaryAccent: string;
type ThemeLayoutMode = 'dark' | 'light';
type ThemeSettings = {
theme_primary_color: string;
theme_primary_light: string;
theme_primary_dark: string;
theme_primary_accent: string;
theme_layout_mode: ThemeLayoutMode;
};
type ThemeContextValue = {
colors: ThemeColors;
theme: ThemeSettings;
isLoading: boolean;
refreshTheme: () => Promise<void>;
updateColors: (colors: Partial<ThemeColors>) => void;
};
const defaultColors: ThemeColors = {
primary: '#d4af37',
primaryLight: '#f5d76e',
primaryDark: '#c9a227',
primaryAccent: '#e8c547',
const defaultTheme: ThemeSettings = {
theme_primary_color: '#d4af37',
theme_primary_light: '#f5d76e',
theme_primary_dark: '#c9a227',
theme_primary_accent: '#e8c547',
theme_layout_mode: 'dark',
};
const ThemeContext = createContext<ThemeContextValue | undefined>(undefined);
@@ -42,58 +45,8 @@ interface ThemeProviderProps {
children: ReactNode;
}
/**
* Converts hex color to RGB values
*/
const hexToRgb = (hex: string): string => {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result
? `${parseInt(result[1], 16)}, ${parseInt(result[2], 16)}, ${parseInt(result[3], 16)}`
: '212, 175, 55'; // Default gold RGB
};
/**
* Applies theme colors as CSS variables to the document root
*/
const applyThemeColors = (colors: ThemeColors) => {
const root = document.documentElement;
// Apply CSS variables
root.style.setProperty('--luxury-gold', colors.primary);
root.style.setProperty('--luxury-gold-light', colors.primaryLight);
root.style.setProperty('--luxury-gold-dark', colors.primaryDark);
root.style.setProperty('--luxury-gold-accent', colors.primaryAccent);
// Add RGB versions for rgba() usage
root.style.setProperty('--luxury-gold-rgb', hexToRgb(colors.primary));
root.style.setProperty('--luxury-gold-light-rgb', hexToRgb(colors.primaryLight));
root.style.setProperty('--luxury-gold-dark-rgb', hexToRgb(colors.primaryDark));
root.style.setProperty('--luxury-gold-accent-rgb', hexToRgb(colors.primaryAccent));
// Also update gradient variables
root.style.setProperty(
'--gradient-gold',
`linear-gradient(135deg, ${colors.primary} 0%, ${colors.primaryLight} 100%)`
);
root.style.setProperty(
'--gradient-gold-dark',
`linear-gradient(135deg, ${colors.primaryDark} 0%, ${colors.primary} 100%)`
);
// Update shadow variables with proper opacity
const primaryRgb = hexToRgb(colors.primary);
root.style.setProperty(
'--shadow-luxury',
`0 4px 20px rgba(${primaryRgb}, 0.15)`
);
root.style.setProperty(
'--shadow-luxury-gold',
`0 8px 30px rgba(${primaryRgb}, 0.25)`
);
};
export const ThemeProvider: React.FC<ThemeProviderProps> = ({ children }) => {
const [colors, setColors] = useState<ThemeColors>(defaultColors);
const [theme, setTheme] = useState<ThemeSettings>(defaultTheme);
const [isLoading, setIsLoading] = useState<boolean>(true);
const loadTheme = async () => {
@@ -101,20 +54,34 @@ export const ThemeProvider: React.FC<ThemeProviderProps> = ({ children }) => {
setIsLoading(true);
const response = await themeService.getThemeSettings();
if (response.data) {
const newColors: ThemeColors = {
primary: response.data.theme_primary_color || defaultColors.primary,
primaryLight: response.data.theme_primary_light || defaultColors.primaryLight,
primaryDark: response.data.theme_primary_dark || defaultColors.primaryDark,
primaryAccent: response.data.theme_primary_accent || defaultColors.primaryAccent,
const themeData: ThemeSettings = {
theme_primary_color: response.data.theme_primary_color || defaultTheme.theme_primary_color,
theme_primary_light: response.data.theme_primary_light || defaultTheme.theme_primary_light,
theme_primary_dark: response.data.theme_primary_dark || defaultTheme.theme_primary_dark,
theme_primary_accent: response.data.theme_primary_accent || defaultTheme.theme_primary_accent,
theme_layout_mode: (response.data.theme_layout_mode === 'light' ? 'light' : 'dark') as ThemeLayoutMode,
};
setColors(newColors);
applyThemeColors(newColors);
setTheme(themeData);
// Apply CSS variables for colors
document.documentElement.style.setProperty('--luxury-gold', themeData.theme_primary_color);
document.documentElement.style.setProperty('--luxury-gold-light', themeData.theme_primary_light);
document.documentElement.style.setProperty('--luxury-gold-dark', themeData.theme_primary_dark);
document.documentElement.style.setProperty('--luxury-gold-accent', themeData.theme_primary_accent);
// Apply layout mode class to body
document.body.classList.remove('theme-dark', 'theme-light');
document.body.classList.add(`theme-${themeData.theme_layout_mode}`);
document.documentElement.classList.remove('theme-dark', 'theme-light');
document.documentElement.classList.add(`theme-${themeData.theme_layout_mode}`);
}
} catch (error) {
console.error('Error loading theme settings:', error);
// Apply default colors on error
applyThemeColors(defaultColors);
setColors(defaultColors);
// Apply defaults
document.body.classList.remove('theme-dark', 'theme-light');
document.body.classList.add('theme-dark');
document.documentElement.classList.remove('theme-dark', 'theme-light');
document.documentElement.classList.add('theme-dark');
} finally {
setIsLoading(false);
}
@@ -122,12 +89,12 @@ export const ThemeProvider: React.FC<ThemeProviderProps> = ({ children }) => {
useEffect(() => {
loadTheme();
// Listen for theme refresh events
const handleRefresh = () => {
loadTheme();
};
if (typeof window !== 'undefined') {
window.addEventListener('refreshTheme', handleRefresh);
return () => {
@@ -140,23 +107,15 @@ export const ThemeProvider: React.FC<ThemeProviderProps> = ({ children }) => {
await loadTheme();
};
const updateColors = (newColors: Partial<ThemeColors>) => {
const updatedColors = { ...colors, ...newColors };
setColors(updatedColors);
applyThemeColors(updatedColors);
};
return (
<ThemeContext.Provider
value={{
colors,
theme,
isLoading,
refreshTheme,
updateColors,
}}
>
{children}
</ThemeContext.Provider>
);
};