"use client"; import type { ActivityEvent, ActivityEventType } from "@/lib/activity"; import { formatRelativeTime } from "@/lib/utils"; // ============================================================================ // Event type icons (inline SVG for each category) // ============================================================================ function EventIcon({ type, className }: { type: ActivityEventType; className?: string }) { const cls = className || "w-3.5 h-3.5 shrink-0"; switch (type) { case "node-created": return ( ); case "node-closed": return ( ); case "node-status-changed": return ( ); case "node-priority-changed": return ( ); case "node-title-changed": return ( ); case "node-owner-changed": return ( ); case "node-assignee-changed": return ( ); case "link-added": return ( ); case "link-removed": return ( ); case "comment-added": case "reply-added": return ( ); case "task-claimed": return ( ); case "task-unclaimed": return ( ); case "like-added": return ( ); } } // ============================================================================ // Event type -> accent color for left border/indicator // ============================================================================ function getEventAccentColor(type: ActivityEventType): string { switch (type) { case "node-created": case "task-claimed": return "bg-emerald-400"; case "node-closed": return "bg-zinc-300"; case "node-status-changed": case "node-priority-changed": case "node-title-changed": case "node-owner-changed": return "bg-amber-400"; case "node-assignee-changed": return "bg-violet-400"; case "link-added": case "comment-added": case "reply-added": return "bg-blue-400"; case "link-removed": case "task-unclaimed": return "bg-red-300"; case "like-added": return "bg-rose-300"; } } // ============================================================================ // Event description text // ============================================================================ function describeEvent(event: ActivityEvent): string { switch (event.type) { case "node-created": { const typeLabel = event.meta?.issueType || "task"; return `created a ${typeLabel}`; } case "node-closed": return `closed this${event.detail && event.detail !== "Closed" ? ` (${event.detail})` : ""}`; case "node-status-changed": return event.detail ? `changed status ${event.detail}` : "changed status"; case "node-priority-changed": return `changed priority ${event.detail || ""}`.trim(); case "node-title-changed": return "updated the title"; case "node-owner-changed": return `changed owner ${event.detail || ""}`.trim(); case "node-assignee-changed": { const to = event.meta?.to; const from = event.meta?.from; if (to && !from) return `assigned ${to}`; if (!to && from) return `unassigned ${from}`; if (to) return `reassigned to ${to}`; return "changed assignee"; } case "link-added": return `added a dependency on ${event.meta?.target || ""}`; case "link-removed": return `removed dependency on ${event.meta?.target || ""}`; case "comment-added": return event.detail ? `commented: "${event.detail}"` : "commented"; case "reply-added": return event.detail ? `replied: "${event.detail}"` : "replied"; case "task-claimed": return "claimed this task"; case "task-unclaimed": return "unclaimed this task"; case "like-added": return event.detail || "liked a comment"; default: return event.detail || "updated"; } } // ============================================================================ // Compact variant (single-line, for overlay) — with left accent bar // ============================================================================ function CompactItem({ event, onNodeClick, onHandleClick, }: { event: ActivityEvent; onNodeClick?: (nodeId: string) => void; onHandleClick?: (handle: string) => void; }) { return (