- Added RandomThemeApplier to apply a random theme on login. - Introduced RandomBackground component for setting a random background from presets. - Updated GlobalKeyboardShortcuts import in RootLayout for consistent keyboard shortcut handling. - Refactored BackgroundContext to include cycleBackground functionality for dynamic background changes. - Removed deprecated useBackgroundCycle hook to streamline background management.
151 lines
6.1 KiB
TypeScript
151 lines
6.1 KiB
TypeScript
'use client';
|
|
|
|
import { createContext, useContext, useEffect, useState, ReactNode } from 'react';
|
|
import { useUserPreferences } from './UserPreferencesContext';
|
|
import { PRESET_BACKGROUNDS, BACKGROUND_NAMES, TOAST_ICONS, getNextBackground } from '@/lib/ui-config';
|
|
import { useSession } from 'next-auth/react';
|
|
import { useToast } from '@/components/ui/Toast';
|
|
|
|
interface BackgroundContextType {
|
|
backgroundImage: string | undefined;
|
|
setBackgroundImage: (image: string | undefined) => void;
|
|
cycleBackground: () => void;
|
|
}
|
|
|
|
const BackgroundContext = createContext<BackgroundContextType | undefined>(undefined);
|
|
|
|
interface BackgroundProviderProps {
|
|
children: ReactNode;
|
|
}
|
|
|
|
export function BackgroundProvider({ children }: BackgroundProviderProps) {
|
|
const { preferences, updateViewPreferences } = useUserPreferences();
|
|
const { data: session } = useSession();
|
|
const { showToast } = useToast();
|
|
const [backgroundImage, setBackgroundImageState] = useState<string | undefined>(
|
|
preferences?.viewPreferences?.backgroundImage
|
|
);
|
|
const [backgroundBlur, setBackgroundBlurState] = useState<number>(
|
|
preferences?.viewPreferences?.backgroundBlur || 0
|
|
);
|
|
const [backgroundOpacity, setBackgroundOpacityState] = useState<number>(
|
|
preferences?.viewPreferences?.backgroundOpacity || 100
|
|
);
|
|
const [mounted, setMounted] = useState(false);
|
|
|
|
// Hydration safe initialization
|
|
useEffect(() => {
|
|
setMounted(true);
|
|
}, []);
|
|
|
|
// Sync with preferences (only for authenticated users)
|
|
useEffect(() => {
|
|
// Only sync if user is authenticated
|
|
if (session?.user?.id && preferences?.viewPreferences?.backgroundImage !== backgroundImage) {
|
|
setBackgroundImageState(preferences?.viewPreferences?.backgroundImage);
|
|
}
|
|
if (preferences?.viewPreferences?.backgroundBlur !== backgroundBlur) {
|
|
setBackgroundBlurState(preferences?.viewPreferences?.backgroundBlur || 0);
|
|
}
|
|
if (preferences?.viewPreferences?.backgroundOpacity !== backgroundOpacity) {
|
|
setBackgroundOpacityState(preferences?.viewPreferences?.backgroundOpacity || 100);
|
|
}
|
|
}, [preferences?.viewPreferences?.backgroundImage, preferences?.viewPreferences?.backgroundBlur, preferences?.viewPreferences?.backgroundOpacity, backgroundImage, backgroundBlur, backgroundOpacity, session?.user?.id]);
|
|
|
|
// Apply background image to document body
|
|
useEffect(() => {
|
|
if (mounted) {
|
|
const body = document.body;
|
|
|
|
// Supprimer l'ancien élément de fond s'il existe
|
|
const existingBackground = document.getElementById('custom-background');
|
|
if (existingBackground) {
|
|
existingBackground.remove();
|
|
}
|
|
|
|
if (backgroundImage) {
|
|
console.log('Creating background element for:', backgroundImage);
|
|
// Créer un élément div pour l'image de fond avec les effets
|
|
const backgroundElement = document.createElement('div');
|
|
backgroundElement.id = 'custom-background';
|
|
backgroundElement.style.position = 'fixed';
|
|
backgroundElement.style.top = '0';
|
|
backgroundElement.style.left = '0';
|
|
backgroundElement.style.width = '100%';
|
|
backgroundElement.style.height = '100%';
|
|
backgroundElement.style.zIndex = '-1';
|
|
backgroundElement.style.pointerEvents = 'none';
|
|
|
|
// Vérifier si c'est une URL d'image ou un preset
|
|
const presetIds = PRESET_BACKGROUNDS.map(preset => preset.id);
|
|
|
|
if (backgroundImage && presetIds.includes(backgroundImage as typeof presetIds[number])) {
|
|
// Trouver le preset correspondant
|
|
const preset = PRESET_BACKGROUNDS.find(p => p.id === backgroundImage);
|
|
if (preset) {
|
|
// Appliquer le gradient directement
|
|
backgroundElement.style.background = preset.preview;
|
|
// Ajouter une classe pour identifier le type de background
|
|
backgroundElement.className = `preset-background preset-${preset.id}`;
|
|
}
|
|
} else {
|
|
// Appliquer l'URL d'image personnalisée
|
|
backgroundElement.style.backgroundImage = `url(${backgroundImage})`;
|
|
backgroundElement.className = 'custom-background';
|
|
}
|
|
|
|
// Appliquer les propriétés communes
|
|
backgroundElement.style.backgroundSize = 'cover';
|
|
backgroundElement.style.backgroundPosition = 'center';
|
|
backgroundElement.style.backgroundRepeat = 'no-repeat';
|
|
backgroundElement.style.filter = `blur(${backgroundBlur}px)`;
|
|
backgroundElement.style.opacity = `${backgroundOpacity / 100}`;
|
|
|
|
// Ajouter l'élément au body
|
|
body.appendChild(backgroundElement);
|
|
body.classList.add('has-background-image');
|
|
} else {
|
|
// Supprimer l'image de fond
|
|
body.classList.remove('has-background-image');
|
|
}
|
|
}
|
|
}, [backgroundImage, backgroundBlur, backgroundOpacity, mounted]);
|
|
|
|
const setBackgroundImage = (image: string | undefined) => {
|
|
setBackgroundImageState(image);
|
|
};
|
|
|
|
const cycleBackground = () => {
|
|
const currentBackground = backgroundImage; // Utiliser le state local au lieu des préférences
|
|
const customImages = preferences?.viewPreferences?.customImages || [];
|
|
|
|
const nextBackground = getNextBackground(currentBackground || 'none', customImages);
|
|
const newBackgroundImage = nextBackground === 'none' ? undefined : nextBackground;
|
|
|
|
setBackgroundImageState(newBackgroundImage);
|
|
|
|
// Sauvegarder seulement si l'utilisateur est authentifié
|
|
if (session?.user?.id) {
|
|
updateViewPreferences({ backgroundImage: newBackgroundImage });
|
|
}
|
|
|
|
// Afficher le toast avec le nom du background
|
|
const backgroundName = BACKGROUND_NAMES[nextBackground] || 'Image personnalisée';
|
|
showToast(`Background: ${backgroundName}`, 2000, TOAST_ICONS.background);
|
|
};
|
|
|
|
return (
|
|
<BackgroundContext.Provider value={{ backgroundImage, setBackgroundImage, cycleBackground }}>
|
|
{children}
|
|
</BackgroundContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function useBackground() {
|
|
const context = useContext(BackgroundContext);
|
|
if (context === undefined) {
|
|
throw new Error('useBackground must be used within a BackgroundProvider');
|
|
}
|
|
return context;
|
|
}
|