feat: replace SVGs with lucide-react icons across components

- Updated ProfilePage, AuthButton, RecentTasks, WelcomeSection, DesktopControls, MobileControls, and various Kanban components to use lucide-react icons instead of SVGs for improved consistency and maintainability.
- Icons replaced include Check, User, Mail, Calendar, Shield, Save, X, Loader2, Filter, Target, List, Grid3X3, ChevronDown, ChevronRight, Edit, Trash2, and Plus.
This commit is contained in:
Julien Froidefond
2025-10-04 06:25:04 +02:00
parent e14b428e12
commit c7ad1c0416
17 changed files with 68 additions and 218 deletions

View File

@@ -7,6 +7,7 @@ import { Button } from '@/components/ui/Button'
import { Input } from '@/components/ui/Input'
import { Header } from '@/components/ui/Header'
import { updateProfile, getProfile } from '@/actions/profile'
import { Check, User, Mail, Calendar, Shield, Save, X, Loader2 } from 'lucide-react'
interface UserProfile {
id: string
@@ -155,16 +156,12 @@ export default function ProfilePage() {
className="w-24 h-24 rounded-full object-cover border-4 border-[var(--primary)]/30 shadow-lg"
/>
<div className="absolute -bottom-2 -right-2 w-8 h-8 bg-[var(--success)] rounded-full border-4 border-[var(--card)] flex items-center justify-center">
<svg className="w-4 h-4 text-white" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
</svg>
<Check className="w-4 h-4 text-white" />
</div>
</div>
) : (
<div className="w-24 h-24 rounded-full bg-[var(--primary)]/20 border-4 border-[var(--primary)]/30 flex items-center justify-center">
<svg className="w-12 h-12 text-[var(--primary)]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
</svg>
<User className="w-12 h-12 text-[var(--primary)]" />
</div>
)}
</div>
@@ -182,9 +179,7 @@ export default function ProfilePage() {
<span className="text-sm font-medium text-[var(--foreground)]">{profile.role}</span>
</div>
<div className="flex items-center gap-2 px-3 py-1 bg-[var(--card)] rounded-full border border-[var(--border)]">
<svg className="w-4 h-4 text-[var(--muted-foreground)]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
<Calendar className="w-4 h-4 text-[var(--muted-foreground)]" />
<span className="text-sm text-[var(--muted-foreground)]">
Membre depuis {new Date(profile.createdAt).toLocaleDateString('fr-FR')}
</span>
@@ -198,17 +193,13 @@ export default function ProfilePage() {
{/* Informations générales */}
<div className="bg-[var(--card)] rounded-xl p-6 border border-[var(--border)]">
<h2 className="text-xl font-mono font-bold text-[var(--foreground)] mb-6 flex items-center gap-2">
<svg className="w-5 h-5 text-[var(--primary)]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<User className="w-5 h-5 text-[var(--primary)]" />
Informations générales
</h2>
<div className="space-y-4">
<div className="flex items-center gap-3 p-3 bg-[var(--input)] rounded-lg border border-[var(--border)]">
<svg className="w-5 h-5 text-[var(--muted-foreground)]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 12a4 4 0 10-8 0 4 4 0 008 0zm0 0v1.5a2.5 2.5 0 005 0V12a9 9 0 10-9 9m4.5-1.206a8.959 8.959 0 01-4.5 1.207" />
</svg>
<Mail className="w-5 h-5 text-[var(--muted-foreground)]" />
<div>
<div className="text-[var(--foreground)] font-medium">{profile.email}</div>
<div className="text-xs text-[var(--muted-foreground)]">Email principal</div>
@@ -216,9 +207,7 @@ export default function ProfilePage() {
</div>
<div className="flex items-center gap-3 p-3 bg-[var(--input)] rounded-lg border border-[var(--border)]">
<svg className="w-5 h-5 text-[var(--muted-foreground)]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<Shield className="w-5 h-5 text-[var(--muted-foreground)]" />
<div>
<div className="text-[var(--foreground)] font-medium">{profile.role}</div>
<div className="text-xs text-[var(--muted-foreground)]">Rôle utilisateur</div>
@@ -227,9 +216,7 @@ export default function ProfilePage() {
{profile.lastLoginAt && (
<div className="flex items-center gap-3 p-3 bg-[var(--input)] rounded-lg border border-[var(--border)]">
<svg className="w-5 h-5 text-[var(--muted-foreground)]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<Calendar className="w-5 h-5 text-[var(--muted-foreground)]" />
<div>
<div className="text-[var(--foreground)] font-medium">
{new Date(profile.lastLoginAt).toLocaleString('fr-FR')}
@@ -244,9 +231,7 @@ export default function ProfilePage() {
{/* Formulaire de modification */}
<div className="bg-[var(--card)] rounded-xl p-6 border border-[var(--border)]">
<h2 className="text-xl font-mono font-bold text-[var(--foreground)] mb-6 flex items-center gap-2">
<svg className="w-5 h-5 text-[var(--primary)]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
</svg>
<User className="w-5 h-5 text-[var(--primary)]" />
Modifier le profil
</h2>
@@ -320,18 +305,14 @@ export default function ProfilePage() {
{error && (
<div className="flex items-center gap-2 p-3 bg-[var(--destructive)]/10 border border-[var(--destructive)]/30 rounded-lg">
<svg className="w-5 h-5 text-[var(--destructive)]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<X className="w-5 h-5 text-[var(--destructive)]" />
<span className="text-[var(--destructive)] text-sm">{error}</span>
</div>
)}
{success && (
<div className="flex items-center gap-2 p-3 bg-[var(--success)]/10 border border-[var(--success)]/30 rounded-lg">
<svg className="w-5 h-5 text-[var(--success)]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<Check className="w-5 h-5 text-[var(--success)]" />
<span className="text-[var(--success)] text-sm">{success}</span>
</div>
)}
@@ -344,16 +325,12 @@ export default function ProfilePage() {
>
{isPending ? (
<div className="flex items-center gap-2">
<svg className="w-4 h-4 animate-spin" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
<Loader2 className="w-4 h-4 animate-spin" />
Sauvegarde...
</div>
) : (
<div className="flex items-center gap-2">
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
<Save className="w-4 h-4" />
Sauvegarder les modifications
</div>
)}

View File

@@ -3,6 +3,7 @@
import { useSession, signOut } from 'next-auth/react'
import { useRouter } from 'next/navigation'
import { Button } from '@/components/ui/Button'
import { User, LogOut } from 'lucide-react'
export function AuthButton() {
const { data: session, status } = useSession()
@@ -44,9 +45,7 @@ export function AuthButton() {
className="w-10 h-10 rounded-full object-cover"
/>
) : (
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
</svg>
<User className="w-6 h-6" />
)}
</Button>
<Button
@@ -56,9 +55,7 @@ export function AuthButton() {
className="p-1 h-auto"
title="Déconnexion"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" />
</svg>
<LogOut className="w-4 h-4" />
</Button>
</div>
)

View File

@@ -5,6 +5,7 @@ import { Card } from '@/components/ui/Card';
import { RecentTaskTimeline } from '@/components/ui/RecentTaskTimeline';
import { useTasksContext } from '@/contexts/TasksContext';
import Link from 'next/link';
import { Clipboard } from 'lucide-react';
interface RecentTasksProps {
tasks: Task[];
@@ -49,9 +50,7 @@ export function RecentTasks({ tasks, selectedSources = [], hiddenSources = [] }:
{recentTasks.length === 0 ? (
<div className="text-center py-8 text-[var(--muted-foreground)]">
<svg className="w-12 h-12 mx-auto mb-3 opacity-50" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5H7a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
</svg>
<Clipboard className="w-12 h-12 mx-auto mb-3 opacity-50" />
<p>Aucune tâche disponible</p>
<p className="text-sm">Créez votre première tâche pour commencer</p>
</div>

View File

@@ -2,6 +2,7 @@
import { useSession } from 'next-auth/react';
import { useState, useEffect, useRef } from 'react';
import { Check, User, ArrowRight } from 'lucide-react';
const WELCOME_GREETINGS = [
"Bienvenue",
@@ -216,16 +217,12 @@ export function WelcomeSection() {
className="relative w-20 h-20 rounded-full object-cover border-4 border-[var(--primary)]/40 shadow-2xl transition-all duration-500 group-hover:scale-110 group-hover:border-[var(--accent)]/60"
/>
<div className="absolute -bottom-2 -right-2 w-7 h-7 bg-gradient-to-r from-[var(--success)] to-[var(--green)] rounded-full border-4 border-[var(--card)] flex items-center justify-center shadow-lg">
<svg className="w-4 h-4 text-white" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
</svg>
<Check className="w-4 h-4 text-white" />
</div>
</div>
) : (
<div className="relative w-20 h-20 rounded-full bg-gradient-to-br from-[var(--primary)]/30 to-[var(--accent)]/30 border-4 border-[var(--primary)]/40 flex items-center justify-center shadow-2xl transition-all duration-500 group-hover:scale-110 group-hover:border-[var(--accent)]/60">
<svg className="w-10 h-10 text-[var(--primary)] transition-colors duration-500 group-hover:text-[var(--accent)]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
</svg>
<User className="w-10 h-10 text-[var(--primary)] transition-colors duration-500 group-hover:text-[var(--accent)]" />
</div>
)}
</div>
@@ -282,14 +279,9 @@ export function WelcomeSection() {
>
<div className="absolute inset-0 bg-gradient-to-r from-[var(--primary)]/10 to-[var(--accent)]/10 rounded-2xl opacity-0 group-hover:opacity-100 transition-opacity duration-500" />
<div className="relative">
<svg
<ArrowRight
className="w-6 h-6 text-[var(--muted-foreground)] group-hover:text-[var(--primary)] transition-all duration-500 group-hover:rotate-180"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
/>
</div>
</button>
</div>

View File

@@ -5,6 +5,7 @@ import { Button, ToggleButton, SearchInput, ControlPanel, ControlSection, Contro
import { IntegrationFilter } from '@/components/dashboard/IntegrationFilter';
import { FontSizeToggle } from '@/components/ui/FontSizeToggle';
import type { KanbanFilters } from '@/lib/types';
import { Filter, Target, Calendar, Plus, List, Grid3X3, Layout } from 'lucide-react';
interface DesktopControlsProps {
showFilters: boolean;
@@ -94,11 +95,7 @@ export function DesktopControls({
isActive={showFilters}
count={activeFiltersCount}
onClick={onToggleFilters}
icon={
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 100 4m0-4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 100 4m0-4v2m0-6V4" />
</svg>
}
icon={<Filter className="w-4 h-4" />}
>
Filtres
</ToggleButton>
@@ -107,11 +104,7 @@ export function DesktopControls({
variant="accent"
isActive={showObjectives}
onClick={onToggleObjectives}
icon={
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4M7.835 4.697a3.42 3.42 0 001.946-.806 3.42 3.42 0 014.438 0 3.42 3.42 0 001.946.806 3.42 3.42 0 013.138 3.138 3.42 3.42 0 00.806 1.946 3.42 3.42 0 010 4.438 3.42 3.42 0 00-.806 1.946 3.42 3.42 0 01-3.138 3.138 3.42 3.42 0 00-1.946.806 3.42 3.42 0 01-4.438 0 3.42 3.42 0 00-1.946-.806 3.42 3.42 0 01-3.138-3.138 3.42 3.42 0 00-.806-1.946 3.42 3.42 0 010-4.438 3.42 3.42 0 00.806-1.946 3.42 3.42 0 013.138-3.138z" />
</svg>
}
icon={<Target className="w-4 h-4" />}
>
Objectifs
</ToggleButton>
@@ -121,11 +114,7 @@ export function DesktopControls({
isActive={kanbanFilters.showWithDueDate}
onClick={handleDueDateFilterToggle}
title={kanbanFilters.showWithDueDate ? "Afficher toutes les tâches" : "Afficher seulement les tâches avec date de fin"}
icon={
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 002 2v12a2 2 0 002 2z" />
</svg>
}
icon={<Calendar className="w-4 h-4" />}
/>
</ControlGroup>
</ControlSection>
@@ -144,15 +133,7 @@ export function DesktopControls({
isActive={compactView}
onClick={onToggleCompactView}
title={compactView ? "Vue détaillée" : "Vue compacte"}
icon={
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
{compactView ? (
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 10h16M4 14h16M4 18h16" />
) : (
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
)}
</svg>
}
icon={compactView ? <List className="w-4 h-4" /> : <Grid3X3 className="w-4 h-4" />}
>
{compactView ? 'Détaillée' : 'Compacte'}
</ToggleButton>
@@ -162,15 +143,7 @@ export function DesktopControls({
isActive={swimlanesByTags}
onClick={onToggleSwimlanes}
title={swimlanesByTags ? "Vue standard" : "Vue swimlanes"}
icon={
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
{swimlanesByTags ? (
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z" />
) : (
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 11H5m14-7H5m14 14H5" />
)}
</svg>
}
icon={swimlanesByTags ? <Layout className="w-4 h-4" /> : <Grid3X3 className="w-4 h-4" />}
>
{swimlanesByTags ? 'Standard' : 'Swimlanes'}
</ToggleButton>
@@ -186,9 +159,7 @@ export function DesktopControls({
onClick={onCreateTask}
className="flex items-center gap-2"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
</svg>
<Plus className="w-4 h-4" />
Nouvelle tâche
</Button>
</ControlSection>

View File

@@ -13,6 +13,7 @@ import { PriorityFilters } from './filters/PriorityFilters';
import { TagFilters } from './filters/TagFilters';
import { GeneralFilters } from './filters/GeneralFilters';
import { ColumnFilters } from './filters/ColumnFilters';
import { Layout, Grid3X3 } from 'lucide-react';
import type { KanbanFilters } from '@/lib/types';
@@ -138,20 +139,7 @@ export function KanbanFilters({ filters, onFiltersChange, hiddenStatuses: propsH
isActive={!!filters.swimlanesByTags}
onClick={handleSwimlanesToggle}
title="Mode d'affichage"
icon={
<svg
className="w-4 h-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
{filters.swimlanesByTags ? (
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 10h16M4 14h16M4 18h16" />
) : (
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" />
)}
</svg>
}
icon={filters.swimlanesByTags ? <Layout className="w-4 h-4" /> : <Grid3X3 className="w-4 h-4" />}
>
{!filters.swimlanesByTags
? 'Normal'

View File

@@ -5,6 +5,7 @@ import { Button, ToggleButton, ControlPanel } from '@/components/ui';
import { IntegrationFilter } from '@/components/dashboard/IntegrationFilter';
import { FontSizeToggle } from '@/components/ui/FontSizeToggle';
import type { KanbanFilters } from '@/lib/types';
import { Menu, Plus, Filter, Target, List, Grid3X3 } from 'lucide-react';
interface MobileControlsProps {
showFilters: boolean;
@@ -43,11 +44,7 @@ export function MobileControls({
isActive={isMenuOpen}
count={activeFiltersCount}
onClick={() => setIsMenuOpen(!isMenuOpen)}
icon={
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
</svg>
}
icon={<Menu className="w-4 h-4" />}
>
Options
</ToggleButton>
@@ -59,9 +56,7 @@ export function MobileControls({
className="flex items-center gap-2"
size="sm"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
</svg>
<Plus className="w-4 h-4" />
<span className="hidden xs:inline">Nouvelle</span>
</Button>
</div>
@@ -82,11 +77,7 @@ export function MobileControls({
onToggleFilters();
setIsMenuOpen(false);
}}
icon={
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 100 4m0-4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 100 4m0-4v2m0-6V4" />
</svg>
}
icon={<Filter className="w-4 h-4" />}
>
Filtres
</ToggleButton>
@@ -98,11 +89,7 @@ export function MobileControls({
onToggleObjectives();
setIsMenuOpen(false);
}}
icon={
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4M7.835 4.697a3.42 3.42 0 001.946-.806 3.42 3.42 0 014.438 0 3.42 3.42 0 001.946.806 3.42 3.42 0 013.138 3.138 3.42 3.42 0 00.806 1.946 3.42 3.42 0 010 4.438 3.42 3.42 0 00-.806 1.946 3.42 3.42 0 01-3.138 3.138 3.42 3.42 0 00-1.946.806 3.42 3.42 0 01-4.438 0 3.42 3.42 0 00-1.946-.806 3.42 3.42 0 01-3.138-3.138 3.42 3.42 0 00-.806-1.946 3.42 3.42 0 010-4.438 3.42 3.42 0 00.806-1.946 3.42 3.42 0 013.138-3.138z" />
</svg>
}
icon={<Target className="w-4 h-4" />}
>
Objectifs
</ToggleButton>
@@ -123,15 +110,7 @@ export function MobileControls({
setIsMenuOpen(false);
}}
className="w-full"
icon={
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
{compactView ? (
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 10h16M4 14h16M4 18h16" />
) : (
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
)}
</svg>
}
icon={compactView ? <List className="w-4 h-4" /> : <Grid3X3 className="w-4 h-4" />}
>
Vue {compactView ? 'détaillée' : 'compacte'}
</ToggleButton>

View File

@@ -7,6 +7,7 @@ import { Task, TaskStatus } from '@/lib/types';
import { TaskCard } from './TaskCard';
import { Card, CardHeader, CardContent } from '@/components/ui/Card';
import { Badge } from '@/components/ui/Badge';
import { ChevronDown } from 'lucide-react';
import {
DndContext,
DragEndEvent,
@@ -156,16 +157,11 @@ export function ObjectivesBoard({
className="lg:hidden p-1 hover:bg-[var(--accent)]/20 rounded transition-colors"
aria-label={isCollapsed ? "Développer" : "Réduire"}
>
<svg
<ChevronDown
className={`w-4 h-4 text-[var(--accent)] transition-transform duration-200 ${
isCollapsed ? 'rotate-180' : ''
}`}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
/>
</button>
</div>
</div>

View File

@@ -8,6 +8,7 @@ import { useState } from 'react';
import { useUserPreferences } from '@/contexts/UserPreferencesContext';
import { useDragAndDrop } from '@/hooks/useDragAndDrop';
import { getAllStatuses, getTechStyle } from '@/lib/status-config';
import { ChevronRight } from 'lucide-react';
import { Card, CardHeader, ColumnHeader, DropZone } from '@/components/ui';
import {
DndContext,
@@ -229,14 +230,9 @@ export function SwimlanesBase({
onClick={() => toggleSwimlane(swimlane.key)}
className="flex items-center gap-2 hover:bg-[var(--card-hover)] rounded p-1 -m-1 transition-colors w-full"
>
<svg
<ChevronRight
className={`w-4 h-4 text-[var(--muted-foreground)] transition-transform ${isCollapsed ? '' : 'rotate-90'}`}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
/>
{swimlane.color && (
<div
className="w-3 h-3 rounded-full"

View File

@@ -1,6 +1,7 @@
'use client';
import { FilterChip } from '@/components/ui';
import { Calendar, CheckCircle } from 'lucide-react';
interface GeneralFiltersProps {
showWithDueDate?: boolean;
@@ -24,16 +25,7 @@ export function GeneralFilters({
<FilterChip
onClick={onDueDateFilterToggle}
variant={showWithDueDate ? 'selected' : 'default'}
icon={
<svg
className="w-4 h-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 002 2v12a2 2 0 002 2z" />
</svg>
}
icon={<Calendar className="w-4 h-4" />}
>
Avec date de fin
</FilterChip>
@@ -41,16 +33,7 @@ export function GeneralFilters({
<FilterChip
onClick={onCompletedLast7DaysFilterToggle}
variant={showCompletedLast7Days ? 'selected' : 'default'}
icon={
<svg
className="w-4 h-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
}
icon={<CheckCircle className="w-4 h-4" />}
>
Complété les 7 derniers jours
</FilterChip>

View File

@@ -2,6 +2,7 @@
import { Card, CardContent } from '@/components/ui/Card';
import Link from 'next/link';
import { ChevronRight } from 'lucide-react';
interface SettingsPage {
href: string;
@@ -50,14 +51,7 @@ export function SettingsNavigation({ settingsPages }: SettingsNavigationProps) {
</div>
</div>
</div>
<svg
className="w-5 h-5 text-[var(--muted-foreground)]"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
<ChevronRight className="w-5 h-5 text-[var(--muted-foreground)]" />
</div>
</CardContent>
</Card>

View File

@@ -3,6 +3,7 @@
import { Button } from '@/components/ui/Button';
import { Card } from '@/components/ui/Card';
import { Tag } from '@/lib/types';
import { Edit, Trash2, Loader2 } from 'lucide-react';
interface TagsGridProps {
tags: (Tag & { usage?: number })[];
@@ -74,9 +75,7 @@ export function TagsGrid({
onClick={() => onEditTag(tag)}
className="h-7 w-7 p-0 text-[var(--muted-foreground)] hover:text-[var(--foreground)]"
>
<svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
</svg>
<Edit className="w-3 h-3" />
</Button>
<Button
variant="ghost"
@@ -90,14 +89,9 @@ export function TagsGrid({
}`}
>
{deletingTagId === tag.id ? (
<svg className="w-3 h-3 animate-spin" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
<path className="opacity-75" fill="currentColor" d="m4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
<Loader2 className="w-3 h-3 animate-spin" />
) : (
<svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
</svg>
<Trash2 className="w-3 h-3" />
)}
</Button>
</div>

View File

@@ -9,6 +9,7 @@ import { TagForm } from '@/components/forms/TagForm';
import { TagsStats } from './TagsStats';
import { TagsFilters } from './TagsFilters';
import { TagsGrid } from './TagsGrid';
import { Plus } from 'lucide-react';
interface TagsManagementProps {
tags: (Tag & { usage: number })[];
@@ -112,9 +113,7 @@ export function TagsManagement({ tags, onRefreshTags, onDeleteTag }: TagsManagem
onClick={() => setIsCreateModalOpen(true)}
className="flex items-center gap-2"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
</svg>
<Plus className="w-4 h-4" />
Nouveau tag
</Button>
</div>

View File

@@ -3,6 +3,7 @@
import { useState, useRef, useEffect, useCallback, ReactNode } from 'react';
import { createPortal } from 'react-dom';
import { cn } from '@/lib/utils';
import { ChevronDown } from 'lucide-react';
export type DropdownPlacement =
| 'top-start'
@@ -255,14 +256,9 @@ export function Dropdown({
)}
>
{trigger}
<svg
<ChevronDown
className={`w-4 h-4 transition-transform ${open ? 'rotate-180' : ''}`}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
/>
</button>
);

View File

@@ -9,6 +9,7 @@ import { Theme, THEME_CONFIG, getThemeIcon } from '@/lib/ui-config';
import { useKeyboardShortcutsModal } from '@/contexts/KeyboardShortcutsContext';
import { AuthButton } from '@/components/AuthButton';
import { useSession, signOut } from 'next-auth/react';
import { Check, X, Menu } from 'lucide-react';
interface HeaderProps {
title?: string;
@@ -144,9 +145,7 @@ export function Header({ title = "TowerControl", subtitle = "Task Management", s
<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>
<Check className="w-4 h-4 ml-auto" />
)}
</button>
))}
@@ -163,13 +162,9 @@ export function Header({ title = "TowerControl", subtitle = "Task Management", s
title="Toggle menu"
>
{mobileMenuOpen ? (
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
<X className="w-5 h-5" />
) : (
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
</svg>
<Menu className="w-5 h-5" />
)}
</button>
</div>
@@ -259,9 +254,7 @@ export function Header({ title = "TowerControl", subtitle = "Task Management", s
<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>
<Check className="w-4 h-4 ml-auto" />
)}
</button>
))}

View File

@@ -5,6 +5,7 @@ import { TaskStatus } from '@/lib/types';
import { PriorityBadge } from './PriorityBadge';
import { TagDisplay } from './TagDisplay';
import { formatDateForDisplay } from '@/lib/date-utils';
import { ChevronRight } from 'lucide-react';
interface RecentTaskTimelineProps extends HTMLAttributes<HTMLDivElement> {
title: string;
@@ -120,9 +121,7 @@ export function RecentTaskTimeline({
{/* Arrow indicator */}
<div className="flex-shrink-0 mt-2 opacity-0 group-hover:opacity-100 transition-opacity">
<svg className="w-4 h-4 text-[var(--primary)]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
<ChevronRight className="w-4 h-4 text-[var(--primary)]" />
</div>
</div>
);

View File

@@ -2,6 +2,7 @@
import { Tag } from '@/lib/types';
import { Badge } from './Badge';
import { Edit, Trash2 } from 'lucide-react';
interface TagDisplayProps {
tags: string[];
@@ -134,9 +135,7 @@ export function TagList({
className="p-1 text-slate-400 hover:text-cyan-400 transition-colors"
title="Éditer le tag"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
</svg>
<Edit className="w-4 h-4" />
</button>
)}
@@ -146,9 +145,7 @@ export function TagList({
className="p-1 text-slate-400 hover:text-red-400 transition-colors"
title="Supprimer le tag"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
</svg>
<Trash2 className="w-4 h-4" />
</button>
)}
</div>