"use client"; import * as React from "react"; import { cn } from "@/lib/utils"; export type TimelineStepStatus = "completed" | "active" | "pending" | "error" | "skipped"; export interface TimelineStepData { id: string; title: string; description?: string; timestamp?: string; status: TimelineStepStatus; metadata?: React.ReactNode; } export interface TimelineStepProps extends React.HTMLAttributes { step: TimelineStepData; isLast?: boolean; } export interface TimelineProps extends React.HTMLAttributes { steps: TimelineStepData[]; } const stepIconConfig: Record = { completed: { iconBg: "bg-primary", iconColor: "text-primary-foreground", connectorClass: "bg-primary", }, active: { iconBg: "bg-white border-2 border-primary", iconColor: "text-primary", connectorClass: "bg-border", }, pending: { iconBg: "bg-white border-2 border-border", iconColor: "text-muted-foreground", connectorClass: "bg-border", }, error: { iconBg: "bg-destructive", iconColor: "text-destructive-foreground", connectorClass: "bg-destructive/30", }, skipped: { iconBg: "bg-muted border-2 border-border", iconColor: "text-muted-foreground", connectorClass: "bg-border", }, }; const StepIcon = ({ status }: { status: TimelineStepStatus }) => { switch (status) { case "completed": return ( ); case "active": return
; case "error": return ( ); case "skipped": return ( ); default: return
; } }; const TimelineStep = React.forwardRef( ({ className, step, isLast = false, ...props }, ref) => { const config = stepIconConfig[step.status]; return (
{/* Icon + connector column */}
{!isLast && (
)}
{/* Content */}

{step.title}

{step.description && (

{step.description}

)} {step.metadata && (
{step.metadata}
)}
{step.timestamp && ( {step.timestamp} )}
); } ); TimelineStep.displayName = "TimelineStep"; const Timeline = React.forwardRef( ({ className, steps, ...props }, ref) => { return (
{steps.map((step, idx) => ( ))}
); } ); Timeline.displayName = "Timeline"; export { TimelineStep, Timeline };