40 lines
1.2 KiB
TypeScript
40 lines
1.2 KiB
TypeScript
import React from 'react';
|
|
import type { ReactNode } from 'react';
|
|
|
|
interface StatCardProps {
|
|
label: string;
|
|
value: string | number;
|
|
icon?: ReactNode;
|
|
change?: number;
|
|
unit?: string;
|
|
}
|
|
|
|
export default function StatCard({ label, value, icon, change, unit }: StatCardProps) {
|
|
const isPositive = change && change > 0;
|
|
const isNegative = change && change < 0;
|
|
|
|
return (
|
|
<div className="p-6 bg-white border border-slate-200 rounded-xl shadow-sm">
|
|
<div className="flex items-start justify-between">
|
|
<div className="p-2 bg-slate-50 rounded-lg text-slate-500">
|
|
{icon}
|
|
</div>
|
|
{change !== undefined && (
|
|
<div className={`flex items-center text-xs font-medium ${isPositive ? 'text-emerald-600' : 'text-rose-600'}`}>
|
|
{isPositive ? '↑' : '↓'} {Math.abs(change)}%
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
<div className="mt-4">
|
|
<p className="text-sm font-medium text-slate-500">{label}</p>
|
|
<div className="flex items-baseline gap-1 mt-1">
|
|
<h3 className="text-2xl font-bold text-slate-900">
|
|
{value}
|
|
</h3>
|
|
{unit && <span className="text-sm font-medium text-slate-500">{unit}</span>}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
} |