Files
reui-blocks/blocks/compare-products1.tsx
T

215 lines
7.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { Check, X as XIcon } from "lucide-react";
import { AspectRatio } from "@/components/ui/aspect-ratio";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { cn } from "@/lib/utils";
interface ProductSpec {
name: string;
values: (string | boolean)[];
}
interface Product {
id: string;
name: string;
image: string;
price: number;
originalPrice?: number;
rating: number;
badge?: string;
}
interface CompareProducts1Props {
products?: Product[];
specs?: ProductSpec[];
className?: string;
}
const DEFAULT_PRODUCTS: Product[] = [
{
id: "1",
name: "هدفون بی‌سیم پرو",
image:
"/block-media/shadcnblocks/block/ecommerce/electronics/Modern-White-Headphones-1.png",
price: 299,
rating: 4.8,
},
{
id: "2",
name: "هدفون استودیویی پلاس",
image:
"/block-media/shadcnblocks/block/ecommerce/electronics/Sleek-Black-Headphones-1.jpeg",
price: 249,
originalPrice: 279,
rating: 4.5,
},
{
id: "3",
name: "هدفون سری پایه",
image:
"/block-media/shadcnblocks/block/ecommerce/electronics/Modern-Headphones-1.jpeg",
price: 149,
rating: 4.2,
},
];
const DEFAULT_SPECS: ProductSpec[] = [
{ name: "اندازه درایور", values: ["۴۰ میلی‌متر", "۵۰ میلی‌متر", "۴۰ میلی‌متر"] },
{
name: "پاسخ فرکانسی",
values: ["۲۰Hz–۲۰kHz", "۱۰Hz–۴۰kHz", "۲۰Hz–۲۰kHz"],
},
{ name: "حذف نویز فعال", values: [true, true, false] },
{ name: "عمر باتری", values: ["۳۰ ساعت", "۲۴ ساعت", "۲۰ ساعت"] },
{ name: "بی‌سیم", values: [true, true, true] },
{ name: "نسخه بلوتوث", values: ["۵٫۳", "۵٫۲", "۵٫۰"] },
{ name: "طراحی تاشو", values: [true, false, true] },
{ name: "وزن", values: ["۲۵۰ گرم", "۲۸۰ گرم", "۲۲۰ گرم"] },
{ name: "کیف همراه", values: [true, true, false] },
{ name: "گارانتی", values: ["۲ سال", "۲ سال", "۱ سال"] },
];
const formatPrice = (price: number) =>
new Intl.NumberFormat("fa-IR", {
style: "currency",
currency: "IRR",
maximumFractionDigits: 0,
}).format(price);
const formatRating = (rating: number) =>
rating.toLocaleString("fa-IR", {
minimumFractionDigits: 1,
maximumFractionDigits: 1,
});
const CompareProducts1 = ({
products = DEFAULT_PRODUCTS,
specs = DEFAULT_SPECS,
className,
}: CompareProducts1Props) => {
const renderValue = (value: string | boolean) => {
if (typeof value === "boolean") {
return value ? (
<Check className="size-5 text-emerald-600" aria-label="دارد" />
) : (
<XIcon className="size-5 text-muted-foreground" aria-label="ندارد" />
);
}
return value;
};
return (
<section
dir="rtl"
lang="fa"
className={cn("py-16 text-start md:py-24", className)}
>
<div className="container">
<div className="mb-8 text-center">
<h2 className="text-xl font-bold tracking-tight md:text-3xl">
مقایسه محصولات
</h2>
<p className="mt-2 text-muted-foreground">
ویژگی‌ها، مشخصات فنی و تفاوت محصولات را مقایسه کنید و بهترین انتخاب را داشته باشید.
</p>
</div>
<div className="overflow-x-auto">
<Table>
<TableHeader>
<TableRow className="border-b-0 hover:bg-transparent">
<TableHead className="w-48 border-e" />
{products.map((product, index) => (
<TableHead
key={product.id}
className={cn(
"min-w-[200px] text-center",
index < products.length - 1 && "border-e",
)}
>
<div className="pb-4">
<div className="mx-auto size-48 overflow-hidden rounded-lg bg-muted">
<AspectRatio ratio={1}>
<img
src={product.image}
alt={product.name}
className="size-full object-cover"
/>
</AspectRatio>
</div>
<div className="-mt-3 flex h-6 items-center justify-center">
{product.badge && (
<Badge className="mx-auto">{product.badge}</Badge>
)}
</div>
<h3 className="mt-2 text-lg leading-tight font-semibold">
{product.name}
</h3>
<div className="flex min-h-[1.5rem] items-center justify-center gap-2">
<span className="text-lg">
{formatPrice(product.price)}
</span>
{product.originalPrice && (
<span className="text-sm text-muted-foreground line-through">
{formatPrice(product.originalPrice)}
</span>
)}
</div>
<div className="flex items-center justify-center gap-1">
<span className="text-amber-500" aria-hidden="true">
★
</span>
<span className="text-sm">
{formatRating(product.rating)}
</span>
</div>
<Button className="mt-4 w-full" size="sm">
افزودن به سبد
</Button>
</div>
</TableHead>
))}
</TableRow>
</TableHeader>
<TableBody>
{specs.map((spec, index) => (
<TableRow key={index}>
<TableCell className="border-e font-medium">
{spec.name}
</TableCell>
{spec.values.map((value, vIndex) => (
<TableCell
key={vIndex}
className={cn(
"text-center",
vIndex < spec.values.length - 1 && "border-e",
)}
>
<div className="flex items-center justify-center">
{renderValue(value)}
</div>
</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
</div>
</div>
</section>
);
};
export { CompareProducts1 };