اعلانهای دستهبندیشده
پیشنمایش تمامصفحههر منبع یک کارت با تازهترین اعلان و «چند اعلانِ دیگر» بازشونده؛ برای کاهشِ شلوغیِ اعلانها.
۱. نصب کامپوننتها
این بلاک از ۴ آیتم دیگ استفاده میکند: buttoncontrol-sizeiconspersian
پکیجمنیجر پیشفرض 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/persian.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/persian.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/persian.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/persian.json۲. کد صفحه
کد را در app/<route>/page.tsx بگذارید و متنها، داده و هندلرها را با محصول خودتان عوض کنید.
notifications-grouped.tsx
"use client"
import * as React from "react"
import { ChevronDownIcon, ReceiptIcon, TruckIcon, UsersIcon } from "@/components/icons"
import { Button } from "@/components/ui/button"
import { ControlSizeProvider } from "@/components/ui/control-size"
import { toFaDigits } from "@/lib/persian"
const GROUPS = [
{ key: "orders", title: "سفارشها", icon: <TruckIcon />, items: ["سفارشِ ۸۸۲۱۰۴۲ ارسال شد", "سفارشِ ۸۸۲۱۰۴۱ تحویل شد", "سفارشِ ۸۸۲۱۰۴۰ آمادهسازی شد", "سفارشِ ۸۸۲۱۰۳۹ مرجوع شد"], time: "۱۰ دقیقه پیش" },
{ key: "team", title: "تیم", icon: <UsersIcon />, items: ["سارا محمدی به تیمِ فروش پیوست", "امیر رضایی نقشِ مدیر گرفت"], time: "۲ ساعت پیش" },
{ key: "finance", title: "مالی", icon: <ReceiptIcon />, items: ["پرداختِ فاکتورِ ۱۴۰۵-۰۲۳۱ انجام شد"], time: "دیروز" },
]
/**
* اعلانهای دستهبندیشده برای کاهشِ شلوغی: هر منبع یک کارت با تازهترین اعلان و «۳ اعلانِ
* دیگر» که باز و بسته میشود (aria-expanded)؛ کاربر بهجای ده ردیف، سه خبرِ اصلی میبیند.
*/
export default function NotificationsGroupedBlock() {
const [open, setOpen] = React.useState<string[]>([])
return (
<ControlSizeProvider size="xl" asChild>
<main className="mx-auto flex w-full max-w-2xl flex-col gap-8 p-4 sm:p-6">
<header className="flex flex-col gap-1">
<h1 className="text-2xl font-bold">اعلانها</h1>
<p className="text-muted-foreground">{toFaDigits(GROUPS.reduce((sum, group) => sum + group.items.length, 0))} اعلان از {toFaDigits(GROUPS.length)} بخش</p>
</header>
<ul className="flex flex-col gap-3">
{GROUPS.map((group) => {
const expanded = open.includes(group.key)
const rest = group.items.length - 1
return (
<li key={group.key} className="flex flex-col rounded-xl border border-border bg-card">
<div className="flex items-start gap-3 p-4">
<span aria-hidden className="flex size-10 shrink-0 items-center justify-center rounded-full bg-subtle text-brand-secondary [&>svg]:size-5">
{group.icon}
</span>
<div className="flex flex-1 flex-col gap-1">
<span className="flex items-center justify-between gap-2">
<span className="text-sm font-semibold text-muted-foreground">{group.title}</span>
<span className="text-xs text-muted-foreground">{group.time}</span>
</span>
<span className="font-medium">{group.items[0]}</span>
</div>
</div>
{rest > 0 && (
<>
{expanded && (
<ul id={`ng-${group.key}`} className="flex flex-col gap-2 border-t border-border px-4 py-3 ps-[4.25rem]">
{group.items.slice(1).map((item) => (
<li key={item} className="text-sm text-muted-foreground">
{item}
</li>
))}
</ul>
)}
<Button
variant="ghost"
aria-expanded={expanded}
aria-controls={`ng-${group.key}`}
onClick={() => setOpen((list) => (expanded ? list.filter((key) => key !== group.key) : [...list, group.key]))}
className="justify-center gap-2 rounded-t-none border-t border-border"
>
{expanded ? "بستن" : `${toFaDigits(rest)} اعلانِ دیگر`}
<ChevronDownIcon className={expanded ? "rotate-180" : ""} />
</Button>
</>
)}
</li>
)
})}
</ul>
</main>
</ControlSizeProvider>
)
}