feat: implement theme system and UI updates
- Added theme context and provider for light/dark mode support. - Integrated theme toggle button in the Header component. - Updated UI components to utilize CSS variables for consistent theming. - Enhanced Kanban components and forms with new theme styles for better visual coherence. - Adjusted global styles to define color variables for both themes, improving maintainability.
This commit is contained in:
@@ -182,7 +182,7 @@ export function KanbanFilters({ filters, onFiltersChange, hiddenStatuses: propsH
|
||||
}, [availableTags, tagCounts]);
|
||||
|
||||
return (
|
||||
<div className="bg-slate-900/50 border-b border-slate-700/50 backdrop-blur-sm">
|
||||
<div className="bg-[var(--card)]/50 border-b border-[var(--border)]/50 backdrop-blur-sm">
|
||||
<div className="container mx-auto px-6 py-4">
|
||||
{/* Header avec recherche et bouton expand */}
|
||||
<div className="flex items-center gap-4">
|
||||
@@ -192,7 +192,7 @@ export function KanbanFilters({ filters, onFiltersChange, hiddenStatuses: propsH
|
||||
value={filters.search || ''}
|
||||
onChange={(e) => handleSearchChange(e.target.value)}
|
||||
placeholder="Rechercher des tâches..."
|
||||
className="bg-slate-800/50 border-slate-600"
|
||||
className="bg-[var(--card)] border-[var(--border)]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -309,7 +309,7 @@ export function KanbanFilters({ filters, onFiltersChange, hiddenStatuses: propsH
|
||||
</svg>
|
||||
Filtres
|
||||
{activeFiltersCount > 0 && (
|
||||
<span className="bg-cyan-500 text-slate-900 text-xs px-2 py-0.5 rounded-full font-medium">
|
||||
<span className="bg-[var(--primary)] text-[var(--primary-foreground)] text-xs px-2 py-0.5 rounded-full font-medium">
|
||||
{activeFiltersCount}
|
||||
</span>
|
||||
)}
|
||||
@@ -327,7 +327,7 @@ export function KanbanFilters({ filters, onFiltersChange, hiddenStatuses: propsH
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={handleClearFilters}
|
||||
className="text-slate-400 hover:text-red-400"
|
||||
className="text-[var(--muted-foreground)] hover:text-[var(--destructive)]"
|
||||
>
|
||||
Effacer
|
||||
</Button>
|
||||
@@ -336,12 +336,12 @@ export function KanbanFilters({ filters, onFiltersChange, hiddenStatuses: propsH
|
||||
|
||||
{/* Filtres étendus */}
|
||||
{isExpanded && (
|
||||
<div className="mt-4 border-t border-slate-700/50 pt-4">
|
||||
<div className="mt-4 border-t border-[var(--border)]/50 pt-4">
|
||||
{/* Grille responsive pour les filtres */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[auto_1fr] gap-6 lg:gap-8">
|
||||
{/* Filtres par priorité */}
|
||||
<div className="space-y-3">
|
||||
<label className="block text-xs font-mono font-medium text-slate-300 uppercase tracking-wider">
|
||||
<label className="block text-xs font-mono font-medium text-[var(--muted-foreground)] uppercase tracking-wider">
|
||||
Priorités
|
||||
</label>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
@@ -352,7 +352,7 @@ export function KanbanFilters({ filters, onFiltersChange, hiddenStatuses: propsH
|
||||
className={`flex items-center gap-2 px-3 py-2 rounded-lg border transition-all text-xs font-medium whitespace-nowrap ${
|
||||
filters.priorities?.includes(priority.value)
|
||||
? 'border-cyan-400 bg-cyan-400/10 text-cyan-400'
|
||||
: 'border-slate-600 bg-slate-800/50 text-slate-400 hover:border-slate-500'
|
||||
: 'border-[var(--border)] bg-[var(--card)] text-[var(--muted-foreground)] hover:border-[var(--border)]'
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
@@ -368,7 +368,7 @@ export function KanbanFilters({ filters, onFiltersChange, hiddenStatuses: propsH
|
||||
{/* Filtres par tags */}
|
||||
{availableTags.length > 0 && (
|
||||
<div className="space-y-3">
|
||||
<label className="block text-xs font-mono font-medium text-slate-300 uppercase tracking-wider">
|
||||
<label className="block text-xs font-mono font-medium text-[var(--muted-foreground)] uppercase tracking-wider">
|
||||
Tags
|
||||
</label>
|
||||
<div className="flex flex-wrap gap-2 max-h-32 overflow-y-auto">
|
||||
@@ -379,7 +379,7 @@ export function KanbanFilters({ filters, onFiltersChange, hiddenStatuses: propsH
|
||||
className={`flex items-center gap-2 px-3 py-2 rounded-lg border transition-all text-xs font-medium ${
|
||||
filters.tags?.includes(tag.name)
|
||||
? 'border-cyan-400 bg-cyan-400/10 text-cyan-400'
|
||||
: 'border-slate-600 bg-slate-800/50 text-slate-400 hover:border-slate-500'
|
||||
: 'border-[var(--border)] bg-[var(--card)] text-[var(--muted-foreground)] hover:border-[var(--border)]'
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
@@ -395,7 +395,7 @@ export function KanbanFilters({ filters, onFiltersChange, hiddenStatuses: propsH
|
||||
</div>
|
||||
|
||||
{/* Visibilité des colonnes */}
|
||||
<div className="col-span-full border-t border-slate-700/50 pt-6 mt-4">
|
||||
<div className="col-span-full border-t border-[var(--border)]/50 pt-6 mt-4">
|
||||
<ColumnVisibilityToggle
|
||||
hiddenStatuses={hiddenStatuses}
|
||||
onToggleStatus={toggleStatusVisibility}
|
||||
@@ -406,23 +406,23 @@ export function KanbanFilters({ filters, onFiltersChange, hiddenStatuses: propsH
|
||||
|
||||
{/* Résumé des filtres actifs */}
|
||||
{activeFiltersCount > 0 && (
|
||||
<div className="bg-slate-800/30 rounded-lg p-3 border border-slate-700/50">
|
||||
<div className="text-xs text-slate-400 font-mono uppercase tracking-wider mb-2">
|
||||
<div className="bg-[var(--card)]/30 rounded-lg p-3 border border-[var(--border)]/50">
|
||||
<div className="text-xs text-[var(--muted-foreground)] font-mono uppercase tracking-wider mb-2">
|
||||
Filtres actifs
|
||||
</div>
|
||||
<div className="space-y-1 text-xs">
|
||||
{filters.search && (
|
||||
<div className="text-slate-300">
|
||||
<div className="text-[var(--muted-foreground)]">
|
||||
Recherche: <span className="text-cyan-400">“{filters.search}”</span>
|
||||
</div>
|
||||
)}
|
||||
{filters.priorities?.length && (
|
||||
<div className="text-slate-300">
|
||||
<div className="text-[var(--muted-foreground)]">
|
||||
Priorités: <span className="text-cyan-400">{filters.priorities.join(', ')}</span>
|
||||
</div>
|
||||
)}
|
||||
{filters.tags?.length && (
|
||||
<div className="text-slate-300">
|
||||
<div className="text-[var(--muted-foreground)]">
|
||||
Tags: <span className="text-cyan-400">{filters.tags.join(', ')}</span>
|
||||
</div>
|
||||
)}
|
||||
@@ -437,7 +437,7 @@ export function KanbanFilters({ filters, onFiltersChange, hiddenStatuses: propsH
|
||||
{isSortExpanded && typeof window !== 'undefined' && createPortal(
|
||||
<div
|
||||
ref={sortDropdownRef}
|
||||
className="fixed w-80 bg-slate-800 border border-slate-700 rounded-lg shadow-xl z-[9999] max-h-64 overflow-y-auto"
|
||||
className="fixed w-80 bg-[var(--card)] border border-[var(--border)] rounded-lg shadow-xl z-[9999] max-h-64 overflow-y-auto"
|
||||
style={{
|
||||
top: dropdownPosition.top,
|
||||
left: dropdownPosition.left
|
||||
@@ -450,10 +450,10 @@ export function KanbanFilters({ filters, onFiltersChange, hiddenStatuses: propsH
|
||||
handleSortChange(option.key);
|
||||
setIsSortExpanded(false);
|
||||
}}
|
||||
className={`w-full px-3 py-2 text-left text-xs font-mono hover:bg-slate-700 transition-colors flex items-center gap-2 ${
|
||||
className={`w-full px-3 py-2 text-left text-xs font-mono hover:bg-[var(--card-hover)] transition-colors flex items-center gap-2 ${
|
||||
(filters.sortBy || 'priority-desc') === option.key
|
||||
? 'bg-cyan-600/20 text-cyan-400 border-l-2 border-cyan-400'
|
||||
: 'text-slate-300'
|
||||
: 'text-[var(--muted-foreground)]'
|
||||
}`}
|
||||
>
|
||||
<span className="text-base">{option.icon}</span>
|
||||
@@ -473,7 +473,7 @@ export function KanbanFilters({ filters, onFiltersChange, hiddenStatuses: propsH
|
||||
{isSwimlaneModeExpanded && typeof window !== 'undefined' && createPortal(
|
||||
<div
|
||||
ref={swimlaneModeDropdownRef}
|
||||
className="fixed bg-slate-800 border border-slate-700 rounded-lg shadow-xl z-[9999] min-w-[140px]"
|
||||
className="fixed bg-[var(--card)] border border-[var(--border)] rounded-lg shadow-xl z-[9999] min-w-[140px]"
|
||||
style={{
|
||||
top: dropdownPosition.top,
|
||||
left: dropdownPosition.left,
|
||||
@@ -481,16 +481,16 @@ export function KanbanFilters({ filters, onFiltersChange, hiddenStatuses: propsH
|
||||
>
|
||||
<button
|
||||
onClick={() => handleSwimlaneModeChange('tags')}
|
||||
className={`w-full px-3 py-2 text-left text-xs hover:bg-slate-700 transition-colors flex items-center gap-2 first:rounded-t-lg ${
|
||||
(!filters.swimlanesMode || filters.swimlanesMode === 'tags') ? 'bg-slate-700 text-cyan-400' : 'text-slate-300'
|
||||
className={`w-full px-3 py-2 text-left text-xs hover:bg-[var(--card-hover)] transition-colors flex items-center gap-2 first:rounded-t-lg ${
|
||||
(!filters.swimlanesMode || filters.swimlanesMode === 'tags') ? 'bg-[var(--card-hover)] text-[var(--primary)]' : 'text-[var(--muted-foreground)]'
|
||||
}`}
|
||||
>
|
||||
🏷️ Par tags
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleSwimlaneModeChange('priority')}
|
||||
className={`w-full px-3 py-2 text-left text-xs hover:bg-slate-700 transition-colors flex items-center gap-2 last:rounded-b-lg ${
|
||||
filters.swimlanesMode === 'priority' ? 'bg-slate-700 text-cyan-400' : 'text-slate-300'
|
||||
className={`w-full px-3 py-2 text-left text-xs hover:bg-[var(--card-hover)] transition-colors flex items-center gap-2 last:rounded-b-lg ${
|
||||
filters.swimlanesMode === 'priority' ? 'bg-[var(--card-hover)] text-[var(--primary)]' : 'text-[var(--muted-foreground)]'
|
||||
}`}
|
||||
>
|
||||
🎯 Par priorité
|
||||
|
||||
Reference in New Issue
Block a user