گرامر بصری

هر بلوک روی یک ظرف، هر صفحه با لایهٔ کم — لایه‌های سطح، جدول تصمیم، سقف‌های صفحهٔ آرام و دروازهٔ بازطراحی

پیش‌فرض قوی، نه قانون مطلق

گرامر بصری پیش‌فرض قوی است، نه قانون مطلق. قاعده‌ها یکسان نیستند:

  • سخت (بدون تأیید مالک هرگز نقض نمی‌شود): دسترسی‌پذیری؛ فقط توکن، بدون رنگ یا اندازهٔ خام؛ درستی RTL؛ رقم ASCII در DOM با نمایش فارسی از فونت؛ گم‌نشدن جریان کاربر، داده یا قاعدهٔ ایمنی هنگام بازطراحی؛ هیچ راز یا توکنی در کد.
  • پیش‌فرض قوی (G1…G20: چیدمان، سطح، تراکم، تایپوگرافی): مگر دلیل طراحیِ مشخصی باشد، همین‌ها را دنبال کنید. نتیجهٔ روی صفحه در هر دو تم و داوری مالک از هر قاعده بالاتر است.

پروتکل انحراف، اگر منحرف می‌شوید:

  1. در MR، PR یا کامیت یک خط بنویسید (چنین):

    Grammar deviation: G4 — <reason>
  2. انحراف را محلی نگه دارید (همین بلوک، همین صفحه)، نه پیش‌فرض تازه.

  3. هرگز بی‌صدا از قاعده نگذرید و برای قبول‌شدن صفحه، قاعده، لینت یا توکن را ویرایش نکنید.

  4. اگر همان انحراف دوبار لازم شد، قاعده یا DS ایراد دارد: تغییر DS پیشنهاد دهید (ds-change)، نه دورزدن تکراری.

انحرافِ مستند در بازبینی پذیرفته است و انحرافِ بی‌سند یک یافته. استثنای مستندِ Data Grid تمام‌عرض (G1) سر جایش می‌ماند. لینت‌های R-SURF-* هشدارند (نه خطا) و انحرافِ موجه با دلیل در همان خط ثبت می‌شود:

// eslint-disable-next-line parto/no-hollow-surface -- Grammar deviation: G2 — <reason>

«سه پرسش پیش از مهاجرت» همچنان الزامی است: ابزار فکر است، نه ممنوعیت.

اصل

سطح و ساختار از ترکیب می‌آید، نه از رنگ. هر بلوک محصور یک ظرف است: پرکننده + مرز + شعاع + سایهٔ کوچک، هر چهار با هم. بقیهٔ آرامش صفحه از کم‌کردن می‌آید: لایهٔ کمتر پیش از داده، تکرار کمتر، رنگ کمتر، کنترل کمتر.

این صفحه راهنمای هر کسی (و هر ایجنتی) است که صفحه می‌سازد یا محصولی را اصلاح و مهاجرت می‌کند. قاعده‌ها شمارهٔ G1…G20 دارند؛ در توضیح MR فقط شمارهٔ قاعده‌ای را بنویسید که اجرا کردید یا آگاهانه از آن منحرف شدید (بالا: پروتکل انحراف). همین متن در AGENTS.md بستهٔ @partodata/ui (بخش 10) و در مهارت‌های parto-ui-build-page، parto-ui-migrate-page و parto-ui-check هم هست: npx --no parto-ui guide surfaces --full.


نمونه بصری

پنج لایهٔ سطح در هر دو تم، با کنتراست هر پله که همین حالا از توکن‌های واقعی خوانده می‌شود، و اعداد Studio کنارشان.

تم تیره

L0
chrome
L1
L2
L3

تم روشن

L0
chrome
L1
L2
L3
پلهکف مجازتیره: ما (زنده)تیره: Studioروشن: ما (زنده)روشن: Studio
پرکنندهٔ L1 روی بوم (فقط رنگ)≥ 1.04…1.054…1.017
مرز روی بوم≥ 1.15…1.19…1.20
مرز روی L1≥ 1.15…1.21…1.20
L2 روی L1—…—…—
L3 روی بوم—…—…—
لایهبرای چهتیرهروشن
L0 بومعنوان، توضیح، نوار ابزار، فاصله……
L0 قابسربرگ، ریل و ستون دوم قاب (فقط خود ProductFrame)……
L1 ظرفجدول، نمودار، شاخص، فرم، نخ، پنل فیلتر……
L2 درون ظرفhover، انتخاب‌شده، حفره (بدون مرز)……
L3 شناورDialog، Sheet، Popover……

اعداد «ما» همین حالا با getComputedStyle از توکن‌های واقعی هر دو تم خوانده شدند (نسبت کنتراست WCAG). اعداد Studio از سورس توکن‌های آن گرفته شده‌اند و اینجا اجرا نشده‌اند.

توکن‌ها عوض نمی‌شوند

در تم تیره پلهٔ بوم ← ظرف (فقط رنگ) در پرتو با Studio یکی است و در تم روشن از Studio قوی‌تر؛ مرزها یکی‌اند. پس «بلوکی هم‌رنگ بوم» هرگز از توکن نمی‌آید: از جایی می‌آید که ظرف اصلاً به کار نرفته. روشن‌تر کردن surface-100 فقط همهٔ ظرف‌های درست را هم عوض می‌کند. پرکننده به‌تنهایی هم جدایی نمی‌سازد (حدود 1.05)؛ مرز چهار تا ده برابر قوی‌تر است، پس جفت «پرکننده + مرز» لازم است.

  • کف مجاز برای هر ظرف روی لایهٔ بالاترش: کنتراست پرکننده ≥ 1.04 و مرز ≥ 1.15، در هر دو تم.
  • روش اندازه‌گیری مرز: کف ≥ 1.15 روی رنگ مرز ترکیب‌شده با بوم است (آنچه آزمون سطوح حساب می‌کند). روی صفحه مرز روی پرکنندهٔ خودِ ظرف می‌نشیند و پیکسل روشن‌تر است: لبهٔ واقعی جدول در تم روشن بوم 245، مرز 234، داخل 255، یعنی 1.10 (Supabase Studio 1.09) و در تیره 1.28. نشاندن مرز روی بوم (background-clip: padding-box) روی جدول واقعی عکس شد: پیکسل مرز 205 (نسبت 1.46) چون سایهٔ کارت از زیر کادر مرزِ ترسیم‌نشده پیدا می‌شود؛ خط سنگین‌تر از Studio است و پذیرفته نشد. قاعدهٔ لبهٔ عکس‌برداری‌شده: ≥ 1.08 روشن (برابر Studio) و ≥ 1.15 تیره؛ توکن و آزمون سطوح عوض نمی‌شوند.
  • دو ظرف هم‌سطح کنار هم (جدول و نمودارش) یک پرکننده دارند؛ یکی توخالی و دیگری پر ممنوع.
  • یک پلهٔ «روشن‌تر» (surface-300) به‌عنوان ذخیره هست و فقط با عکس قبل/بعد روی صفحهٔ واقعی تصمیم‌گیری می‌شود، نه با عدد. تراکم ردیف جدول (40/44) هم تا آزمون واقعی دست نمی‌خورد.

جدول تصمیم: چه چیزی روی کدام لایه

محتوالایهکامپوننتممنوع
عنوان صفحه، توضیح، نوار ابزار، عنوان بخشL0 بوم، بی‌قابقالبقاب یا پرکننده دورش
جدول فهرستL1 (ظرف خودش)DataTable، فرزند مستقیم ListPageDataTable داخل Card؛ Table خام
جدول کوچک در بخش یا کارتL1Card + TableTable مستقیم روی PageSection یا بوم
نمودارL1ChartCard / DashboardChartنمودار بی‌ظرف
شاخصL1MetricCard، فقط شمارندهٔ عمل‌پذیر یا مقایسه‌دارکارت پرکننده؛ شبکهٔ یتیم
فرم یا گروه تنظیماتL1SettingsSection، FormPageفرم‌ردیف‌های آزاد روی بوم
نخ نظر، timeline، key-valueL1DetailSection (سطح خودکار) یا Cardمتن آزاد روی بوم
سایدبار فیلتر (ستون دوم قاب)کروم ستون، بی ظرفfilterPanel قالب، FilterPanelپنل کارت‌شکل کنار جدول (منسوخ)
بخشی درون ظرف (hover، انتخاب، حفره)L2bg-surface-200 بدون مرز، SeparatorCard در Card
حالت خالیL1 خط‌چینEmpty، pageStateقاب توپُر
Dialog، Sheet، PopoverL3کامپوننت‌های DS—
هر چیز بیرون این جدول—npx --no parto-ui gap addکلاس خام bg-* روی بلوک صفحه

تنها استثنا: Data Grid تمام‌عرض (جدول لبه‌به‌لبه در CustomPage layout="fill") که قابش را نوار ابزار و فوترِ خودش می‌سازد. جدول‌های معمول صفحه همیشه ظرف دارند.

مرز، شعاع، سایه، فاصله

موردقاعده
border کاملقاب یک L1
border-muted افقیجداکنندهٔ درون یک L1 (سربرگ کارت، ردیف جدول)
border-b / border-eجدا کردن chrome از محتوا
border-strongکنترل‌ها (ورودی، دکمهٔ ثانویه)
border-dashedفقط حالت خالی یا خاموش
شعاعسه تا: rounded-lg ظرف، rounded-md کنترل، rounded-full فقط آواتار و برچسب
سایهshadow-sm روی L1، shadow-lg روی L3؛ هیچ سایهٔ دیگری
فاصلهاز توکن‌های --layout-*: 48 بین بخش‌ها، 24 بین بلوک‌ها، 16 فاصلهٔ ابزار و padding کارت، 8 بین کنترل‌ها

ممنوع: مرز دور متنِ تنها، دو مرز تودرتو، border-2 روی بلوک، مرز بدون پرکننده روی بلوک داده، پرکننده بدون مرز روی ظرف.

کالبد بخش و صفحه

[عنوان بخش  heading 18/600]            [اکشن‌های بخش]        ← L0
[توضیح یک‌خطی، رنگ lighter]                                    ← L0
┌───────────────────────────────────────────┐
│ L1: محتوا (جدول / نمودار / فرم / نخ)      │  پرکننده + مرز + شعاع + سایه
└───────────────────────────────────────────┘
فاصلهٔ 48 تا بخش بعد
  • همهٔ قالب‌ها: حداکثر دو لایه (تب، نوار منبع، نوار ابزار، نوار خلاصه، نوار هشدار) بین عنوان صفحه و اولین ردیف داده.
  • ListPage: عنوان و یک اکشن اصلی ← یک ردیف ابزار (جست‌وجو، حداکثر 3 فیلتر پرتکرار، «فیلتر بیشتر»؛ حداکثر 8 کنترل) ← DataTable. فیلتر زیاد: ستون فیلتر قاب. شمارندهٔ وضعیت‌ها جزو تب‌هاست، نه کارت پرکننده. پست‌ها: فید کارت.
  • DashboardPage: عنوان و بازهٔ تاریخ ← یک ردیف 3 تا 4 شاخص عمل‌پذیر یا مقایسه‌دار ← DashboardSectionها با DashboardChart ← جدول «نیازمند اقدام». عرض wide.
  • DetailPage: سربرگ هویت ← تب (بیش از 3 بخش) ← DetailSectionها: عنوان روی بوم، محتوا در L1. ستون کناری هم L1.
  • SettingsPage / FormPage: عرض narrow؛ هر گروه یک SettingsSection با ذخیرهٔ خودش؛ FormPage یک L1 و یک ذخیره.
  • صفحهٔ جست‌وجو (ListPage query): ردیف جست‌وجو و فیلترهای پرتکرار در یک ردیف؛ شمار نتایج در سربرگ نتایج؛ فقط یک منبع.

قوانین اجباری

ده جفت، هر کدام دو رندر واقعی روی بوم صفحه؛ نیمهٔ «نادرست» اشتباه را عمداً مرتکب می‌شود. اگر پنل در تم تیره همرنگ بوم دیده شد، تم را عوض کنید و دوباره نگاه کنید.

G1 و G2: جدول روی ظرف می‌نشیند

Table خام ظرف ندارد: ردیف‌هایش در تم تیره دقیقاً رنگ بوم‌اند و در تم روشن فقط یک نوار بی‌حاشیه می‌بینید.

اکانتمنشنوضعیت
فروشگاه آفتاب1,240فعال
کافه نارنج860فعال
نشر پرتو415متوقف
درست — Card + Table (یا در فهرست، DataTable که خودش ظرف دارد)
اکانتمنشنوضعیت
فروشگاه آفتاب1,240فعال
کافه نارنج860فعال
نشر پرتو415متوقف
نادرست — Table مستقیم روی بوم: ردیف‌ها و بوم یک رنگ‌اند

G4: قاب در قاب ممنوع

داخل یک ظرف فقط L2 (بدون مرز) یا یک خط مجاز است. DataTable هرگز داخل Card نمی‌رود و Table خام همیشه می‌رود.

خلاصهٔ هفته

یادداشت: 3 منشن نیازمند پاسخ است.
درست — حفرهٔ بدون مرز (bg-surface-200) داخل ظرف

خلاصهٔ هفته

یادداشت: 3 منشن نیازمند پاسخ است.
نادرست — ظرف داخل ظرف: دو مرز، دو سایه، شلوغی

G2 و G3: بلوک توخالی نه

bg-background، bg-transparent، bg-sidebar و bg-alternative رنگ خود بوم‌اند؛ پوستهٔ بلوک نیستند.

پیشنهاد هفته

زمان ارسال را به 18 تا 20 ببرید.

درست — Card: پرکننده + مرز + شعاع + سایه

پیشنهاد هفته

زمان ارسال را به 18 تا 20 ببرید.

نادرست — مرز و شعاع روی رنگ بوم: در تم تیره توخالی است

G1: فرم تعاملی روی ظرف

هر گروه فرم یک ظرف با دکمهٔ «ذخیره»ٔ خودش است (SettingsSection، FormPage).

نام کمپین
ایمیل گزارش
درست — گروه فرم در یک ظرف، ذخیره در انتهای همان ظرف
نام کمپین
ایمیل گزارش
نادرست — ورودی‌ها و دکمه آزاد روی بوم

G14: شبکهٔ شاخص بدون یتیم

5 تا 6 کارت در ردیف‌های سه‌تایی، 7 تا 8 در چهارتایی؛ ردیف آخر هرگز یک کارت تنها یا نیمه‌خالی نیست. شبکهٔ شاخص قالب‌ها (kpis، summary) این را خودکار از شمار کارت‌ها می‌سازد.

منشن‌ها12,480
نرخ تعامل4.6%
دیدگاه مثبت68%
منفی1,320
نیازمند اقدام23
درست — 5 کارت: 3 + 2 با دو کارت پهن‌تر در ردیف آخر
منشن‌ها12,480
نرخ تعامل4.6%
دیدگاه مثبت68%
منفی1,320
نیازمند اقدام23
نادرست — 4 + 1: یک کارت یتیم در ردیف دوم

G15: ستون فیلتر، دو گروه پرتکرار باز

گروه‌های پرتکرار باز، بقیه بسته با خلاصهٔ فعالِ آشکار («2 فعال»)؛ ستون دوم فقط یک نقش دارد: فیلتر.

فیلترها
پلتفرم−
احساس−
نوع محتوا+
زبان+
کشور+
بازهٔ فعالیت+
درست — دو گروه باز، چهار گروه بسته، فعال‌ها دیده می‌شوند
فیلترها
پلتفرم−
احساس−
نوع محتوا−
زبان−
کشور−
بازهٔ فعالیت−
نادرست — شش گروه باز: ستون بلندتر از صفحه و فیلتر فعال گم می‌شود

G11 و G12: لایه‌های پیش از داده

حداکثر دو لایه (تب، نوار منبع، نوار ابزار، خلاصه، هشدار) بین عنوان صفحه و اولین ردیف داده؛ یک ردیف ابزار با حداکثر 8 کنترل.

تب‌ها با شمار هر وضعیتلایه 1
یک ردیف ابزار: جست‌وجو و فیلترهالایه 2
اکانتمنشنوضعیت
فروشگاه آفتاب1,240فعال
کافه نارنج860فعال
نشر پرتو415متوقف
درست — تب با شمار ← یک ردیف ابزار ← جدول
تب‌هالایه 1
نوار منبعلایه 2
شش کارت شاخصلایه 3
راهنمای رنگلایه 4
فیلترهالایه 5
نوار ابزارلایه 6
… و بعد، اولین ردیف داده
نادرست — شش لایه پیش از اولین ردیف داده

G13: یک اطلاعات، یک شکل

شمار هر وضعیت یا در تب است یا در کارت یا در فیلتر، نه چند جا.

در حال اجرا · 12متوقف · 3خطا · 1
اکانتمنشنوضعیت
فروشگاه آفتاب1,240فعال
کافه نارنج860فعال
نشر پرتو415متوقف
درست — شمار وضعیت‌ها فقط در تب
در حال اجرا · 12متوقف · 3
در حال اجرا12
متوقف3
خطا1
راهنما: ● در حال اجرا (12) ● متوقف (3) ● خطا (1)
فیلتر وضعیت: در حال اجرا (12)، متوقف (3)
نادرست — همان «12» در تب، کارت، راهنمای رنگ و فیلتر

G10: رنگ فقط برای وضعیت

یک رنگ برند؛ رنگ معنایی فقط برای وضعیت و حداکثر 4 رنگ معنایی در یک صفحه‌نمایش؛ ابر کلمات تک‌رنگ با شدت.

برندتخفیفارسالبسته‌بندیکیفیتقیمتپشتیبانیتجربه
درست — یک رنگ برند، شدت از روشنی و اندازه
برندتخفیفارسالبسته‌بندیکیفیتقیمتپشتیبانیتجربه
نادرست — پنج رنگ معنایی برای تزئین؛ معنایشان از دست می‌رود

G19: مهاجرت یعنی بازطراحی

پیش از لمس هر صفحه سه پرسش را در MR جواب بدهید (کار صفحه و کاربرش، بخش تکراری، نزدیک‌ترین نمای Studio) و DS را پیش از قضاوت بصری به آخرین major ببرید. جایگزینی قالب با همان بخش‌ها و همان ترتیب ناقص است.

کار صفحه: «کدام اکانت امروز اقدام می‌خواهد؟»
تب‌ها با شمار ← یک ردیف ابزار
اکانتمنشنوضعیت
فروشگاه آفتاب1,240فعال
کافه نارنج860فعال
نشر پرتو415متوقف

سه پرسش پاسخ داده شد؛ تکرارها حذف شد؛ الگو: نمای فهرست Studio.

درست — کار صفحه روشن، تکرار حذف، الگوی Studio
فاز 2 · خلاصه · راهنما · تحلیل · عملیات
همان پنج بخش، همان ترتیب
فقط PageShell به ListPage عوض شد

«فقط تم»: همان چیدمان با رنگ تازه (درجهٔ 1 تا 3).

نادرست — فقط تم یا قالب عوض شده: درجهٔ 1 تا 3

موارد استفاده رایج

جدول کوچک در یک بخش

import { Card, Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@partodata/ui'

export function Accounts() {
  return (
    <Card>
      <Table>
        <TableHeader>
          <TableRow>
            <TableHead>اکانت</TableHead>
            <TableHead>منشن</TableHead>
          </TableRow>
        </TableHeader>
        <TableBody>
          <TableRow>
            <TableCell>فروشگاه آفتاب</TableCell>
            <TableCell>1,240</TableCell>
          </TableRow>
        </TableBody>
      </Table>
    </Card>
  )
}

بخش جزئیات با محتوای آزاد

DetailSection محتوایی را که خودش سطح ندارد (نخ نظر، timeline، key-value، Table خام، پست با layout="row") خودکار در یک ظرف L1 می‌گذارد؛ محتوایی که خودش سطح است (DataTable، ChartCard، Card، پست کارتی) را دوبار قاب نمی‌گیرد. برای محتوای سفارشی که سطح خودش را می‌کشد surface="none" بدهید.

چه چیزی خودکار بررسی می‌شود

  • lint: parto/surface-for-blocks (جدول یا نمودار مستقیم در PageSection و مانند آن)، parto/no-hollow-surface (بلوک مرزدار و دارای padding روی رنگ بوم)، parto/no-card-in-card (ظرف در ظرف، DataTable در Card). هر سه در 7.2 در سطح warn هستند و پس از baseline محصولات error می‌شوند.
  • کنسول توسعه: Table خام یا نمودار روی بوم، و ظرف در ظرف، یک‌بار هشدار می‌دهند. هر ظرف نشانهٔ data-surface دارد؛ Dialog، Sheet و Popover نشانهٔ overlay دارند و تودرتویی را از نو شروع می‌کنند. کامپوننت سفارشی که سطح خودش را می‌کشد، روی ریشه‌اش data-surface="none" می‌گذارد.
  • آزمون سطوح در مخزن DS: در هر دو تم، پرکنندهٔ هر ظرف ≥ 1.04 و مرز ≥ 1.15، صفر ظرف تودرتو، صفر بلوک بی‌ظرف.

چه نکنیم

این فهرست هم «پیش‌فرض قوی» است، نه قانون مطلق: انحراف با دلیل و یک خط در MR (بالا) مجاز است؛ بی‌صدا نه.

  • توکن‌های سطح و مرز را برای «جداتر دیده شدن» روشن‌تر یا تیره‌تر نکنید؛ ظرف را به کار ببرید.
  • پیش‌فرض DS (تراکم جدول، سایه، شعاع) را برای رسیدن به یک عدد عوض نکنید.
  • برای نبودن کامپوننت مناسب، جایگزین زورکی نسازید: npx --no parto-ui gap add.
  • کارت شاخص را برای پر کردن شبکه نسازید و بیش از 4 رنگ معنایی در یک صفحه نیاورید.
  • متن راهنمای بلندتر از دو خط را داخل صفحه نگذارید: Popover یا Callout قابل‌جمع.
  • هر کارت یک عنوان و حداکثر یک پیوند عمیق کوچک؛ نه چند دکمهٔ ghost.

قاعده‌های G1 تا G20 (فهرست فشرده)

همهٔ این بیست قاعده «پیش‌فرض قوی» هستند (دستهٔ دوم بالا)؛ دستهٔ سخت جدا و بدون انحراف است.

#قاعده
G1هر بلوک داده، فرم تعاملی، نمودار و نخ روی L1 است؛ فقط Data Grid تمام‌عرض استثناست.
G2L1 = surface-100 + border + rounded-lg + shadow-sm، هر چهار با هم.
G3توکن‌های سطح عوض نمی‌شوند؛ bg-background، bg-transparent، bg-sidebar، bg-dash-sidebar و bg-alternative پوستهٔ بلوک نیستند.
G4قاب در قاب ممنوع؛ DataTable هرگز داخل Card، Table خام همیشه داخل Card.
G5عنوان، توضیح و نوار ابزار روی بوم بدون قاب؛ محتوا روی L1.
G6خط فقط برای قاب L1، جداکنندهٔ درون L1، کنترل، chrome و خط‌چین خالی؛ دور متنِ تنها نه.
G7سه شعاع (lg ظرف، md کنترل، full آواتار/برچسب)؛ سایه فقط sm روی L1 و lg روی L3.
G8فاصله فقط 48 / 24 / 16 / 8 از توکن‌های --layout-*.
G9تراکم و تایپ پیش‌فرض DS (هدر 40، ردیف 44)، نقش‌های متن، یک وزن عنوان 600، تأکید ≤ 500.
G10یک رنگ برند؛ رنگ معنایی فقط وضعیت؛ ≤ 4 رنگ معنایی در صفحه‌نمایش.
G11حداکثر دو لایه بین عنوان صفحه و اولین ردیف داده.
G12یک ردیف ابزار، حداکثر 8 کنترل، یک اکشن اصلی در هر ناحیه.
G13یک اطلاعات، یک شکل.
G14کارت شاخص فقط برای شمارندهٔ عمل‌پذیر یا مقایسه‌دار؛ شبکهٔ شاخص بدون یتیم.
G15ستون فیلتر: دو گروه پرتکرار باز، بقیه بسته با خلاصهٔ فعالِ آشکار؛ ستون دوم یک نقش دارد.
G16عرض ثابت درون خانوادهٔ صفحه (فهرست default، داشبورد wide، فرم narrow) و فقط از قالب.
G17متن راهنمای بلندتر از دو خط در صفحه نیاید: Popover یا Callout قابل‌جمع.
G18هر کارت یک عنوان و حداکثر یک پیوند عمیق.
G19مهاجرت = بازطراحی: سه پرسش در MR، ارتقای DS پیش از قضاوت بصری؛ «فقط تم» ناقص است.
G20تأیید با عکس هر دو تم و آزمون سطوح؛ پیش‌فرض DS برای رسیدن به یک عدد عوض نمی‌شود.

صفحات مرتبط