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:
@@ -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` علامت خوردهاند.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user