feat: add line clamp utility and integrate RecentTaskTimeline component

- Added a new CSS utility for line clamping to `globals.css` for better text overflow handling.
- Integrated `WelcomeSection` into `HomePageClient` for enhanced user experience.
- Replaced `TaskCard` with `RecentTaskTimeline` in `RecentTasks` for improved task visualization.
- Updated `ui/index.ts` to export `RecentTaskTimeline` and showcased it in `CardsSection` and `FeedbackSection`.
This commit is contained in:
Julien Froidefond
2025-09-30 23:34:03 +02:00
parent d8ca4ef00b
commit 8519ec094f
8 changed files with 428 additions and 43 deletions

View File

@@ -0,0 +1,129 @@
import { HTMLAttributes } from 'react';
import { cn } from '@/lib/utils';
import { StatusBadge } from './StatusBadge';
import { TaskStatus } from '@/lib/types';
import { PriorityBadge } from './PriorityBadge';
import { TagDisplay } from './TagDisplay';
import { formatDateForDisplay } from '@/lib/date-utils';
interface RecentTaskTimelineProps extends HTMLAttributes<HTMLDivElement> {
title: string;
description?: string;
tags?: string[];
priority?: 'low' | 'medium' | 'high';
status?: TaskStatus;
dueDate?: Date;
completedAt?: Date;
updatedAt?: Date;
source?: 'manual' | 'jira' | 'tfs' | 'reminders';
jiraKey?: string;
tfsPullRequestId?: number;
onClick?: () => void;
className?: string;
availableTags?: Array<{ id: string; name: string; color: string }>;
}
export function RecentTaskTimeline({
title,
description,
tags = [],
priority,
status = 'todo',
dueDate,
completedAt,
updatedAt,
source = 'manual',
jiraKey,
tfsPullRequestId,
onClick,
className,
availableTags = [],
...props
}: RecentTaskTimelineProps) {
const getSourceIcon = () => {
switch (source) {
case 'jira':
return <div className="w-2 h-2 bg-[var(--primary)] rounded-full" />;
case 'tfs':
return <div className="w-2 h-2 bg-[var(--blue)] rounded-full" />;
case 'reminders':
return <div className="w-2 h-2 bg-[var(--accent)] rounded-full" />;
default:
return <div className="w-2 h-2 bg-[var(--gray)] rounded-full" />;
}
};
const getTimeInfo = () => {
if (completedAt) {
return `Terminé ${formatDateForDisplay(completedAt)}`;
}
if (dueDate) {
return `Échéance ${formatDateForDisplay(dueDate)}`;
}
if (updatedAt) {
return `Modifié ${formatDateForDisplay(updatedAt)}`;
}
return null;
};
return (
<div
className={cn(
"group relative flex items-start gap-4 p-3 rounded-lg hover:bg-[var(--card-hover)] transition-colors cursor-pointer",
className
)}
onClick={onClick}
{...props}
>
{/* Timeline dot */}
<div className="flex-shrink-0 mt-2">
{getSourceIcon()}
</div>
{/* Content */}
<div className="flex-1 min-w-0">
<div className="flex items-start justify-between gap-2 mb-1">
<h4 className="font-medium text-[var(--foreground)] text-sm group-hover:text-[var(--primary)] transition-colors">
{title}
</h4>
<div className="flex items-center gap-1 flex-shrink-0">
{priority && <PriorityBadge priority={priority} />}
<StatusBadge status={status} />
</div>
</div>
{description && (
<p className="text-xs text-[var(--muted-foreground)] mb-2 line-clamp-1">
{description}
</p>
)}
{tags.length > 0 && (
<div className="mb-2">
<TagDisplay
tags={tags}
availableTags={availableTags}
maxTags={2}
size="sm"
/>
</div>
)}
<div className="flex items-center justify-between text-xs text-[var(--muted-foreground)]">
<div className="flex items-center gap-2">
{jiraKey && <span className="font-mono text-[var(--primary)]">{jiraKey}</span>}
{tfsPullRequestId && <span className="font-mono text-[var(--blue)]">PR #{tfsPullRequestId}</span>}
</div>
<span>{getTimeInfo()}</span>
</div>
</div>
{/* 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>
</div>
</div>
);
}

View File

@@ -10,6 +10,7 @@ export { StatCard } from './StatCard';
export { ProgressBar } from './ProgressBar';
export { ActionCard } from './ActionCard';
export { TaskCard } from './TaskCard';
export { RecentTaskTimeline } from './RecentTaskTimeline';
export { MetricCard } from './MetricCard';
// Composants Kanban