گزارشها و نمودارها
پیشنمایش تمامصفحهکارتهای آمارِ hi-fi با بازهٔ ۷/۳۰/۹۰ روز: نمودار خطی، نوار تا هدف، سهمها، دونات کانالها، قیف خرید و عقربهٔ اعتبار.
۱. نصب کامپوننتها
این بلاک از ۵ آیتم دیگ استفاده میکند: control-sizeiconspersianstat-tiletoggle-group
پکیجمنیجر پیشفرض Node.jsنصب سریع با لینک سخت و دیسک مشترکYarn نسخهٔ ۲ به بالا (Berry)رانتایم و پکیجمنیجر Bun
npx digdesign@latest add 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/stat-tile.json https://docs.digdesign.ir/r/toggle-group.jsonpnpm dlx digdesign@latest add 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/stat-tile.json https://docs.digdesign.ir/r/toggle-group.jsonyarn dlx digdesign@latest add 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/stat-tile.json https://docs.digdesign.ir/r/toggle-group.jsonbunx --bun digdesign@latest add 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/stat-tile.json https://docs.digdesign.ir/r/toggle-group.json۲. کد صفحه
کد را در app/<route>/page.tsx بگذارید و متنها، داده و هندلرها را با محصول خودتان عوض کنید.
analytics.tsx
"use client"
import * as React from "react"
import { UsersIcon, WalletIcon } from "@/components/icons"
import {
StatTile,
StatTileAction,
StatTileBar,
StatTileChart,
StatTileContent,
StatTileDescription,
StatTileGauge,
StatTileHeader,
StatTileIcon,
StatTileLabel,
StatTileList,
StatTileMeter,
StatTileRing,
StatTileSegments,
StatTileSparkline,
StatTileTrend,
StatTileUnit,
StatTileValue,
} from "@/components/ui/stat-tile"
import { ControlSizeProvider } from "@/components/ui/control-size"
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
import { formatNumber } from "@/lib/persian"
/** دادهٔ نمونه برای هر بازه؛ در پروژهٔ واقعی همینها پاسخِ API هستند. */
const DATA = {
"7": { visits: [42, 48, 45, 52, 61, 58, 66], revenue: 186, orders: 820, conversion: 3.4 },
"30": { visits: [38, 41, 47, 44, 52, 49, 58, 55, 63, 60, 68, 72], revenue: 824, orders: 3_285, conversion: 3.9 },
"90": { visits: [30, 34, 33, 41, 39, 45, 50, 47, 55, 58, 61, 66, 70], revenue: 2_410, orders: 9_870, conversion: 4.2 },
} as const
const CHANNELS = [
{ label: "فروشگاه آنلاین", value: 45, color: "var(--chart-1)" },
{ label: "اپلیکیشن", value: 35, color: "var(--chart-2)" },
{ label: "فروش حضوری", value: 20, color: "var(--chart-4)" },
]
export default function AnalyticsBlock() {
const [period, setPeriod] = React.useState<keyof typeof DATA>("30")
const data = DATA[period]
return (
<ControlSizeProvider size="xl" asChild>
<main className="mx-auto flex w-full min-w-0 max-w-6xl flex-col gap-6 bg-muted p-4 sm:p-6">
<header className="flex flex-wrap items-end justify-between gap-x-4 gap-y-8">
<div className="flex flex-col gap-1">
<h1 className="text-2xl font-bold">گزارشها</h1>
<p className="text-sm text-muted-foreground">نمای کلی فروش، بازدید و مشتریان در بازهٔ انتخابی.</p>
</div>
<ToggleGroup type="single" variant="segmented" value={period} onValueChange={(value) => value && setPeriod(value as keyof typeof DATA)} aria-label="بازهٔ زمانی">
<ToggleGroupItem value="7" className="px-4">۷ روز</ToggleGroupItem>
<ToggleGroupItem value="30" className="px-4">۳۰ روز</ToggleGroupItem>
<ToggleGroupItem value="90" className="px-4">۹۰ روز</ToggleGroupItem>
</ToggleGroup>
</header>
{/* ردیفِ اول: چهار شاخص، هر کدام یک نوع نمایشِ سبک. */}
<section aria-label="شاخصهای کلیدی" className="grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4">
<StatTile className="gap-3">
<StatTileHeader>
<StatTileLabel>درآمد</StatTileLabel>
<StatTileAction aria-label="جزئیات درآمد" />
</StatTileHeader>
<StatTileContent>
<StatTileValue className="text-2xl">
{formatNumber(data.revenue)}
<StatTileUnit>میلیون تومان</StatTileUnit>
</StatTileValue>
<StatTileTrend value={12.5} formatValue={() => "+۱۲٫۵٪"} />
</StatTileContent>
<StatTileSparkline values={[...data.visits]} />
</StatTile>
<StatTile className="gap-3">
<StatTileHeader>
<StatTileLabel>سفارشها</StatTileLabel>
<StatTileAction aria-label="جزئیات سفارشها" />
</StatTileHeader>
<StatTileContent>
<StatTileValue className="text-2xl">{formatNumber(data.orders)}</StatTileValue>
<span className="ms-auto text-sm text-muted-foreground">
<strong className="font-semibold text-foreground">٪۴۲</strong> تا هدف
</span>
</StatTileContent>
<StatTileMeter value={42} />
</StatTile>
<StatTile className="gap-3">
<StatTileHeader>
<StatTileLabel>مشتریان تازه</StatTileLabel>
<StatTileAction aria-label="جزئیات مشتریان" />
</StatTileHeader>
<div className="grid grid-cols-[62fr_38fr] gap-1.5">
<div className="flex flex-col gap-1.5 border-s-2 border-info ps-3">
<span className="text-2xl font-bold tabular-nums">{formatNumber(302)}</span>
<span className="text-xs text-muted-foreground">خرید مستقیم</span>
</div>
<div className="flex flex-col gap-1.5 border-s-2 border-warning ps-3">
<span className="text-2xl font-bold tabular-nums">{formatNumber(184)}</span>
<span className="text-xs text-muted-foreground">معرفی</span>
</div>
</div>
<StatTileSegments
segments={[
{ value: 302, color: "var(--info)" },
{ value: 184, color: "var(--warning)" },
]}
/>
</StatTile>
<StatTile className="gap-3">
<StatTileHeader>
<StatTileLabel>نرخ تبدیل</StatTileLabel>
<StatTileAction aria-label="جزئیات نرخ تبدیل" />
</StatTileHeader>
<div className="flex items-end justify-between gap-3">
<div className="flex flex-col gap-1.5">
<StatTileValue className="text-2xl">٪{formatNumber(data.conversion)}</StatTileValue>
<StatTileTrend value={9.2} formatValue={() => "+۹٫۲٪"} />
</div>
<StatTileChart
className="h-20 min-w-0 max-w-44 flex-1"
color="var(--success)"
data={[
{ label: "تیر", value: 40 },
{ label: "مرداد", value: 36 },
{ label: "شهریور", value: 33 },
{ label: "مهر", value: 45 },
]}
/>
</div>
</StatTile>
</section>
{/* ردیفِ دوم: نمودارهای بزرگتر، کنارِ هم با ارتفاعِ برابر. */}
<section aria-label="جزئیات" className="grid grid-cols-1 gap-4 lg:grid-cols-3">
<StatTile>
<StatTileHeader>
<StatTileLabel className="text-base text-foreground">سهمِ کانالهای فروش</StatTileLabel>
<StatTileAction aria-label="جزئیات کانالها" />
</StatTileHeader>
<StatTileRing segments={CHANNELS}>
<span className="text-2xl font-bold tabular-nums">{formatNumber(1_560)}</span>
<span className="text-xs text-muted-foreground">سفارش</span>
</StatTileRing>
<ul className="flex flex-col gap-2.5 text-sm">
{CHANNELS.map((item) => (
<li key={item.label} className="flex items-center gap-2">
<span aria-hidden className="size-2.5 rounded-full" style={{ background: item.color }} />
<span className="text-muted-foreground">{item.label}</span>
<span className="ms-auto font-semibold tabular-nums">٪{formatNumber(item.value)}</span>
</li>
))}
</ul>
</StatTile>
<StatTile>
<StatTileHeader>
<StatTileLabel className="text-base text-foreground">قیفِ خرید</StatTileLabel>
<StatTileAction aria-label="جزئیات قیف" />
</StatTileHeader>
<StatTileContent>
<StatTileValue className="text-3xl">٪۶۲</StatTileValue>
<StatTileDescription>به سبد خرید رسیدهاند</StatTileDescription>
</StatTileContent>
<StatTileList
items={[
{ label: "بازدید", value: 100, display: "٪۱۰۰" },
{ label: "دیدنِ محصول", value: 74, display: "٪۷۴" },
{ label: "افزودن به سبد", value: 62, display: "٪۶۲" },
{ label: "شروعِ پرداخت", value: 38, display: "٪۳۸" },
{ label: "خریدِ موفق", value: 21, display: "٪۲۱" },
]}
/>
</StatTile>
<StatTile>
<StatTileHeader>
<StatTileLabel className="text-base text-foreground">اعتبارِ پیامک</StatTileLabel>
<StatTileAction aria-label="خرید اعتبار پیامک" />
</StatTileHeader>
<StatTileGauge value={62} className="mt-2">
<span className="text-3xl font-bold tabular-nums">{formatNumber(750)}</span>
<span className="text-xs text-muted-foreground">پیامک باقیمانده</span>
</StatTileGauge>
<StatTileDescription className="text-center">
با این روند، اعتبار تا <strong>۱۲ روز</strong> دیگر کافی است.
</StatTileDescription>
</StatTile>
</section>
{/* ردیفِ سوم: شاخصهای عملیاتی با آیکون و نوارِ پیشرفت. */}
<section aria-label="عملیات" className="grid grid-cols-1 gap-4 sm:grid-cols-2">
<StatTile>
<StatTileHeader>
<StatTileIcon tone="success">
<UsersIcon />
</StatTileIcon>
<StatTileLabel>تیکتهای پاسخدادهشده</StatTileLabel>
</StatTileHeader>
<StatTileContent>
<StatTileValue>٪۹۲</StatTileValue>
<StatTileTrend value={12} formatValue={() => "+۱۲٪"} />
</StatTileContent>
<StatTileBar value={92} />
<StatTileDescription>تقریباً همهٔ تیکتها زیرِ یک ساعت پاسخ گرفتهاند.</StatTileDescription>
</StatTile>
<StatTile>
<StatTileHeader>
<StatTileIcon tone="accent">
<WalletIcon />
</StatTileIcon>
<StatTileLabel>میانگینِ سبد خرید</StatTileLabel>
</StatTileHeader>
<StatTileContent>
<StatTileValue>
{formatNumber(562_000)}
<StatTileUnit>تومان</StatTileUnit>
</StatTileValue>
<StatTileTrend value={-3.1} formatValue={() => "−۳٫۱٪"} />
</StatTileContent>
<StatTileSparkline values={[6, 5.6, 5.9, 5.2, 5.4, 4.9, 5.1, 4.8]} color="var(--destructive)" />
</StatTile>
</section>
</main>
</ControlSizeProvider>
)
}