Files
TasGrid/src/components/TaskCard.tsx
T
2026-01-30 14:10:11 -06:00

84 lines
3.9 KiB
TypeScript

import { type Component, createMemo } from "solid-js";
import { type Task, toggleTask, calculateUrgencyFromDate, setActiveTaskId } from "@/store";
import { cn } from "@/lib/utils";
import { CheckCircle2, Circle, Clock, ArrowUpCircle } from "lucide-solid";
export const TaskCard: Component<{ task: Task }> = (props) => {
const urgencyLevel = createMemo(() => calculateUrgencyFromDate(props.task.dueDate));
const urgencyColor = () => {
const u = urgencyLevel();
if (u >= 8) return "text-red-500";
if (u >= 6) return "text-orange-500";
if (u >= 4) return "text-blue-500";
return "text-muted-foreground";
};
const formattedDate = () => {
const date = new Date(props.task.dueDate);
return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' });
};
return (
<div
class={cn(
"group flex items-center p-4 bg-card border border-border rounded-2xl transition-all duration-300 hover:shadow-xl hover:shadow-primary/5 hover:-translate-y-0.5 cursor-pointer",
props.task.completed && "opacity-60"
)}
onClick={() => setActiveTaskId(props.task.id)}
>
<button
onClick={(e) => { e.stopPropagation(); toggleTask(props.task.id); }}
class="mr-4 text-muted-foreground hover:text-primary transition-colors shrink-0"
>
{props.task.completed ? (
<CheckCircle2 class="text-green-500" size={24} />
) : (
<Circle size={24} />
)}
</button>
<div class="flex-1 min-w-0">
<h3 class={cn(
"text-base font-semibold truncate transition-all",
props.task.completed && "line-through"
)}>
{props.task.title}
</h3>
<div class="flex items-center space-x-4 mt-1">
{/* Priority */}
<div class="flex items-center gap-1.5 min-w-[32px]">
<ArrowUpCircle size={12} class="text-primary opacity-60" />
<span>P{props.task.priority}</span>
</div>
{/* Due Date + Urgency Slide-out */}
<div class="relative group/date flex items-center h-6 cursor-help">
{/* Due Date - Static Layer on Top */}
<div class="flex items-center space-x-1.5 text-[10px] font-bold text-muted-foreground uppercase tracking-wider bg-card relative z-20 pr-1">
<Clock size={12} class="text-primary/60" />
<span>{formattedDate()}</span>
</div>
{/* Urgency Number - Slides out from behind with fade */}
<div class={cn(
"absolute left-4 top-0 bottom-0 flex items-center transition-all duration-300 ease-out z-10 opacity-0 group-hover/date:opacity-100 group-hover/date:left-full whitespace-nowrap",
urgencyColor()
)}>
<span class="text-[10px] font-bold ml-2 transition-all duration-300 transform translate-x-[-8px] group-hover/date:translate-x-0 group-hover/date:blur-none blur-[2px]">
Urgency {urgencyLevel()}
</span>
</div>
</div>
</div>
</div>
<div class="ml-4 opacity-0 group-hover:opacity-100 transition-opacity shrink-0">
<button class="p-2 hover:bg-muted rounded-full transition-colors">
<div class="w-1.5 h-1.5 bg-muted-foreground rounded-full" />
</button>
</div>
</div>
);
};