Pipeline/frontend/src/components/dashboard/DashboardMetricCard.tsx

52 lines
1.5 KiB
TypeScript
Raw Normal View History

2026-05-19 23:11:32 -05:00
import type { ReactNode } from "react";
import { Info } from "lucide-react";
import { toneIcon, toneCard, type MetricToneKey } from "./tokens";
2026-05-19 23:11:32 -05:00
interface DashboardMetricCardProps {
title: string;
value: string;
secondary?: string;
infoText?: string;
icon: ReactNode;
tone: MetricToneKey;
}
/**
* Top-row metric card. Tone drives the icon container color only
* card background and text always come from design tokens.
*/
export function DashboardMetricCard({
title,
value,
secondary,
infoText,
icon,
tone,
}: DashboardMetricCardProps) {
return (
<section className={`rounded-xl p-4 md:p-6 transition hover:-translate-y-0.5 hover:shadow-md ${toneCard[tone]}`}>
2026-05-19 23:11:32 -05:00
<div className="flex items-start justify-between gap-3">
<div>
<div className="flex items-center gap-1.5">
<p className="text-xs font-semibold uppercase tracking-wider text-muted">
{title}
</p>
{infoText && (
<span className="inline-flex text-muted" title={infoText} aria-label={infoText}>
<Info className="h-3.5 w-3.5" />
</span>
)}
</div>
<div className="mt-2 flex items-end gap-2">
<p className="font-heading text-4xl font-bold text-strong">{value}</p>
{secondary && (
<p className="pb-1 text-xs text-muted">{secondary}</p>
)}
</div>
</div>
<div className={`rounded-lg p-2 ${toneIcon[tone]}`}>{icon}</div>
</div>
</section>
);
}