diff --git a/components/kanban/TaskCard.tsx b/components/kanban/TaskCard.tsx index 3fb6b8a..e4060ef 100644 --- a/components/kanban/TaskCard.tsx +++ b/components/kanban/TaskCard.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react'; +import { useState, useEffect, useRef } from 'react'; import { Task } from '@/lib/types'; import { formatDistanceToNow } from 'date-fns'; import { fr } from 'date-fns/locale'; @@ -20,6 +20,8 @@ interface TaskCardProps { export function TaskCard({ task, onDelete, onEdit, onUpdateTitle, compactView = false }: TaskCardProps) { const [isEditingTitle, setIsEditingTitle] = useState(false); const [editTitle, setEditTitle] = useState(task.title); + const [showTooltip, setShowTooltip] = useState(false); + const timeoutRef = useRef(null); const { tags: availableTags } = useTasksContext(); // Configuration du draggable @@ -37,6 +39,16 @@ export function TaskCard({ task, onDelete, onEdit, onUpdateTitle, compactView = useEffect(() => { setEditTitle(task.title); }, [task.title]); + + // Nettoyer le timeout au démontage + useEffect(() => { + return () => { + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + } + }; + }, []); + const handleDelete = async (e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); @@ -83,6 +95,23 @@ export function TaskCard({ task, onDelete, onEdit, onUpdateTitle, compactView = handleTitleCancel(); } }; + + const handleMouseEnter = () => { + if (!isEditingTitle) { + timeoutRef.current = setTimeout(() => { + setShowTooltip(true); + }, 100); + } + }; + + const handleMouseLeave = () => { + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + timeoutRef.current = null; + } + setShowTooltip(false); + }; + // Style de transformation pour le drag const style = transform ? { transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`, @@ -92,6 +121,29 @@ export function TaskCard({ task, onDelete, onEdit, onUpdateTitle, compactView = const emojiRegex = /(?:[\u{1F600}-\u{1F64F}]|[\u{1F300}-\u{1F5FF}]|[\u{1F680}-\u{1F6FF}]|[\u{1F900}-\u{1F9FF}]|[\u{1F1E0}-\u{1F1FF}]|[\u{2600}-\u{26FF}]|[\u{2700}-\u{27BF}])(?:[\u{200D}][\u{1F600}-\u{1F64F}]|[\u{1F300}-\u{1F5FF}]|[\u{1F680}-\u{1F6FF}]|[\u{1F900}-\u{1F9FF}]|[\u{1F1E0}-\u{1F1FF}]|[\u{2600}-\u{26FF}]|[\u{2700}-\u{27BF}]|[\u{FE0F}])*/gu; const titleEmojis = task.title.match(emojiRegex) || []; const titleWithoutEmojis = task.title.replace(emojiRegex, '').trim(); + + // Composant titre avec tooltip + const TitleWithTooltip = () => ( +
+

+ {titleWithoutEmojis} +

+ + {/* Tooltip */} + {showTooltip && ( +
+ {titleWithoutEmojis} +
+
+ )} +
+ ); // Si pas d'emoji dans le titre, utiliser l'emoji du premier tag let displayEmojis: string[] = titleEmojis; @@ -149,13 +201,7 @@ export function TaskCard({ task, onDelete, onEdit, onUpdateTitle, compactView = className="flex-1 bg-transparent border-none outline-none text-[var(--foreground)] font-mono text-sm font-medium leading-tight" /> ) : ( -

- {titleWithoutEmojis} -

+ )}
@@ -234,13 +280,7 @@ export function TaskCard({ task, onDelete, onEdit, onUpdateTitle, compactView = className="flex-1 bg-transparent border-none outline-none text-[var(--foreground)] font-mono text-sm font-medium leading-tight" /> ) : ( -

- {titleWithoutEmojis} -

+ )}