داربست صفحه (Page*)

خانوادهٔ چیدمان صفحه به‌صورت اسلات‌محور — PageContainer، PageHeaderRoot، PageSection و کروم تمام‌عرض

معرفی

خانوادهٔ Page* مجموعهٔ ساختاریافته و اسلات‌محور چیدمان صفحه است، برگرفته از نسل جدید Page* سوپابیس و برای RTL امن‌شده (فقط خصوصیات منطقی، container-query محور). این خانواده سه لایه دارد: کانتینر عرض (PageContainer)، سربرگ ترکیبی صفحه (PageHeaderRoot + اجزایش) و بخش‌های صفحه (PageSection + اجزایش)، به‌علاوهٔ کرومِ تمام‌عرض (PageBreadcrumbs، PageNav).

در صفحهٔ محصول: قالب صفحه

قالب‌های صفحه روی همین اجزا ساخته شده‌اند و صفحهٔ محصول با یکی از آن‌ها ساخته می‌شود. PageContainer، PageHeaderRoot و بقیهٔ این خانواده اجزای سطح پایین‌ترند؛ در صفحهٔ محصول فقط PageSection درون CustomPage.

PageHeaderRoot در مقابل PageHeader تخت

سیستم طراحی از قبل یک PageHeader تخت و prop-محور دارد (صفحهٔ PageHeader) که دست‌نخورده مانده — تغییر شکستن ندارد. ریشهٔ سربرگ ترکیبی این‌جا با نام PageHeaderRoot export می‌شود (دقیقاً همان نامی که سوپابیس داخلی استفاده می‌کند)، پس این دو بدون تداخل بارل کنار هم زندگی می‌کنند. سرِ قالب‌های صفحه PageHeader تخت است و قالب آن را رندر می‌کند؛ PageHeaderRoot جزء سطح پایینی برای کد خود سیستم طراحی است. هیچ‌کدام در صفحهٔ محصول نوشته نمی‌شود — حتی در CustomPage، که سرش را از propهای خودش می‌سازد. هر دو data-slot="page-header" دارند و سربرگ ترکیبی علاوه بر آن data-variant="compound" می‌گیرد.

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

  • PageSection و اجزایش: بخش‌های محتوای یک CustomPage (صفحه‌ای که در هیچ قالبی جا نمی‌شود و DS-GAP دارد)، هر بخش با عنوان/توضیح/اقدام‌ها و بدنه
  • PageContainer و PageHeaderRoot: فقط در کد خود سیستم طراحی، برای ساختن یک قالب یا بلوک صفحه‌ای

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

  • برای ساختن یک صفحهٔ محصول — هر صفحه یک قالب صفحه است که عرض، سرِ صفحه، ریتم، اقدام‌ها و حالت‌ها را خودش می‌دهد؛ PageContainer یا سربرگی از خودتان ننویسید (قاعدهٔ ESLint parto/page-template)
  • برای سرِ صفحه‌ای با زبانه، متا یا راه بازگشت — DetailPage (tabs، meta، back)
  • برای چیدمان داخل یک کارت یا بخش کوچک — از Card/FormHeader استفاده کنید
  • برای صفحات مستندات یا محتوای متنی که فریم‌ورک خودش را دارد

گزارش کمپین تخفیف فصلی

نمای کلی عملکرد کمپین در شبکه‌های اجتماعی

پوشش انتشار

تعداد پست‌های منتشرشده به تفکیک پلتفرم
جایگاه جدول پوشش انتشار

بازخورد مخاطبان

خلاصه نظرات ثبت‌شده درباره بسته‌بندی جدید
جایگاه نمودار بازخورد

استفاده

در صفحهٔ محصول این خانواده فقط به شکل PageSectionها درون یک CustomPage می‌آید؛ سرِ صفحه، عرض و ریتم را خود قالب می‌دهد:

'use client'
import {
  Button,
  PageSection,
  PageSectionContent,
  PageSectionDescription,
  PageSectionMeta,
  PageSectionSummary,
  PageSectionTitle,
} from '@partodata/ui'
import { Icons } from '@partodata/ui/icons'
import { CustomPage } from '@partodata/ui/templates'

declare function createBulletin(): void

export default function CampaignReportPage() {
  return (
    // A page is ONE template; one that fits none is a CustomPage, whose content is PageSections.
    <CustomPage
      dsGap="DS-GAP-15: گزارش ترکیبی کمپین"
      title="گزارش کمپین تخفیف فصلی"
      description="نمای کلی عملکرد کمپین در شبکه‌های اجتماعی"
      primaryAction={
        <Button onClick={createBulletin} iconStart={<Icons.plus />}>
          ساخت بولتن
        </Button>
      }
    >
      <PageSection>
        <PageSectionMeta>
          <PageSectionSummary>
            <PageSectionTitle>پوشش انتشار</PageSectionTitle>
            <PageSectionDescription>تعداد پست‌های منتشرشده به تفکیک پلتفرم</PageSectionDescription>
          </PageSectionSummary>
        </PageSectionMeta>
        <PageSectionContent>{/* جدول یا نمودار */}</PageSectionContent>
      </PageSection>
    </CustomPage>
  )
}

درون قالب‌ها: سربرگ داخل PageContainer؛ یک بار عرض و حاشیه

این بخش برای کسی است که یک قالب یا بلوک صفحه‌ای را در خود سیستم طراحی می‌سازد؛ صفحهٔ محصول هیچ‌کدام را نمی‌نویسد. قالب‌ها سربرگ را (PageHeader) اولین فرزند PageContainer خودشان رندر می‌کنند. اجزای خودپیچِ سربرگ ترکیبی (PageHeaderMeta، PageHeaderNavigationTabs، PageHeaderBreadcrumb) و ردیف‌های کروم (PageBreadcrumbs، PageNav) داخل یک PageContainer ظرف دومی نمی‌سازند و عرض و حاشیهٔ همان ظرف را می‌گیرند؛ پس حاشیه هیچ‌وقت دو بار اعمال نمی‌شود و size سربرگ آن‌جا نادیده گرفته می‌شود (بالای سربرگ همیشه همان 48 پیکسل صفحه است). شکل پیش از 4.0 — PageHeaderRoot پیش از PageContainer و هم‌سطح آن — هنوز همان‌طور رندر می‌شود.

اجزا و ساختار

PageContainer — کانتینر عرض

عرض حداکثر و padding افقی محتوا را تعیین می‌کند و context @container است که هر container-query داخلی نسبت به آن حل می‌شود. اندازه‌ها: small (768px)، default (1200px)، large (1600px)، full (بدون حد). اندازه را نوع صفحه تعیین می‌کند: small فرم و تنظیمات، default فهرست و جزئیات، large داشبورد و تحلیل، full فقط جدول بسیار پهن یا لاگ (هندسهٔ صفحه).

<PageContainer size="default">{/* محتوا */}</PageContainer>

PageHeaderRoot — سربرگ ترکیبی

سربرگ ترکیبی (آیکون، ردیف متا، تب‌های ناوبری)، جزء سطح پایینی برای کد خود سیستم طراحی؛ در صفحهٔ محصول نوشته نمی‌شود (صفحه‌ای که زبانه یا متا در سرش لازم دارد DetailPage است). بیرون از PageContainer (شکل پیش از 4.0) size را از طریق context به اجزای خودپیچ می‌دهد. اجزای آن:

  • PageHeaderMeta — ردیف متا: چیدمان آیکون / خلاصه / aside
  • PageHeaderIcon — آیکون پیشرو
  • PageHeaderSummary — پشتهٔ عنوان + توضیح
  • PageHeaderTitle — عنوان صفحه (h1، 24px، وزن متوسط)
  • PageHeaderDescription — متن پشتیبان زیر عنوان
  • PageHeaderAside — خوشهٔ اقدامات (دکمه، منو)؛ اقدام اصلی آخرین دکمه و تنها دکمهٔ variant="primary" آن است (از 4.0 دکمهٔ بی‌variant خنثی است)
  • PageHeaderNavigationTabs — فوتر تب‌های ناوبری سربرگ
  • PageHeaderBreadcrumb — ردیف breadcrumb داخل سربرگ (زیرجزء legacy؛ برای صفحات جدید PageBreadcrumbs را ترجیح دهید)

PageSection — بخش صفحه

هر بخش 48px ریتم بالا، 24px فاصلهٔ داخلی و 48px دنبالهٔ آخرین بخش دارد. با orientation="horizontal" به یک گرید 1fr/2fr (متا ⁄ محتوا) در @3xl تقسیم می‌شود. اجزای آن:

  • PageSectionMeta — ردیف متا: خلاصه + aside
  • PageSectionSummary — پشتهٔ عنوان + توضیح
  • PageSectionTitle — عنوان بخش (h2، 20px، وزن متوسط)
  • PageSectionDescription — متن پشتیبان زیر عنوان بخش
  • PageSectionAside — خوشهٔ اقدامات بخش
  • PageSectionContent — بدنهٔ اصلی بخش (فرم، جدول، گرید)

PageSectionMain وجود ندارد

عمداً هیچ PageSectionMain وجود ندارد — محتوا در PageSectionContent می‌رود؛ و PageSectionAside یک خوشهٔ اقدامات است، نه یک ستون. برای چیدمان دو ستونی از orientation="horizontal" استفاده کنید (ستون اول متا/محتوای باریک، ستون دوم محتوای پهن).

کرومِ تمام‌عرض — PageBreadcrumbs و PageNav

این دو ردیفِ کرومِ تمام‌عرض‌اند که بالای سربرگ و بیرون از PageContainer می‌نشینند، نه داخل سربرگ. (داخل یک PageContainer هم ظرف دومی نمی‌سازند و به عرض آن ظرف درمی‌آیند.) مسیر بازگشت و زبانه‌های یک صفحهٔ محصول را قالبش می‌دهد (back، breadcrumbs، tabs)؛ این دو برای کد خود سیستم طراحی‌اند:

import {
  PageBreadcrumbs,
  PageBreadcrumbsActions,
  PageNav,
  Breadcrumb,
  BreadcrumbList,
  BreadcrumbItem,
  BreadcrumbLink,
  BreadcrumbPage,
  Button,
} from '@partodata/ui'
;<>
  <PageBreadcrumbs
    actions={
      <PageBreadcrumbsActions>
        <Button variant="default">اقدام</Button>
      </PageBreadcrumbsActions>
    }
  >
    <BreadcrumbList>
      <BreadcrumbItem>
        <BreadcrumbLink href="/campaigns">کمپین‌ها</BreadcrumbLink>
      </BreadcrumbItem>
      <BreadcrumbItem>
        <BreadcrumbPage>کمپین تخفیف فصلی</BreadcrumbPage>
      </BreadcrumbItem>
    </BreadcrumbList>
  </PageBreadcrumbs>

  <PageNav>{/* یک NavMenu یا nav تب‌ها */}</PageNav>
</>

هر دو ردیف با PageContainer inset="chrome" رندر می‌شوند: فاصلهٔ افقی‌شان در همهٔ عرض‌ها ثابت 16px است و مثل محتوای صفحه با نردبان page-inset (16/24/40px) پهن نمی‌شود. اگر خودتان کانتینری برای کروم می‌سازید، همین inset="chrome" را بدهید؛ گذاشتن ps-4 روی کانتینرِ پیش‌فرض کار نمی‌کند، چون page-inset خصوصیت میان‌بُر padding-inline را می‌نویسد و در ترتیب CSS بعد از کلاس‌های ps-* می‌آید.

چیدمان افقی (دو ستونی)

یک بخش از محتوای CustomPage:

<PageSection orientation="horizontal">
  {/* ستون باریک (1fr): متا/خلاصه */}
  <PageSectionMeta>
    <PageSectionSummary>
      <PageSectionTitle>خلاصهٔ اینفلوئنسر</PageSectionTitle>
      <PageSectionDescription>اطلاعات کلی و پلتفرم‌ها</PageSectionDescription>
    </PageSectionSummary>
  </PageSectionMeta>
  {/* ستون پهن (2fr): محتوای اصلی */}
  <PageSectionContent>{/* نمودارها و آمار */}</PageSectionContent>
</PageSection>

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

بکنید

  • صفحهٔ محصول را با یک قالب بسازید و در CustomPage فقط PageSectionها را بنویسید - محتوای بخش را در PageSectionContent بگذارید و عنوان/توضیح را در PageSectionSummary داخل PageSectionMeta - در کد خود سیستم طراحی، سربرگ را اولین فرزند PageContainer بگذارید و size را فقط به PageContainer بدهید

نکنید

  • PageContainer، PageHeader یا PageHeaderRoot را در صفحهٔ محصول ننویسید — قالب آن‌ها را رندر می‌کند (قاعدهٔ ESLint parto/page-template) - از PageSectionMain استفاده نکنید؛ وجود ندارد — PageSectionContent را به کار ببرید
  • PageSectionAside را به‌عنوان ستون محتوا استفاده نکنید؛ یک خوشهٔ اقدامات است - فاصله‌گذاری دستی به بخش‌ها اضافه نکنید؛ ریتم داخلی خانواده از قبل تنظیم شده

جدول ویژگی‌ها

PageContainer

Prop

Type

PageHeaderRoot

Prop

Type

PageSection

Prop

Type

PageSectionContent

Prop

Type

Prop

Type

Prop

Type

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

  • PageHeaderTitle یک h1 واقعی و PageSectionTitle یک h2 است، پس سلسله‌مراتب تیترها برای ناوبری صفحه‌خوان درست می‌ماند — h1 صفحه را قالب می‌دهد
  • کل خانواده از خصوصیات منطقی CSS (ps/pe، start/end) استفاده می‌کند و به‌صورت خودکار RTL-صحیح است
  • چیدمان‌ها container-query محورند، پس در عرض‌های مختلف (نه فقط viewport) درست پاسخ می‌دهند؛ کرومِ تمام‌عرض ارتفاع ثابت 48px و فاصلهٔ افقی ثابت 16px دارد

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

  • PageHeader — سرِ صفحه‌ای که قالب‌ها رندر می‌کنند
  • انتخاب قالب صفحه — هر صفحهٔ محصول یک قالب است
  • CustomPage — تنها جایی که PageSection مستقیم در صفحه می‌آید
  • چیدمان (الگو) — اجزای سطح پایینی که قالب‌ها رویشان ساخته شده‌اند
  • صفحهٔ تحلیل — نمونهٔ کامل یک صفحهٔ تحلیل، با قالب DetailPage
  • Breadcrumb — عناصر breadcrumb که داخل PageBreadcrumbs قرار می‌گیرند