refactor: update theme management and enhance UI components
- Refactored theme imports in `preferences.ts` and `ThemeSelector.tsx` to use centralized `theme-config`. - Added new CSS variables for special cards in `globals.css` to improve theme consistency. - Enhanced `Header` and `TaskCard` components with theme dropdown functionality for better user experience. - Updated `ThemeProvider` to support cycling through dark themes, improving theme selection flexibility. - Cleaned up unused imports and streamlined component structures for better maintainability.
This commit is contained in:
@@ -5,6 +5,8 @@ import { useJiraConfig } from '@/contexts/JiraConfigContext';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import Link from 'next/link';
|
||||
import { useState } from 'react';
|
||||
import { Theme } from '@/lib/theme-config';
|
||||
import { THEME_CONFIG, getThemeMetadata } from '@/lib/theme-config';
|
||||
|
||||
interface HeaderProps {
|
||||
title?: string;
|
||||
@@ -13,10 +15,22 @@ interface HeaderProps {
|
||||
}
|
||||
|
||||
export function Header({ title = "TowerControl", subtitle = "Task Management", syncing = false }: HeaderProps) {
|
||||
const { theme, toggleTheme, userPreferredTheme } = useTheme();
|
||||
const { theme, setTheme } = useTheme();
|
||||
const { isConfigured: isJiraConfigured, config: jiraConfig } = useJiraConfig();
|
||||
const pathname = usePathname();
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
||||
const [themeDropdownOpen, setThemeDropdownOpen] = useState(false);
|
||||
|
||||
// Liste des thèmes disponibles avec leurs labels et icônes
|
||||
const themes: { value: Theme; label: string; icon: string }[] = THEME_CONFIG.allThemes.map(themeValue => {
|
||||
const metadata = getThemeMetadata(themeValue);
|
||||
|
||||
return {
|
||||
value: themeValue,
|
||||
label: metadata.name,
|
||||
icon: metadata.icon
|
||||
};
|
||||
});
|
||||
|
||||
// Fonction pour déterminer si un lien est actif
|
||||
const isActiveLink = (href: string) => {
|
||||
@@ -83,24 +97,53 @@ export function Header({ title = "TowerControl", subtitle = "Task Management", s
|
||||
|
||||
{/* Controls mobile/tablette */}
|
||||
<div className="flex items-center gap-2 flex-shrink-0">
|
||||
{/* Theme Toggle */}
|
||||
<button
|
||||
onClick={toggleTheme}
|
||||
className="text-[var(--muted-foreground)] hover:text-[var(--primary)] transition-colors p-2 rounded-md hover:bg-[var(--card-hover)]"
|
||||
title={theme === 'light' ? `Switch to ${userPreferredTheme} theme` : 'Switch to light theme'}
|
||||
>
|
||||
{theme === 'light' ? (
|
||||
// Soleil pour le thème clair
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
|
||||
</svg>
|
||||
) : (
|
||||
// Lune pour tous les thèmes sombres
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
|
||||
</svg>
|
||||
{/* Theme Dropdown */}
|
||||
<div className="relative">
|
||||
<button
|
||||
onClick={() => setThemeDropdownOpen(!themeDropdownOpen)}
|
||||
className="text-[var(--muted-foreground)] hover:text-[var(--primary)] transition-colors p-2 rounded-md hover:bg-[var(--card-hover)]"
|
||||
title="Select theme"
|
||||
>
|
||||
{themes.find(t => t.value === theme)?.icon || '🎨'}
|
||||
</button>
|
||||
|
||||
{themeDropdownOpen && (
|
||||
<>
|
||||
{/* Backdrop */}
|
||||
<div
|
||||
className="fixed inset-0 z-[200]"
|
||||
onClick={() => setThemeDropdownOpen(false)}
|
||||
/>
|
||||
{/* Dropdown */}
|
||||
<div className="absolute right-0 top-full mt-2 w-48 bg-[var(--card)] border border-[var(--border)] rounded-lg shadow-lg z-[201] overflow-hidden">
|
||||
<div className="py-2">
|
||||
{themes.map((themeOption) => (
|
||||
<button
|
||||
key={themeOption.value}
|
||||
onClick={() => {
|
||||
setTheme(themeOption.value);
|
||||
setThemeDropdownOpen(false);
|
||||
}}
|
||||
className={`w-full text-left px-4 py-2 text-sm transition-colors flex items-center gap-3 ${
|
||||
theme === themeOption.value
|
||||
? 'text-[var(--primary)] bg-[var(--primary)]/10'
|
||||
: 'text-[var(--muted-foreground)] hover:text-[var(--foreground)] hover:bg-[var(--card-hover)]'
|
||||
}`}
|
||||
>
|
||||
<span className="text-base">{themeOption.icon}</span>
|
||||
<span className="font-mono">{themeOption.label}</span>
|
||||
{theme === themeOption.value && (
|
||||
<svg className="w-4 h-4 ml-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
)}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Menu burger */}
|
||||
<button
|
||||
@@ -154,22 +197,53 @@ export function Header({ title = "TowerControl", subtitle = "Task Management", s
|
||||
</Link>
|
||||
))}
|
||||
|
||||
{/* Theme Toggle desktop */}
|
||||
<button
|
||||
onClick={toggleTheme}
|
||||
className="text-[var(--muted-foreground)] hover:text-[var(--primary)] transition-colors p-1 rounded-md hover:bg-[var(--card-hover)]"
|
||||
title={`Switch to ${theme === 'dark' ? 'light' : 'dark'} theme`}
|
||||
>
|
||||
{theme === 'dark' ? (
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
|
||||
</svg>
|
||||
) : (
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
|
||||
</svg>
|
||||
{/* Theme Dropdown desktop */}
|
||||
<div className="relative">
|
||||
<button
|
||||
onClick={() => setThemeDropdownOpen(!themeDropdownOpen)}
|
||||
className="text-[var(--muted-foreground)] hover:text-[var(--primary)] transition-colors p-1 rounded-md hover:bg-[var(--card-hover)]"
|
||||
title="Select theme"
|
||||
>
|
||||
{themes.find(t => t.value === theme)?.icon || '🎨'}
|
||||
</button>
|
||||
|
||||
{themeDropdownOpen && (
|
||||
<>
|
||||
{/* Backdrop */}
|
||||
<div
|
||||
className="fixed inset-0 z-[200]"
|
||||
onClick={() => setThemeDropdownOpen(false)}
|
||||
/>
|
||||
{/* Dropdown */}
|
||||
<div className="absolute right-0 top-full mt-2 w-48 bg-[var(--card)] border border-[var(--border)] rounded-lg shadow-lg z-[201] overflow-hidden">
|
||||
<div className="py-2">
|
||||
{themes.map((themeOption) => (
|
||||
<button
|
||||
key={themeOption.value}
|
||||
onClick={() => {
|
||||
setTheme(themeOption.value);
|
||||
setThemeDropdownOpen(false);
|
||||
}}
|
||||
className={`w-full text-left px-4 py-2 text-sm transition-colors flex items-center gap-3 ${
|
||||
theme === themeOption.value
|
||||
? 'text-[var(--primary)] bg-[var(--primary)]/10'
|
||||
: 'text-[var(--muted-foreground)] hover:text-[var(--foreground)] hover:bg-[var(--card-hover)]'
|
||||
}`}
|
||||
>
|
||||
<span className="text-base">{themeOption.icon}</span>
|
||||
<span className="font-mono">{themeOption.label}</span>
|
||||
{theme === themeOption.value && (
|
||||
<svg className="w-4 h-4 ml-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
)}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user