metis-desk/packages/rdx-ui/src/components/time-line.tsx

56 lines
1.7 KiB
TypeScript
Raw Normal View History

import type { ReactNode } from "react";
export type TimeLineItem = {
id: string;
title: ReactNode;
dateTime: string;
dateLabel: string;
meta?: ReactNode;
content?: ReactNode;
};
/** Secuencia vertical: el consumidor aporta orden, fechas formateadas y contenido de cada evento. */
export function TimeLine({
items,
label,
emptyMessage,
}: {
items: readonly TimeLineItem[];
label: string;
emptyMessage: string;
}) {
if (items.length === 0) {
return (
<p className="text-sm text-muted-foreground" role="status">
{emptyMessage}
</p>
);
}
return (
<ol aria-label={label} className="min-w-0">
{items.map((item, index) => (
<li className="relative min-w-0 ps-8 pb-6 last:pb-0" key={item.id}>
{index < items.length - 1 && (
<span aria-hidden="true" className="absolute start-2 top-3 -bottom-3 w-px bg-border" />
)}
<span
aria-hidden="true"
className="absolute start-0.5 top-1.5 size-3 rounded-full border-2 border-background bg-primary ring-1 ring-primary/30"
/>
<article className="min-w-0 space-y-3 rounded-lg border bg-card p-4 text-card-foreground">
<div className="flex flex-wrap items-start justify-between gap-2">
<h3 className="min-w-0 break-words text-sm font-semibold">{item.title}</h3>
<time className="text-xs text-muted-foreground" dateTime={item.dateTime}>
{item.dateLabel}
</time>
</div>
{item.meta && <div className="text-xs text-muted-foreground">{item.meta}</div>}
{item.content}
</article>
</li>
))}
</ol>
);
}