style(admin): align color tokens to Figma purple (#5559CE)
Set primary to tauri purple, bg #fafafa/#1f1d2b, dark surface #222433, text #D7D8ED/#A1A1A1. Sync sRGB fallbacks and @supports oklch block. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
# همسانسازی کامل UI پنل ادمین clinicpro با فیگما (زبان طراحی clinic-pro-tauri)
|
||||
|
||||
## پروژه
|
||||
|
||||
`clinicpro` — فقط لایهی frontend پنل ادمین (`assets/admin/`). بدون تغییر backend/API. تسک صرفاً بصری است: توکنهای طراحی + کامپوننتهای مشترک + layout هر صفحه.
|
||||
|
||||
## هدف کلی
|
||||
|
||||
**همهی صفحات پنل ادمین clinicpro باید ظاهر و زبان طراحیِ این فیگما را داشته باشند** — همان رنگها، تایپوگرافی، کارتها، جدولها، فرمها، badgeها، سایدبار/هدر، و الگوهای موبایل (bottom sheet، منوی پایین). clinic-pro-tauri پیادهسازی مرجعِ همین طراحی است؛ هرجا فیگما و tauri همخوان بودند از همان مقادیر استفاده کن.
|
||||
|
||||
**فیگما:** `https://www.figma.com/design/76Z5FkibRdsMRisqPTIXKU/nobat724?node-id=3598-18842`
|
||||
- `fileKey = 76Z5FkibRdsMRisqPTIXKU` — page: `Cover` — board: `3598:18842` (name «new version»، کل صفحات اینجاست)
|
||||
- ابزار: Figma MCP → `get_screenshot`, `get_variable_defs`, `get_metadata` روی **node-id هر فریم جداگانه** (بورد کامل ۴۹۸۳۳×۱۶۰۰۰ است، یکجا نگیر).
|
||||
|
||||
## معماری فعلی (مهم — قبل از شروع بخوان)
|
||||
|
||||
پنل ادمین clinicpro **از قبل یک design-system سفارشی کامل دارد** و تا حدی به سمت tauri رفته (کامنتهای `styles.css` صراحتاً «دقیقاً مطابق clinic-pro-tauri»):
|
||||
- استک: **Tailwind v4 + CSS variables**، نه MUI. **MUI را وارد نکن؛ معماری را عوض نکن.** فقط مقدار متغیرها و کلاسهای موجود را به مقادیر فیگما/tauri برسان.
|
||||
- فایل توکن/کامپوننت: `assets/admin/styles.css` (۸۳۱ خط) — کلاسهای `.cp-*` (کارت/input/button/stat/badge)، `.app/.sidebar/.topbar/.nav-item`، `.seg`, `.avatar`, `.modal`.
|
||||
- dark mode: کلاس `.dark` + `data-theme="dark"` روی `<html>` (در `AdminLayout.tsx` خطوط ۱۶–۲۲). عیناً مثل tauri؛ نگهدار.
|
||||
- RTL + فونت Vazirmatn از قبل درست است؛ دست نزن.
|
||||
|
||||
پس این تسک «بازنویسی از صفر» نیست؛ دو بخش است: **(الف)** یکبار توکن/کامپوننتهای مشترک را دقیق مطابق فیگما کن، **(ب)** بعد تکتک صفحات را با فریم فیگمای متناظر مقایسه و اصلاح کن.
|
||||
|
||||
---
|
||||
|
||||
## بخش الف — سیستم طراحی مشترک (یکبار، پایهی همهی صفحات)
|
||||
|
||||
فایل: `assets/admin/styles.css` + `stores/uiStore.ts` + `components/layout/*`.
|
||||
|
||||
### الف-۱. توکنهای رنگ (light + dark)
|
||||
|
||||
اختلاف فعلی با فیگما/tauri:
|
||||
|
||||
| توکن | فعلی clinicpro | هدف (tauri/فیگما) |
|
||||
|------|----------------|-------------------|
|
||||
| primary | oklch پویا `~#5457dd` | بنفش ثابت **`#5559CE`** (hover `#494CB3`، dark selected `#6B6FD6`) |
|
||||
| bg light | `#eef2f8` | **`#fafafa`** |
|
||||
| bg dark (body) | `#080d16` | **`#1f1d2b`** |
|
||||
| surface dark (سایدبار/هدر/کارت) | `#111a29` | **`#222433`** |
|
||||
| border dark | `#243042` | **`#343645`** (اغلب فریمها transparent) |
|
||||
| text dark | `#e9eef7` / `#9eb0c6` | **`#D7D8ED`** / **`#A1A1A1`** |
|
||||
|
||||
```css
|
||||
:root {
|
||||
--brand-h: 277; --brand-c: 0.14; /* تأیید با نمونهگیری #5559CE از get_variable_defs */
|
||||
--primary: #5559CE; --primary-600: #494CB3; --primary-700: #3E41A0;
|
||||
--bg: #fafafa; --bg-2: #f2f2f5; --surface: #ffffff;
|
||||
}
|
||||
[data-theme="dark"] {
|
||||
--bg: #1f1d2b; --bg-2: #1a1826;
|
||||
--surface: #222433; --surface-2: #2a2c3d; --surface-3: #313349;
|
||||
--border: #343645; --text: #D7D8ED; --text-2: #A1A1A1;
|
||||
--primary: #6B6FD6;
|
||||
}
|
||||
```
|
||||
> بلوک `@supports (color: color-mix(in oklch …))` (خطوط ۱۱۳–۱۳۹) هم primary/dark را از نو میسازد؛ **هم sRGB و هم oklch را هماهنگ کن** وگرنه مرورگر مدرن رنگ متفاوت میدهد. رنگهای status/stat-card را با `get_variable_defs` فیگما تأیید کن (accent نارنجی `#F17732`، سبز `#009D79`، amber `#FFC051` از قبل کپی شدهاند).
|
||||
|
||||
### الف-۲. سلکتور رنگ کاربر
|
||||
|
||||
primary فعلاً «قابلتعویض» است (`brandHue` در `uiStore` + سلکتور در `Topbar.tsx`). فیگما این را ندارد. **پیشفرض `brandHue` را روی بنفش بگذار**؛ سلکتور رنگ بماند اما default بنفش (اگر کارفرما تکرنگ میخواهد، بلوک سلکتور رنگ در `Topbar.tsx` خطوط ۱۱۶–۱۳۶ را حذف کن).
|
||||
|
||||
### الف-۳. ابعاد و رفتار layout
|
||||
|
||||
- عرض سایدبار: `--sidebar-w: 243px`، حالت جمع **`90px`** (بجای `252/76`). همهی `76px` هاردکدشده (`styles.css` خطوط ۳۱۳، ۳۲۶، ۷۱۵) → `90px`.
|
||||
- **hover-expand** سایدبار مثل tauri: در `data-collapsed="true"` روی `:hover` عرض به `243px` و برچسبها/`brand-text` دوباره ظاهر شوند (مرجع: `clinic-pro-tauri/src/components/layout/sidebar/index.jsx`، کلاس `hover-mode-sidebar`).
|
||||
- ارتفاع هدر ریسپانسیو مثل tauri (`56 → 67 → 79 → 90px`)؛ مقدار دقیق دسکتاپ را از فریم `header` فیگما بگیر.
|
||||
- border سایدبار/هدر در dark عملاً محو (`dark:border-transparent`).
|
||||
|
||||
### الف-۴. شعاعها و input/button
|
||||
|
||||
- input/select/textarea شعاع **8px** (tauri `mui.js`)؛ `--r-sm` را به `8px` ببر یا `--r-input: 8px` بساز و در `.cp-input/.cp-select/.cp-textarea` (خطوط ۲۰۱–۲۲۸) استفاده کن. focus بنفش (بعد از تغییر primary خودکار).
|
||||
- ارتفاع دکمهها را با فریم button فیگما مقایسه کن (اگر tauri 40px است، `.cp-btn-*` از 42px به 40px).
|
||||
|
||||
### الف-۵. کامپوننتهای مشترک مطابق فیگما
|
||||
|
||||
این کلاسها/کامپوننتها پایهی همهی صفحاتاند؛ هرکدام را با کامپوننت متناظر فیگما یکبهیک تطبیق بده (شعاع، سایه، padding، رنگ، حالت hover/active):
|
||||
|
||||
| کامپوننت clinicpro | فایل | فریم مرجع فیگما |
|
||||
|---|---|---|
|
||||
| کارت | `.cp-card` (styles.css) | کارتهای `dashboard` (`4836:5435`) |
|
||||
| stat card | `components/ui/StatCard.tsx` + `.cp-stat` | کارتهای بالای `dashboard` |
|
||||
| جدول | `components/ui/DataTable.tsx` | `appointments-table` (`4840:7773`)، `patients-grid` (`5265:8540`) |
|
||||
| صفحهبندی | `components/ui/Pagination.tsx` | پایین جدولها |
|
||||
| مودال | `components/ui/Modal.tsx` + `.modal` | `appointments-info` (`5635:11700`) |
|
||||
| badge وضعیت | `components/ui/StatusBadge.tsx`, `AppointmentStatusDropdown.tsx` | ستون status جدولها، `status` (`6070:35666`) |
|
||||
| هدر صفحه | `components/ui/PageHeader.tsx` | نوار عنوان فریمها |
|
||||
| فرم/input | `.cp-input/.cp-label/...` + `MobileInput.tsx`, `PriceInput.tsx` | `add patients` (`5287:32314`)، `add services` |
|
||||
| تقویم/تاریخ شمسی | `PersianDatePicker/Calendar/DateInput.tsx` | `calendar-mobile` (`6070:36125`)، فریمهای reserve |
|
||||
| آواتار | `.avatar` | آواتار هدر/کارت بیمار |
|
||||
| سایدبار ناوبری | `components/layout/Sidebar.tsx` | فریم `menu`/سایدبار |
|
||||
| هدر بالا | `components/layout/Topbar.tsx` | instance `header` (`7788:39703`) |
|
||||
|
||||
---
|
||||
|
||||
## بخش ب — تطبیق تکتک صفحات با فریم فیگما
|
||||
|
||||
### ایندکس فریمهای فیگما (۴ section، node-id دسکتاپ)
|
||||
|
||||
**section `edited-appointment` (نوبتها) — `4836:5434`:**
|
||||
| فریم | node-id |
|
||||
|---|---|
|
||||
| dashboard | `4836:5435` |
|
||||
| appointments-table | `4840:7773` |
|
||||
| appointments-info | `5635:11700` |
|
||||
| appointments-replace | `5635:14347` |
|
||||
| appointments-change | `5126:7712` |
|
||||
| transfer | `6026:23601` / `6030:12460` |
|
||||
| reserve-table | `5484:10961` |
|
||||
| add reserve / add patients | `5760:34891` |
|
||||
| edit | `6026:23229` |
|
||||
|
||||
**section `patients` (پرونده/بیماران) — `5265:8539`:**
|
||||
| فریم | node-id | | فریم | node-id |
|
||||
|---|---|---|---|---|
|
||||
| patients-grid | `5265:8540` | | detail | `6020:22415` |
|
||||
| patients-card | `5642:11515` | | invoice | `5892:15788` |
|
||||
| add patients | `5287:32314` | | wallet | `6046:13257` |
|
||||
| services | `5339:9489` | | call center | `6328:9693` |
|
||||
| add services | `5892:12711` | | document | `6419:10086` |
|
||||
| booked | `6214:9519` | | patients-filter | `5272:31373` |
|
||||
| payment / payment1–4 | `5892:13200` … `5892:14976` | | | |
|
||||
|
||||
**section `inventory` (انبار) — `7492:16182`:**
|
||||
| inventory | `7492:15558` | inventory-package | `7501:15827` |
|
||||
|
||||
**section `setting` (تنظیمات) — `6838:34246`:** ~۲۵ فریم `seetting` (تبهای مختلف). شروعها: `6923:34358`, `6945:14186`, `7043:24804`, `7091:14411`, `7291:33902`. هر تب را با `get_screenshot` جدا بگیر.
|
||||
|
||||
> **موبایل:** هر فریم دسکتاپ نسخهی `*-mobile` (عرض ۳۶۰) دارد + الگوهای مشترک: `menu` (نوار پایین، `360x56`)، `bottom sheet`، `filters-mobile`، `status`. این الگوها را در نسخهی responsive صفحات clinicpro پیاده کن (بویژه bottom-sheet بجای مودال روی موبایل، و منوی پایین موبایل).
|
||||
|
||||
### mapping صفحات clinicpro → فریم فیگما
|
||||
|
||||
پنل clinicpro علاوه بر صفحات پزشک/کلینیک، صفحات super-admin دارد که معادل مستقیم در فیگما ندارند. قانون:
|
||||
- **معادل مستقیم دارد** → دقیقاً از فریم فیگما پیروی کن (layout، اجزا، رنگ).
|
||||
- **معادل ندارد** (super-admin) → همان **کامپوننتلایبرری و استایل مشترک** (بخش الف) را اعمال کن تا همخانوادهی فیگما بهنظر برسد؛ ساختار جدول/فرم/کارت را از نزدیکترین الگوی فیگما (جدول = `patients-grid`، فرم = `add patients`، تنظیمات = `seetting`) وام بگیر.
|
||||
|
||||
| صفحه clinicpro | فریم فیگمای مرجع | نوع |
|
||||
|---|---|---|
|
||||
| `DashboardPage.tsx` | dashboard `4836:5435` | مستقیم |
|
||||
| `AppointmentsPage.tsx` | appointments-table `4840:7773` | مستقیم |
|
||||
| `AppointmentDetailPage.tsx` | appointments-info `5635:11700` | مستقیم |
|
||||
| `NewSessionPage.tsx` | add reserve `5760:34891` | مستقیم |
|
||||
| `MyPatientsPage.tsx` | patients-grid `5265:8540` | مستقیم |
|
||||
| `PaymentsPage.tsx` / `PaymentDetailPage.tsx` | payment `5892:13200`, invoice `5892:15788` | مستقیم |
|
||||
| `SettingsPage.tsx` / `MyClinicPage.tsx` / `DoctorProfilePage.tsx` | seetting `6923:34358`… | مستقیم |
|
||||
| `MyFinancialPage.tsx` / `FinancialReportPage.tsx` | wallet `6046:13257` | مستقیم |
|
||||
| `ClinicServicesPage.tsx` / `InsurancePricingPage.tsx` | services `5339:9489` | مستقیم |
|
||||
| `SmsPage.tsx` / `SmsWalletPage.tsx` | wallet `6046:13257` | نیمهمستقیم |
|
||||
| `MySecretariesPage.tsx` / `SecretariesPage.tsx` / `StaffPage.tsx` | patients-grid (جدول) + add patients (فرم) | الگو |
|
||||
| `DoctorsPage/ClinicsPage/UsersPage/RepresentationsPage/BlogsPage/CommentsPage/RatingsPage/ClaimsPage/PreRegistrationsPage/LogsPage/SettlementsPage/SubscriptionPage` و صفحات `*DetailPage`/`*FormPage` | جدول = `patients-grid` `5265:8540`، فرم = `add patients` `5287:32314`، جزئیات = `detail` `6020:22415` | الگو |
|
||||
| `CategoriesPage.tsx` | seetting (تبدار) | الگو |
|
||||
| `LoginPage.tsx` / `SelectContextPage.tsx` | — (اگر فریم auth در فیگما نبود، استایل مشترک) | الگو |
|
||||
|
||||
> صفحات با تست (`BlogFormPage.test.tsx`, `BlogsPage.test.tsx`, `LoginPage.test.tsx`) — بعد از تغییر UI، تستها را اجرا کن و اگر selectorها شکستند بهروز کن.
|
||||
|
||||
---
|
||||
|
||||
## روش کار پیشنهادی (گامبهگام و ایمن)
|
||||
|
||||
1. **بخش الف** را کامل کن (توکن + کامپوننت مشترک)، سپس با یک صفحهی نمونه (Dashboard) صحت پایه را تأیید کن.
|
||||
2. صفحات را **گروهبهگروه** جلو ببر (اول «مستقیم»ها: dashboard → appointments → patients → payments → settings؛ بعد «الگو»ها).
|
||||
3. برای هر صفحه: `get_screenshot` فریم فیگما → مقایسه با اجرای محلی → اصلاح. **رنگ/شعاع را در توکنهای `styles.css` عوض کن، نه inline در کامپوننت** (مگر جایی که tauri هم inline دارد).
|
||||
4. موبایل: bottom-sheet و منوی پایین را طبق فریمهای `*-mobile` اضافه کن.
|
||||
|
||||
## نکات مهم
|
||||
|
||||
- **فقط CSS/توکن/layout و JSX ظاهری؛ منطق داده/API/route را دست نزن.** هیچ فایل backend یا `docs/api/*` تغییر نمیکند.
|
||||
- MUI وارد نکن؛ Tailwind v4 + CSS variables را نگهدار. tauri فقط «مرجع ظاهری» است.
|
||||
- fallback مرورگر قدیمی (بلوک `@supports oklch`) را حفظ کن؛ sRGB و oklch را هماهنگ بهروز کن.
|
||||
- بعد از هر گروه: `ddev exec yarn dev` (خطای native lightningcss داخل ddev بیربط است؛ فقط JS/TS مهم) و `ddev exec npx tsc --noEmit`. تستها: `ddev exec yarn test` یا vitest.
|
||||
- پایان کار: `graphify update .` در `clinicpro/`.
|
||||
- بهخاطر بزرگی تسک، حتماً incremental commit بزن (هر گروه صفحه یک commit).
|
||||
```
|
||||
|
||||
## دستور اجرا
|
||||
|
||||
```
|
||||
/run-prompt clinicpro/.claude/prompt/admin-ui-match-tauri.md
|
||||
```
|
||||
+29
-29
@@ -15,10 +15,10 @@
|
||||
|
||||
/* ── Template Design System Variables ─────────────────────────── */
|
||||
:root {
|
||||
--brand-h: 256;
|
||||
--brand-c: 0.15;
|
||||
--bg: #eef2f8;
|
||||
--bg-2: #e6ecf4;
|
||||
--brand-h: 277;
|
||||
--brand-c: 0.177;
|
||||
--bg: #fafafa;
|
||||
--bg-2: #f2f2f5;
|
||||
--surface: #ffffff;
|
||||
--surface-2: #f6f8fc;
|
||||
--surface-3: #eef2f8;
|
||||
@@ -28,9 +28,9 @@
|
||||
--text-2: #56657c;
|
||||
--text-3: #8a98ad;
|
||||
/* مقادیر sRGB پایه (fallback WebKit قدیمی iPhone 8)؛ نسخه oklch در @supports پایین فایل */
|
||||
--primary: #5457dd;
|
||||
--primary-600: #464ac9;
|
||||
--primary-700: #3b3eae;
|
||||
--primary: #5559CE;
|
||||
--primary-600: #494CB3;
|
||||
--primary-700: #3E41A0;
|
||||
--primary-soft: #ecedfb;
|
||||
--primary-soft2: #d9dbf6;
|
||||
--on-primary: #ffffff;
|
||||
@@ -53,7 +53,7 @@
|
||||
--stat-violet-bg: rgba(85,89,206,0.08); --stat-violet-fg: #5559CE;
|
||||
--stat-green-bg: rgba(0,157,121,0.10); --stat-green-fg: #009D79;
|
||||
--stat-pink-bg: rgba(241,119,50,0.10); --stat-pink-fg: #F17732;
|
||||
--ring: rgba(84,87,221,.32);
|
||||
--ring: rgba(85,89,206,.32);
|
||||
--shadow-sm: 0 1px 2px rgba(15,27,46,.06), 0 1px 3px rgba(15,27,46,.05);
|
||||
--shadow: 0 2px 6px rgba(15,27,46,.06), 0 8px 24px rgba(15,27,46,.06);
|
||||
--shadow-lg: 0 12px 32px rgba(15,27,46,.12), 0 4px 10px rgba(15,27,46,.06);
|
||||
@@ -73,23 +73,23 @@
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
--bg: #080d16;
|
||||
--bg-2: #0b1220;
|
||||
--surface: #111a29;
|
||||
--surface-2: #16202f;
|
||||
--surface-3: #1b2738;
|
||||
--border: #243042;
|
||||
--border-2: #2e3c52;
|
||||
--text: #e9eef7;
|
||||
--text-2: #9eb0c6;
|
||||
--text-3: #67788e;
|
||||
--bg: #1f1d2b;
|
||||
--bg-2: #1a1826;
|
||||
--surface: #222433;
|
||||
--surface-2: #2a2c3d;
|
||||
--surface-3: #313349;
|
||||
--border: #343645;
|
||||
--border-2: #3d4152;
|
||||
--text: #D7D8ED;
|
||||
--text-2: #A1A1A1;
|
||||
--text-3: #6d6e82;
|
||||
/* مقادیر sRGB پایه (fallback WebKit قدیمی)؛ نسخه oklch/color-mix در @supports پایین فایل */
|
||||
--primary: #7a7cf1;
|
||||
--primary-600: #686ae6;
|
||||
--primary-700: #565ad9;
|
||||
--primary-soft: #222a49;
|
||||
--primary-soft2: #2c335d;
|
||||
--on-primary: #07101f;
|
||||
--primary: #6B6FD6;
|
||||
--primary-600: #5c60cf;
|
||||
--primary-700: #494CB3;
|
||||
--primary-soft: #2b2d47;
|
||||
--primary-soft2: #363a63;
|
||||
--on-primary: #EFEFEF;
|
||||
--success-bg: #123332;
|
||||
--warning-bg: #352e23;
|
||||
--danger-bg: #36202f;
|
||||
@@ -112,17 +112,17 @@
|
||||
نگه میدارند؛ مرورگر مدرن این نسخههای oklch را استفاده میکند (بدون تغییر ظاهر). */
|
||||
@supports (color: color-mix(in oklch, red, blue)) {
|
||||
:root {
|
||||
--primary: oklch(0.55 var(--brand-c) var(--brand-h));
|
||||
--primary-600: oklch(0.49 var(--brand-c) var(--brand-h));
|
||||
--primary: oklch(0.53 var(--brand-c) var(--brand-h));
|
||||
--primary-600: oklch(0.47 var(--brand-c) var(--brand-h));
|
||||
--primary-700: oklch(0.43 var(--brand-c) var(--brand-h));
|
||||
--primary-soft: oklch(0.95 0.03 var(--brand-h));
|
||||
--primary-soft2: oklch(0.90 0.05 var(--brand-h));
|
||||
--ring: color-mix(in oklch, var(--primary) 32%, transparent);
|
||||
}
|
||||
[data-theme="dark"] {
|
||||
--primary: oklch(0.66 var(--brand-c) var(--brand-h));
|
||||
--primary-600: oklch(0.60 var(--brand-c) var(--brand-h));
|
||||
--primary-700: oklch(0.54 var(--brand-c) var(--brand-h));
|
||||
--primary: oklch(0.59 var(--brand-c) var(--brand-h));
|
||||
--primary-600: oklch(0.53 var(--brand-c) var(--brand-h));
|
||||
--primary-700: oklch(0.47 var(--brand-c) var(--brand-h));
|
||||
--primary-soft: color-mix(in oklch, var(--primary) 16%, var(--surface));
|
||||
--primary-soft2: color-mix(in oklch, var(--primary) 26%, var(--surface));
|
||||
--success-bg: color-mix(in oklch, var(--success) 18%, var(--surface));
|
||||
|
||||
Reference in New Issue
Block a user