{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "timeline",
  "title": "Timeline",
  "description": "A horizontal or vertical timeline component for displaying ordered events, steps, or milestones",
  "files": [
    {
      "path": "components/ui/slide-cn/timeline.tsx",
      "content": "import * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\n/**\n * Timeline\n *\n * A compound component for rendering horizontal or vertical timelines in slides.\n * Useful for chronological events, process steps, roadmaps, or any ordered sequence.\n *\n * Responsibilities:\n * - Render items connected by a continuous line through their markers\n * - Support horizontal layout (converts to vertical on mobile) and vertical layout\n * - Support left-aligned and center (alternating) vertical layouts\n * - Accept custom markers (icons, numbers) or default filled dot\n *\n * Usage:\n * ```tsx\n * // Horizontal (default) — auto-converts to vertical on mobile\n * <Timeline>\n *   <Timeline.Item label=\"Q1 2024\">Shipped v1</Timeline.Item>\n *   <Timeline.Item label=\"Q2 2024\" marker={<Rocket />}>Shipped v2</Timeline.Item>\n * </Timeline>\n *\n * // Always vertical, left-aligned\n * <Timeline orientation=\"vertical\">\n *   <Timeline.Item label=\"2020\">Founded the company</Timeline.Item>\n * </Timeline>\n *\n * // Vertical alternating sides\n * <Timeline orientation=\"vertical\" align=\"center\">\n *   <Timeline.Item label=\"2020\">Founded</Timeline.Item>\n *   <Timeline.Item label=\"2021\">First product</Timeline.Item>\n * </Timeline>\n * ```\n *\n * Notes:\n * - Horizontal timelines auto-convert to vertical left-aligned on screens below md (768px)\n * - orientation, align, index, isFirst, isLast are injected by Timeline via cloneElement\n * - Pass any ReactNode to the `marker` prop for custom icons or step numbers\n */\n\n// ─── Marker ─────────────────────────────────────────────────────────────────\n\nfunction TimelineMarker({ children }: { children?: React.ReactNode }) {\n\tif (children) {\n\t\treturn (\n\t\t\t<div className=\"relative z-10 flex h-9 w-9 shrink-0 items-center justify-center rounded-full border-2 border-primary/30 bg-background text-primary [&_svg]:h-4 [&_svg]:w-4\">\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t);\n\t}\n\treturn (\n\t\t<div className=\"relative z-10 h-3 w-3 shrink-0 rounded-full bg-primary ring-4 ring-background\" />\n\t);\n}\n\n// ─── Timeline.Item ──────────────────────────────────────────────────────────\n\nexport interface TimelineItemProps {\n\t/** Date, step label, or any node shown near the marker */\n\tlabel?: React.ReactNode;\n\t/** Custom marker content (icon, number). Defaults to a filled dot. */\n\tmarker?: React.ReactNode;\n\tclassName?: string;\n\tchildren?: React.ReactNode;\n\t/** Injected by Timeline via cloneElement — do not pass manually */\n\torientation?: \"horizontal\" | \"vertical\";\n\t/** Injected by Timeline via cloneElement — do not pass manually */\n\talign?: \"left\" | \"center\";\n\t/** Injected by Timeline via cloneElement — do not pass manually */\n\tindex?: number;\n\t/** Injected by Timeline via cloneElement — do not pass manually */\n\tisFirst?: boolean;\n\t/** Injected by Timeline via cloneElement — do not pass manually */\n\tisLast?: boolean;\n}\n\nfunction TimelineItem({\n\tlabel,\n\tmarker,\n\tclassName,\n\tchildren,\n\torientation = \"horizontal\",\n\talign = \"left\",\n\tindex = 0,\n\tisFirst = false,\n\tisLast = false,\n}: TimelineItemProps) {\n\t// ── Vertical left-aligned ──\n\tif (orientation === \"vertical\" && align !== \"center\") {\n\t\treturn (\n\t\t\t<div className={cn(\"flex flex-row items-stretch\", className)}>\n\t\t\t\t{/* Left column: marker at top, line fills downward */}\n\t\t\t\t<div className=\"flex flex-col items-center mr-5 shrink-0\">\n\t\t\t\t\t<TimelineMarker>{marker}</TimelineMarker>\n\t\t\t\t\t<div className={cn(\"w-px flex-1 bg-border mt-1\", isLast && \"opacity-0\")} />\n\t\t\t\t</div>\n\t\t\t\t{/* Right column: label + content */}\n\t\t\t\t<div className={cn(\"flex flex-col gap-1.5\", isLast ? \"pb-0\" : \"pb-10\")}>\n\t\t\t\t\t{label && <p className=\"text-sm font-semibold leading-none\">{label}</p>}\n\t\t\t\t\t{children && (\n\t\t\t\t\t\t<div className=\"text-sm text-muted-foreground leading-relaxed\">\n\t\t\t\t\t\t\t{children}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t);\n\t}\n\n\t// ── Vertical center (alternating) ──\n\tif (orientation === \"vertical\" && align === \"center\") {\n\t\tconst isEven = index % 2 === 0;\n\t\treturn (\n\t\t\t<div className={cn(\"grid grid-cols-[1fr_auto_1fr]\", className)}>\n\t\t\t\t{/* Left cell: content for even items, empty for odd */}\n\t\t\t\t<div\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"flex flex-col gap-1.5 items-end text-right pr-6\",\n\t\t\t\t\t\tisLast ? \"pb-0\" : \"pb-10\"\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t{isEven && label && (\n\t\t\t\t\t\t<p className=\"text-sm font-semibold leading-none\">{label}</p>\n\t\t\t\t\t)}\n\t\t\t\t\t{isEven && children && (\n\t\t\t\t\t\t<div className=\"text-sm text-muted-foreground leading-relaxed\">\n\t\t\t\t\t\t\t{children}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t{/* Center cell: connector always at the same horizontal position */}\n\t\t\t\t<div className=\"flex flex-col items-center\">\n\t\t\t\t\t<TimelineMarker>{marker}</TimelineMarker>\n\t\t\t\t\t<div className={cn(\"w-px flex-1 bg-border mt-1\", isLast && \"opacity-0\")} />\n\t\t\t\t</div>\n\t\t\t\t{/* Right cell: content for odd items, empty for even */}\n\t\t\t\t<div\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"flex flex-col gap-1.5 items-start text-left pl-6\",\n\t\t\t\t\t\tisLast ? \"pb-0\" : \"pb-10\"\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t{!isEven && label && (\n\t\t\t\t\t\t<p className=\"text-sm font-semibold leading-none\">{label}</p>\n\t\t\t\t\t)}\n\t\t\t\t\t{!isEven && children && (\n\t\t\t\t\t\t<div className=\"text-sm text-muted-foreground leading-relaxed\">\n\t\t\t\t\t\t\t{children}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t);\n\t}\n\n\t// ── Horizontal (default) — vertical on mobile, horizontal on desktop ──\n\treturn (\n\t\t<div className={cn(\"flex-1 min-w-0\", className)}>\n\t\t\t{/* Mobile: left-aligned vertical */}\n\t\t\t<div className=\"flex flex-row items-stretch md:hidden\">\n\t\t\t\t<div className=\"flex flex-col items-center mr-5 shrink-0\">\n\t\t\t\t\t<TimelineMarker>{marker}</TimelineMarker>\n\t\t\t\t\t<div className={cn(\"w-px flex-1 bg-border mt-1\", isLast && \"opacity-0\")} />\n\t\t\t\t</div>\n\t\t\t\t<div className={cn(\"flex flex-col gap-1.5\", isLast ? \"pb-0\" : \"pb-10\")}>\n\t\t\t\t\t{label && <p className=\"text-sm font-semibold leading-none\">{label}</p>}\n\t\t\t\t\t{children && (\n\t\t\t\t\t\t<div className=\"text-sm text-muted-foreground leading-relaxed\">\n\t\t\t\t\t\t\t{children}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t{/* Desktop: horizontal */}\n\t\t\t<div className=\"hidden md:flex flex-col items-center gap-3\">\n\t\t\t\t{/* Label above — fixed min-height keeps all markers on the same horizontal axis */}\n\t\t\t\t<div className=\"min-h-8 flex items-end pb-1\">\n\t\t\t\t\t{label && (\n\t\t\t\t\t\t<p className=\"text-sm font-semibold text-center leading-snug\">{label}</p>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t{/* Connector row: left arm — marker — right arm */}\n\t\t\t\t<div className=\"flex items-center w-full\">\n\t\t\t\t\t<div className={cn(\"h-px flex-1 bg-border\", isFirst && \"opacity-0\")} />\n\t\t\t\t\t<TimelineMarker>{marker}</TimelineMarker>\n\t\t\t\t\t<div className={cn(\"h-px flex-1 bg-border\", isLast && \"opacity-0\")} />\n\t\t\t\t</div>\n\t\t\t\t{/* Content below */}\n\t\t\t\t<div className=\"text-sm text-muted-foreground text-center leading-relaxed max-w-[90%]\">\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\n// ─── Timeline (root) ─────────────────────────────────────────────────────────\n\nexport interface TimelineProps {\n\t/** Layout direction. \"horizontal\" converts to vertical on mobile. */\n\torientation?: \"horizontal\" | \"vertical\";\n\t/** Vertical only — \"left\" keeps content on the right; \"center\" alternates sides. */\n\talign?: \"left\" | \"center\";\n\tclassName?: string;\n\tchildren?: React.ReactNode;\n}\n\nexport function Timeline({\n\torientation = \"horizontal\",\n\talign = \"left\",\n\tclassName,\n\tchildren,\n}: TimelineProps) {\n\tconst items = React.Children.toArray(children);\n\tconst count = items.length;\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"w-full\",\n\t\t\t\torientation === \"horizontal\" ? \"flex flex-col md:flex-row\" : \"flex flex-col\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t>\n\t\t\t{items.map((child, index) => {\n\t\t\t\tif (!React.isValidElement(child)) return child;\n\t\t\t\treturn React.cloneElement(child as React.ReactElement<TimelineItemProps>, {\n\t\t\t\t\tkey: index,\n\t\t\t\t\torientation,\n\t\t\t\t\talign,\n\t\t\t\t\tindex,\n\t\t\t\t\tisFirst: index === 0,\n\t\t\t\t\tisLast: index === count - 1,\n\t\t\t\t});\n\t\t\t})}\n\t\t</div>\n\t);\n}\n\nTimeline.Item = TimelineItem;\n",
      "type": "registry:component",
      "target": "components/ui/slide-cn/timeline.tsx"
    }
  ],
  "type": "registry:component"
}