94 lines
2.1 KiB
TypeScript
94 lines
2.1 KiB
TypeScript
import React from 'react';
|
|
import { clsx } from 'clsx';
|
|
import StatsCard, { StatsCardProps } from './StatsCard';
|
|
|
|
export interface StatsGridProps {
|
|
stats: StatsCardProps[];
|
|
columns?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
gap?: 'sm' | 'md' | 'lg';
|
|
className?: string;
|
|
loading?: boolean;
|
|
title?: string;
|
|
description?: string;
|
|
}
|
|
|
|
const StatsGrid: React.FC<StatsGridProps> = ({
|
|
stats,
|
|
columns = 3,
|
|
gap = 'md',
|
|
className,
|
|
loading = false,
|
|
title,
|
|
description,
|
|
}) => {
|
|
const gridClasses = {
|
|
1: 'grid-cols-1',
|
|
2: 'grid-cols-1 sm:grid-cols-2',
|
|
3: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3',
|
|
4: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-4',
|
|
5: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5',
|
|
6: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6',
|
|
};
|
|
|
|
const gapClasses = {
|
|
sm: 'gap-3',
|
|
md: 'gap-4',
|
|
lg: 'gap-6',
|
|
};
|
|
|
|
const containerClasses = clsx(
|
|
'grid',
|
|
gridClasses[columns],
|
|
gapClasses[gap],
|
|
className
|
|
);
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
{/* Header */}
|
|
{(title || description) && (
|
|
<div className="space-y-2">
|
|
{title && (
|
|
<h2
|
|
className="text-2xl font-bold leading-tight"
|
|
style={{ color: 'var(--text-primary)' }}
|
|
>
|
|
{title}
|
|
</h2>
|
|
)}
|
|
{description && (
|
|
<p
|
|
className="text-base leading-relaxed"
|
|
style={{ color: 'var(--text-secondary)' }}
|
|
>
|
|
{description}
|
|
</p>
|
|
)}
|
|
</div>
|
|
)}
|
|
|
|
{/* Stats Grid */}
|
|
<div className={containerClasses}>
|
|
{loading
|
|
? Array.from({ length: stats.length || 6 }).map((_, index) => (
|
|
<StatsCard
|
|
key={index}
|
|
title=""
|
|
value=""
|
|
loading
|
|
/>
|
|
))
|
|
: stats.map((stat, index) => (
|
|
<StatsCard
|
|
key={stat.title || index}
|
|
{...stat}
|
|
loading={loading}
|
|
/>
|
|
))
|
|
}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default StatsGrid; |