قیمتگذاریِ یکبارپرداخت
پیشنمایش تمامصفحهقیمتگذاریِ مادامالعمر: برچسبِ پیشنهادِ محدود، انتخابِ تکنفره/تیمی با کارتِ رادیویی و قیمتِ قبلی، دکمهٔ خرید با مبلغ، سه ضمانت، اقلامِ شامل و نظرِ مشتری.
۱. نصب کامپوننتها
این بلاک از ۶ آیتم دیگ استفاده میکند: 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.jsonpnpm 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.jsonyarn 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.jsonbunx --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>
)
}