گرامر بصری
هر بلوک روی یک ظرف، هر صفحه با لایهٔ کم — لایههای سطح، جدول تصمیم، سقفهای صفحهٔ آرام و دروازهٔ بازطراحی
پیشفرض قوی، نه قانون مطلق
گرامر بصری پیشفرض قوی است، نه قانون مطلق. قاعدهها یکسان نیستند:
- سخت (بدون تأیید مالک هرگز نقض نمیشود): دسترسیپذیری؛ فقط توکن، بدون رنگ یا اندازهٔ خام؛ درستی RTL؛ رقم ASCII در DOM با نمایش فارسی از فونت؛ گمنشدن جریان کاربر، داده یا قاعدهٔ ایمنی هنگام بازطراحی؛ هیچ راز یا توکنی در کد.
- پیشفرض قوی (
G1…G20: چیدمان، سطح، تراکم، تایپوگرافی): مگر دلیل طراحیِ مشخصی باشد، همینها را دنبال کنید. نتیجهٔ روی صفحه در هر دو تم و داوری مالک از هر قاعده بالاتر است.
پروتکل انحراف، اگر منحرف میشوید:
-
در MR، PR یا کامیت یک خط بنویسید (چنین):
Grammar deviation: G4 — <reason> -
انحراف را محلی نگه دارید (همین بلوک، همین صفحه)، نه پیشفرض تازه.
-
هرگز بیصدا از قاعده نگذرید و برای قبولشدن صفحه، قاعده، لینت یا توکن را ویرایش نکنید.
-
اگر همان انحراف دوبار لازم شد، قاعده یا 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 کنارشان.
تم تیره
تم روشن
| پله | کف مجاز | تیره: ما (زنده) | تیره: 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، فرزند مستقیم ListPage | DataTable داخل Card؛ Table خام |
| جدول کوچک در بخش یا کارت | L1 | Card + Table | Table مستقیم روی PageSection یا بوم |
| نمودار | L1 | ChartCard / DashboardChart | نمودار بیظرف |
| شاخص | L1 | MetricCard، فقط شمارندهٔ عملپذیر یا مقایسهدار | کارت پرکننده؛ شبکهٔ یتیم |
| فرم یا گروه تنظیمات | L1 | SettingsSection، FormPage | فرمردیفهای آزاد روی بوم |
| نخ نظر، timeline، key-value | L1 | DetailSection (سطح خودکار) یا Card | متن آزاد روی بوم |
| سایدبار فیلتر (ستون دوم قاب) | کروم ستون، بی ظرف | filterPanel قالب، FilterPanel | پنل کارتشکل کنار جدول (منسوخ) |
| بخشی درون ظرف (hover، انتخاب، حفره) | L2 | bg-surface-200 بدون مرز، Separator | Card در Card |
| حالت خالی | L1 خطچین | Empty، pageState | قاب توپُر |
| Dialog، Sheet، Popover | L3 | کامپوننتهای 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 | متوقف |
| اکانت | منشن | وضعیت |
|---|---|---|
| فروشگاه آفتاب | 1,240 | فعال |
| کافه نارنج | 860 | فعال |
| نشر پرتو | 415 | متوقف |
G4: قاب در قاب ممنوع
داخل یک ظرف فقط L2 (بدون مرز) یا یک خط مجاز است. DataTable هرگز داخل Card نمیرود و Table خام همیشه میرود.
خلاصهٔ هفته
خلاصهٔ هفته
G2 و G3: بلوک توخالی نه
bg-background، bg-transparent، bg-sidebar و bg-alternative رنگ خود بوماند؛ پوستهٔ بلوک نیستند.
پیشنهاد هفته
زمان ارسال را به 18 تا 20 ببرید.
پیشنهاد هفته
زمان ارسال را به 18 تا 20 ببرید.
G1: فرم تعاملی روی ظرف
هر گروه فرم یک ظرف با دکمهٔ «ذخیره»ٔ خودش است (SettingsSection، FormPage).
G14: شبکهٔ شاخص بدون یتیم
5 تا 6 کارت در ردیفهای سهتایی، 7 تا 8 در چهارتایی؛ ردیف آخر هرگز یک کارت تنها یا نیمهخالی نیست. شبکهٔ شاخص
قالبها (kpis، summary) این را خودکار از شمار کارتها میسازد.
G15: ستون فیلتر، دو گروه پرتکرار باز
گروههای پرتکرار باز، بقیه بسته با خلاصهٔ فعالِ آشکار («2 فعال»)؛ ستون دوم فقط یک نقش دارد: فیلتر.
G11 و G12: لایههای پیش از داده
حداکثر دو لایه (تب، نوار منبع، نوار ابزار، خلاصه، هشدار) بین عنوان صفحه و اولین ردیف داده؛ یک ردیف ابزار با حداکثر 8 کنترل.
| اکانت | منشن | وضعیت |
|---|---|---|
| فروشگاه آفتاب | 1,240 | فعال |
| کافه نارنج | 860 | فعال |
| نشر پرتو | 415 | متوقف |
G13: یک اطلاعات، یک شکل
شمار هر وضعیت یا در تب است یا در کارت یا در فیلتر، نه چند جا.
| اکانت | منشن | وضعیت |
|---|---|---|
| فروشگاه آفتاب | 1,240 | فعال |
| کافه نارنج | 860 | فعال |
| نشر پرتو | 415 | متوقف |
G10: رنگ فقط برای وضعیت
یک رنگ برند؛ رنگ معنایی فقط برای وضعیت و حداکثر 4 رنگ معنایی در یک صفحهنمایش؛ ابر کلمات تکرنگ با شدت.
G19: مهاجرت یعنی بازطراحی
پیش از لمس هر صفحه سه پرسش را در MR جواب بدهید (کار صفحه و کاربرش، بخش تکراری، نزدیکترین نمای Studio) و DS را پیش از قضاوت بصری به آخرین major ببرید. جایگزینی قالب با همان بخشها و همان ترتیب ناقص است.
| اکانت | منشن | وضعیت |
|---|---|---|
| فروشگاه آفتاب | 1,240 | فعال |
| کافه نارنج | 860 | فعال |
| نشر پرتو | 415 | متوقف |
سه پرسش پاسخ داده شد؛ تکرارها حذف شد؛ الگو: نمای فهرست Studio.
«فقط تم»: همان چیدمان با رنگ تازه (درجهٔ 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 تمامعرض استثناست. |
| G2 | L1 = 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 برای رسیدن به یک عدد عوض نمیشود. |
صفحات مرتبط
- رنگها: توکنهای سطح (
surface-100،canvas) و نقش هر کدام. - عمق، گوشه و لایهبندی: سایه، شعاع و z-index.
- هندسهٔ صفحه: عرض قالبها و ریتم فاصله.
- Table و DataTable: جدول خام در
Card،DataTableبا ظرف خودش.