This commit is contained in:
Iliyan Angelov
2025-12-07 20:36:17 +02:00
parent 876af48145
commit b818d645a9
91 changed files with 3692 additions and 4501 deletions

View File

@@ -0,0 +1,162 @@
import React, {
createContext,
useContext,
useEffect,
useState,
ReactNode,
} from 'react';
import { themeService } from '../../features/system/services/systemSettingsService';
type ThemeColors = {
primary: string;
primaryLight: string;
primaryDark: string;
primaryAccent: string;
};
type ThemeContextValue = {
colors: ThemeColors;
isLoading: boolean;
refreshTheme: () => Promise<void>;
updateColors: (colors: Partial<ThemeColors>) => void;
};
const defaultColors: ThemeColors = {
primary: '#d4af37',
primaryLight: '#f5d76e',
primaryDark: '#c9a227',
primaryAccent: '#e8c547',
};
const ThemeContext = createContext<ThemeContextValue | undefined>(undefined);
export const useTheme = () => {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme must be used within ThemeProvider');
}
return context;
};
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 [isLoading, setIsLoading] = useState<boolean>(true);
const loadTheme = async () => {
try {
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,
};
setColors(newColors);
applyThemeColors(newColors);
}
} catch (error) {
console.error('Error loading theme settings:', error);
// Apply default colors on error
applyThemeColors(defaultColors);
setColors(defaultColors);
} finally {
setIsLoading(false);
}
};
useEffect(() => {
loadTheme();
// Listen for theme refresh events
const handleRefresh = () => {
loadTheme();
};
if (typeof window !== 'undefined') {
window.addEventListener('refreshTheme', handleRefresh);
return () => {
window.removeEventListener('refreshTheme', handleRefresh);
};
}
}, []);
const refreshTheme = async () => {
await loadTheme();
};
const updateColors = (newColors: Partial<ThemeColors>) => {
const updatedColors = { ...colors, ...newColors };
setColors(updatedColors);
applyThemeColors(updatedColors);
};
return (
<ThemeContext.Provider
value={{
colors,
isLoading,
refreshTheme,
updateColors,
}}
>
{children}
</ThemeContext.Provider>
);
};