72 lines
2.0 KiB
TypeScript
72 lines
2.0 KiB
TypeScript
import React from 'react';
|
|
import { Card } from './Card';
|
|
import { Text } from './Text';
|
|
import { Icon } from './Icon';
|
|
import { LucideIcon } from 'lucide-react';
|
|
|
|
interface StatCardProps {
|
|
label: string;
|
|
value: string | number;
|
|
subValue?: string;
|
|
icon?: LucideIcon;
|
|
variant?: 'blue' | 'purple' | 'green' | 'orange';
|
|
className?: string;
|
|
trend?: {
|
|
value: number;
|
|
isPositive: boolean;
|
|
};
|
|
}
|
|
|
|
export function StatCard({
|
|
label,
|
|
value,
|
|
subValue,
|
|
icon,
|
|
variant = 'blue',
|
|
className = '',
|
|
trend,
|
|
}: StatCardProps) {
|
|
const variantClasses = {
|
|
blue: 'bg-gradient-to-br from-blue-900/20 to-blue-700/10 border-blue-500/30',
|
|
purple: 'bg-gradient-to-br from-purple-900/20 to-purple-700/10 border-purple-500/30',
|
|
green: 'bg-gradient-to-br from-green-900/20 to-green-700/10 border-green-500/30',
|
|
orange: 'bg-gradient-to-br from-orange-900/20 to-orange-700/10 border-orange-500/30'
|
|
};
|
|
|
|
const iconColorClasses = {
|
|
blue: '#60a5fa',
|
|
purple: '#a78bfa',
|
|
green: '#34d399',
|
|
orange: '#fb923c'
|
|
};
|
|
|
|
return (
|
|
<Card className={`${variantClasses[variant]} ${className}`}>
|
|
<div className="flex items-start justify-between">
|
|
<div>
|
|
<Text size="sm" color="text-gray-400" className="mb-1" block>
|
|
{label}
|
|
</Text>
|
|
<Text size="3xl" weight="bold" color="text-white" block>
|
|
{value}
|
|
</Text>
|
|
{subValue && (
|
|
<Text size="xs" color="text-gray-500" className="mt-1" block>
|
|
{subValue}
|
|
</Text>
|
|
)}
|
|
</div>
|
|
<div className="flex flex-col items-end gap-2">
|
|
{icon && (
|
|
<Icon icon={icon} size={8} color={iconColorClasses[variant]} />
|
|
)}
|
|
{trend && (
|
|
<Text size="sm" color={trend.isPositive ? 'text-performance-green' : 'text-error-red'}>
|
|
{trend.isPositive ? '↑' : '↓'}{Math.abs(trend.value)}%
|
|
</Text>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
);
|
|
} |