ویترینِ فروشگاه
پیشنمایش تمامصفحهصفحهٔ دسته یا خانهٔ فروشگاه: هیروی دوتکه با عکس و دعوت به کلکسیون، کاشیهای دسته با عکس و تعداد، پرفروشها با کارتِ محصول و تخفیف، و بنرِ تیرهٔ ارسالِ رایگان.
۱. نصب کامپوننتها
این بلاک از ۷ آیتم دیگ استفاده میکند: add-to-cartbuttoncontrol-sizeiconspersianproduct-cardreveal
پکیجمنیجر پیشفرض Node.jsنصب سریع با لینک سخت و دیسک مشترکYarn نسخهٔ ۲ به بالا (Berry)رانتایم و پکیجمنیجر Bun
npx digdesign@latest add https://docs.digdesign.ir/r/add-to-cart.json https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/icons.json https://docs.digdesign.ir/r/persian.json https://docs.digdesign.ir/r/product-card.json https://docs.digdesign.ir/r/reveal.jsonpnpm dlx digdesign@latest add https://docs.digdesign.ir/r/add-to-cart.json https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/icons.json https://docs.digdesign.ir/r/persian.json https://docs.digdesign.ir/r/product-card.json https://docs.digdesign.ir/r/reveal.jsonyarn dlx digdesign@latest add https://docs.digdesign.ir/r/add-to-cart.json https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/icons.json https://docs.digdesign.ir/r/persian.json https://docs.digdesign.ir/r/product-card.json https://docs.digdesign.ir/r/reveal.jsonbunx --bun digdesign@latest add https://docs.digdesign.ir/r/add-to-cart.json https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/icons.json https://docs.digdesign.ir/r/persian.json https://docs.digdesign.ir/r/product-card.json https://docs.digdesign.ir/r/reveal.json۲. کد صفحه
کد را در app/<route>/page.tsx بگذارید و متنها، داده و هندلرها را با محصول خودتان عوض کنید.
product-showcase.tsx
"use client"
import { ChevronLeftIcon, TruckIcon } from "@/components/icons"
import { AddToCart } from "@/components/ui/add-to-cart"
import { Button } from "@/components/ui/button"
import { ControlSizeProvider } from "@/components/ui/control-size"
import { ProductCard, ProductCardBody, ProductCardCategory, ProductCardFooter, ProductCardMedia, ProductCardPrice, ProductCardTitle } from "@/components/ui/product-card"
import { Reveal } from "@/components/ui/reveal"
import { formatCurrency, toFaDigits } from "@/lib/persian"
import { stockImages, type StockImageName } from "@/lib/stock-images"
const CATEGORIES: { title: string; count: number; image: StockImageName }[] = [
{ title: "گلدان و سفال", count: 128, image: "productVase" },
{ title: "نوشتافزار", count: 86, image: "coverNotebook" },
{ title: "میزِ کار", count: 64, image: "coverOfficeSupplies" },
{ title: "دکورِ خانه", count: 152, image: "coverMinimalRoom" },
]
const BEST: { id: string; title: string; category: string; image: StockImageName; price: number; oldPrice?: number }[] = [
{ id: "1", title: "گلدانِ سرامیکی دوقلو", category: "گلدان و سفال", image: "productVase", price: 1_290_000, oldPrice: 1_590_000 },
{ id: "2", title: "دفترِ یادداشتِ جلدسخت", category: "نوشتافزار", image: "coverNotebook", price: 180_000 },
{ id: "3", title: "ست لوازمالتحریرِ رومیزی", category: "میزِ کار", image: "coverOfficeSupplies", price: 640_000 },
{ id: "4", title: "ماشینحسابِ رومیزی کلاسیک", category: "میزِ کار", image: "coverCalculator", price: 420_000, oldPrice: 520_000 },
]
/**
* ویترینِ فروشگاه (صفحهٔ دسته): هیروی دوتکه با عکس، کاشیهای دسته با عکس و تعداد،
* پرفروشها با کارتِ محصول و بنرِ تیرهٔ ارسالِ رایگان. برای فهرستِ کامل با فیلتر،
* واریانتِ «فیلتردار» را ببینید.
*/
export default function ProductShowcaseBlock() {
return (
<ControlSizeProvider size="xl" asChild>
<main className="mx-auto flex w-full max-w-6xl flex-col gap-20 px-4 py-10 sm:px-6">
<section className="grid grid-cols-1 overflow-hidden rounded-xl bg-[var(--dig-orange-50)] md:grid-cols-2 dark:bg-inverse-raised">
<div className="flex flex-col justify-center gap-5 p-8 sm:p-12">
<span className="text-sm font-semibold text-[var(--dig-orange-700)] dark:text-[var(--dig-orange-400)]">کلکسیونِ پاییز</span>
<h1 className="text-4xl leading-snug font-black text-balance sm:text-5xl sm:leading-snug">خانهای گرمتر با سفالِ دستساز</h1>
<p className="text-lg leading-8 text-muted-foreground">گلدانها و ظرفهای تازه از کارگاههای لالجین و میبد؛ هر تکه یکی است.</p>
<div className="mt-3 flex flex-wrap gap-3">
<Button>دیدنِ کلکسیون</Button>
<Button variant="outline">همهٔ دستهها</Button>
</div>
</div>
{/* eslint-disable-next-line @next/next/no-img-element -- عکس از کتابخانهٔ تصویرِ دیگ */}
<img src={stockImages.studioSunlit.src} alt={stockImages.studioSunlit.alt} className="aspect-[4/3] size-full object-cover md:aspect-auto" />
</section>
<section aria-labelledby="shop-categories" className="flex flex-col gap-8">
<h2 id="shop-categories" className="text-2xl font-black">
خرید بر اساسِ دسته
</h2>
<ul className="grid grid-cols-2 gap-4 lg:grid-cols-4">
{CATEGORIES.map((category, index) => (
<Reveal asChild key={category.title} delay={index * 100}>
<li>
<a href="#" className="group flex flex-col gap-3">
<span className="overflow-hidden rounded-xl">
{/* eslint-disable-next-line @next/next/no-img-element -- عکس از کتابخانهٔ تصویرِ دیگ */}
<img src={stockImages[category.image].src} alt="" loading="lazy" className="aspect-square w-full object-cover transition-transform duration-500 group-hover:scale-105" />
</span>
<span className="flex items-center justify-between gap-2">
<span className="flex flex-col">
<span className="font-semibold">{category.title}</span>
<span className="text-sm text-muted-foreground">{toFaDigits(category.count)} کالا</span>
</span>
<ChevronLeftIcon aria-hidden className="size-5 text-muted-foreground transition-transform group-hover:-translate-x-1 ltr:rotate-180" />
</span>
</a>
</li>
</Reveal>
))}
</ul>
</section>
<section aria-labelledby="shop-best" className="flex flex-col gap-8">
<div className="flex items-center justify-between gap-4">
<h2 id="shop-best" className="text-2xl font-black">
پرفروشهای هفته
</h2>
<Button variant="ghost">
همه
<ChevronLeftIcon className="ltr:rotate-180" />
</Button>
</div>
<div className="grid grid-cols-2 gap-4 lg:grid-cols-4">
{BEST.map((item, index) => (
<Reveal key={item.id} delay={index * 100}>
<ProductCard className="h-full w-full">
<ProductCardMedia>
{/* eslint-disable-next-line @next/next/no-img-element -- عکس از کتابخانهٔ تصویرِ دیگ */}
<img src={stockImages[item.image].src} alt={stockImages[item.image].alt} loading="lazy" />
</ProductCardMedia>
<ProductCardBody>
<ProductCardCategory>{item.category}</ProductCardCategory>
<ProductCardTitle>{item.title}</ProductCardTitle>
<ProductCardPrice
amount={formatCurrency(item.price)}
originalAmount={item.oldPrice ? formatCurrency(item.oldPrice) : undefined}
discount={item.oldPrice ? `٪${toFaDigits(Math.round((1 - item.price / item.oldPrice) * 100))}` : undefined}
/>
</ProductCardBody>
<ProductCardFooter>
<AddToCart fullWidth label="افزودن" itemName={item.title} />
</ProductCardFooter>
</ProductCard>
</Reveal>
))}
</div>
</section>
<section className="flex flex-col items-start gap-6 rounded-xl bg-inverse p-8 text-[var(--dig-white)] [--muted-foreground:var(--dig-neutral-400)] sm:flex-row sm:items-center sm:justify-between sm:p-12">
<div className="flex items-center gap-4">
<span aria-hidden className="flex size-12 shrink-0 items-center justify-center rounded-xl bg-inverse-raised text-[var(--dig-orange-400)] [&>svg]:size-6">
<TruckIcon />
</span>
<div className="flex flex-col gap-1">
<h2 className="text-xl font-bold">ارسالِ رایگان برای خریدِ بالای ۳ میلیون</h2>
<p className="text-muted-foreground">بستهبندی ضدضربه و ضمانتِ سالمرسیدن.</p>
</div>
</div>
<Button className="bg-[var(--dig-white)] text-[var(--dig-graphite-900)] hover:bg-[var(--dig-neutral-200)]">شروعِ خرید</Button>
</section>
</main>
</ControlSizeProvider>
)
}