51 lines
1.4 KiB
TypeScript
51 lines
1.4 KiB
TypeScript
import React from 'react';
|
|
|
|
export interface MetricCardProps {
|
|
label: string;
|
|
value: string | number;
|
|
icon?: React.ReactNode;
|
|
trend?: {
|
|
value: number;
|
|
positive: boolean;
|
|
};
|
|
color?: 'blue' | 'green' | 'purple' | 'orange' | 'red';
|
|
}
|
|
|
|
export const MetricCard: React.FC<MetricCardProps> = ({
|
|
label,
|
|
value,
|
|
icon,
|
|
trend,
|
|
color = 'blue'
|
|
}) => {
|
|
const colorClasses = {
|
|
blue: 'text-blue-600 bg-blue-50',
|
|
green: 'text-green-600 bg-green-50',
|
|
purple: 'text-purple-600 bg-purple-50',
|
|
orange: 'text-orange-600 bg-orange-50',
|
|
red: 'text-red-600 bg-red-50'
|
|
};
|
|
|
|
return (
|
|
<div className="bg-white rounded-lg border border-gray-200 p-6">
|
|
<div className="flex items-start justify-between">
|
|
<div className="flex-1">
|
|
<p className="text-sm font-medium text-gray-600">{label}</p>
|
|
<p className="mt-2 text-3xl font-bold text-gray-900">{value}</p>
|
|
{trend && (
|
|
<div className={`mt-2 flex items-center text-sm ${trend.positive ? 'text-green-600' : 'text-red-600'}`}>
|
|
<span>{trend.positive ? '↑' : '↓'}</span>
|
|
<span className="ml-1">{Math.abs(trend.value)}%</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
{icon && (
|
|
<div className={`p-3 rounded-lg ${colorClasses[color]}`}>
|
|
{icon}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|