مراحلِ کار، آکاردئونی
پیشنمایش تمامصفحهبخشِ روندِ کار: مراحلِ شمارهدار که هر بار یکی باز است با توضیح و اقدام، و عکسِ همان مرحله کنارش با محوشدن عوض میشود.
۱. نصب کامپوننتها
این بلاک از ۵ آیتم دیگ استفاده میکند: accordionbuttoncontrol-sizeiconspersian
پکیجمنیجر پیشفرض Node.jsنصب سریع با لینک سخت و دیسک مشترکYarn نسخهٔ ۲ به بالا (Berry)رانتایم و پکیجمنیجر Bun
npx digdesign@latest add https://docs.digdesign.ir/r/accordion.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.jsonpnpm dlx digdesign@latest add https://docs.digdesign.ir/r/accordion.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.jsonyarn dlx digdesign@latest add https://docs.digdesign.ir/r/accordion.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.jsonbunx --bun digdesign@latest add https://docs.digdesign.ir/r/accordion.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۲. کد صفحه
کد را در app/<route>/page.tsx بگذارید و متنها، داده و هندلرها را با محصول خودتان عوض کنید.
process-accordion.tsx
"use client"
import * as React from "react"
import { ArrowUpIcon } from "@/components/icons"
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion"
import { Button } from "@/components/ui/button"
import { ControlSizeProvider } from "@/components/ui/control-size"
import { toFaDigits } from "@/lib/persian"
import { cn } from "@/lib/utils"
import { stockImages, type StockImageName } from "@/lib/stock-images"
const STEPS: { title: string; text: string; action: string; photo: StockImageName }[] = [
{
title: "بازدید از محل",
text: "کارشناسِ ما نور، جهتِ ساختمان و فضای بام را میسنجد و همان روز گزارش میدهد.",
action: "گزارشِ نمونه را ببینید",
photo: "coverMinimalRoom",
},
{
title: "طراحیِ سامانه",
text: "بر اساسِ مصرفِ قبضهای یک سالِ اخیر، اندازهٔ پنل و باتری را دقیق حساب میکنیم.",
action: "ماشینحسابِ مصرف",
photo: "projectDashboard",
},
{
title: "مجوز و قرارداد",
text: "همهٔ کارهای اداری با توزیعِ برق و شهرداری را خودمان پیگیری میکنیم.",
action: "مدارکِ لازم",
photo: "coverOfficeSupplies",
},
{
title: "نصب در یک روز",
text: "تیمِ نصب صبح میرسد و عصر سامانه به شبکه وصل است؛ بدونِ قطعیِ طولانی.",
action: "تقویمِ نصب",
photo: "studioSunlit",
},
{
title: "پایش و نگهداری",
text: "تولیدِ هر پنل را در اپ میبینید و اگر افت کند، پیش از شما خبردار میشویم.",
action: "اپ را ببینید",
photo: "projectMobileApp",
},
]
/**
* مراحلِ کار بهشکلِ آکاردئونِ شمارهدار: هر بار یک مرحله باز است با توضیح و اقدام، و عکسِ
* همان مرحله کنارش با محوشدن عوض میشود؛ در موبایل عکس داخلِ همان مرحله میآید.
*/
export default function ProcessAccordionBlock() {
const [open, setOpen] = React.useState(0)
return (
<ControlSizeProvider size="xl" asChild>
<section aria-labelledby="pa-title" className="mx-auto flex w-full max-w-6xl flex-col gap-12 px-4 py-24 sm:px-6">
<div className="flex max-w-2xl flex-col gap-3">
<span className="text-sm font-semibold text-brand-secondary">روندِ کار</span>
<h2 id="pa-title" className="text-3xl leading-snug font-black text-balance sm:text-4xl">
از اولین تماس تا اولین کیلووات، پنج قدم
</h2>
</div>
<div className="grid grid-cols-1 items-start gap-8 lg:grid-cols-2">
<Accordion
type="single"
variant="light"
hideIndicator
value={String(open)}
onValueChange={(value) => value && setOpen(Number(value))}
className="flex flex-col gap-2"
>
{STEPS.map((step, index) => {
const expanded = open === index
return (
<AccordionItem
key={step.title}
value={String(index)}
className={cn("rounded-xl border-0 px-4 transition-colors duration-300 sm:px-5", expanded ? "bg-subtle" : "hover:bg-muted")}
>
<AccordionTrigger className="gap-4 py-4 text-lg font-bold hover:no-underline sm:py-5">
<span className="flex items-center gap-4">
<span
aria-hidden
className={cn(
"flex size-9 shrink-0 items-center justify-center rounded-full text-sm tabular-nums transition-colors",
expanded ? "bg-foreground text-background" : "bg-muted text-muted-foreground"
)}
>
{toFaDigits(index + 1)}
</span>
{step.title}
</span>
</AccordionTrigger>
<AccordionContent>
<div className="flex flex-col items-start gap-4 pb-1 ps-[3.25rem]">
<p className="leading-7 text-muted-foreground">{step.text}</p>
<Button variant="secondary">
{step.action}
<ArrowUpIcon aria-hidden className="-rotate-45" />
</Button>
{/* eslint-disable-next-line @next/next/no-img-element -- عکس از کتابخانهٔ تصویرِ دیگ */}
<img src={stockImages[step.photo].src} alt="" className="aspect-[16/10] w-full rounded-lg object-cover lg:hidden" />
</div>
</AccordionContent>
</AccordionItem>
)
})}
</Accordion>
<div className="sticky top-6 hidden aspect-[4/3] overflow-hidden rounded-xl bg-muted lg:block">
{STEPS.map((step, index) => (
// eslint-disable-next-line @next/next/no-img-element -- عکس از کتابخانهٔ تصویرِ دیگ
<img
key={step.title}
src={stockImages[step.photo].src}
alt={index === open ? stockImages[step.photo].alt : ""}
aria-hidden={index !== open}
className={cn("absolute inset-0 size-full object-cover transition-[opacity,scale] duration-700", index === open ? "scale-100" : "scale-105 [opacity:0]")}
/>
))}
<span className="absolute start-4 top-4 rounded-full bg-card px-3 py-1.5 text-sm font-semibold shadow-sm">
قدمِ {toFaDigits(open + 1)} از {toFaDigits(STEPS.length)}
</span>
</div>
</div>
</section>
</ControlSizeProvider>
)
}