بلاک‌ها · معرفی محصول

قیمت‌گذاریِ یک‌بارپرداخت

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

قیمت‌گذاریِ مادام‌العمر: برچسبِ پیشنهادِ محدود، انتخابِ تک‌نفره/تیمی با کارتِ رادیویی و قیمتِ قبلی، دکمهٔ خرید با مبلغ، سه ضمانت، اقلامِ شامل و نظرِ مشتری.

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

این بلاک از ۶ آیتم دیگ استفاده می‌کند: avatarbuttoncontrol-sizeiconspersianradio-group

پکیج‌منیجر پیش‌فرض Node.jsنصب سریع با لینک سخت و دیسک مشترکYarn نسخهٔ ۲ به بالا (Berry)رانتایم و پکیج‌منیجر Bun
npx digdesign@latest add https://docs.digdesign.ir/r/avatar.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/radio-group.json
pnpm dlx digdesign@latest add https://docs.digdesign.ir/r/avatar.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/radio-group.json
yarn dlx digdesign@latest add https://docs.digdesign.ir/r/avatar.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/radio-group.json
bunx --bun digdesign@latest add https://docs.digdesign.ir/r/avatar.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/radio-group.json

۲. کد صفحه

کد را در app/<route>/page.tsx بگذارید و متن‌ها، داده و هندلرها را با محصول خودتان عوض کنید.

pricing-lifetime.tsx
"use client"

import * as React from "react"

import { CheckIcon, RefreshIcon, ShieldCheckIcon, SparklesIcon, StarIcon } from "@/components/icons"
import { Avatar } from "@/components/ui/avatar"
import { Button } from "@/components/ui/button"
import { ControlSizeProvider } from "@/components/ui/control-size"
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
import { formatNumber } from "@/lib/persian"
import { cn } from "@/lib/utils"
import { stockImages } from "@/lib/stock-images"

const OPTIONS = [
  { id: "solo", name: "تک‌نفره", text: "یک کاربر، همهٔ قالب‌ها و به‌روزرسانی‌های آینده", price: 2_900_000, was: 4_200_000 },
  { id: "team", name: "تیمی", text: "تا ۱۰ کاربر، فضای مشترک و مدیریتِ دسترسی", price: 8_900_000, was: 13_500_000 },
]
const INCLUDED = ["بیش از ۲۰۰ قالبِ آماده", "به‌روزرسانیِ رایگانِ همیشگی", "خروجی برای وب و موبایل", "مجوزِ استفادهٔ تجاری", "دسترسی به انجمنِ کاربران", "پشتیبانیِ ایمیلی"]

/**
 * قیمت‌گذاریِ یک‌بارپرداخت (مادام‌العمر): برچسبِ پیشنهادِ محدود، انتخابِ تک‌نفره/تیمی با کارتِ
 * رادیویی و قیمتِ قبلیِ خط‌خورده، دکمهٔ خرید با مبلغِ انتخاب‌شده، سه ضمانت، فهرستِ اقلام و یک
 * نظرِ مشتری؛ بدونِ اشتراکِ ماهانه.
 */
export default function PricingLifetimeBlock() {
  const [choice, setChoice] = React.useState("solo")
  const selected = OPTIONS.find((option) => option.id === choice) ?? OPTIONS[0]

  return (
    <ControlSizeProvider size="xl" asChild>
      <main className="w-full bg-[radial-gradient(ellipse_at_top,var(--dig-amber-100),var(--background)_60%)] px-4 py-24 sm:px-6 dark:bg-[radial-gradient(ellipse_at_top,var(--dig-amber-950),var(--background)_60%)]">
        <div className="mx-auto grid w-full max-w-5xl grid-cols-1 gap-12 lg:grid-cols-[1.1fr_1fr]">
          <div className="flex flex-col items-start gap-6">
            <span className="flex items-center gap-2 rounded-full bg-[var(--dig-amber-200)] px-3 py-1 text-sm font-semibold text-[var(--dig-amber-900)] dark:bg-[var(--dig-amber-900)] dark:text-[var(--dig-amber-100)]">
              <SparklesIcon aria-hidden className="size-4" />
              پیشنهادِ ویژهٔ پاییز، تا پایانِ آبان
            </span>
            <h1 className="text-4xl leading-tight font-black text-balance sm:text-5xl">یک بار بپرداز، برای همیشه استفاده کن</h1>
            <p className="leading-8 text-muted-foreground">بدونِ اشتراک و بدونِ هزینهٔ تمدید. هر قالب و امکانی که بعداً اضافه شود هم مالِ شماست.</p>
            <ul className="grid w-full grid-cols-1 gap-3 sm:grid-cols-2">
              {INCLUDED.map((item) => (
                <li key={item} className="flex items-center gap-2.5 text-sm">
                  <span aria-hidden className="flex size-5 items-center justify-center rounded-full bg-success-subtle text-success-subtle-foreground">
                    <CheckIcon className="size-3.5" />
                  </span>
                  {item}
                </li>
              ))}
            </ul>
            <figure className="mt-4 flex flex-col gap-3 rounded-xl border border-border bg-card p-5">
              <span className="flex text-[var(--dig-amber-500)]" aria-label="۵ ستاره">
                {Array.from({ length: 5 }, (_, index) => (
                  <StarIcon key={index} aria-hidden className="size-4 fill-current" />
                ))}
              </span>
              <blockquote className="leading-7">«سه سال است اشتراکِ ماهانه نمی‌دهم و هنوز هر ماه قالبِ تازه می‌گیرم. بهترین خریدِ ابزارم بود.»</blockquote>
              <figcaption className="flex items-center gap-3 text-sm">
                <Avatar src={stockImages.personWoman2.src} alt="" size="sm" />
                <span>
                  <span className="font-bold">مینا سلطانی</span>
                  <span className="text-muted-foreground">، طراحِ مستقل</span>
                </span>
              </figcaption>
            </figure>
          </div>

          <div className="flex flex-col gap-4 self-start rounded-xl border border-border bg-card p-6 shadow-xl sm:p-8">
            <h2 className="font-bold">نسخه را انتخاب کنید</h2>
            <RadioGroup value={choice} onValueChange={setChoice} aria-label="نسخه" className="flex flex-col gap-3">
              {OPTIONS.map((option) => (
                <label
                  key={option.id}
                  htmlFor={`life-${option.id}`}
                  className={cn(
                    "flex cursor-pointer items-start gap-3 rounded-lg border-2 p-4 transition-colors",
                    choice === option.id ? "border-foreground bg-subtle" : "border-border hover:border-input"
                  )}
                >
                  <RadioGroupItem id={`life-${option.id}`} value={option.id} className="mt-1" />
                  <span className="flex flex-1 flex-col gap-1">
                    <span className="flex items-baseline justify-between gap-2">
                      <span className="font-bold">{option.name}</span>
                      <span className="flex items-baseline gap-2">
                        <span className="text-sm text-muted-foreground line-through">{formatNumber(option.was / 1000)}</span>
                        <span className="text-lg font-black tabular-nums">{formatNumber(option.price / 1000)} هزار</span>
                      </span>
                    </span>
                    <span className="text-sm leading-6 text-muted-foreground">{option.text}</span>
                  </span>
                </label>
              ))}
            </RadioGroup>
            <Button fullWidth>خرید با {formatNumber(selected.price / 1000)} هزار تومان</Button>
            <ul className="flex flex-col gap-2 border-t border-border pt-4 text-sm text-muted-foreground">
              <li className="flex items-center gap-2">
                <RefreshIcon aria-hidden className="size-4" />
                ۱۴ روز ضمانتِ بازگشتِ کاملِ پول
              </li>
              <li className="flex items-center gap-2">
                <ShieldCheckIcon aria-hidden className="size-4" />
                پرداختِ امن با همهٔ کارت‌های عضوِ شتاب
              </li>
              <li className="flex items-center gap-2">
                <SparklesIcon aria-hidden className="size-4" />
                بعداً می‌توانید به تیمی ارتقا دهید و فقط مابه‌التفاوت را بپردازید
              </li>
            </ul>
          </div>
        </div>
      </main>
    </ControlSizeProvider>
  )
}