Files
reui-blocks/blocks/product-list3.tsx
T

246 lines
6.7 KiB
TypeScript

import { AspectRatio } from "@/components/ui/aspect-ratio";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
Card,
CardAction,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { cn } from "@/lib/utils";
interface Product {
name: string;
image: {
src: string;
alt: string;
};
link: string;
description: string;
price: ProductPrice;
badge?: {
text: string;
color?: string;
};
}
type ProductCardProps = Product;
interface ProductPrice {
regular: number;
sale?: number;
currency: string;
}
type ProductList = Array<Product>;
const PRODUCTS_LIST: ProductList = [
{
name: "وکسون کور‌استپ ۰۸ ال‌ایکس",
image: {
src: "/block-media/shadcnblocks/block/ecommerce/clothes/joshua-diaz-ETNoDLl8yFE-unsplash-1.jpg",
alt: "کفش ورزشی با طراحی سه‌رنگ",
},
link: "#",
description:
"راحتی روزمره در کنار استایل جسورانه سه‌رنگ، در طراحی عمل‌گرایانه.",
price: {
regular: 499000.0,
sale: 399000.0,
currency: "ریال",
},
badge: {
text: "دارد سریع فروش می‌رود!",
color: "oklch(57.7% 0.245 27.325)",
},
},
{
name: "جاکت شهری راحت",
image: {
src: "/block-media/shadcnblocks/block/ecommerce/clothes/Man-in-Hoodie-&-Jacket-2.png",
alt: "جاکت پفی جین با طیف آبی",
},
link: "#",
description:
"پفی جین با طیف آبی ملایم، مناسب لایه‌لایه پوشیدن در همه فصل‌ها.",
price: {
regular: 180000.0,
currency: "ریال",
},
},
{
name: "کیف مزون لیورا",
image: {
src: "/block-media/shadcnblocks/block/ecommerce/clothes/Woman-with-Tote-Bag-1.png",
alt: "کیف زنانه توت‌بگ",
},
link: "#",
description:
"کیفی شیک که به‌راحتی از حالت شانه‌ای به کراس‌بادی یا دسته‌دار تبدیل می‌شود.",
price: {
regular: 420000.0,
currency: "ریال",
},
badge: {
text: "جدید",
},
},
{
name: "وکسون تیون‌پادز پرو",
image: {
src: "/block-media/shadcnblocks/block/ecommerce/electronics/White-Wireless-Earbuds-in-Charging-Case-1.jpeg",
alt: "ایرباد بی‌سیم سفید در کیف شارژ",
},
link: "#",
description:
"تیون‌پادز پرو با صدای فراگیر، راحتی تمام‌روز و شارژ سریع در قابی جمع‌وجور و آماده جیب ارائه می‌شود.",
price: {
regular: 129000.0,
sale: 990000.0,
currency: "ریال",
},
},
{
name: "سرم درخشان رادیانت گلو",
image: {
src: "/block-media/shadcnblocks/block/ecommerce/skin-care-product/pexels-alesiakozik-7795810-1.jpg",
alt: "سرم مراقبت پوست",
},
link: "#",
description:
"سرم درخشان لونارا، سرمی سبک و سریع‌الجذب برای روشن‌تر کردن، آبرسانی و یکدست‌تر کردن رنگ پوست.",
price: {
regular: 490000.0,
currency: "ریال",
},
},
{
name: "هدفون شادوتون",
image: {
src: "/block-media/shadcnblocks/block/ecommerce/electronics/Luxurious-Headphones-1.jpeg",
alt: "هدفون لوکس",
},
link: "#",
description:
"صدایی نرم و عمیق؛ هر نت با وضوح و هر ضرب با عمق احساس می‌شود.",
price: {
regular: 530000.0,
currency: "ریال",
},
},
];
interface ProductList3Props {
className?: string;
}
const ProductList3 = ({ className }: ProductList3Props) => {
return (
<section className={cn("py-32", className)}>
<div className="container">
<div className="grid grid-cols-1 place-items-center gap-6 md:grid-cols-[repeat(auto-fit,minmax(var(--container-xs),auto))]">
{PRODUCTS_LIST.map((item, index) => (
<ProductCard key={`product-list-3-card-${index}`} {...item} />
))}
</div>
</div>
</section>
);
};
const ProductCard = ({
name,
description,
link,
image,
badge,
price,
}: ProductCardProps) => {
const { regular, sale, currency } = price;
return (
<a href={link} className="block h-full w-fit">
<Card className="group h-full w-full max-w-md min-w-xs overflow-hidden p-0">
<CardHeader className="relative block p-0">
<AspectRatio ratio={1.268115942} className="overflow-hidden">
<img
src={image.src}
alt={image.alt}
className="block size-full object-cover object-center"
/>
</AspectRatio>
<CardAction className="absolute bottom-4 w-full px-4 transition-opacity md:opacity-0 md:group-hover:opacity-100">
<Button className="w-full">افزودن به سبد</Button>
</CardAction>
{badge && (
<Badge
style={{
backgroundColor: badge.color,
}}
className="absolute start-4 top-4"
>
{badge.text}
</Badge>
)}
</CardHeader>
<CardContent className="flex h-full flex-col gap-4 pb-6">
<CardTitle className="text-xl font-semibold">{name}</CardTitle>
<CardDescription className="font-medium text-muted-foreground">
{description}
</CardDescription>
<div className="mt-auto">
<ProductCardPrice
regular={regular}
sale={sale}
currency={currency}
/>
</div>
</CardContent>
</Card>
</a>
);
};
const formatCurrency = (
value: number,
currency: string = "ریال",
locale: string = "fa-IR",
) => {
return `${value.toLocaleString(locale)} ${currency}`;
};
const ProductCardPrice = ({
regular,
sale,
currency,
}: {
regular: number;
sale?: number;
currency: string;
}) => {
const onSale = sale != null;
return (
<div className="flex flex-wrap items-center gap-x-2 text-lg font-semibold">
{onSale ? (
<span className="leading-tight text-foreground">
{formatCurrency(sale, currency)}
</span>
) : null}
<span
className={cn(
"leading-tight",
onSale
? "text-muted-foreground line-through"
: "text-foreground",
)}
>
{formatCurrency(regular, currency)}
</span>
</div>
);
};
export { ProductList3 };