246 lines
6.7 KiB
TypeScript
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 };
|