داشبوردِ مالی
پیشنمایش تمامصفحهداشبوردِ مالی: بنرِ گرادیانیِ موجودیِ نقد با دو اقدام، نوارِ سه شاخص با روند، نمودارِ ناحیهایِ این ماه/ماهِ قبل، پرداختهای پیشِ رو با هشدار و فعالیتهای اخیرِ تیم.
۱. نصب کامپوننتها
این بلاک از ۹ آیتم دیگ استفاده میکند: avatarbadgebuttoncardchart-presetscontrol-sizeiconspersiantoggle-group
پکیجمنیجر پیشفرض Node.jsنصب سریع با لینک سخت و دیسک مشترکYarn نسخهٔ ۲ به بالا (Berry)رانتایم و پکیجمنیجر Bun
npx digdesign@latest add https://docs.digdesign.ir/r/avatar.json https://docs.digdesign.ir/r/badge.json https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/card.json https://docs.digdesign.ir/r/chart-presets.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/icons.json https://docs.digdesign.ir/r/persian.json https://docs.digdesign.ir/r/toggle-group.jsonpnpm dlx digdesign@latest add https://docs.digdesign.ir/r/avatar.json https://docs.digdesign.ir/r/badge.json https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/card.json https://docs.digdesign.ir/r/chart-presets.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/icons.json https://docs.digdesign.ir/r/persian.json https://docs.digdesign.ir/r/toggle-group.jsonyarn dlx digdesign@latest add https://docs.digdesign.ir/r/avatar.json https://docs.digdesign.ir/r/badge.json https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/card.json https://docs.digdesign.ir/r/chart-presets.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/icons.json https://docs.digdesign.ir/r/persian.json https://docs.digdesign.ir/r/toggle-group.jsonbunx --bun digdesign@latest add https://docs.digdesign.ir/r/avatar.json https://docs.digdesign.ir/r/badge.json https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/card.json https://docs.digdesign.ir/r/chart-presets.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/icons.json https://docs.digdesign.ir/r/persian.json https://docs.digdesign.ir/r/toggle-group.json۲. کد صفحه
کد را در app/<route>/page.tsx بگذارید و متنها، داده و هندلرها را با محصول خودتان عوض کنید.
dashboard-finance.tsx
"use client"
import * as React from "react"
import { ArrowUpIcon, CalendarIcon, CreditCardIcon, ReceiptIcon, TrendingUpIcon, WalletIcon } from "@/components/icons"
import { Avatar } from "@/components/ui/avatar"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Card, CardAction, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { AreaChart } from "@/components/ui/chart-presets"
import { ControlSizeProvider } from "@/components/ui/control-size"
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
import { formatCurrency, formatNumber, toFaDigits } from "@/lib/persian"
import { avatarPhoto } from "@/lib/stock-images"
const WEEKS = [
{ label: "۱ مهر", now: 62, last: 54 },
{ label: "۳ مهر", now: 70, last: 58 },
{ label: "۵ مهر", now: 66, last: 63 },
{ label: "۷ مهر", now: 84, last: 61 },
{ label: "۹ مهر", now: 78, last: 70 },
{ label: "۱۱ مهر", now: 92, last: 68 },
{ label: "۱۳ مهر", now: 88, last: 74 },
{ label: "۱۵ مهر", now: 104, last: 77 },
]
const KPIS = [
{ icon: <ArrowUpIcon />, label: "درآمدِ این ماه", value: "۱٫۱۸ میلیارد", trend: 19, good: true },
{ icon: <ReceiptIcon />, label: "هزینهٔ این ماه", value: "۷۶۰ میلیون", trend: -5, good: true },
{ icon: <TrendingUpIcon />, label: "حاشیهٔ سود", value: "٪۳۶", trend: 4, good: true },
]
const BILLS = [
{ title: "اجارهٔ دفتر", due: "۳ روز دیگر", amount: 85_000_000, urgent: true },
{ title: "لیستِ بیمهٔ مهر", due: "۱۲ روز دیگر", amount: 142_000_000 },
{ title: "قسطِ وامِ تجهیزات", due: "۱۸ روز دیگر", amount: 36_500_000 },
]
const ACTIVITY = [
{ name: "سارا محمدی", gender: "female" as const, action: "فاکتورِ ۱۰۴۲ را پرداخت کرد", amount: "+۴۸", time: "۱۰:۱۵" },
{ name: "امیر رضایی", gender: "male" as const, action: "هزینهٔ تبلیغات را ثبت کرد", amount: "−۱۲", time: "۰۹:۴۰" },
{ name: "نگار احمدی", gender: "female" as const, action: "صورتحسابِ شهریور را بست", amount: null, time: "دیروز" },
]
/**
* داشبوردِ مالی: سلام و تاریخ، بنرِ طراحیشدهٔ «موجودیِ نقد» (گرادیانِ برند با پترن، عددِ درشت،
* تغییر به کلمه و دو اقدامِ اصلی)، سه شاخص با جداکننده و روندِ رنگی، نمودارِ ناحیهایِ این ماه
* در برابرِ ماهِ قبل، پرداختهای پیشِ رو با هشدارِ نزدیکترین، و فعالیتهای اخیرِ تیم با عکس.
*/
export default function DashboardFinanceBlock() {
const [range, setRange] = React.useState("month")
const data = range === "week" ? WEEKS.slice(-4) : WEEKS
return (
<ControlSizeProvider size="xl" asChild>
<main className="mx-auto flex w-full max-w-6xl flex-col gap-8 p-4 sm:p-6">
<header className="flex flex-wrap items-end justify-between gap-x-4 gap-y-6">
<div className="flex flex-col gap-1">
<h1 className="text-2xl leading-snug font-black sm:text-3xl">سلام آرمیتا</h1>
<p className="text-muted-foreground">وضعِ مالیِ کسبوکار؛ تا هدفِ ماه کمی مانده.</p>
</div>
<span className="flex items-center gap-2 rounded-full border border-border px-4 py-2 text-sm [&>svg]:size-4 [&>svg]:text-muted-foreground">
<CalendarIcon aria-hidden />
۱۵ مهر ۱۴۰۵
</span>
</header>
<div className="grid grid-cols-1 items-start gap-6 lg:grid-cols-[minmax(0,1fr)_22rem]">
<div className="flex min-w-0 flex-col gap-6">
{/* بنرِ موجودی: گرادیان، پترنِ نقطهای و حلقهٔ تزئینی؛ عدد و اقدامها روی آن. */}
<section aria-labelledby="cash-title" className="relative isolate flex flex-col gap-6 overflow-hidden rounded-xl bg-[linear-gradient(135deg,var(--dig-violet-700),var(--dig-indigo-800))] p-6 text-[var(--dig-white)] sm:p-8">
<span aria-hidden className="pointer-events-none absolute inset-0 -z-10 bg-[radial-gradient(circle_at_90%_0%,var(--dig-violet-400),transparent_45%),radial-gradient(circle_at_0%_100%,var(--dig-blue-500),transparent_40%)]" />
<span aria-hidden className="pointer-events-none absolute inset-0 -z-10 bg-[radial-gradient(color-mix(in_oklab,var(--dig-white)_30%,transparent)_1.2px,transparent_1.3px)] [background-size:18px_18px] [mask-image:linear-gradient(to_left,black,transparent_60%)]" />
<span aria-hidden className="pointer-events-none absolute -end-14 -bottom-20 -z-10 size-56 rounded-full border-[24px] border-[color-mix(in_oklab,var(--dig-white)_10%,transparent)]" />
<div className="flex items-start justify-between gap-4">
<div className="flex flex-col gap-2">
<span id="cash-title" className="flex items-center gap-2 text-sm text-[var(--dig-violet-100)] [&>svg]:size-4">
<WalletIcon aria-hidden />
موجودیِ نقد
</span>
<span className="text-3xl font-black tabular-nums sm:text-4xl">{formatCurrency(1_284_000_000)}</span>
<span className="w-fit rounded-full bg-[color-mix(in_oklab,var(--dig-white)_16%,var(--dig-violet-800))] px-3 py-1 text-xs font-semibold">٪۱۲ بیشتر از ماهِ قبل</span>
</div>
</div>
<div className="flex flex-wrap gap-3">
<Button className="bg-[var(--dig-white)] text-[var(--dig-violet-800)] hover:bg-[var(--dig-violet-50)]">
<ReceiptIcon />
فاکتورِ تازه
</Button>
<Button className="bg-[color-mix(in_oklab,var(--dig-white)_16%,var(--dig-violet-800))] text-[var(--dig-white)] hover:bg-[color-mix(in_oklab,var(--dig-white)_24%,var(--dig-violet-800))]">
<CreditCardIcon />
پرداخت
</Button>
</div>
</section>
{/* سه شاخص در یک نوار با جداکننده؛ روندِ مثبت/منفی با کلمه و رنگ. */}
<ul className="grid grid-cols-1 divide-y divide-border rounded-xl border border-border bg-card sm:grid-cols-3 sm:divide-x sm:divide-y-0 rtl:sm:divide-x-reverse">
{KPIS.map((kpi) => (
<li key={kpi.label} className="flex items-center gap-3 p-5">
<span aria-hidden className="flex size-11 shrink-0 items-center justify-center rounded-full bg-muted [&>svg]:size-5">
{kpi.icon}
</span>
<span className="flex flex-col gap-0.5">
<span className="text-sm text-muted-foreground">{kpi.label}</span>
<span className="flex items-baseline gap-2">
<span className="text-xl font-black tabular-nums">{kpi.value}</span>
<bdi dir="ltr" className={`text-xs font-semibold ${kpi.good ? "text-success" : "text-destructive"}`}>
{kpi.trend > 0 ? "+" : "−"}٪{toFaDigits(Math.abs(kpi.trend))}
</bdi>
</span>
</span>
</li>
))}
</ul>
<Card>
<CardHeader>
<CardTitle className="text-lg">درآمدِ روزانه</CardTitle>
<CardAction>
<ToggleGroup type="single" variant="segmented" value={range} onValueChange={(value) => value && setRange(value as string)} aria-label="بازه">
<ToggleGroupItem value="week">هفته</ToggleGroupItem>
<ToggleGroupItem value="month">ماه</ToggleGroupItem>
</ToggleGroup>
</CardAction>
</CardHeader>
<CardContent>
<AreaChart
className="h-64"
data={data}
categoryKey="label"
smooth
showPoints={false}
series={[
{ key: "now", label: "این ماه", color: "var(--dig-violet-500)" },
{ key: "last", label: "ماهِ قبل", color: "var(--dig-amber-500)" },
]}
valueFormatter={(value) => `${formatNumber(value)} میلیون`}
/>
</CardContent>
</Card>
</div>
<div className="flex flex-col gap-6">
<Card>
<CardHeader>
<CardTitle className="text-lg">پرداختهای پیشِ رو</CardTitle>
</CardHeader>
<CardContent>
<ul className="flex flex-col divide-y divide-border">
{BILLS.map((bill) => (
<li key={bill.title} className="flex items-center justify-between gap-3 py-4 first:pt-0 last:pb-0">
<span className="flex flex-col gap-1">
<span className="font-medium">{bill.title}</span>
{bill.urgent ? (
<Badge variant="soft" color="warning" className="self-start">
{bill.due}
</Badge>
) : (
<span className="text-sm text-muted-foreground">{bill.due}</span>
)}
</span>
<span className="font-bold tabular-nums">{formatCurrency(bill.amount)}</span>
</li>
))}
</ul>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle className="text-lg">فعالیتهای اخیر</CardTitle>
</CardHeader>
<CardContent>
<ul className="flex flex-col gap-5">
{ACTIVITY.map((item) => (
<li key={item.name + item.time} className="flex items-start gap-3">
<Avatar alt={item.name} src={avatarPhoto(item.name, item.gender)} className="size-10" />
<span className="flex min-w-0 flex-1 flex-col gap-0.5">
<span className="flex items-center justify-between gap-2">
<span className="text-sm font-bold">{item.name}</span>
<span className="text-xs text-muted-foreground tabular-nums">{item.time}</span>
</span>
<span className="text-sm text-muted-foreground">{item.action}</span>
{item.amount && (
<span className={`text-sm font-bold tabular-nums ${item.amount.startsWith("+") ? "text-success" : "text-foreground"}`}>
<bdi dir="ltr">{item.amount}</bdi> میلیون تومان
</span>
)}
</span>
</li>
))}
</ul>
</CardContent>
</Card>
</div>
</div>
</main>
</ControlSizeProvider>
)
}