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:
@@ -110,12 +110,12 @@ export function KanbanBoard({ tasks, onCreateTask, onDeleteTask, onEditTask, onU
|
||||
onDragStart={handleDragStart}
|
||||
onDragEnd={handleDragEnd}
|
||||
>
|
||||
<div className="h-full flex flex-col bg-slate-950">
|
||||
<div className="h-full flex flex-col bg-[var(--background)]">
|
||||
{/* Header avec bouton nouvelle tâche */}
|
||||
<div className="flex justify-between items-center p-6 pb-0">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-2 h-2 bg-cyan-400 rounded-full animate-pulse"></div>
|
||||
<h2 className="text-lg font-mono font-bold text-slate-100 uppercase tracking-wider">
|
||||
<div className="w-2 h-2 bg-[var(--primary)] rounded-full animate-pulse"></div>
|
||||
<h2 className="text-lg font-mono font-bold text-[var(--foreground)] uppercase tracking-wider">
|
||||
Kanban Board
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
@@ -35,9 +35,9 @@ export function KanbanColumn({ id, tasks, onCreateTask, onDeleteTask, onEditTask
|
||||
<div className="flex-shrink-0 w-80 md:w-1/4 md:flex-1 h-full">
|
||||
<Card
|
||||
ref={setNodeRef}
|
||||
variant="elevated"
|
||||
variant="column"
|
||||
className={`h-full flex flex-col transition-all duration-200 ${
|
||||
isOver ? 'ring-2 ring-cyan-400/50 bg-slate-800/60' : ''
|
||||
isOver ? 'ring-2 ring-[var(--primary)]/50 bg-[var(--card-hover)]' : ''
|
||||
}`}
|
||||
>
|
||||
<CardHeader className="pb-3">
|
||||
@@ -55,7 +55,7 @@ export function KanbanColumn({ id, tasks, onCreateTask, onDeleteTask, onEditTask
|
||||
{onCreateTask && (
|
||||
<button
|
||||
onClick={() => setShowQuickAdd(true)}
|
||||
className={`w-5 h-5 rounded-full border border-dashed ${style.border} ${style.accent} hover:bg-slate-800/50 transition-colors flex items-center justify-center text-xs font-mono`}
|
||||
className={`w-5 h-5 rounded-full border border-dashed ${style.border} ${style.accent} hover:bg-[var(--card-hover)] transition-colors flex items-center justify-center text-xs font-mono`}
|
||||
title="Ajouter une tâche rapide"
|
||||
>
|
||||
+
|
||||
@@ -81,10 +81,10 @@ export function KanbanColumn({ id, tasks, onCreateTask, onDeleteTask, onEditTask
|
||||
|
||||
{tasks.length === 0 && !showQuickAdd ? (
|
||||
<div className="text-center py-20">
|
||||
<div className={`w-16 h-16 mx-auto mb-4 rounded-full bg-slate-800 border-2 border-dashed ${style.border} flex items-center justify-center`}>
|
||||
<div className={`w-16 h-16 mx-auto mb-4 rounded-full bg-[var(--card)] border-2 border-dashed ${style.border} flex items-center justify-center`}>
|
||||
<span className={`text-2xl ${style.accent} opacity-50`}>{statusConfig.icon}</span>
|
||||
</div>
|
||||
<p className="text-xs font-mono text-slate-500 uppercase tracking-wide">NO DATA</p>
|
||||
<p className="text-xs font-mono text-[var(--muted-foreground)] uppercase tracking-wide">NO DATA</p>
|
||||
<div className="mt-2 flex justify-center">
|
||||
<div className={`w-8 h-0.5 ${style.accent.replace('text-', 'bg-')} opacity-30`}></div>
|
||||
</div>
|
||||
|
||||
@@ -30,7 +30,7 @@ export function ColumnVisibilityToggle({
|
||||
|
||||
return (
|
||||
<div className={`flex items-center gap-2 ${className}`}>
|
||||
<span className="text-sm font-mono font-medium text-slate-400">
|
||||
<span className="text-sm font-mono font-medium text-[var(--muted-foreground)]">
|
||||
Colonnes :
|
||||
</span>
|
||||
{statuses.map(statusConfig => (
|
||||
@@ -39,8 +39,8 @@ export function ColumnVisibilityToggle({
|
||||
onClick={() => onToggleStatus(statusConfig.key)}
|
||||
className={`px-3 py-1 rounded-lg text-xs font-mono font-medium transition-colors ${
|
||||
hiddenStatuses.has(statusConfig.key)
|
||||
? 'bg-slate-700/50 text-slate-500 hover:bg-slate-700'
|
||||
: 'bg-blue-600/20 text-blue-300 border border-blue-500/30 hover:bg-blue-600/30'
|
||||
? 'bg-[var(--muted)]/20 text-[var(--muted)] hover:bg-[var(--muted)]/30'
|
||||
: 'bg-[var(--primary)]/20 text-[var(--primary)] border border-[var(--primary)]/30 hover:bg-[var(--primary)]/30'
|
||||
}`}
|
||||
title={hiddenStatuses.has(statusConfig.key) ? `Afficher ${statusConfig.label}` : `Masquer ${statusConfig.label}`}
|
||||
>
|
||||
|
||||
@@ -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é
|
||||
|
||||
@@ -32,7 +32,7 @@ export function ObjectivesBoard({
|
||||
return (
|
||||
<div className="bg-gradient-to-r from-purple-900/20 to-blue-900/20 border-b border-purple-500/30">
|
||||
<div className="container mx-auto px-6 py-4">
|
||||
<Card className="bg-slate-800/50 border-purple-500/30 shadow-purple-500/10 shadow-lg">
|
||||
<Card className="bg-[var(--card)] border-[var(--accent)]/30 shadow-[var(--accent)]/10 shadow-lg">
|
||||
<CardHeader className="pb-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<button
|
||||
@@ -105,13 +105,13 @@ export function ObjectivesBoard({
|
||||
En cours / À faire
|
||||
</h3>
|
||||
<div className="flex-1"></div>
|
||||
<span className="text-xs text-slate-400 bg-slate-800/50 px-2 py-1 rounded">
|
||||
<span className="text-xs text-[var(--muted-foreground)] bg-[var(--card)] px-2 py-1 rounded">
|
||||
{activeTasks.length}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{activeTasks.length === 0 ? (
|
||||
<div className="text-center py-8 text-slate-400 text-sm">
|
||||
<div className="text-center py-8 text-[var(--muted-foreground)] text-sm">
|
||||
<div className="text-2xl mb-2">🎯</div>
|
||||
Aucun objectif actif
|
||||
</div>
|
||||
@@ -140,13 +140,13 @@ export function ObjectivesBoard({
|
||||
Terminé
|
||||
</h3>
|
||||
<div className="flex-1"></div>
|
||||
<span className="text-xs text-slate-400 bg-slate-800/50 px-2 py-1 rounded">
|
||||
<span className="text-xs text-[var(--muted-foreground)] bg-[var(--card)] px-2 py-1 rounded">
|
||||
{completedTasks.length}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{completedTasks.length === 0 ? (
|
||||
<div className="text-center py-8 text-slate-400 text-sm">
|
||||
<div className="text-center py-8 text-[var(--muted-foreground)] text-sm">
|
||||
<div className="text-2xl mb-2">✅</div>
|
||||
Aucun objectif terminé
|
||||
</div>
|
||||
|
||||
@@ -115,7 +115,7 @@ export function QuickAddTask({ status, onSubmit, onCancel }: QuickAddTaskProps)
|
||||
|
||||
return (
|
||||
<div onBlur={handleBlur}>
|
||||
<Card className="p-3 border-dashed border-cyan-500/30 bg-slate-800/50 hover:border-cyan-500/50 transition-all duration-300">
|
||||
<Card className="p-3 border-dashed border-[var(--primary)]/30 bg-[var(--card)]/50 hover:border-[var(--primary)]/50 transition-all duration-300">
|
||||
{/* Header avec titre et priorité */}
|
||||
<div className="flex items-start gap-2 mb-2">
|
||||
<input
|
||||
@@ -127,7 +127,7 @@ export function QuickAddTask({ status, onSubmit, onCancel }: QuickAddTaskProps)
|
||||
onFocus={() => setActiveField('title')}
|
||||
placeholder="Titre de la tâche..."
|
||||
disabled={isSubmitting}
|
||||
className="flex-1 bg-transparent border-none outline-none text-slate-100 font-mono text-sm font-medium placeholder-slate-500 leading-tight"
|
||||
className="flex-1 bg-transparent border-none outline-none text-[var(--foreground)] font-mono text-sm font-medium placeholder-[var(--muted-foreground)] leading-tight"
|
||||
/>
|
||||
|
||||
{/* Indicateur de priorité */}
|
||||
@@ -135,7 +135,7 @@ export function QuickAddTask({ status, onSubmit, onCancel }: QuickAddTaskProps)
|
||||
value={formData.priority}
|
||||
onChange={(e) => setFormData(prev => ({ ...prev, priority: e.target.value as TaskPriority }))}
|
||||
disabled={isSubmitting}
|
||||
className="bg-transparent border-none outline-none text-xs font-mono text-slate-400"
|
||||
className="bg-transparent border-none outline-none text-xs font-mono text-[var(--muted-foreground)]"
|
||||
>
|
||||
{getAllPriorities().map(priorityConfig => (
|
||||
<option key={priorityConfig.key} value={priorityConfig.key}>
|
||||
@@ -154,7 +154,7 @@ export function QuickAddTask({ status, onSubmit, onCancel }: QuickAddTaskProps)
|
||||
placeholder="Description..."
|
||||
rows={2}
|
||||
disabled={isSubmitting}
|
||||
className="w-full bg-transparent border-none outline-none text-xs text-slate-400 font-mono placeholder-slate-500 resize-none mb-2"
|
||||
className="w-full bg-transparent border-none outline-none text-xs text-[var(--muted-foreground)] font-mono placeholder-[var(--muted-foreground)] resize-none mb-2"
|
||||
/>
|
||||
|
||||
{/* Tags */}
|
||||
@@ -169,7 +169,7 @@ export function QuickAddTask({ status, onSubmit, onCancel }: QuickAddTaskProps)
|
||||
</div>
|
||||
|
||||
{/* Footer avec date et actions */}
|
||||
<div className="pt-2 border-t border-slate-700/50">
|
||||
<div className="pt-2 border-t border-[var(--border)]/50">
|
||||
<div className="flex items-center justify-between text-xs min-w-0">
|
||||
<input
|
||||
type="datetime-local"
|
||||
@@ -180,12 +180,12 @@ export function QuickAddTask({ status, onSubmit, onCancel }: QuickAddTaskProps)
|
||||
}))}
|
||||
onFocus={() => setActiveField('date')}
|
||||
disabled={isSubmitting}
|
||||
className="bg-transparent border-none outline-none text-slate-400 font-mono text-xs flex-shrink min-w-0"
|
||||
className="bg-transparent border-none outline-none text-[var(--muted-foreground)] font-mono text-xs flex-shrink min-w-0"
|
||||
/>
|
||||
|
||||
{isSubmitting && (
|
||||
<div className="flex items-center gap-1 text-cyan-400 font-mono text-xs flex-shrink-0">
|
||||
<div className="w-3 h-3 border border-cyan-400 border-t-transparent rounded-full animate-spin"></div>
|
||||
<div className="flex items-center gap-1 text-[var(--primary)] font-mono text-xs flex-shrink-0">
|
||||
<div className="w-3 h-3 border border-[var(--primary)] border-t-transparent rounded-full animate-spin"></div>
|
||||
<span>...</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -83,7 +83,7 @@ function DroppableColumn({
|
||||
className="w-full p-2 flex justify-center transition-colors"
|
||||
title="Ajouter une tâche"
|
||||
>
|
||||
<div className="w-5 h-5 rounded-full bg-slate-800/30 hover:bg-slate-700/50 flex items-center justify-center text-slate-600 hover:text-slate-300 transition-all text-sm">
|
||||
<div className="w-5 h-5 rounded-full bg-[var(--card)] hover:bg-[var(--card-hover)] flex items-center justify-center text-[var(--muted-foreground)] hover:text-[var(--foreground)] transition-all text-sm">
|
||||
+
|
||||
</div>
|
||||
</button>
|
||||
@@ -209,11 +209,11 @@ export function SwimlanesBase({
|
||||
onDragStart={handleDragStart}
|
||||
onDragEnd={handleDragEnd}
|
||||
>
|
||||
<div className="flex flex-col h-full bg-slate-950">
|
||||
<div className="flex flex-col h-full bg-[var(--background)]">
|
||||
{/* Header */}
|
||||
<div className="flex-shrink-0 px-6 py-4 border-b border-slate-700/50">
|
||||
<div className="flex-shrink-0 px-6 py-4 border-b border-[var(--border)]/50">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-lg font-mono font-bold text-slate-200 uppercase tracking-wider">
|
||||
<h2 className="text-lg font-mono font-bold text-[var(--foreground)] uppercase tracking-wider">
|
||||
{title}
|
||||
</h2>
|
||||
|
||||
@@ -239,7 +239,7 @@ export function SwimlanesBase({
|
||||
const statusConfig = allStatuses.find(s => s.key === status);
|
||||
return (
|
||||
<div key={status} className="text-center">
|
||||
<h3 className="text-sm font-mono font-bold text-slate-300 uppercase tracking-wider">
|
||||
<h3 className="text-sm font-mono font-bold text-[var(--foreground)] uppercase tracking-wider">
|
||||
{statusConfig?.icon} {statusConfig?.label}
|
||||
</h3>
|
||||
</div>
|
||||
@@ -254,15 +254,15 @@ export function SwimlanesBase({
|
||||
const isCollapsed = collapsedSwimlanes.has(swimlane.key);
|
||||
|
||||
return (
|
||||
<div key={swimlane.key} className="border border-slate-700/50 rounded-lg bg-slate-900/30">
|
||||
<div key={swimlane.key} className="border border-[var(--border)]/50 rounded-lg bg-[var(--card)]/30">
|
||||
{/* Header de la swimlane */}
|
||||
<div className="flex items-center p-2 border-b border-slate-700/50">
|
||||
<div className="flex items-center p-2 border-b border-[var(--border)]/50">
|
||||
<button
|
||||
onClick={() => toggleSwimlane(swimlane.key)}
|
||||
className="flex items-center gap-2 hover:bg-slate-800/50 rounded p-1 -m-1 transition-colors"
|
||||
className="flex items-center gap-2 hover:bg-[var(--card-hover)] rounded p-1 -m-1 transition-colors"
|
||||
>
|
||||
<svg
|
||||
className={`w-4 h-4 text-slate-400 transition-transform ${isCollapsed ? '' : 'rotate-90'}`}
|
||||
className={`w-4 h-4 text-[var(--muted-foreground)] transition-transform ${isCollapsed ? '' : 'rotate-90'}`}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
@@ -275,7 +275,7 @@ export function SwimlanesBase({
|
||||
style={{ backgroundColor: swimlane.color }}
|
||||
/>
|
||||
)}
|
||||
<span className="text-slate-200 font-medium text-sm">
|
||||
<span className="text-[var(--foreground)] font-medium text-sm">
|
||||
{swimlane.icon && `${swimlane.icon} `}
|
||||
{swimlane.label} ({swimlane.tasks.length})
|
||||
</span>
|
||||
|
||||
@@ -100,7 +100,7 @@ export function TaskCard({ task, onDelete, onEdit, onUpdateTitle, compactView =
|
||||
<Card
|
||||
ref={setNodeRef}
|
||||
style={style}
|
||||
className={`p-2 hover:border-cyan-500/30 hover:shadow-lg hover:shadow-cyan-500/10 transition-all duration-300 cursor-pointer group ${
|
||||
className={`p-2 hover:border-[var(--primary)]/30 hover:shadow-lg hover:shadow-[var(--primary)]/10 transition-all duration-300 cursor-pointer group ${
|
||||
isDragging ? 'opacity-50 rotate-3 scale-105' : ''
|
||||
}`}
|
||||
{...attributes}
|
||||
@@ -132,11 +132,11 @@ export function TaskCard({ task, onDelete, onEdit, onUpdateTitle, compactView =
|
||||
onKeyDown={handleTitleKeyPress}
|
||||
onBlur={handleTitleSave}
|
||||
autoFocus
|
||||
className="flex-1 bg-transparent border-none outline-none text-slate-100 font-mono text-sm font-medium leading-tight"
|
||||
className="flex-1 bg-transparent border-none outline-none text-[var(--foreground)] font-mono text-sm font-medium leading-tight"
|
||||
/>
|
||||
) : (
|
||||
<h4
|
||||
className="font-mono text-xs font-medium text-slate-100 leading-tight line-clamp-2 flex-1 cursor-pointer hover:text-cyan-300 transition-colors"
|
||||
className="font-mono text-xs font-medium text-[var(--foreground)] leading-tight line-clamp-2 flex-1 cursor-pointer hover:text-[var(--primary)] transition-colors"
|
||||
onClick={handleTitleClick}
|
||||
title={onUpdateTitle ? "Cliquer pour éditer" : undefined}
|
||||
>
|
||||
@@ -182,7 +182,7 @@ export function TaskCard({ task, onDelete, onEdit, onUpdateTitle, compactView =
|
||||
<Card
|
||||
ref={setNodeRef}
|
||||
style={style}
|
||||
className={`p-3 hover:border-cyan-500/30 hover:shadow-lg hover:shadow-cyan-500/10 transition-all duration-300 cursor-pointer group ${
|
||||
className={`p-3 hover:border-[var(--primary)]/30 hover:shadow-lg hover:shadow-[var(--primary)]/10 transition-all duration-300 cursor-pointer group ${
|
||||
isDragging ? 'opacity-50 rotate-3 scale-105' : ''
|
||||
}`}
|
||||
{...attributes}
|
||||
@@ -215,11 +215,11 @@ export function TaskCard({ task, onDelete, onEdit, onUpdateTitle, compactView =
|
||||
onKeyDown={handleTitleKeyPress}
|
||||
onBlur={handleTitleSave}
|
||||
autoFocus
|
||||
className="flex-1 bg-transparent border-none outline-none text-slate-100 font-mono text-sm font-medium leading-tight"
|
||||
className="flex-1 bg-transparent border-none outline-none text-[var(--foreground)] font-mono text-sm font-medium leading-tight"
|
||||
/>
|
||||
) : (
|
||||
<h4
|
||||
className="font-mono text-sm font-medium text-slate-100 leading-tight line-clamp-2 flex-1 cursor-pointer hover:text-cyan-300 transition-colors"
|
||||
className="font-mono text-sm font-medium text-[var(--foreground)] leading-tight line-clamp-2 flex-1 cursor-pointer hover:text-[var(--primary)] transition-colors"
|
||||
onClick={handleTitleClick}
|
||||
title={onUpdateTitle ? "Cliquer pour éditer" : undefined}
|
||||
>
|
||||
@@ -232,7 +232,7 @@ export function TaskCard({ task, onDelete, onEdit, onUpdateTitle, compactView =
|
||||
{onEdit && (
|
||||
<button
|
||||
onClick={handleEdit}
|
||||
className="opacity-0 group-hover:opacity-100 w-4 h-4 rounded-full bg-blue-900/50 hover:bg-blue-800/80 border border-blue-500/30 hover:border-blue-400/50 flex items-center justify-center transition-all duration-200 text-blue-400 hover:text-blue-300 text-xs"
|
||||
className="opacity-0 group-hover:opacity-100 w-4 h-4 rounded-full bg-[var(--primary)]/20 hover:bg-[var(--primary)]/30 border border-[var(--primary)]/30 hover:border-[var(--primary)]/50 flex items-center justify-center transition-all duration-200 text-[var(--primary)] hover:text-[var(--primary)] text-xs"
|
||||
title="Modifier la tâche"
|
||||
>
|
||||
✎
|
||||
@@ -243,7 +243,7 @@ export function TaskCard({ task, onDelete, onEdit, onUpdateTitle, compactView =
|
||||
{onDelete && (
|
||||
<button
|
||||
onClick={handleDelete}
|
||||
className="opacity-0 group-hover:opacity-100 w-4 h-4 rounded-full bg-red-900/50 hover:bg-red-800/80 border border-red-500/30 hover:border-red-400/50 flex items-center justify-center transition-all duration-200 text-red-400 hover:text-red-300 text-xs"
|
||||
className="opacity-0 group-hover:opacity-100 w-4 h-4 rounded-full bg-[var(--destructive)]/20 hover:bg-[var(--destructive)]/30 border border-[var(--destructive)]/30 hover:border-[var(--destructive)]/50 flex items-center justify-center transition-all duration-200 text-[var(--destructive)] hover:text-[var(--destructive)] text-xs"
|
||||
title="Supprimer la tâche"
|
||||
>
|
||||
×
|
||||
@@ -263,7 +263,7 @@ export function TaskCard({ task, onDelete, onEdit, onUpdateTitle, compactView =
|
||||
|
||||
{/* Description tech */}
|
||||
{task.description && (
|
||||
<p className="text-xs text-slate-400 mb-3 line-clamp-1 font-mono">
|
||||
<p className="text-xs text-[var(--muted-foreground)] mb-3 line-clamp-1 font-mono">
|
||||
{task.description}
|
||||
</p>
|
||||
)}
|
||||
@@ -287,10 +287,10 @@ export function TaskCard({ task, onDelete, onEdit, onUpdateTitle, compactView =
|
||||
|
||||
{/* Footer tech avec séparateur néon - seulement si des données à afficher */}
|
||||
{(task.dueDate || (task.source && task.source !== 'manual') || task.completedAt) && (
|
||||
<div className="pt-2 border-t border-slate-700/50">
|
||||
<div className="pt-2 border-t border-[var(--border)]/50">
|
||||
<div className="flex items-center justify-between text-xs">
|
||||
{task.dueDate ? (
|
||||
<span className="flex items-center gap-1 text-slate-400 font-mono">
|
||||
<span className="flex items-center gap-1 text-[var(--muted-foreground)] font-mono">
|
||||
<span className="text-cyan-400">⏰</span>
|
||||
{formatDistanceToNow(new Date(task.dueDate), {
|
||||
addSuffix: true,
|
||||
|
||||
Reference in New Issue
Block a user