dimensionlab-website/src/lib/ui/components/TelemetryCard.tsx

51 lines
1.5 KiB
TypeScript

import type { CSSProperties } from "react";
import { clampPercent, formatMetricValue } from "../format";
import type { UiTelemetryCard } from "../types";
import { IconGlyph } from "./IconGlyph";
import { LineChart } from "./LineChart";
export interface TelemetryCardProps {
card: UiTelemetryCard;
}
export function TelemetryCard({ card }: TelemetryCardProps) {
const progress = resolveProgress(card);
const value = formatMetricValue(card.value);
return (
<article
className="telemetry-card"
data-severity={card.severity}
data-model-id={card.id}
>
<header>
{card.icon ? <IconGlyph name={card.icon} size="sm" /> : null}
<h3>{card.label}</h3>
</header>
<strong>{value}</strong>
{progress !== null ? (
<div className="telemetry-card__bar" aria-hidden="true">
<span style={{ "--metric-progress": `${progress}%` } as CSSProperties} />
</div>
) : null}
{card.sparkline?.length ? (
<LineChart
values={card.sparkline}
severity={card.severity}
label={`${card.label} trend`}
/>
) : null}
{card.detail || card.description ? (
<p>{card.detail || card.description}</p>
) : null}
</article>
);
}
function resolveProgress(card: UiTelemetryCard): number | null {
if (typeof card.progress === "number") return clampPercent(card.progress);
if (card.value.kind !== "percent") return null;
const progress = Number(card.value.value);
return Number.isFinite(progress) ? clampPercent(progress) : null;
}