بلاک‌ها · فروشگاهی

ویترینِ فروشگاه

پیش‌نمایش تمام‌صفحه

صفحهٔ دسته یا خانهٔ فروشگاه: هیروی دوتکه با عکس و دعوت به کلکسیون، کاشی‌های دسته با عکس و تعداد، پرفروش‌ها با کارتِ محصول و تخفیف، و بنرِ تیرهٔ ارسالِ رایگان.

۱. نصب کامپوننت‌ها

این بلاک از ۷ آیتم دیگ استفاده می‌کند: 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.json
pnpm 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.json
yarn 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.json
bunx --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>
  )
}