قالب داشبورد (DashboardPage)

شاخص‌ها و نمودارها در یک بازهٔ زمانی — انتخابگر بازه در سرِ صفحه، ردیف شاخص بی نقطهٔ شکست، و بخش‌های نمودار با یک ارتفاع

معرفی

DashboardPage قالب صفحهٔ شاخص و نمودار با بازهٔ زمانی است. همهٔ عددهای چیدمان داشبورد در قالب است:

  • عرض پهن 1600 پیکسل (wide)، یا بی‌سقف (full)؛
  • انتخابگر بازه (period) اولین کنترل اقدام‌های سرِ صفحه؛
  • تا 4 فیلتر کل داشبورد (filters) در نوارابزار؛ برای فیلترهای بیشتر یا دارای شمارش، filterPanel در ستون دومِ آزاد قاب؛ کنار ناوبری بخش، نوار افقی و در عرض کم Sheet؛
  • ردیف شاخص‌ها (kpis): هر کاشی دست‌کم --layout-tile-min-width (256 پیکسل) و کش‌آمده تا ردیف پر شود — بی نقطهٔ شکست. ستون‌ها از شمار کارت می‌آیند و ردیف آخر هرگز یک کارت یتیم نیست: 3 یا 4 کارت در یک ردیف، 5 کارت 3 + 2 (از عرض 86rem یک ردیف)، 6 کارت 3 + 3، 7 کارت 4 + 3 و 8 کارت 4 + 4 با کارت‌های پهن‌تر در ردیف آخر؛ این قاعده فقط برای شاخص‌هاست و فید پست و شبکهٔ کارت مجموعه‌ها را عوض نمی‌کند؛
  • بخش‌های نمودار (DashboardSection): نمودارها در شبکه‌ای با کمترین عرض --layout-chart-min-width (448 پیکسل) — دو نمودار در عرض پیش‌فرض، سه در عرض پهن، یکی روی موبایل؛
  • هر نمودار (DashboardChart) در یک ChartCard با ارتفاع ثابت --layout-chart-height (288 پیکسل)، با حالت‌های بارگذاری، خطا و خالی خودش در ناحیهٔ نمودار.

چه زمانی استفاده کنیم:

  • صفحهٔ خلاصه با شاخص‌ها و نمودارها در یک بازهٔ زمانی: داشبورد اصلی، خلاصهٔ یک کمپین.

چه زمانی استفاده نکنیم:

  • فهرست قابل‌فیلتر موجودیت‌ها: ListPage.
  • صفحهٔ یک موجودیت با چند نمودار دربارهٔ همان موجودیت: DetailPage با DashboardChartها در یک DetailSection.

استفاده

'use client'
import * as React from 'react'
import {
  MetricCard,
  MetricCardContent,
  MetricCardHeader,
  MetricCardLabel,
  MetricCardValue,
  PartoBarChart,
  DateRangePicker,
  formatNumber,
  resolveDateRangePreset,
  type DateRangeValue,
} from '@partodata/ui'
import { DashboardChart, DashboardPage, DashboardSection } from '@partodata/ui/templates'

const byPlatform = [
  { ماه: 'فروردین', اینستاگرام: 3200, تلگرام: 980 },
  { ماه: 'اردیبهشت', اینستاگرام: 3650, تلگرام: 1140 },
]

export default function DashboardHome() {
  // A new dashboard starts on «ماه گذشته».
  const [period, setPeriod] = React.useState<DateRangeValue | undefined>(() => resolveDateRangePreset('30d'))
  return (
    <DashboardPage
      title="داشبورد"
      description="خلاصهٔ گفت‌وگوهای برند"
      period={<DateRangePicker value={period} onChange={setPeriod} />}
      kpis={
        <MetricCard>
          <MetricCardHeader>
            <MetricCardLabel>کل منشن‌ها</MetricCardLabel>
          </MetricCardHeader>
          <MetricCardContent>
            <MetricCardValue>{formatNumber(12480)}</MetricCardValue>
          </MetricCardContent>
        </MetricCard>
      }
    >
      <DashboardSection title="روند گفت‌وگو">
        <DashboardChart title="منشن‌ها به تفکیک پلتفرم">
          <PartoBarChart data={byPlatform} keys={['اینستاگرام', 'تلگرام']} indexBy="ماه" legend />
        </DashboardChart>
      </DashboardSection>
    </DashboardPage>
  )
}

نمودار داخل DashboardChart ارتفاع خودش را ندارد و ناحیهٔ نمودار را پر می‌کند؛ عدد ارتفاع (h-64، height={300}) ننویسید.

حالت‌ها و انواع

جای اقدام‌ها

period همیشه اولین اقدام سرِ صفحه است. اقدام اصلی و اقدام‌های ثانوی قاعدهٔ ListPage را دارند: با filters در انتهای نوارابزار، بی آن در انتهای سرِ صفحه؛ اقدامی که کاربر اجازه‌اش را ندارد GatedAction است (غیرفعال با دلیل، هرگز پنهان).

وضعیت بازه و فیلترها

بازه (period) و فیلترها وضعیت جزءاند (React.useState در همان کامپوننتی که قالب را رندر می‌کند) یا، وقتی نمای داشبورد باید با پیوند به اشتراک گذاشته شود، با useViewParams در نشانی می‌روند (range: periodParam('30d')، tab، فیلترها؛ هوک): مثل ListPage، نه با useSearchParams، useFilterParams/FilterProvider و history.replaceState خودتان (قاعدهٔ ESLint parto/page-template).

زبانه‌ها

داشبوردی که بخش‌هایش صفحه‌های خودشان‌اند — یک مرکز عملیات («اکنون»، «رخدادها»، «کارها»)، گزارشی با چند نما — tabs می‌گیرد: زیر سرِ صفحه، هر زبانه پیوند با نشانی خودش (یک بخش مسیر، /ops/incidents)، و زبانهٔ جاری از pathname قاب. هر صفحهٔ زبانه همین DashboardPage را با همین tabs رندر می‌کند. داشبوردی که خودش تازه می‌شود state را با pageState({ …, live }) می‌سازد (دادهٔ زنده): نشانگر «آخرین به‌روزرسانی» پیش از بازه می‌نشیند.

نمودار پهن و جدول

span="full" نمودار را در کل ردیف بخش می‌گذارد. جدول یا فهرستی که در یک کارت داشبورد است height="content" می‌گیرد: به‌اندازهٔ محتوا، بی حاشیهٔ داخلی.

حالت‌ها

state روی DashboardPage (با pageState({ data, isLoading, error, onRetry })؛ isEmpty اگر دوره‌ای بی‌داده حالت خالی است) کل محتوا را عوض می‌کند (در بارگذاری: اسکلت ردیف شاخص و نمودارها، با یک اعلام). وقتی دورهٔ دیگری بارگذاری می‌شود، شاخص‌ها و نمودارهای روی صفحه کم‌رنگ می‌مانند تا دادهٔ تازه برسد. state روی یک DashboardChart فقط ناحیهٔ همان نمودار را: کارت و عنوانش می‌مانند و عنوان حالت، سرعنوانی جدا از عنوان کارت نیست. جدول یا فهرستی که در کارت داشبورد است DashboardChart height="content" با state خودش است، نه PageState داخل Card.

راهنمای استفاده

بکنید

  • شاخص‌ها را MetricCard کنید و در kpis بدهید؛ چیدمان ردیف را قالب می‌سازد.
  • هر نمودار را در یک DashboardChart بگذارید و نمودارهای مرتبط را در یک DashboardSection کنار هم.
  • اعداد شاخص را با formatNumber یا formatLargeNumber(n, 'fa') بنویسید.

نکنید

  • برای ردیف شاخص‌ها grid-cols-* با نقطهٔ شکست (sm:، lg:، xl:) ننویسید.
  • نمودار را در Card یا div دست‌ساز با عنوان خودتان نپیچید، و ارتفاع نمودار را عدد ندهید.
  • انتخابگر بازه را در نوار بالای قاب یا داخل یک کارت نگذارید؛ جایش period است.
  • بازه یا فیلترها را در نشانی صفحه نگذارید؛ React.useState صفحه‌اند.

Props

DashboardPage

Prop

Type

DashboardSection

Prop

Type

DashboardChart

Prop

Type

دسترسی‌پذیری

  • هر نمودار Parto ariaLabel می‌گیرد؛ آن را جمله‌ای کامل بنویسید («منشن‌ها به تفکیک پلتفرم در چهار ماه اخیر»).
  • ترتیب سرعنوان‌ها نمی‌پرد: عنوان صفحه h1، ردیف شاخص‌ها زیر سرعنوان پنهان «شاخص‌ها» (h2، برچسب هر شاخص h3)، بخش عنوان‌دار یک ناحیهٔ نام‌دار با عنوان h2، و عنوان هر نمودار سرعنوانی یک سطح پایین‌تر (h3) که نام ناحیهٔ (region) کارت نمودار است.
  • حالت‌های بلوک (بارگذاری کل داشبورد، و خالی) در یک ناحیهٔ status مؤدب اعلام می‌شوند که همیشه در صفحه است؛ خطا role="alert" خودش را دارد. متن حالت‌های هر نمودار به زبان صفحه (locale قالب) است.

کامپوننت‌های مرتبط

  • MetricCard — کاشی هر شاخص.
  • ChartCard — کارتی که DashboardChart روی آن ساخته شده.
  • DateRangePicker — انتخابگر بازه در period، با بازه‌های آماده.
  • PeriodSelector — فقط در سرِ یک کارت نمودار (actions در DashboardChart).

پنل فیلتر و دورهٔ مقایسه

filterPanel همان نوع ListPageFilterPanel است: سایدبار فیلتر در ستون دوم قاب، با همه‌چیز داخلش (شمار و «پاک کردن همه»، چیپ‌های activeFilters، نشانگر بخش‌ها) و بی دکمهٔ «فیلترها» در نوار ابزار. با collapsible: true کاربر ستون را با «بستن فیلترها» یا Ctrl+B می‌بندد و از زبانهٔ «فیلترها» در خود قاب برمی‌گرداند. نقش سایدبار دوم می‌تواند بین صفحه‌های یک محصول متفاوت باشد؛ در همین صفحه فقط ناوبری یا فیلتر دارد. ستون آزاد پنل را می‌گیرد؛ اگر ناوبری همین صفحه ستون را اشغال کرده یا ستون در دسترس نباشد، بخش‌ها در نوار افقی بالای محتوا هستند و هر عنوان Popover گزینه‌ها را باز می‌کند؛ زیر عرض محتوای 36rem، کنترل «فیلترها» همان پنل را در Sheet بومی باز می‌کند. وضعیت فیلتر در صفحه می‌ماند؛ filters و filterPanel را هم‌زمان ندهید.

<DashboardPage title="نمای کلی" filterPanel={{ panel: <OverviewFilters />, activeCount: activeFilters }}>
  <DashboardSection title="روند انتشار">
    <DashboardChart title="انتشار روزانه" description="1 تا 30 مهر در برابر 1 تا 30 شهریور">
      <PartoAreaChart
        data={dailyData}
        dataKeys={['current', 'previous']}
        seriesStyles={{ previous: { color: 'var(--foreground-lighter)', strokeDasharray: '5 4', fillOpacity: 0 } }}
      />
    </DashboardChart>
  </DashboardSection>
</DashboardPage>

توضیح نمودار و comparisonLabel رشد باید از دورهٔ واقعی داده بیایند؛ «دورهٔ قبل» را از درصد تغییر استنباط نکنید. سربرگ نمودار خودش فاصلهٔ عنوان، توضیح و اقدام‌ها را مدیریت می‌کند.