75 lines
2.1 KiB
TypeScript
75 lines
2.1 KiB
TypeScript
import React from "react";
|
|
import { formatNumber } from "~/lib/utils";
|
|
|
|
interface DataItem {
|
|
label: string;
|
|
value: number;
|
|
color: string;
|
|
}
|
|
|
|
interface DashboardCustomBarChartProps {
|
|
title: string;
|
|
data: DataItem[];
|
|
loading?: boolean;
|
|
}
|
|
|
|
export function DashboardCustomBarChart({
|
|
title,
|
|
data,
|
|
loading = false,
|
|
}: DashboardCustomBarChartProps) {
|
|
if (loading) {
|
|
return (
|
|
<div className="w-full">
|
|
<h3 className="text-lg font-bold text-white font-persian mb-4 text-center border-b-2 border-gray-500/20 pb-3">
|
|
{title}
|
|
</h3>
|
|
<div className="space-y-3">
|
|
{[1, 2, 3].map((i) => (
|
|
<div key={i} className="animate-pulse">
|
|
<div className="h-12 bg-gray-600/30 rounded-lg"></div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Calculate the maximum value for scaling
|
|
const maxValue = Math.max(...data.map((item) => item.value));
|
|
|
|
return (
|
|
<div className="w-full">
|
|
<h3 className="text-lg font-bold text-white font-persian mb-4 text-center border-b-2 border-gray-500/20">
|
|
{title}
|
|
</h3>
|
|
<div className="px-4">
|
|
{data.map((item, index) => {
|
|
const widthPercentage =
|
|
maxValue > 0 ? (item.value / maxValue) * 100 : 0;
|
|
|
|
return (
|
|
<div key={index} className="relative">
|
|
{/* Bar container */}
|
|
<div className="relative min-h-6 h-10 rounded-lg overflow-hidden">
|
|
{/* Animated bar */}
|
|
<div
|
|
className={`absolute left-0 h-auto gap-2 top-0 ${item.color} rounded-lg transition-all duration-1000 ease-out flex items-center justify-between px-2`}
|
|
style={{ width: `${widthPercentage}%` }}
|
|
>
|
|
<span className="text-white font-bold text-base">
|
|
{formatNumber(item.value)}
|
|
</span>
|
|
<span className="text-[#3F415A] font-persian font-medium text-sm w-max">
|
|
{item.label}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|