36 lines
1.3 KiB
TypeScript
36 lines
1.3 KiB
TypeScript
import React from 'react';
|
|
import { cn } from '@/lib/utils';
|
|
|
|
interface StatItem {
|
|
key: string;
|
|
label: string;
|
|
value: string | number;
|
|
icon?: React.ReactNode;
|
|
hint?: string;
|
|
}
|
|
|
|
interface StatCarouselProps {
|
|
items: StatItem[];
|
|
}
|
|
|
|
export function StatCarousel({ items }: StatCarouselProps) {
|
|
return (
|
|
<div className="-mx-4 flex snap-x snap-mandatory gap-3 overflow-x-auto px-4 pb-2 sm:mx-0 sm:grid sm:snap-none sm:overflow-visible sm:px-0 sm:pb-0 sm:grid-cols-2 lg:grid-cols-4">
|
|
{items.map((item) => (
|
|
<div key={item.key} className="min-w-[70%] snap-center sm:min-w-0">
|
|
<div className="rounded-2xl border border-slate-200 bg-white p-4 shadow-sm dark:border-white/10 dark:bg-white/5">
|
|
<div className="flex items-center justify-between">
|
|
<span className="text-xs uppercase tracking-wide text-slate-500 dark:text-slate-400">{item.label}</span>
|
|
{item.icon ? <span className="text-rose-500 dark:text-rose-200">{item.icon}</span> : null}
|
|
</div>
|
|
<div className="mt-3 text-2xl font-semibold text-slate-900 dark:text-white">{item.value}</div>
|
|
{item.hint ? (
|
|
<p className="mt-2 text-xs text-slate-500 dark:text-slate-400">{item.hint}</p>
|
|
) : null}
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|