Skip to content
Source
Sign inSign up
Open History to see the last commit

TimelineSystemDivider.tsx

85 lines2.7 KB

1import type { ReactNode } from "react";
2import type { LucideIcon } from "lucide-react";
3​
4import { cn } from "~/lib/utils";
5import { Tooltip, TooltipPopup, TooltipTrigger } from "~/components/ui/tooltip";
6​
7export function TimelineSystemDivider(props: {
8 readonly label: string;
9 readonly detail?: ReactNode | null;
10 readonly tone?: "neutral" | "danger";
11 readonly icon?: LucideIcon;
12 readonly showDetailSeparator?: boolean;
13 readonly wrapDetail?: boolean;
14 readonly actionLabel?: string;
15 readonly onAction?: () => void;
16}) {
17 const Icon = props.icon;
18 const content = (
19 <>
20 <span
21 className={cn(
22 "inline-flex items-baseline gap-1.5 align-baseline font-medium",
23 props.wrapDetail && "shrink-0 whitespace-nowrap",
24 )}
25 >
26 {Icon ? <Icon className="size-3 shrink-0 self-center" /> : null}
27 {props.label}
28 </span>
29 {props.detail ? (
30 <span
31 className={cn(
32 "min-w-0 opacity-70",
33 props.wrapDetail ? "ml-1.5 wrap-anywhere" : "inline-flex items-center",
34 typeof props.detail === "string" &&
35 (props.wrapDetail ? "whitespace-pre-wrap" : "max-w-80 truncate"),
36 )}
37 >
38 {props.showDetailSeparator === false ? null : "·\u00a0"}
39 {props.detail}
40 </span>
41 ) : null}
42 </>
43 );
44​
45 return (
46 <div
47 className={cn(
48 "flex min-w-0 items-center gap-2 py-2 text-2xs text-muted-foreground",
49 props.tone === "danger" && "text-destructive",
50 )}
51 >
52 <span aria-hidden="true" className="h-px flex-1 bg-border/70" />
53 {props.onAction ? (
54 <Tooltip>
55 <TooltipTrigger
56 render={
57 <button
58 type="button"
59 aria-label={props.actionLabel}
60 onClick={props.onAction}
61 className={cn(
62 "min-w-0 cursor-pointer rounded-full border border-border/70 bg-background px-2.5 py-1 transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring/70",
63 props.wrapDetail ? "text-center" : "flex items-center gap-1.5",
64 )}
65 />
66 }
67 >
68 {content}
69 </TooltipTrigger>
70 <TooltipPopup side="top">{props.actionLabel}</TooltipPopup>
71 </Tooltip>
72 ) : (
73 <span
74 className={cn(
75 "min-w-0 rounded-full px-2 py-1",
76 props.wrapDetail ? "text-center" : "flex flex-wrap items-center justify-center gap-1.5",
77 )}
78 >
79 {content}
80 </span>
81 )}
82 <span aria-hidden="true" className="h-px flex-1 bg-border/70" />
83 </div>
84 );