بلاک‌ها · پشتیبانی و محتوا

مستندات: فهرستِ راهنماها با صفحهٔ فعال، مسیرِ صفحه، گام‌های شماره‌دار، فهرستِ مطالبِ چسبان و «این راهنما مفید بود؟».

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

این بلاک از ۴ آیتم دیگ استفاده می‌کند: breadcrumbbuttoncontrol-sizeicons

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

۲. کد صفحه

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

article-docs.tsx
"use client"

import * as React from "react"

import { ChevronDownIcon, ThumbsDownIcon, ThumbsUpIcon } from "@/components/icons"
import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from "@/components/ui/breadcrumb"
import { Button } from "@/components/ui/button"
import { ControlSizeProvider } from "@/components/ui/control-size"

const TOC = [
  { id: "need", title: "پیش از شروع" },
  { id: "steps", title: "مراحلِ ساختِ فاکتور" },
  { id: "send", title: "ارسال برای مشتری" },
  { id: "faq", title: "خطاهای رایج" },
]
const NAV = ["شروعِ کار", "ساختِ فاکتور", "ارسالِ پیامکی", "گزارش‌ها", "تنظیماتِ مالیات"]

/**
 * مقالهٔ راهنما (مستندات): فهرستِ راهنماها در ستونِ راست با صفحهٔ فعال، متن با مسیرِ
 * صفحه و گام‌های شماره‌دار، فهرستِ مطالب در ستونِ چپ، و «این راهنما مفید بود؟» در پایان.
 */
export default function ArticleDocsBlock() {
  const [vote, setVote] = React.useState<"up" | "down" | null>(null)

  return (
    <ControlSizeProvider size="xl" asChild>
      <main className="mx-auto grid w-full max-w-6xl grid-cols-1 items-start gap-10 p-4 sm:p-6 lg:grid-cols-[13rem_minmax(0,1fr)_12rem]">
        <nav aria-label="راهنماها" className="hidden flex-col gap-1 lg:flex lg:sticky lg:top-6">
          {NAV.map((item) => (
            <a
              key={item}
              href="#"
              aria-current={item === "ساختِ فاکتور" ? "page" : undefined}
              className={`rounded-lg px-3 py-2.5 text-sm ${item === "ساختِ فاکتور" ? "bg-primary-subtle font-semibold" : "text-muted-foreground hover:bg-subtle hover:text-foreground"}`}
            >
              {item}
            </a>
          ))}
        </nav>
        <article className="flex flex-col gap-8">
          <Breadcrumb>
            <BreadcrumbList>
              <BreadcrumbItem>
                <BreadcrumbLink href="#">راهنما</BreadcrumbLink>
              </BreadcrumbItem>
              <BreadcrumbSeparator />
              <BreadcrumbItem>
                <BreadcrumbPage>ساختِ فاکتور</BreadcrumbPage>
              </BreadcrumbItem>
            </BreadcrumbList>
          </Breadcrumb>
          {/* در موبایل ستون‌های کناری پنهان‌اند؛ راهنماهای دیگر و فهرستِ مطالب در یک بازشو. */}
          <details className="group rounded-xl border border-border bg-card lg:hidden">
            <summary className="flex min-h-12 cursor-pointer list-none items-center justify-between gap-3 px-4 text-sm font-medium [&::-webkit-details-marker]:hidden">
              فهرستِ راهنما و مطالب
              <ChevronDownIcon aria-hidden className="size-4 text-muted-foreground transition-transform group-open:rotate-180" />
            </summary>
            <div className="grid grid-cols-1 gap-4 border-t border-border p-4 sm:grid-cols-2">
              <nav aria-label="راهنماها (موبایل)" className="flex flex-col gap-1">
                <span className="px-3 pb-1 text-xs font-medium text-muted-foreground">راهنماها</span>
                {NAV.map((item) => (
                  <a key={item} href="#" aria-current={item === "ساختِ فاکتور" ? "page" : undefined} className={`flex min-h-11 items-center rounded-lg px-3 text-sm ${item === "ساختِ فاکتور" ? "bg-primary-subtle font-semibold" : "text-muted-foreground"}`}>
                    {item}
                  </a>
                ))}
              </nav>
              <nav aria-label="در این صفحه (موبایل)" className="flex flex-col gap-1">
                <span className="px-3 pb-1 text-xs font-medium text-muted-foreground">در این صفحه</span>
                {TOC.map((item) => (
                  <a key={item.id} href={`#${item.id}`} className="flex min-h-11 items-center rounded-lg px-3 text-sm text-muted-foreground">
                    {item.title}
                  </a>
                ))}
              </nav>
            </div>
          </details>
          <header className="flex flex-col gap-3">
            <h1 className="text-3xl font-bold">ساختِ اولین فاکتور</h1>
            <p className="text-lg leading-8 text-muted-foreground">در کمتر از دو دقیقه فاکتورِ رسمی بساز و برای مشتری بفرست.</p>
          </header>
          <section id="need" className="flex flex-col gap-3 scroll-mt-6">
            <h2 className="text-xl font-bold">پیش از شروع</h2>
            <p className="leading-8 text-muted-foreground">اطلاعاتِ شرکت و لوگو را در «تنظیمات ← کسب‌وکار» کامل کن تا روی فاکتور بیاید.</p>
          </section>
          <section id="steps" className="flex flex-col gap-4 scroll-mt-6">
            <h2 className="text-xl font-bold">مراحلِ ساختِ فاکتور</h2>
            <ol className="flex flex-col gap-4">
              {["از منوی «فاکتورها» دکمهٔ «فاکتورِ تازه» را بزن.", "مشتری را انتخاب کن یا تازه بساز.", "اقلام، تعداد و تخفیف را وارد کن؛ مالیات خودش حساب می‌شود.", "«ذخیره» را بزن؛ شماره خودکار می‌گیرد."].map((step, index) => (
                <li key={step} className="flex gap-4">
                  <span aria-hidden className="flex size-8 shrink-0 items-center justify-center rounded-full bg-subtle text-sm font-bold">
                    {"۱۲۳۴"[index]}
                  </span>
                  <span className="pt-1 leading-7">{step}</span>
                </li>
              ))}
            </ol>
          </section>
          <section id="send" className="flex flex-col gap-3 scroll-mt-6">
            <h2 className="text-xl font-bold">ارسال برای مشتری</h2>
            <p className="leading-8 text-muted-foreground">در صفحهٔ فاکتور «ارسال» را بزن؛ مشتری پیامکی با لینکِ مشاهده و پرداخت می‌گیرد.</p>
          </section>
          <section id="faq" className="flex flex-col gap-3 rounded-xl bg-subtle p-5 scroll-mt-6">
            <h2 className="font-bold">خطاهای رایج</h2>
            <p className="text-sm leading-7 text-muted-foreground">«شمارهٔ مشتری نامعتبر است»: شماره باید با ۰۹ شروع شود و ۱۱ رقم باشد.</p>
          </section>
          <div className="flex flex-wrap items-center gap-4 border-t border-border pt-8" aria-live="polite">
            {vote ? (
              <span className="text-sm">ممنون از بازخوردت!</span>
            ) : (
              <>
                <span className="text-sm font-medium">این راهنما مفید بود؟</span>
                <Button variant="outline" onClick={() => setVote("up")}>
                  <ThumbsUpIcon />
                  بله
                </Button>
                <Button variant="outline" onClick={() => setVote("down")}>
                  <ThumbsDownIcon />
                  نه
                </Button>
              </>
            )}
          </div>
        </article>
        <nav aria-label="در این صفحه" className="hidden flex-col gap-2 text-sm lg:flex lg:sticky lg:top-6">
          <span className="font-semibold">در این صفحه</span>
          {TOC.map((item) => (
            <a key={item.id} href={`#${item.id}`} className="text-muted-foreground hover:text-foreground">
              {item.title}
            </a>
          ))}
        </nav>
      </main>
    </ControlSizeProvider>
  )
}