diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 208d79d..38dd45b 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -8,6 +8,7 @@ import { UserPreferencesProvider } from "@/contexts/UserPreferencesContext";
import { KeyboardShortcutsProvider } from "@/contexts/KeyboardShortcutsContext";
import { userPreferencesService } from "@/services/core/user-preferences";
import { KeyboardShortcuts } from "@/components/KeyboardShortcuts";
+import { GlobalKeyboardShortcuts } from "@/components/GlobalKeyboardShortcuts";
import { AuthProvider } from "../components/AuthProvider";
import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth';
@@ -55,6 +56,7 @@ export default async function RootLayout({
+
{children}
diff --git a/src/components/GlobalKeyboardShortcuts.tsx b/src/components/GlobalKeyboardShortcuts.tsx
new file mode 100644
index 0000000..cf007d9
--- /dev/null
+++ b/src/components/GlobalKeyboardShortcuts.tsx
@@ -0,0 +1,14 @@
+'use client';
+
+import { useGlobalKeyboardShortcuts } from '@/hooks/useGlobalKeyboardShortcuts';
+import { useBackgroundCycle } from '@/hooks/useBackgroundCycle';
+
+export function GlobalKeyboardShortcuts() {
+ const { cycleBackground } = useBackgroundCycle();
+
+ useGlobalKeyboardShortcuts({
+ onCycleBackground: cycleBackground
+ });
+
+ return null;
+}
diff --git a/src/components/settings/BackgroundImageSelector.tsx b/src/components/settings/BackgroundImageSelector.tsx
index b9cd056..da755be 100644
--- a/src/components/settings/BackgroundImageSelector.tsx
+++ b/src/components/settings/BackgroundImageSelector.tsx
@@ -87,11 +87,20 @@ export function BackgroundImageSelector() {
const [customUrl, setCustomUrl] = useState('');
const [showCustomInput, setShowCustomInput] = useState(false);
const [showAdvancedOptions, setShowAdvancedOptions] = useState(false);
+ const [preservedCustomUrl, setPreservedCustomUrl] = useState('');
const currentBackground = preferences?.viewPreferences?.backgroundImage;
const backgroundBlur = preferences?.viewPreferences?.backgroundBlur || 0;
const backgroundOpacity = preferences?.viewPreferences?.backgroundOpacity || 100;
+ // Préserver l'URL personnalisée si elle existe
+ useEffect(() => {
+ if (currentBackground && !PRESET_BACKGROUNDS.some(preset => preset.id === currentBackground)) {
+ setPreservedCustomUrl(currentBackground);
+ localStorage.setItem('preservedCustomBackground', currentBackground);
+ }
+ }, [currentBackground]);
+
const handlePresetSelect = (presetId: string) => {
const backgroundImage = presetId === 'none' ? undefined : presetId;
updateViewPreferences({ backgroundImage });
@@ -100,14 +109,24 @@ export function BackgroundImageSelector() {
const handleCustomUrlSubmit = () => {
if (!customUrl.trim()) return;
- updateViewPreferences({ backgroundImage: customUrl.trim() });
+ const url = customUrl.trim();
+ updateViewPreferences({ backgroundImage: url });
+ setPreservedCustomUrl(url);
+ localStorage.setItem('preservedCustomBackground', url);
setCustomUrl('');
setShowCustomInput(false);
};
-
const handleRemoveCustom = () => {
updateViewPreferences({ backgroundImage: undefined });
+ setPreservedCustomUrl('');
+ localStorage.removeItem('preservedCustomBackground');
+ };
+
+ const handleRestoreCustom = () => {
+ if (preservedCustomUrl) {
+ updateViewPreferences({ backgroundImage: preservedCustomUrl });
+ }
};
const handleBlurChange = (blur: number) => {
@@ -212,13 +231,25 @@ export function BackgroundImageSelector() {
Ajoutez votre propre image de fond
-
+
+ {preservedCustomUrl && (
+
+ )}
+
+
{showCustomInput && (
diff --git a/src/contexts/KeyboardShortcutsContext.tsx b/src/contexts/KeyboardShortcutsContext.tsx
index 66655fa..45ae910 100644
--- a/src/contexts/KeyboardShortcutsContext.tsx
+++ b/src/contexts/KeyboardShortcutsContext.tsx
@@ -32,6 +32,11 @@ const PAGE_SHORTCUTS: PageShortcuts = {
description: 'Faire tourner les thèmes dark',
category: 'Apparence'
},
+ {
+ keys: ['Shift', 'B'],
+ description: 'Changer le background',
+ category: 'Apparence'
+ },
{
keys: ['Esc'],
description: 'Fermer les modales/annuler',
diff --git a/src/hooks/useBackgroundCycle.ts b/src/hooks/useBackgroundCycle.ts
new file mode 100644
index 0000000..1e93a90
--- /dev/null
+++ b/src/hooks/useBackgroundCycle.ts
@@ -0,0 +1,103 @@
+'use client';
+
+import { useUserPreferences } from '@/contexts/UserPreferencesContext';
+
+// Liste des backgrounds prédéfinis pour le cycle
+const BACKGROUND_CYCLE = [
+ 'none',
+ 'theme-subtle',
+ 'theme-primary',
+ 'theme-accent',
+ 'theme-success',
+ 'theme-purple',
+ 'theme-diagonal',
+ 'theme-radial',
+ 'theme-sunset',
+ 'theme-ocean',
+ 'theme-forest',
+ 'theme-galaxy'
+];
+
+export function useBackgroundCycle() {
+ const { preferences, updateViewPreferences } = useUserPreferences();
+
+ const cycleBackground = () => {
+ const currentBackground = preferences?.viewPreferences?.backgroundImage;
+
+ // Construire la liste complète des backgrounds (prédéfinis + personnalisé)
+ const allBackgrounds = [...BACKGROUND_CYCLE];
+
+ // Ajouter l'image personnalisée préservée si elle existe
+ const preservedCustomUrl = localStorage.getItem('preservedCustomBackground');
+ console.log('Debug cycle:', {
+ currentBackground,
+ preservedCustomUrl,
+ localStorageKeys: Object.keys(localStorage)
+ });
+
+ if (preservedCustomUrl && !BACKGROUND_CYCLE.includes(preservedCustomUrl)) {
+ allBackgrounds.push(preservedCustomUrl);
+ }
+
+ // Ajouter aussi l'image actuelle si elle est personnalisée ET différente de celle préservée
+ if (currentBackground &&
+ !BACKGROUND_CYCLE.includes(currentBackground) &&
+ currentBackground !== preservedCustomUrl) {
+ allBackgrounds.push(currentBackground);
+ }
+
+ const currentIndex = allBackgrounds.findIndex(bg => bg === currentBackground);
+
+ // Si on ne trouve pas l'index, c'est qu'on est sur "none" (undefined)
+ // Dans ce cas, on commence au début de la liste
+ let actualCurrentIndex = currentIndex;
+ if (currentIndex === -1) {
+ actualCurrentIndex = -1; // On est sur "none", on va commencer à l'index 0
+ }
+
+ const nextIndex = (actualCurrentIndex + 1) % allBackgrounds.length;
+ const nextBackground = allBackgrounds[nextIndex];
+
+ // Si c'est 'none', on met undefined
+ const backgroundImage = nextBackground === 'none' ? undefined : nextBackground;
+
+ // Si on est sur "none" (undefined) et qu'on va vers "none", on va vers le suivant
+ if (currentBackground === undefined && nextBackground === 'none') {
+ const nextNextIndex = (nextIndex + 1) % allBackgrounds.length;
+ const nextNextBackground = allBackgrounds[nextNextIndex];
+ const finalBackgroundImage = nextNextBackground === 'none' ? undefined : nextNextBackground;
+
+ console.log('Cycle result:', {
+ allBackgrounds,
+ currentIndex,
+ actualCurrentIndex,
+ nextIndex,
+ nextBackground,
+ backgroundImage,
+ currentBackground,
+ nextNextIndex,
+ nextNextBackground,
+ finalBackgroundImage
+ });
+
+ updateViewPreferences({ backgroundImage: finalBackgroundImage });
+ return;
+ }
+
+ console.log('Cycle result:', {
+ allBackgrounds,
+ currentIndex,
+ actualCurrentIndex,
+ nextIndex,
+ nextBackground,
+ backgroundImage,
+ currentBackground
+ });
+
+ updateViewPreferences({ backgroundImage });
+ };
+
+ return {
+ cycleBackground
+ };
+}
diff --git a/src/hooks/useGlobalKeyboardShortcuts.ts b/src/hooks/useGlobalKeyboardShortcuts.ts
index acf657f..2f9b153 100644
--- a/src/hooks/useGlobalKeyboardShortcuts.ts
+++ b/src/hooks/useGlobalKeyboardShortcuts.ts
@@ -21,6 +21,7 @@ interface KeyboardShortcutsActions {
onSave?: () => void;
onBackup?: () => void;
onOpenSearch?: () => void;
+ onCycleBackground?: () => void;
}
export function useGlobalKeyboardShortcuts(actions: KeyboardShortcutsActions = {}) {
@@ -56,6 +57,10 @@ export function useGlobalKeyboardShortcuts(actions: KeyboardShortcutsActions = {
event.preventDefault();
actions.onOpenSearch?.();
return;
+ case 'B':
+ event.preventDefault();
+ actions.onCycleBackground?.();
+ return;
}
}