1import { formatPercent } from "@t3tools/shared/usageFormat";
2import type { ReactNode } from "react";
3
4import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip";
5
6export interface ShareSegment {
7 readonly label: string;
8 readonly value: number;
9 readonly color: string;
10}
11
12/**
13 * One part-to-whole bar with its legend, for cost or tokens split by type or
14 * speed. Empty segments are left out, and nothing renders without a total.
15 */
16export function UsageShareBar({
17 label,
18 segments,
19 format,
20 aside,
21}: {
22 readonly label: string;
23 readonly segments: readonly ShareSegment[];
24 readonly format: (value: number) => string;
25 readonly aside?: ReactNode;
26}) {
27 const visible = segments.filter((segment) => segment.value > 0);
28 const total = visible.reduce((sum, segment) => sum + segment.value, 0);
29 if (total <= 0) return null;
30
31 return (
32 <div className="flex min-w-0 flex-col gap-2.5">
33 <div className="flex items-baseline justify-between gap-3">
34 <h3 className="text-sm font-medium text-foreground">{label}</h3>
35 {aside}
36 </div>
37 <div
38 role="img"
39 aria-label={`${label}: ${visible.map((segment) => `${segment.label} ${format(segment.value)}`).join(", ")}`}
40 className="flex h-2 gap-0.5"
41 >
42 {visible.map((segment) => (
43 <Tooltip key={segment.label}>
44 <TooltipTrigger
45 render={
46 <div
47 className="h-full min-w-1 rounded-xs first:rounded-l-full last:rounded-r-full"
48 style={{ flex: `${segment.value} 1 0`, backgroundColor: segment.color }}
49 />
50 }
51 />
52 <TooltipPopup>
53 {segment.label} · {format(segment.value)} · {formatPercent(segment.value / total)}
54 </TooltipPopup>
55 </Tooltip>
56 ))}
57 </div>
58 <div className="flex flex-wrap gap-x-4 gap-y-1 text-xs">
59 {visible.map((segment) => (
60 <span key={segment.label} className="flex items-center gap-1.5">
61 <span
62 aria-hidden
63 className="size-2 rounded-xs"
64 style={{ backgroundColor: segment.color }}
65 />
66 <span className="text-muted-foreground">{segment.label}</span>
67 <span className="text-foreground tabular-nums">{format(segment.value)}</span>
68 </span>
69 ))}
70 </div>
71 </div>
72 );
73}