metis-desk/packages/rdx-ui/src/components/statistic-card.tsx

75 lines
2.0 KiB
TypeScript
Raw Normal View History

import type { ReactNode } from "react";
const TONES = {
teal: "bg-primary/5",
rose: "bg-destructive/5",
amber: "bg-amber-500/5",
green: "bg-emerald-500/5",
violet: "bg-violet-500/5",
};
const ICON_TONES = {
teal: "text-primary",
rose: "text-destructive",
amber: "text-amber-700 dark:text-amber-400",
green: "text-emerald-700 dark:text-emerald-400",
violet: "text-violet-700 dark:text-violet-400",
};
export function StatisticCard({
icon,
label,
value,
tone = "teal",
onClick,
status,
compact = false,
}: {
compact?: boolean;
icon: ReactNode;
label: string;
value?: number | undefined;
tone?: "teal" | "rose" | "amber" | "green" | "violet";
onClick: () => void;
status?: string | undefined;
}) {
return (
<button
className={`flex items-start gap-3 rounded-xl border border-border text-left transition-colors hover:border-primary focus-visible:outline-2 focus-visible:outline-ring ${compact ? "min-h-28 p-5" : "min-h-28 p-4 shadow-sm"} ${TONES[tone]}`}
onClick={onClick}
type="button"
>
<span
aria-hidden="true"
className={`flex size-10 shrink-0 items-center justify-center rounded-full bg-background/60 [&_svg]:size-5 ${ICON_TONES[tone]}`}
>
{icon}
</span>
<span className="min-w-0">
<span
className={
compact
? "block text-sm font-medium text-foreground"
: "block text-xs font-medium text-foreground"
}
>
{label}
</span>
<strong
className={`mt-2 block font-semibold tabular-nums text-foreground ${compact ? "text-4xl tracking-tight" : "text-3xl"}`}
>
{value ?? "—"}
</strong>
{status && (
<small className="block mt-1 text-muted-foreground" role="status">
{status}
</small>
)}
</span>
<span aria-hidden="true" className="ml-auto self-center text-lg text-primary">
›
</span>
</button>
);
}