feat: integrate ToastProvider and enhance theme management
- Added `ToastProvider` to `RootLayout` for improved user feedback on theme changes. - Updated `ThemeProvider` to display toast notifications with theme names and icons upon theme changes. - Refactored theme-related imports to streamline code and improve maintainability. - Simplified background cycling logic in `useBackgroundCycle` to utilize centralized background definitions. - Cleaned up unused background definitions in `BackgroundContext` for better clarity and performance.
This commit is contained in:
@@ -40,7 +40,7 @@ export const THEME_CONFIG = {
|
||||
'solarized'
|
||||
] as Theme[],
|
||||
|
||||
// Métadonnées des thèmes (pour l'UI future)
|
||||
// Métadonnées des thèmes (déplacées vers ui-config.ts)
|
||||
metadata: {
|
||||
light: { name: 'Light', description: 'Thème clair par défaut', icon: '☀️' },
|
||||
dark: { name: 'Dark', description: 'Thème sombre classique', icon: '🌙' },
|
||||
|
||||
254
src/lib/ui-config.ts
Normal file
254
src/lib/ui-config.ts
Normal file
@@ -0,0 +1,254 @@
|
||||
// ===== CONFIGURATION DES THÈMES =====
|
||||
|
||||
// Types de thèmes
|
||||
export type Theme = 'light' | 'dark' | 'dracula' | 'monokai' | 'nord' | 'gruvbox' | 'tokyo_night' | 'catppuccin' | 'rose_pine' | 'one_dark' | 'material' | 'solarized';
|
||||
|
||||
// Configuration des thèmes
|
||||
export const THEME_CONFIG = {
|
||||
// Thème par défaut
|
||||
default: 'dark' as Theme,
|
||||
|
||||
// Thème light
|
||||
light: 'light' as Theme,
|
||||
|
||||
// Liste de tous les thèmes dark disponibles
|
||||
darkThemes: [
|
||||
'dark',
|
||||
'dracula',
|
||||
'monokai',
|
||||
'nord',
|
||||
'gruvbox',
|
||||
'tokyo_night',
|
||||
'catppuccin',
|
||||
'rose_pine',
|
||||
'one_dark',
|
||||
'material',
|
||||
'solarized'
|
||||
] as Theme[],
|
||||
|
||||
// Tous les thèmes disponibles
|
||||
allThemes: [
|
||||
'light',
|
||||
'dark',
|
||||
'dracula',
|
||||
'monokai',
|
||||
'nord',
|
||||
'gruvbox',
|
||||
'tokyo_night',
|
||||
'catppuccin',
|
||||
'rose_pine',
|
||||
'one_dark',
|
||||
'material',
|
||||
'solarized'
|
||||
] as Theme[]
|
||||
} as const;
|
||||
|
||||
// Métadonnées des thèmes pour l'affichage
|
||||
export const THEME_METADATA: Record<Theme, { name: string; description: string; icon: string }> = {
|
||||
light: { name: 'Light', description: 'Thème clair par défaut', icon: '☀️' },
|
||||
dark: { name: 'Dark', description: 'Thème sombre classique', icon: '🌙' },
|
||||
dracula: { name: 'Dracula', description: 'Inspiré du thème Dracula', icon: '🧛' },
|
||||
monokai: { name: 'Monokai', description: 'Inspiré du thème Monokai', icon: '🎨' },
|
||||
nord: { name: 'Nord', description: 'Palette Nord arctique', icon: '❄️' },
|
||||
gruvbox: { name: 'Gruvbox', description: 'Palette Gruvbox retro', icon: '🎭' },
|
||||
tokyo_night: { name: 'Tokyo Night', description: 'Nuit tokyoïte', icon: '🌃' },
|
||||
catppuccin: { name: 'Catppuccin', description: 'Palette pastel douce', icon: '🐱' },
|
||||
rose_pine: { name: 'Rose Pine', description: 'Palette rose et pin', icon: '🌹' },
|
||||
one_dark: { name: 'One Dark', description: 'Inspiré d\'Atom One Dark', icon: '🌑' },
|
||||
material: { name: 'Material', description: 'Inspiré de Material Design', icon: '📱' },
|
||||
solarized: { name: 'Solarized', description: 'Palette Solarized', icon: '☀️' }
|
||||
};
|
||||
|
||||
// Fonctions utilitaires pour les thèmes
|
||||
export const getNextDarkTheme = (currentTheme: Theme): Theme => {
|
||||
const currentIndex = THEME_CONFIG.darkThemes.indexOf(currentTheme);
|
||||
if (currentIndex === -1) {
|
||||
return THEME_CONFIG.darkThemes[0];
|
||||
}
|
||||
const nextIndex = (currentIndex + 1) % THEME_CONFIG.darkThemes.length;
|
||||
return THEME_CONFIG.darkThemes[nextIndex];
|
||||
};
|
||||
|
||||
export const isDarkTheme = (theme: Theme): boolean => {
|
||||
return THEME_CONFIG.darkThemes.includes(theme);
|
||||
};
|
||||
|
||||
export const getThemeMetadata = (theme: Theme) => {
|
||||
return THEME_METADATA[theme] || { name: theme, description: 'Thème personnalisé', icon: '🎨' };
|
||||
};
|
||||
|
||||
// ===== CONFIGURATION DES BACKGROUNDS =====
|
||||
|
||||
// Configuration des backgrounds prédéfinis
|
||||
export const PRESET_BACKGROUNDS = [
|
||||
{
|
||||
id: 'none',
|
||||
name: 'Aucun fond',
|
||||
description: 'Fond par défaut du système',
|
||||
preview: 'var(--background)'
|
||||
},
|
||||
{
|
||||
id: 'theme-subtle',
|
||||
name: 'Dégradé subtil',
|
||||
description: 'Dégradé très léger et discret',
|
||||
preview: 'linear-gradient(135deg, color-mix(in srgb, var(--primary) 8%, var(--background)) 0%, color-mix(in srgb, var(--accent) 5%, var(--background)) 100%)'
|
||||
},
|
||||
{
|
||||
id: 'theme-primary',
|
||||
name: 'Dégradé primaire',
|
||||
description: 'Dégradé avec la couleur primaire',
|
||||
preview: 'linear-gradient(135deg, color-mix(in srgb, var(--primary) 25%, var(--background)) 0%, color-mix(in srgb, var(--primary) 15%, var(--background)) 100%)'
|
||||
},
|
||||
{
|
||||
id: 'theme-accent',
|
||||
name: 'Dégradé accent',
|
||||
description: 'Dégradé avec la couleur accent',
|
||||
preview: 'linear-gradient(135deg, color-mix(in srgb, var(--accent) 25%, var(--background)) 0%, color-mix(in srgb, var(--accent) 15%, var(--background)) 100%)'
|
||||
},
|
||||
{
|
||||
id: 'theme-success',
|
||||
name: 'Dégradé vert',
|
||||
description: 'Dégradé avec la couleur de succès',
|
||||
preview: 'linear-gradient(135deg, color-mix(in srgb, var(--success) 25%, var(--background)) 0%, color-mix(in srgb, var(--success) 15%, var(--background)) 100%)'
|
||||
},
|
||||
{
|
||||
id: 'theme-purple',
|
||||
name: 'Dégradé violet',
|
||||
description: 'Dégradé avec la couleur violette',
|
||||
preview: 'linear-gradient(135deg, color-mix(in srgb, var(--purple) 25%, var(--background)) 0%, color-mix(in srgb, var(--purple) 15%, var(--background)) 100%)'
|
||||
},
|
||||
{
|
||||
id: 'theme-diagonal',
|
||||
name: 'Dégradé diagonal',
|
||||
description: 'Dégradé diagonal dynamique',
|
||||
preview: 'linear-gradient(45deg, color-mix(in srgb, var(--primary) 20%, var(--background)) 0%, color-mix(in srgb, var(--accent) 20%, var(--background)) 50%, color-mix(in srgb, var(--success) 20%, var(--background)) 100%)'
|
||||
},
|
||||
{
|
||||
id: 'theme-radial',
|
||||
name: 'Dégradé radial',
|
||||
description: 'Dégradé radial depuis le centre',
|
||||
preview: 'radial-gradient(circle, color-mix(in srgb, var(--primary) 20%, var(--background)) 0%, color-mix(in srgb, var(--accent) 10%, var(--background)) 70%, var(--background) 100%)'
|
||||
},
|
||||
{
|
||||
id: 'theme-sunset',
|
||||
name: 'Dégradé coucher',
|
||||
description: 'Dégradé inspiré du coucher de soleil',
|
||||
preview: 'linear-gradient(135deg, color-mix(in srgb, var(--accent) 25%, var(--background)) 0%, color-mix(in srgb, var(--purple) 20%, var(--background)) 50%, color-mix(in srgb, var(--primary) 15%, var(--background)) 100%)'
|
||||
},
|
||||
{
|
||||
id: 'theme-ocean',
|
||||
name: 'Dégradé océan',
|
||||
description: 'Dégradé inspiré de l\'océan',
|
||||
preview: 'linear-gradient(135deg, color-mix(in srgb, var(--primary) 25%, var(--background)) 0%, color-mix(in srgb, var(--blue) 20%, var(--background)) 50%, color-mix(in srgb, var(--success) 15%, var(--background)) 100%)'
|
||||
},
|
||||
{
|
||||
id: 'theme-forest',
|
||||
name: 'Dégradé forêt',
|
||||
description: 'Dégradé inspiré de la forêt',
|
||||
preview: 'linear-gradient(135deg, color-mix(in srgb, var(--success) 25%, var(--background)) 0%, color-mix(in srgb, var(--green) 20%, var(--background)) 50%, color-mix(in srgb, var(--accent) 15%, var(--background)) 100%)'
|
||||
},
|
||||
{
|
||||
id: 'theme-galaxy',
|
||||
name: 'Dégradé galaxie',
|
||||
description: 'Dégradé inspiré de la galaxie',
|
||||
preview: 'linear-gradient(135deg, color-mix(in srgb, var(--purple) 25%, var(--background)) 0%, color-mix(in srgb, var(--blue) 20%, var(--background)) 100%)'
|
||||
}
|
||||
] as const;
|
||||
|
||||
// Liste des backgrounds pour le cycle (IDs seulement)
|
||||
export const BACKGROUND_CYCLE = PRESET_BACKGROUNDS.map(bg => bg.id);
|
||||
|
||||
// Types pour les backgrounds
|
||||
export type BackgroundId = typeof PRESET_BACKGROUNDS[number]['id'];
|
||||
|
||||
// Fonctions utilitaires pour les backgrounds
|
||||
export const getBackgroundById = (id: BackgroundId) => {
|
||||
return PRESET_BACKGROUNDS.find(bg => bg.id === id);
|
||||
};
|
||||
|
||||
export const isPresetBackground = (id: string): id is BackgroundId => {
|
||||
return PRESET_BACKGROUNDS.some(bg => bg.id === id);
|
||||
};
|
||||
|
||||
export const getNextBackground = (currentBackground: string, customImages: string[] = []): string => {
|
||||
const allBackgrounds = [...BACKGROUND_CYCLE];
|
||||
|
||||
// Ajouter toutes les images personnalisées
|
||||
customImages.forEach(url => {
|
||||
if (!allBackgrounds.includes(url as typeof BACKGROUND_CYCLE[number])) {
|
||||
allBackgrounds.push(url as typeof BACKGROUND_CYCLE[number]);
|
||||
}
|
||||
});
|
||||
|
||||
const currentIndex = allBackgrounds.findIndex(bg => bg === currentBackground);
|
||||
|
||||
// Si on ne trouve pas l'index, c'est qu'on est sur "none" (undefined)
|
||||
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 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;
|
||||
return allBackgrounds[nextNextIndex];
|
||||
}
|
||||
|
||||
return nextBackground;
|
||||
};
|
||||
|
||||
// ===== MÉTADONNÉES D'AFFICHAGE =====
|
||||
|
||||
// Mapping des noms de backgrounds pour l'affichage
|
||||
export const BACKGROUND_NAMES: Record<string, string> = {
|
||||
'none': 'Aucun fond',
|
||||
'theme-subtle': 'Dégradé subtil',
|
||||
'theme-primary': 'Dégradé primaire',
|
||||
'theme-accent': 'Dégradé accent',
|
||||
'theme-success': 'Dégradé vert',
|
||||
'theme-purple': 'Dégradé violet',
|
||||
'theme-diagonal': 'Dégradé diagonal',
|
||||
'theme-radial': 'Dégradé radial',
|
||||
'theme-sunset': 'Dégradé coucher',
|
||||
'theme-ocean': 'Dégradé océan',
|
||||
'theme-forest': 'Dégradé forêt',
|
||||
'theme-galaxy': 'Dégradé galaxie'
|
||||
};
|
||||
|
||||
// Mapping des noms de thèmes pour l'affichage
|
||||
export const THEME_NAMES: Record<Theme, string> = {
|
||||
'light': 'Thème clair',
|
||||
'dark': 'Thème sombre',
|
||||
'dracula': 'Thème Dracula',
|
||||
'monokai': 'Thème Monokai',
|
||||
'nord': 'Thème Nord',
|
||||
'gruvbox': 'Thème Gruvbox',
|
||||
'tokyo_night': 'Thème Tokyo Night',
|
||||
'catppuccin': 'Thème Catppuccin',
|
||||
'rose_pine': 'Thème Rose Pine',
|
||||
'one_dark': 'Thème One Dark',
|
||||
'material': 'Thème Material',
|
||||
'solarized': 'Thème Solarized'
|
||||
};
|
||||
|
||||
// Fonctions utilitaires pour les métadonnées
|
||||
export const getThemeIcon = (theme: Theme): string => {
|
||||
return THEME_METADATA[theme].icon;
|
||||
};
|
||||
|
||||
export const getThemeName = (theme: Theme): string => {
|
||||
return THEME_METADATA[theme].name;
|
||||
};
|
||||
|
||||
export const getThemeDescription = (theme: Theme): string => {
|
||||
return THEME_METADATA[theme].description;
|
||||
};
|
||||
|
||||
// Icônes pour les toasts
|
||||
export const TOAST_ICONS = {
|
||||
background: '🎨',
|
||||
theme: '🎭'
|
||||
} as const;
|
||||
Reference in New Issue
Block a user