o2o-infinith-demo/src/components/report/ui/MetricCard.tsx

45 lines
1.3 KiB
TypeScript

import type { ReactNode } from 'react';
import { ArrowUp, ArrowDown, Minus } from 'lucide-react';
interface MetricCardProps {
key?: string | number;
label: string;
value: string | number;
subtext?: string;
icon?: ReactNode;
trend?: 'up' | 'down' | 'neutral';
}
const trendConfig = {
up: { icon: ArrowUp, color: 'text-emerald-500' },
down: { icon: ArrowDown, color: 'text-red-500' },
neutral: { icon: Minus, color: 'text-slate-400' },
};
export function MetricCard({ label, value, subtext, icon, trend }: MetricCardProps) {
return (
<div className="rounded-2xl border border-slate-100 shadow-sm bg-white p-5 relative">
{icon && (
<div className="absolute top-4 right-4 text-slate-300">
{icon}
</div>
)}
<p className="text-sm text-slate-500 mb-1">{label}</p>
<div className="flex items-end gap-2">
<span className="text-3xl font-bold text-[#0A1128]">{value}</span>
{trend && (
<span className={`${trendConfig[trend].color} mb-1`}>
{(() => {
const TrendIcon = trendConfig[trend].icon;
return <TrendIcon size={18} />;
})()}
</span>
)}
</div>
{subtext && (
<p className="text-xs text-slate-400 mt-1">{subtext}</p>
)}
</div>
);
}