ویژگیهای یکدرمیان
پیشنمایش تمامصفحهبخشِ ویژگیها با ردیفهای عکس و متن که جایشان یکدرمیان عوض میشود؛ هر ردیف برچسب، تیتر، توضیح، نکتههای تیکدار و دکمهٔ بیشتر.
۱. نصب کامپوننتها
این بلاک از ۴ آیتم دیگ استفاده میکند: buttoncontrol-sizeiconsreveal
پکیجمنیجر پیشفرض Node.jsنصب سریع با لینک سخت و دیسک مشترکYarn نسخهٔ ۲ به بالا (Berry)رانتایم و پکیجمنیجر Bun
npx digdesign@latest add 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/reveal.jsonpnpm dlx digdesign@latest add 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/reveal.jsonyarn dlx digdesign@latest add 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/reveal.jsonbunx --bun digdesign@latest add 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/reveal.json۲. کد صفحه
کد را در app/<route>/page.tsx بگذارید و متنها، داده و هندلرها را با محصول خودتان عوض کنید.
features-alternating.tsx
"use client"
import { CheckIcon } from "@/components/icons"
import { Button } from "@/components/ui/button"
import { ControlSizeProvider } from "@/components/ui/control-size"
import { Reveal } from "@/components/ui/reveal"
import { stockImages, type StockImageName } from "@/lib/stock-images"
const ROWS: { eyebrow: string; title: string; text: string; points: string[]; image: StockImageName }[] = [
{ eyebrow: "فاکتور", title: "فاکتورِ رسمی، بدونِ اکسل", text: "قالبِ آماده با لوگوی خودت؛ شماره، مالیات و تخفیف خودشان حساب میشوند.", points: ["ارسالِ پیامکی و لینکِ پرداخت", "یادآورِ خودکارِ فاکتورهای معوق"], image: "coverCalculator" },
{ eyebrow: "گزارش", title: "بدانی پولت کجا میرود", text: "نمودارِ سود و هزینه هر روز بهروز میشود؛ ماهِ قبل را با همین ماه مقایسه کن.", points: ["دستهبندی خودکارِ هزینهها", "خروجی PDF برای حسابدار"], image: "coverFinanceDesk" },
{ eyebrow: "تیم", title: "همه روی یک دفتر", text: "حسابدار، مدیر و فروشنده هر کدام دسترسی خودشان را دارند.", points: ["نقشها و مجوزهای جدا", "تاریخچهٔ هر تغییر"], image: "coverWorkspace" },
]
/**
* ویژگیهای یکدرمیان: هر ردیف عکسِ واقعی کنارِ متن، و جای عکس و متن ردیفبهردیف عوض
* میشود تا چشم زیگزاگ پایین برود؛ هر ردیف برچسب، تیتر، توضیح و دو نکتهٔ تیکدار دارد.
*/
export default function FeaturesAlternatingBlock() {
return (
<ControlSizeProvider size="xl" asChild>
<section aria-label="امکانات" className="mx-auto flex w-full max-w-6xl flex-col gap-24 px-4 py-24 sm:px-6">
{ROWS.map((row, index) => (
<Reveal key={row.title}>
<article className="grid grid-cols-1 items-center gap-10 lg:grid-cols-2 lg:gap-16">
{/* eslint-disable-next-line @next/next/no-img-element -- عکس از کتابخانهٔ تصویرِ دیگ */}
<img src={stockImages[row.image].src} alt={stockImages[row.image].alt} loading="lazy" className={`aspect-[4/3] w-full rounded-xl object-cover ${index % 2 ? "lg:order-last" : ""}`} />
<div className="flex flex-col items-start gap-5">
<span className="text-sm font-semibold text-brand-secondary">{row.eyebrow}</span>
<h2 className="text-3xl leading-snug font-black text-balance">{row.title}</h2>
<p className="text-lg leading-8 text-muted-foreground">{row.text}</p>
<ul className="flex flex-col gap-3">
{row.points.map((point) => (
<li key={point} className="flex items-center gap-3">
<span aria-hidden className="flex size-6 items-center justify-center rounded-full bg-success-subtle text-success [&>svg]:size-3.5">
<CheckIcon />
</span>
{point}
</li>
))}
</ul>
<Button variant="outline" className="mt-3">
بیشتر بدان
</Button>
</div>
</article>
</Reveal>
))}
</section>
</ControlSizeProvider>
)
}