updates
This commit is contained in:
162
Frontend/src/shared/contexts/ThemeContext.tsx
Normal file
162
Frontend/src/shared/contexts/ThemeContext.tsx
Normal 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>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user