73 lines
2.0 KiB
TypeScript
73 lines
2.0 KiB
TypeScript
/**
|
|
* 统一的 StatsCard 组件
|
|
* 用于显示统计数据卡片
|
|
*/
|
|
import React from "react";
|
|
import type { LucideIcon } from "lucide-react";
|
|
|
|
export type StatsCardVariant = "blue" | "green" | "purple" | "orange" | "red";
|
|
|
|
export interface StatsCardProps {
|
|
title: string;
|
|
value: string | number;
|
|
icon: LucideIcon;
|
|
variant?: StatsCardVariant;
|
|
subtitle?: string;
|
|
className?: string;
|
|
}
|
|
|
|
const variantStyles: Record<StatsCardVariant, { container: string; iconBg: string; iconColor: string }> = {
|
|
blue: {
|
|
container: "bg-gradient-to-br from-blue-600/20 to-blue-800/20 border-blue-500/30",
|
|
iconBg: "bg-blue-600/30",
|
|
iconColor: "text-blue-300",
|
|
},
|
|
green: {
|
|
container: "bg-gradient-to-br from-green-600/20 to-green-800/20 border-green-500/30",
|
|
iconBg: "bg-green-600/30",
|
|
iconColor: "text-green-300",
|
|
},
|
|
purple: {
|
|
container: "bg-gradient-to-br from-purple-600/20 to-purple-800/20 border-purple-500/30",
|
|
iconBg: "bg-purple-600/30",
|
|
iconColor: "text-purple-300",
|
|
},
|
|
orange: {
|
|
container: "bg-gradient-to-br from-orange-600/20 to-orange-800/20 border-orange-500/30",
|
|
iconBg: "bg-orange-600/30",
|
|
iconColor: "text-orange-300",
|
|
},
|
|
red: {
|
|
container: "bg-gradient-to-br from-red-600/20 to-red-800/20 border-red-500/30",
|
|
iconBg: "bg-red-600/30",
|
|
iconColor: "text-red-300",
|
|
},
|
|
};
|
|
|
|
export const StatsCard: React.FC<StatsCardProps> = ({
|
|
title,
|
|
value,
|
|
icon: Icon,
|
|
variant = "blue",
|
|
subtitle,
|
|
className = "",
|
|
}) => {
|
|
const styles = variantStyles[variant];
|
|
|
|
return (
|
|
<div className={`border rounded-lg p-4 ${styles.container} ${className}`.trim()}>
|
|
<div className="flex items-center gap-3">
|
|
<div className={`p-2 rounded-lg ${styles.iconBg}`}>
|
|
<Icon className={`w-6 h-6 ${styles.iconColor}`} />
|
|
</div>
|
|
<div>
|
|
<p className="text-2xl font-bold text-white">{value}</p>
|
|
<p className="text-sm text-gray-400">{title}</p>
|
|
{subtitle && <p className="text-xs text-gray-500 mt-0.5">{subtitle}</p>}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|