114 lines
3.2 KiB
TypeScript
114 lines
3.2 KiB
TypeScript
import { Minus, TrendingDown, TrendingUp } from "lucide-react";
|
|
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardDescription,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from "@/components/ui/card";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
const formatNumber = (value: number) => value.toLocaleString("fa-IR");
|
|
|
|
const formatChangeAmount = (value: number) =>
|
|
new Intl.NumberFormat("fa-IR", {
|
|
signDisplay: "exceptZero",
|
|
}).format(value);
|
|
|
|
interface LeaderboardItem {
|
|
name: string;
|
|
value: string;
|
|
change: "up" | "down" | "same";
|
|
changeAmount?: string;
|
|
}
|
|
|
|
interface Leaderboard3Props {
|
|
title?: string;
|
|
description?: string;
|
|
items?: LeaderboardItem[];
|
|
className?: string;
|
|
}
|
|
|
|
const defaultItems: LeaderboardItem[] = [
|
|
{
|
|
name: "SEO و محتوای ارگانیک",
|
|
value: formatNumber(12450),
|
|
change: "up",
|
|
changeAmount: formatChangeAmount(2340),
|
|
},
|
|
{
|
|
name: "ورود مستقیم",
|
|
value: formatNumber(8230),
|
|
change: "up",
|
|
changeAmount: formatChangeAmount(890),
|
|
},
|
|
{
|
|
name: "شبکههای اجتماعی B2B",
|
|
value: formatNumber(5120),
|
|
change: "down",
|
|
changeAmount: formatChangeAmount(-320),
|
|
},
|
|
{
|
|
name: "ارجاع همکاران",
|
|
value: formatNumber(3890),
|
|
change: "same",
|
|
},
|
|
{
|
|
name: "ایمیل بازاریابی",
|
|
value: formatNumber(2150),
|
|
change: "up",
|
|
changeAmount: formatChangeAmount(180),
|
|
},
|
|
];
|
|
|
|
const Leaderboard3 = ({
|
|
title = "کانالهای جذب سرنخ",
|
|
description = "سهم هر کانال از سرنخهای واجد شرایط",
|
|
items = defaultItems,
|
|
className,
|
|
}: Leaderboard3Props) => {
|
|
return (
|
|
<Card dir="rtl" lang="fa" className={cn("w-full max-w-2xl", className)}>
|
|
<CardHeader>
|
|
<CardTitle>{title}</CardTitle>
|
|
<CardDescription>{description}</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-4">
|
|
{items.map((item, index) => (
|
|
<div key={index} className="flex items-center justify-between">
|
|
<div className="flex items-center gap-3">
|
|
<span className="flex size-8 items-center justify-center rounded-full bg-muted text-sm font-medium">
|
|
{formatNumber(index + 1)}
|
|
</span>
|
|
<span className="font-medium">{item.name}</span>
|
|
</div>
|
|
<div className="flex items-center gap-3">
|
|
<span className="text-sm font-semibold">{item.value}</span>
|
|
<div
|
|
className={cn(
|
|
"flex items-center gap-1 text-sm",
|
|
item.change === "up" && "text-green-500",
|
|
item.change === "down" && "text-red-500",
|
|
item.change === "same" && "text-muted-foreground",
|
|
)}
|
|
>
|
|
{item.change === "up" && <TrendingUp className="size-4" />}
|
|
{item.change === "down" && (
|
|
<TrendingDown className="size-4" />
|
|
)}
|
|
{item.change === "same" && <Minus className="size-4" />}
|
|
{item.changeAmount && <span>{item.changeAmount}</span>}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
};
|
|
|
|
export { Leaderboard3 };
|