75 lines
3.0 KiB
TypeScript
75 lines
3.0 KiB
TypeScript
|
|
"use client";
|
||
|
|
|
||
|
|
import Image from "next/image";
|
||
|
|
import { Card, CardBody } from "@heroui/react";
|
||
|
|
|
||
|
|
interface StatData {
|
||
|
|
label: string;
|
||
|
|
value: string;
|
||
|
|
change: string;
|
||
|
|
isPositive: boolean;
|
||
|
|
}
|
||
|
|
|
||
|
|
interface StatsCardsProps {
|
||
|
|
stats?: StatData[];
|
||
|
|
}
|
||
|
|
|
||
|
|
export default function StatsCards({ stats = [] }: StatsCardsProps) {
|
||
|
|
if (!stats || stats.length === 0) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="flex flex-row gap-6 items-start justify-start self-stretch">
|
||
|
|
{stats.map((stat, index) => {
|
||
|
|
const isLastCard = index === stats.length - 1;
|
||
|
|
const isFirstCard = index === 0;
|
||
|
|
const valueColor = isLastCard && stat.value === "--" ? "text-green-500" : "text-text-primary dark:text-white";
|
||
|
|
|
||
|
|
return (
|
||
|
|
<Card
|
||
|
|
key={index}
|
||
|
|
className={`flex-1 rounded-[2rem] h-full relative overflow-hidden group bg-bg-subtle dark:bg-gray-800 border border-border-gray dark:border-gray-700 shadow-[0_8px_32px_rgba(0,0,0,0.03)] transition-all duration-500 hover:shadow-[0_16px_48px_rgba(0,0,0,0.06)]
|
||
|
|
${index === 0 ? 'bg-gradient-to-br from-blue-50/80 to-transparent dark:from-blue-900/20 dark:to-transparent' : ''}
|
||
|
|
${index === 1 ? 'bg-gradient-to-br from-green-50/80 to-transparent dark:from-green-900/20 dark:to-transparent' : ''}
|
||
|
|
${index === 2 ? 'bg-gradient-to-br from-purple-50/80 to-transparent dark:from-purple-900/20 dark:to-transparent' : ''}
|
||
|
|
`}
|
||
|
|
>
|
||
|
|
<CardBody className="p-7 flex flex-col gap-3">
|
||
|
|
{/* Header with label and change badge */}
|
||
|
|
<div className={`flex flex-row gap-2 items-center ${index === 1 || index === 2 || index === 3 ? 'justify-between' : 'justify-start'} self-stretch`}>
|
||
|
|
<div className="text-text-tertiary dark:text-gray-400 text-[10px] font-bold leading-[150%] tracking-[0.01em] font-inter">
|
||
|
|
{stat.label}
|
||
|
|
</div>
|
||
|
|
<div
|
||
|
|
className={`bg-green-50 dark:bg-green-900/30 rounded-full px-1 py-0.5 flex flex-row gap-0 items-center justify-start h-5 ${
|
||
|
|
isFirstCard ? 'opacity-0' : 'opacity-100'
|
||
|
|
}`}
|
||
|
|
>
|
||
|
|
<Image
|
||
|
|
src="/stats-icon.svg"
|
||
|
|
alt=""
|
||
|
|
width={12}
|
||
|
|
height={12}
|
||
|
|
className="flex-shrink-0"
|
||
|
|
/>
|
||
|
|
<div className="text-green-500 dark:text-green-400 text-[10px] font-bold leading-[150%] tracking-[0.01em] font-inter">
|
||
|
|
{stat.change}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Value */}
|
||
|
|
<div className="flex flex-row gap-4 items-end justify-start">
|
||
|
|
<div className={`${valueColor} text-heading-h2 font-extrabold font-jetbrains`}>
|
||
|
|
{stat.value}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</CardBody>
|
||
|
|
</Card>
|
||
|
|
);
|
||
|
|
})}
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|