Implement comprehensive dark/light mode overhaul for admin panel

- Refactor color palette in `ui-design-spec.md` to utilize CSS variables exclusively, eliminating fixed hex values and Tailwind utility classes.
- Complete dark mode implementation in `uiStore.ts`, ensuring proper theme application via `applyTheme()` and `applyBrand()`.
- Create `admin-theme-dark-light-audit.md` to document the transition process, outlining issues with inline styles and fixed colors.
- Introduce `theme-tokens.test.ts` to enforce rules against fixed hex colors and ensure compliance with the design system.
- Update various components and styles to replace inline styles and fixed colors with CSS variables, ensuring consistent theming across light and dark modes.
- Ensure all changes maintain visual integrity in both light and dark modes, with a focus on accessibility and contrast standards.
This commit is contained in:
hamed
2026-07-27 16:41:52 +03:30
parent c29035c21e
commit 55ab2f5dfc
73 changed files with 1485 additions and 1110 deletions
+71 -43
View File
@@ -7,44 +7,55 @@
### رنگ‌بندی (Color Palette)
> **منبع حقیقت `assets/admin/styles.css` است.** توکن‌ها در `:root` تعریف و در
> `[data-theme="dark"]` بازتعریف می‌شوند؛ نسخهٔ oklch/color-mix زیر `@supports` می‌آید و
> مرورگر قدیمی روی همان مقادیر sRGB می‌ماند. هیچ توکنی نباید فقط داخل `@supports` تعریف شود.
```css
/* Primary — Purple (Panelix style) */
--color-primary-50: #f5f3ff;
--color-primary-100: #ede9fe;
--color-primary-200: #ddd6fe;
--color-primary-300: #c4b5fd;
--color-primary-400: #a78bfa;
--color-primary-500: #8b5cf6; /* main */
--color-primary-600: #7c3aed;
--color-primary-700: #6d28d9;
--color-primary-800: #5b21b6;
--color-primary-900: #4c1d95;
/* Neutrals */
--color-gray-50: #f9fafb;
--color-gray-100: #f3f4f6;
--color-gray-200: #e5e7eb;
--color-gray-300: #d1d5db;
--color-gray-400: #9ca3af;
--color-gray-500: #6b7280;
--color-gray-600: #4b5563;
--color-gray-700: #374151;
--color-gray-800: #1f2937;
--color-gray-900: #111827;
/* Status Colors */
--color-success: #10b981;
--color-warning: #f59e0b;
--color-danger: #ef4444;
--color-info: #3b82f6;
/* Background */
--color-bg-body: #f1f5f9; /* light gray page bg */
--color-bg-card: #ffffff;
--color-bg-sidebar: #0f172a; /* dark navy sidebar */
--color-bg-sidebar-active: rgba(139, 92, 246, 0.15);
/* Brand — indigo (نه بنفشِ این سند در نسخه‌های قدیمی) */
--primary --primary-600 --primary-700 --primary-soft --primary-soft2 --on-primary
/* Accent — نارنجی هم‌خانواده با clinic-pro-tauri */
--accent --accent-600 --accent-bg
/* سطوح و متن */
--bg --bg-2 --surface --surface-2 --surface-3 --border --border-2
--text --text-2 --text-3
/* وضعیت */
--success/-bg --warning/-bg --danger/-bg --info/-bg --violet/-bg
/* کارت‌های آمار داشبورد */
--stat-{amber,violet,green,pink}-{bg,fg}
```
**قاعدهٔ الزامی:** در `assets/admin` رنگ ثابت ممنوع است — نه hex، نه کلاس پالت Tailwind
(`bg-white`, `text-gray-800`, `border-slate-200`, …). به‌جایش:
| به‌جای | بنویس |
|---|---|
| `style={{ color: '#525252' }}` | `style={{ color: 'var(--text)' }}` |
| `className="text-[#525252] dark:text-[#D7D8ED]"` | `className="text-[var(--text)]"` |
| `className="bg-white border border-gray-100"` | `className="bg-[var(--surface)] border border-[var(--border)]"` |
| `stroke="#616161"` روی SVG | `style={{ stroke: 'var(--text-2)' }}` یا `stroke="currentColor"` |
نگاشت hexهای قدیمی به توکن (از آدیت ۱۴۰۵/۰۵):
| hex | توکن |
|---|---|
| `#525252` `#3b3b3b` `#2f2f2f` `#111827` `#374151` · دارک: `#d7d8ed` | `--text` |
| `#616161` `#6b7280` `#7e7e7e` `#858d9d` · دارک: `#a1a1a1` | `--text-2` |
| `#9ca3af` `#94a3b8` `#9b9b9b` | `--text-3` |
| `#5559ce` | `--primary` · `#494cb3``--primary-600` · `#3b3f9f``--primary-700` |
| `#f17732` `#f0682a` `#f97316` | `--accent` |
| `#ffffff` (سطح کارت) · دارک: `#222433` | `--surface` |
| `#efefef` `#ededed` `#e7e7e7` · دارک: `#35343d` `#343645` | `--border` |
| `#e0e0e0` `#e1e1e1` `#dbdbdb` `#d7d7d7` · دارک: `#404040` | `--border-2` |
| `#ef4444` `#d32f2f` `#e53935` | `--danger` (پس‌زمینه: `--danger-bg`) |
| `#2e7d32` `#3c9a4f` `#22c55e` | `--success` (پس‌زمینه: `--success-bg`) |
| `#f59e0b` `#fdd835` `#ffc051` | `--warning` (پس‌زمینه: `--warning-bg`) |
| `#f4f5fd` `#f7f8ff` `#eef0ff` | `--primary-soft` · `#e8ebff` `#c7cef4``--primary-soft2` |
استثناهای پذیرفته‌شده (در تست گارد ثبت شده‌اند): پالت انتخابی برچسب‌ها
(`TagsSettingsPage`)، اسکریم مودال (`bg-black/50`، مثل `.overlay`)، و `BrandFixed`
هیوی نارنجی در `stores/uiStore.ts`.
### تایپوگرافی
```
@@ -442,17 +453,34 @@ Row 3: [Bar Chart — آمار ماهانه نمایندگان (60%)] | [لیس
---
## 16. Dark Mode (اختیاری — فاز دوم)
## 16. Dark Mode (پیاده‌شده)
دارک‌مود کامل شیپ شده است. `stores/uiStore.ts``applyTheme()` روی `<html>` هم‌زمان
کلاس `dark` (برای واریانت Tailwind) و `data-theme="dark"` (برای توکن‌های CSS) را ست
می‌کند و مقدارش در `localStorage['clinicpro-ui']` می‌ماند. `applyBrand()` هم
`--brand-h/--brand-c` و در صورت وجود `BrandFixed` مقادیر `--primary*` را inline می‌گذارد.
```css
/* با Tailwind dark: variant */
.dark {
--color-bg-body: #0f172a;
--color-bg-card: #1e293b;
--color-bg-sidebar: #0a0f1e;
}
/* styles.css */
@custom-variant dark (&:where(.dark, .dark *));
:root { --surface: #ffffff; --text: #3b3b3b; /* … */ }
[data-theme="dark"] { --surface: #222433; --text: #D7D8ED; /* … */ }
```
Toggle در topbar ← ذخیره در `localStorage`
قواعد:
- رنگ از توکن بیاید؛ آن‌وقت دارک‌مود **خودکار** درست است و `dark:` لازم نیست.
- `dark:` فقط وقتی که واقعاً توکنِ متفاوتی در دو تم لازم است — نه برای جبران hex ثابت.
- **inline style همیشه بر کلاس غالب است.** `style={{ color: '#525252' }}` کنار
`className="dark:text-[#D7D8ED]"` یعنی کلاس هیچ‌وقت اعمال نمی‌شود؛ این الگو در
تست گارد `assets/admin/test/theme-tokens.test.ts` fail می‌دهد.
- `var(--token)` داخل `style` کار می‌کند؛ برای SVG یا `stroke="currentColor"` بگذار و
رنگ را از والد بگیر، یا `style={{ stroke: 'var(--…)' }}`.
- الفای هگزی (`${color}30`) روی توکن بی‌معنی است — `color-mix(in srgb, var(--x) 19%, transparent)`.
فاز باقی‌مانده: `pages/DoctorDetailPage.tsx`، `pages/UserDetailPage.tsx` و
`components/schedule/ScheduleSection.tsx` هنوز جفت `slate/gray` + `dark:` دارند
(کار می‌کنند ولی با brand hue هماهنگ نمی‌شوند) — در تست گارد به‌عنوان `DEFERRED` علامت خورده‌اند.
---