feat: improve TaskCard and TagList components, enhance task loading logic

- Updated TaskCard to conditionally render footer elements based on available data (due date, source, completion status).
- Enhanced TagList to visually indicate deleting tags and improved button styles for better UX.
- Modified useTasks hook to refresh tasks only if no initial data is present, optimizing loading behavior.
- Updated TagsPageClient to manage local tags and handle optimistic UI updates during tag deletion.
This commit is contained in:
Julien Froidefond
2025-09-14 17:22:06 +02:00
parent 5e09759c2b
commit c1844cfb71
7 changed files with 94 additions and 67 deletions

View File

@@ -1,5 +1,4 @@
import { Tag } from '@/lib/types';
import { Button } from '@/components/ui/Button';
interface TagListProps {
tags: (Tag & { usage?: number })[];
@@ -7,13 +6,15 @@ interface TagListProps {
onTagDelete?: (tag: Tag) => void;
showActions?: boolean;
showUsage?: boolean;
deletingTagId?: string | null;
}
export function TagList({
tags,
onTagEdit,
onTagDelete,
showActions = true
showActions = true,
deletingTagId
}: TagListProps) {
if (tags.length === 0) {
return (
@@ -27,10 +28,15 @@ export function TagList({
return (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
{tags.map((tag) => (
{tags.map((tag) => {
const isDeleting = deletingTagId === tag.id;
return (
<div
key={tag.id}
className="group relative bg-slate-800/50 rounded-lg border border-slate-700 hover:border-slate-600 transition-all duration-200 hover:shadow-lg hover:shadow-slate-900/20 p-3"
className={`group relative bg-slate-800/50 rounded-lg border border-slate-700 hover:border-slate-600 transition-all duration-200 hover:shadow-lg hover:shadow-slate-900/20 p-3 ${
isDeleting ? 'opacity-50 pointer-events-none' : ''
}`}
>
{/* Contenu principal */}
<div className="flex items-center gap-3">
@@ -57,24 +63,21 @@ export function TagList({
{showActions && (onTagEdit || onTagDelete) && (
<div className="absolute top-2 right-2 flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
{onTagEdit && (
<Button
variant="ghost"
size="sm"
<button
onClick={() => onTagEdit(tag)}
className="h-7 px-2 text-xs bg-slate-700/80 backdrop-blur-sm border border-slate-600 hover:border-slate-500 hover:bg-slate-600"
className="h-7 px-2 text-xs bg-slate-800/50 backdrop-blur-sm border border-slate-700 hover:border-slate-600 hover:bg-slate-700/50 rounded-md transition-all duration-200 text-slate-300 hover:text-slate-200"
>
</Button>
</button>
)}
{onTagDelete && (
<Button
variant="ghost"
size="sm"
<button
onClick={() => onTagDelete(tag)}
className="h-7 px-2 text-xs bg-slate-700/80 backdrop-blur-sm border border-slate-600 hover:border-red-500 hover:text-red-400 hover:bg-red-900/20"
disabled={isDeleting}
className="h-7 px-2 text-xs bg-slate-800/50 backdrop-blur-sm border border-slate-700 hover:border-red-500/50 hover:text-red-400 hover:bg-red-900/20 rounded-md transition-all duration-200 text-slate-300 disabled:opacity-50 disabled:cursor-not-allowed"
>
🗑
</Button>
{isDeleting ? '⏳' : '🗑️'}
</button>
)}
</div>
)}
@@ -85,7 +88,8 @@ export function TagList({
style={{ backgroundColor: tag.color }}
/>
</div>
))}
);
})}
</div>
);
}