75 lines
2.0 KiB
TypeScript
75 lines
2.0 KiB
TypeScript
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>
|
||
);
|
||
}
|