خطِ زمانِ داستان
پیشنمایش تمامصفحهبخشِ خطِ زمان: سالها روی محورِ عمودی، رویدادها یکدرمیان دو طرفِ محور با عکسِ اختیاری و رویدادِ امروز برجسته؛ برای داستانِ شرکت و 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.jsonpnpm dlx digdesign@latest add https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/reveal.jsonyarn dlx digdesign@latest add https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/reveal.jsonbunx --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>
)
}