بلاک‌ها · بخش‌های صفحه

نرخ‌نامهٔ خدمات

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

بخشِ نرخ‌نامه: سگمنتِ ساعتی/روزانه/ماهانه همهٔ نرخ‌ها را با تخفیفِ حجمی عوض می‌کند؛ هر ردیف تیتر، توضیح و نرخ، با برچسبِ پرطرفدار و پانویسِ شرایط.

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

این بلاک از ۵ آیتم دیگ استفاده می‌کند: badgebuttoncontrol-sizepersiantoggle-group

پکیج‌منیجر پیش‌فرض Node.jsنصب سریع با لینک سخت و دیسک مشترکYarn نسخهٔ ۲ به بالا (Berry)رانتایم و پکیج‌منیجر Bun
npx digdesign@latest add https://docs.digdesign.ir/r/badge.json https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/persian.json https://docs.digdesign.ir/r/toggle-group.json
pnpm dlx digdesign@latest add https://docs.digdesign.ir/r/badge.json https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/persian.json https://docs.digdesign.ir/r/toggle-group.json
yarn dlx digdesign@latest add https://docs.digdesign.ir/r/badge.json https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/persian.json https://docs.digdesign.ir/r/toggle-group.json
bunx --bun digdesign@latest add https://docs.digdesign.ir/r/badge.json https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/persian.json https://docs.digdesign.ir/r/toggle-group.json

۲. کد صفحه

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

services-rate-card.tsx
"use client"

import * as React from "react"

import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { ControlSizeProvider } from "@/components/ui/control-size"
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
import { formatCurrency } from "@/lib/persian"

const RATES = [
  { title: "مشاورهٔ فنی", text: "بازبینیِ معماری، کد یا زیرساخت", hour: 2_400_000, popular: false },
  { title: "طراحیِ محصول", text: "پژوهش، نقشهٔ صفحه و طراحیِ نهایی", hour: 1_800_000, popular: true },
  { title: "توسعهٔ فرانت‌اند", text: "پیاده‌سازی با کامپوننت‌های دیگ", hour: 1_600_000, popular: false },
  { title: "نوشتنِ محتوا", text: "متنِ رابط، راهنما و صفحهٔ فرود", hour: 900_000, popular: false },
]
const UNITS = { hour: { label: "ساعتی", factor: 1, per: "هر ساعت" }, day: { label: "روزانه", factor: 7, per: "هر روز" }, month: { label: "ماهانه", factor: 140, per: "هر ماه" } }

/**
 * جدولِ نرخِ خدمات: سگمنتِ ساعتی/روزانه/ماهانه همهٔ نرخ‌ها را با هم عوض می‌کند (روزانه و ماهانه
 * با تخفیفِ حجمی)، هر ردیف تیتر، توضیح و نرخ دارد و پرطرفدار برچسب می‌خورد؛ پانویسِ شرایط و
 * دکمهٔ رزروِ جلسه.
 */
export default function ServicesRateCardBlock() {
  const [unit, setUnit] = React.useState<keyof typeof UNITS>("hour")
  const current = UNITS[unit]

  return (
    <ControlSizeProvider size="xl" asChild>
      <section aria-labelledby="rc-title" className="mx-auto flex w-full max-w-3xl flex-col gap-10 px-4 py-24 sm:px-6">
        <div className="flex flex-col items-center gap-4 text-center">
          <span className="text-sm font-semibold text-brand-secondary">نرخ‌نامه</span>
          <h2 id="rc-title" className="text-3xl font-black sm:text-4xl">
            هزینهٔ همکاری
          </h2>
          <ToggleGroup type="single" variant="segmented" value={unit} onValueChange={(value) => value && setUnit(value as keyof typeof UNITS)} aria-label="واحدِ نرخ">
            {Object.entries(UNITS).map(([key, item]) => (
              <ToggleGroupItem key={key} value={key}>
                {item.label}
              </ToggleGroupItem>
            ))}
          </ToggleGroup>
        </div>
        <div className="overflow-hidden rounded-xl border border-border bg-card">
          <ul aria-live="polite" className="divide-y divide-border">
            {RATES.map((rate) => {
              const price = Math.round((rate.hour * current.factor * (unit === "hour" ? 1 : unit === "day" ? 0.92 : 0.85)) / 10_000) * 10_000
              return (
                <li key={rate.title} className="flex flex-wrap items-center justify-between gap-x-6 gap-y-2 p-5 sm:p-6">
                  <span className="flex flex-col gap-1">
                    <span className="flex items-center gap-2 font-bold">
                      {rate.title}
                      {rate.popular && (
                        <Badge color="violet" variant="soft" size="sm">
                          پرطرفدار
                        </Badge>
                      )}
                    </span>
                    <span className="text-sm text-muted-foreground">{rate.text}</span>
                  </span>
                  <span className="flex items-baseline gap-1.5">
                    <span className="text-xl font-black tabular-nums">{formatCurrency(price)}</span>
                    <span className="text-sm text-muted-foreground">{current.per}</span>
                  </span>
                </li>
              )
            })}
          </ul>
          <div className="flex flex-col items-start justify-between gap-4 bg-subtle p-5 sm:flex-row sm:items-center sm:p-6">
            <p className="text-sm leading-6 text-muted-foreground">نرخِ روزانه ۸٪ و ماهانه ۱۵٪ تخفیف دارد. پیش‌پرداخت ۳۰٪، بقیه پس از تحویل.</p>
            <Button className="shrink-0">رزروِ جلسهٔ آشنایی</Button>
          </div>
        </div>
      </section>
    </ControlSizeProvider>
  )
}