feat: enhance TaskCard with tooltip functionality
- Added tooltip to TaskCard title for improved user interaction, displaying the title on hover. - Introduced cleanup for timeout on component unmount to prevent memory leaks. - Refactored title rendering to use a new TitleWithTooltip component for better code organization.
This commit is contained in:
@@ -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<NodeJS.Timeout | null>(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 = () => (
|
||||
<div className="relative flex-1">
|
||||
<h4
|
||||
className="font-mono text-sm font-medium text-[var(--foreground)] leading-tight line-clamp-2 cursor-pointer hover:text-[var(--primary)] transition-colors"
|
||||
onClick={handleTitleClick}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
title={onUpdateTitle ? "Cliquer pour éditer" : undefined}
|
||||
>
|
||||
{titleWithoutEmojis}
|
||||
</h4>
|
||||
|
||||
{/* Tooltip */}
|
||||
{showTooltip && (
|
||||
<div className="absolute z-50 bottom-full left-0 mb-2 px-2 py-1 bg-[var(--background)] border border-[var(--border)] rounded-md shadow-lg max-w-xs whitespace-normal break-words text-xs font-mono text-[var(--foreground)]">
|
||||
{titleWithoutEmojis}
|
||||
<div className="absolute top-full left-2 w-0 h-0 border-l-4 border-r-4 border-t-4 border-transparent border-t-[var(--border)]"></div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
// 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"
|
||||
/>
|
||||
) : (
|
||||
<h4
|
||||
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}
|
||||
>
|
||||
{titleWithoutEmojis}
|
||||
</h4>
|
||||
<TitleWithTooltip />
|
||||
)}
|
||||
|
||||
<div className="flex items-center gap-1 flex-shrink-0">
|
||||
@@ -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"
|
||||
/>
|
||||
) : (
|
||||
<h4
|
||||
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}
|
||||
>
|
||||
{titleWithoutEmojis}
|
||||
</h4>
|
||||
<TitleWithTooltip />
|
||||
)}
|
||||
|
||||
<div className="flex items-center gap-1 flex-shrink-0">
|
||||
|
||||
Reference in New Issue
Block a user