Adopt ant-design-vue and a shared antdTheme for leads, pipeline, invoices, and shared form controls under strict single-page governance. Co-authored-by: Cursor <cursoragent@cursor.com>
12 KiB
وضعیت دیزاینسیستم منتکت (Montact CRM)
سند audit وضعیت واقعی لایهٔ UI در apps/web — نه آرزو، نه Figma.
آخرین بهروزرسانی: ۲۶ مهر ۱۴۰۵
راهنما:
- آماده = در کد وجود دارد و بهطور منسجم قابل اتکا است
- نیمهآماده = وجود دارد ولی پوشش/انضباط ناقص است
- نیست = در کدبیس پیاده نشده
خلاصهٔ اجرایی
دیزاینسیستم منتکت نیمهآماده / در حال رشد است: توکنهای CSS، کلاسهای الگوی crm-*، و یک کیت داخلی ۱۸تایی Ui* وجود دارد؛ اما API دوگانهٔ لگسی (.btn / .field)، hardcode گستردهٔ رنگ و فاصله در scoped CSS، نبود Storybook، و نبود چند primitive پرکاربرد مانع «سیستم واقعی» است.
| معیار | مقدار |
|---|---|
| امتیاز کلی آمادگی | حدود ۵۰٪ (بازهٔ واقعبینانه ۴۵–۵۵٪) |
| استک UI | Vue 3 SFC + Composition API — بدون Tailwind / UI kit شخصثالث |
primitives Ui* |
۱۸ کامپوننت + barrel |
| adoption مستقیم در views | ۵۲ از ۷۶ (~۶۸٪) |
| تم تاریک / چندتم | نیست |
| کاتالوگ زنده (Storybook و مشابه) | نیست |
حکم یکخطی: زبان بصری teal + RTL برای CRM شکل گرفته؛ انضباط و پوشش کامپوننت هنوز به سطح design system کامل نرسیده.
استک و مرز سیستم
tokens (main.css :root)
↓
utilities / patterns (tokens.css → .crm-*)
↓
primitives (components/ui/Ui*)
↓
domain composites (pipeline/, gamification/, nav/, …)
↓
views + layouts
| لایه | مسیر | نقش |
|---|---|---|
| تعریف توکنها | apps/web/src/styles/main.css |
:root — رنگ، تایپو، فاصله، سایه، z-index، کنترلها؛ همچنین استایل لگسی .btn / .field |
| الگوهای CRM | apps/web/src/styles/tokens.css |
utilityهای .crm-page, .crm-card, .crm-toolbar, … (نام فایل «tokens» است؛ تعریف توکن اینجا نیست) |
| فونت | apps/web/src/styles/fonts.css |
IRANSans FaNum خودمیزبان |
| کیت UI | apps/web/src/components/ui/ |
۱۸ SFC + index.ts |
| آیکن | apps/web/src/components/UiIcon.vue |
بیرون از barrel ui/ |
| شِل اپ | layouts/AppLayout.vue، layouts/AdmLayout.vue |
سایدبار + workspace / ادمین پلتفرم |
وابستگیهای UI در package.json وب: فقط Vue، Vue Router، Pinia، Axios، ECharts / vue-echarts، xlsx. هیچ Element Plus / Vuetify / Naive / Headless / Tailwind نیست.
ماتریس آمادگی
| لایه | وضعیت | توضیح کوتاه |
|---|---|---|
| توکن رنگ / تایپو / فاصله / سایه | آماده | پالت teal روی slate؛ scale فونت و spacing و shadow تعریف شده |
| مقیاس radius | نیمهآماده | همهٔ --radius-* (جز full) روی ۱۰px قفلاند — سلسلهمراتب واقعی نیست |
| spacing کامل | نیمهآماده | --sp-1…6 و 8 و 10؛ --sp-7 / --sp-9 نیست |
الگوی صفحه crm-* |
نیمهآماده | مجموعهٔ خوب برای page/header/card/table/form؛ adoption ناقص |
primitives Ui* |
نیمهآماده | ۱۸ قطعهٔ کاربردی؛ چند کنترل پایهٔ فرم/فیدبک غایب |
آیکن UiIcon |
آماده | ~۷۰ آیکن stroke، currentColor، بدون پکیج خارجی |
| Layout اپ / ادمین | آماده | شِل دسکتاپ + موبایل tabbar؛ ادم جدا |
| RTL + IRANSans + جلالی | آماده | dir="rtl"، فونت فارسی، lib/jalali.ts، ارقام فارسی |
| Dark mode / multi-theme | نیست | فقط تم روشن |
| Storybook / Histoire / playground | نیست | اسکریپت lint وب هم placeholder است |
Checkbox / Switch / Tabs / Toast / Tooltip / Table / DatePicker بهعنوان Ui* |
نیست | معادلها اغلب ad-hoc یا دامنهٔ خاص (JalaliDateInput و …) |
| vue-i18n | نیست | متنها فارسی hardcode در template |
| lint / اجبار توکن (منع hex خام) | نیست | رنگ و rem زیاد در scoped CSS تکرار شده |
توکنها (آنچه واقعاً هست)
تعریف در :root داخل main.css:
| دسته | نمونه |
|---|---|
| سطح | --bg, --surface, --surface-subtle, --surface-hover |
| متن / خط | --ink, --ink-secondary, --muted, --line, … |
| accent | --accent (#14b8a6) و hover/deep/soft/subtle/contrast |
| معنایی | --danger, --success, --warning, --info (+ soft/deep) |
| تایپو | --fs-xs…--fs-3xl, --fw-*, --lh-*, --font |
| فاصله | --sp-1…--sp-6, --sp-8, --sp-10 |
| کنترل | --control-h-sm/h/md/lg, --pad-modal |
| سایه / حرکت / z | --shadow-*, --transition-*, --z-dropdown…--z-toast |
| alias لگسی | --color-primary, --color-text, --color-border, … |
ضعفها: radius تخت؛ --fw-extrabold برابر bold؛ توکنهای محلی در AppLayout (مثل --sidebar-card) بیرون از :root سراسری؛ CHART_PALETTE در UiChart تا حدی جدا از توکنها.
کاتالوگ کامپوننتهای Ui*
منبع: barrel components/ui/index.ts.
| کامپوننت | نقش |
|---|---|
UiButton |
دکمه — variant / size / loading / block |
UiInput |
ورودی متن — defineModel، prefix/suffix |
UiTextarea |
متن چندخطی |
UiSelect |
select بومی با slot برای <option> |
UiField |
برچسب + hint + error دور کنترل |
UiCard |
کارت با header / actions / footer |
UiModal |
مودال + قفل اسکرول body |
UiDrawer |
کشو از کنار |
UiBusyOverlay |
پوشش busy / progress |
UiPageHeader |
عنوان صفحه + lead + actions + back |
UiBadge |
نشان وضعیت |
UiPagination |
صفحهبندی + page size |
UiEmptyState |
حالت خالی |
UiSearch |
جستجوی ساده |
UiFilterBar |
نوار جستجو + پنل فیلتر |
UiSegmented |
کنترل segmented |
UiChart |
ECharts + CHART_PALETTE |
UiDropdownMenu |
منوی کشویی با trigger slot |
مرتبط ولی خارج از barrel: UiIcon.vue.
domain composites (دیزاینسیستم نیستند): پوشههایی مثل pipeline/, gamification/, dashboard/, routines/, nav/, person-profile/ — ترکیب ویژگیمحور روی primitives یا استایل محلی.
پترنهای UI واقعی در پروژه
۱) الگوی ترجیحی (هدف فعلی)
import { UiButton, UiModal, UiPageHeader } from '@/components/ui';
صفحه با .crm-page + UiPageHeader / UiFilterBar / UiCard / جدول .crm-table*.
۲) الگوی موازی / لگسی
- کلاسهای سراسری
.btn,.btn-ghost,.fieldدرmain.css <button>/<input>خام + scoped CSS در viewهای قدیمیتر یا خاص (Login، Notes، adm، …)- import مستقیم فایل بهجای barrel در بعضی viewها (
import UiButton from '@/components/ui/UiButton.vue')
۳) الگوی غیرمستقیم
بعضی viewها خودشان ui/ را import نمیکنند ولی childها میکنند (مثلاً HomeView → components/dashboard/* → UiChart / UiButton).
لایهبندی مفهومی
flowchart TB
tokens[CSS_tokens_main_css]
utils[crm_utilities_tokens_css]
ui[Ui_primitives]
domain[Domain_composites]
views[Views_and_Layouts]
legacy[Legacy_btn_field]
tokens --> utils
tokens --> ui
utils --> views
ui --> domain
ui --> views
domain --> views
legacy --> views
Adoption کمی (views)
| متریک | عدد |
|---|---|
کل viewهای apps/web/src/views |
۷۶ |
view با import مستقیم از components/ui |
۵۲ (~۶۸٪) |
| view بدون import مستقیم | ۲۴ (~۳۲٪) |
بدون import مستقیم ui/ (ممکن است از child یا لگسی استفاده کنند)
ActivitiesCalendarView,ActivityDetailViewadm/AdmAdminsView,AdmBillingPanel,AdmDashboardView,AdmLoginView,AdmOrganizationsView,AdmUsersViewAttachmentsView,ConversationsViewgamification/GamificationView,GamificationAdminViewHomeView,InvoiceFormView,LeadFormPublicViewLoginView,NotesView,PersonProfileView,PortalView,ProfileViewProjectCardFormView,QuoteFormView,QuotesView,RegisterView
نکتهٔ کیفیت: حتی viewهایی که Ui* دارند اغلب هنوز hex/rem محلی در <style scoped> دارند؛ adoption کامپوننت ≠ انضباط توکن.
ساختار پوشهٔ components/ (خلاصه)
components/
├── ui/ ← primitives + index.ts (تنها barrel)
├── UiIcon.vue ← آیکن مشترک
├── activities|auth|automations|brand|dashboard|
│ gamification|nav|person-*|pipeline|routines|…
└── *.vue ← ورودیهای متقاطع (JalaliDateInput, MoneyInput, …)
الگوی غالب: Composition API با <script setup lang="ts">؛ استایل scoped روی کامپوننت + مصرف var(--…).
شکافها و اولویت پیشنهادی
ترتیب پیشنهادی برای نزدیکشدن به design system واقعی (فقط نقشه — خارج از scope این سند):
- یک API برای دکمه/فرم — مهاجرت تدریجی از
.btn/.fieldبهUiButton/UiField+ حذف یا thin-wrapper کردن لگسی - تکمیل primitives پرکاربرد — حداقل Toast، Tabs، Checkbox/Switch، Table (یا wrapper روی الگوی
.crm-table) - اجبار توکن — جایگزینی تدریجی hex تکراری با
var(--…)؛ در حد ممکن rule/lint - کاتالوگ زنده — Storybook / Histoire یا یک صفحهٔ داخلی فقط برای
Ui* - تم — فقط اگر محصول dark/multi-brand میخواهد؛ فعلاً پیشنیاز انضباط توکن است
چکلیست «آیا design system هستیم؟»
| قابلیت | وضعیت |
|---|---|
| توکنهای مشترک | بله |
| لایهٔ الگوی صفحه | بله (ناقص) |
| کیت primitive داخلی | بله (ناقص) |
| آیکن یکپارچه | بله |
| شِل و RTL فارسی | بله |
| پوشش اکثر صفحات | نسبتاً بله (~۶۸٪ مستقیم) |
| یک منبع حقیقت بدون لگسی موازی | خیر |
| مستند/کاتالوگ زنده | خیر |
| تم / i18n / lint توکن | خیر |
جمعبندی: پروژه یک design language + UI kit در حال رشد دارد، نه یک design system کامل و منضبط. برای کار روزمرهٔ فیچر کافی است؛ برای اسکیل بدون drift بصری، اولویتهای ۱–۴ بالا ضروریاند. )