geo/frontend/components/dashboard/ScoreCard.tsx

68 lines
1.7 KiB
TypeScript

"use client";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { cn } from "@/lib/utils";
import { TrendingUp, TrendingDown, Minus } from "lucide-react";
interface ScoreCardProps {
title: string;
score: number;
change?: number;
changeLabel?: string;
icon?: React.ReactNode;
className?: string;
}
export function ScoreCard({
title,
score,
change,
changeLabel = "较昨日",
icon,
className,
}: ScoreCardProps) {
const getTrendIcon = () => {
if (change === undefined || change === 0) {
return <Minus className="h-4 w-4 text-muted-foreground" />;
}
return change > 0 ? (
<TrendingUp className="h-4 w-4 text-emerald-600" />
) : (
<TrendingDown className="h-4 w-4 text-red-600" />
);
};
const getTrendColor = () => {
if (change === undefined || change === 0) return "text-muted-foreground";
return change > 0 ? "text-emerald-600" : "text-red-600";
};
return (
<Card className={cn("", className)}>
<CardHeader className="flex flex-row items-center justify-between pb-2">
<CardTitle className="text-sm font-medium text-muted-foreground">
{title}
</CardTitle>
{icon && <div className="text-muted-foreground">{icon}</div>}
</CardHeader>
<CardContent>
<div className="text-3xl font-bold">{score}</div>
{change !== undefined && (
<div
className={cn(
"mt-1 flex items-center gap-1 text-sm",
getTrendColor(),
)}
>
{getTrendIcon()}
<span>
{change > 0 ? "+" : ""}
{change} {changeLabel}
</span>
</div>
)}
</CardContent>
</Card>
);
}