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

خطِ زمانِ داستان

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

بخشِ خطِ زمان: سال‌ها روی محورِ عمودی، رویدادها یک‌درمیان دو طرفِ محور با عکسِ اختیاری و رویدادِ امروز برجسته؛ برای داستانِ شرکت و changelogِ بزرگ.

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

این بلاک از ۲ آیتم دیگ استفاده می‌کند: control-sizereveal

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

۲. کد صفحه

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

process-timeline.tsx
"use client"

import { ControlSizeProvider } from "@/components/ui/control-size"
import { Reveal } from "@/components/ui/reveal"
import { cn } from "@/lib/utils"
import { stockImages, type StockImageName } from "@/lib/stock-images"

const MILESTONES: { year: string; title: string; text: string; photo?: StockImageName; now?: boolean }[] = [
  { year: "۱۳۹۶", title: "یک میز در پارکِ فناوری", text: "سه نفر با یک ایده: حسابداری که صاحبِ مغازه هم بفهمد." },
  { year: "۱۳۹۸", title: "هزار فروشگاهِ اول", text: "نسخهٔ موبایل منتشر شد و فروشگاه‌های شهرستان‌ها آمدند.", photo: "projectMobileApp" },
  { year: "۱۴۰۰", title: "سرمایهٔ دورِ اول", text: "تیم به چهل نفر رسید و دفترِ تبریز باز شد." },
  { year: "۱۴۰۲", title: "پرداخت و صورت‌حساب", text: "درگاهِ پرداخت و صورت‌حسابِ رسمی داخلِ خودِ پنل.", photo: "coverFinanceDesk" },
  { year: "۱۴۰۵", title: "سی هزار کسب‌وکار", text: "امروز هر روز یک میلیون فاکتور از پنل صادر می‌شود.", now: true },
]

/**
 * خطِ زمانِ داستانِ شرکت: سال‌ها روی یک محورِ عمودی، نقطهٔ هر رویداد با حلقه، و چند
 * رویداد با عکس؛ در دسکتاپ رویدادها یک‌درمیان دو طرفِ محور می‌نشینند و رویدادِ «امروز» برجسته است.
 */
export default function ProcessTimelineBlock() {
  return (
    <ControlSizeProvider size="xl" asChild>
      <section aria-labelledby="pt-title" className="mx-auto flex w-full max-w-5xl flex-col gap-14 px-4 py-24 sm:px-6">
        <div className="mx-auto flex max-w-2xl flex-col items-center gap-3 text-center">
          <span className="text-sm font-semibold text-brand-secondary">داستانِ ما</span>
          <h2 id="pt-title" className="text-3xl leading-snug font-black text-balance sm:text-4xl">
            نُه سال، یک مسیر
          </h2>
        </div>
        <ol className="relative flex flex-col gap-10 before:absolute before:inset-y-2 before:start-[0.6875rem] before:w-0.5 before:bg-border md:before:start-1/2 md:before:-translate-x-1/2 rtl:md:before:translate-x-1/2">
          {MILESTONES.map((item, index) => (
            <Reveal asChild key={item.year} from="start" delay={60}>
              <li className={cn("relative grid grid-cols-[1.5rem_1fr] gap-x-5 md:grid-cols-[1fr_1.5rem_1fr]", index % 2 === 1 && "md:[&>div]:col-start-1 md:[&>div]:row-start-1 md:[&>div]:text-end md:[&>div]:items-end")}>
                <span
                  aria-hidden
                  className={cn(
                    "relative z-10 mt-1.5 flex size-6 items-center justify-center rounded-full border-4 border-background md:col-start-2",
                    item.now ? "bg-brand-secondary ring-4 ring-[color-mix(in_oklab,var(--brand-secondary)_25%,transparent)]" : "bg-foreground"
                  )}
                />
                <div className="flex flex-col items-start gap-2 md:col-start-3">
                  <span className={cn("text-sm font-bold tabular-nums", item.now ? "text-brand-secondary" : "text-muted-foreground")}>{item.year}</span>
                  <h3 className="text-xl font-bold">{item.title}</h3>
                  <p className="max-w-sm leading-7 text-muted-foreground">{item.text}</p>
                  {item.photo && (
                    // eslint-disable-next-line @next/next/no-img-element -- عکس از کتابخانهٔ تصویرِ دیگ
                    <img src={stockImages[item.photo].src} alt={stockImages[item.photo].alt} className="mt-2 aspect-[16/10] w-full max-w-sm rounded-xl object-cover" />
                  )}
                </div>
              </li>
            </Reveal>
          ))}
        </ol>
      </section>
    </ControlSizeProvider>
  )
}