- 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.
25 KiB
اصلاح کامل لایتمود / دارکمود در پنل ادمین (SPA)
پروژه
clinicpro — فقط فرانتاند پنل ادمین (assets/admin/). بکاند و API دست نمیخورد.
زمینه
پنل ادمین یک design-system کامل مبتنی بر CSS variable دارد که در assets/admin/styles.css تعریف شده:
:rootمقادیر لایت (--bg,--surface,--text,--text-2,--border,--primary,--danger, …)[data-theme="dark"]همان توکنها را برای دارک بازتعریف میکندassets/admin/stores/uiStore.ts→applyTheme()رویdocument.documentElementهم کلاسdarkو همdata-themeرا ست میکند، پس همdark:واریانت Tailwind و همvar(--token)هر دو فعالاند
مشکل این است که بخش بزرگی از صفحات این سیستم را دور میزنند و رنگ ثابت مینویسند. آمار واقعی امروز (اندازهگیریشده روی assets/admin، بدون فایلهای تست):
| الگو | تعداد |
|---|---|
style={{ color/background: ... }} |
۱۰۳۷ نقطه در ~۶۰ فایل |
hex ثابت داخل .tsx |
۷۵۲ |
utility رنگ ثابت Tailwind (bg-white, text-slate-400, border-gray-100, …) |
۸۸۵ در ۲۰ فایل |
از اینها با جفت dark: |
۳۲۳ |
کلاسهای Tailwind با توکن (text-[var(--text-3)]) |
فقط ۱۵ مورد |
مشکل / هدف
در دارکمود بخشهایی از پنل روشن/ناخوانا میمانند. سه دستهٔ خرابی، به ترتیب اهمیت:
دستهٔ A — style inline با رنگ ثابت (خرابی قطعی)
inline style قابل override با dark: نیست. در ~۹۰ نقطه دقیقاً همین اشتباه رخ داده: کنار inline style یک کلاس dark: نوشته شده که هیچوقت اعمال نمیشود چون specificity کلاس همیشه کمتر از style attribute است.
فایلهای آلوده به این الگوی مرده:
| فایل | تعداد نقطهٔ dark: مرده |
|---|---|
components/session/PaymentStep.tsx |
۲۷ |
components/session/DetailsStep.tsx |
۲۶ |
components/session/CreateStep.tsx |
۱۴ |
components/SessionPaymentAccordion.tsx |
۷ |
components/PatientCaseBanner.tsx |
۷ |
components/SessionServiceCard.tsx |
۵ |
pages/SessionPaymentPage.tsx, pages/NewSessionPage.tsx, pages/EditSessionPage.tsx, components/AppointmentTurnCard.tsx |
۲ هرکدام |
پرمصرفترین فایلها از نظر کل inline style رنگی: pages/MyPatientsPage.tsx (۶۷)، pages/PatientDetailPage.tsx (۶۲)، pages/SmsWalletPage.tsx (۴۶)، components/session/PaymentStep.tsx (۴۳)، pages/SubscriptionPage.tsx (۳۱)، pages/DoctorDetailPage.tsx (۳۰)، pages/ClinicServicesPage.tsx (۲۹)، components/session/DetailsStep.tsx (۲۸)، components/session/CreateStep.tsx (۲۷)، pages/PatientsListPage.tsx (۲۶).
دستهٔ B — utility روشن بدون جفت dark:
| فایل | utility رنگی | تعداد dark: |
|---|---|---|
pages/RepresentationDetailPage.tsx |
۳۳ | ۱ |
pages/AppointmentDetailPage.tsx |
۲۷ | ۲ |
pages/PaymentDetailPage.tsx |
۱۲ | ۲ |
components/ImageCropModal.tsx |
۲۳ | ۹ (ناقص) |
دستهٔ C — CSS ثابت در styles.css و آیکونهای SVG
.inv-table thead tr { background: #e1e1e1 }و.inv-table th { color: #616161 }و.inv-table td { border-bottom: 1px solid #DBDBDB }— هیچ override.darkندارند (فقطtdborder و hover دارند).inv-tabs,.inv-tab,.inv-badge.*با hex ثابت + override دستی.dark— بهجای توکن- آیکونهای SVG با
stroke="#616161"/stroke="#3B3B3B"ثابت (مثلاًpages/MySecretariesPage.tsxخط ۲۶–۳۵،components/icons/) در دارکمود روی پسزمینهٔ تیره محو میشوند
هدف: هر رنگ سطحی/متنی/حاشیهای در پنل ادمین از توکنهای styles.css بیاید، طوری که toggle دارکمود بدون هیچ نقطهٔ روشن/ناخوانا کار کند — و رگرسیون بعدی با تست گارد گرفته شود.
معیار پذیرش
- ✅ موفق: با
darkMode: true(کلیدclinicpro-uiدر localStorage یا دکمهٔ toggle در topbar)، در هر صفحهٔ فهرست «فایلهای مرتبط» هیچ کارت/متن/حاشیه/badge با رنگ لایت باقی نمیماند؛ کنتراست متن اصلی روی--surfaceحداقل ۴.۵:۱ و متن ثانویه حداقل ۳:۱. - ✅ موفق (لایت): بعد از تغییرات، همان صفحات در لایتمود دقیقاً مثل قبل رندر میشوند — این ریفکتور نباید ظاهر لایت را عوض کند (توکنها همان hexهای فعلیاند).
- ❌ خطا / رگرسیون: یک تست گارد (
assets/admin/test/theme-tokens.test.ts) سورس را اسکن میکند و اگر در فایلهای پاکشده دوباره hex ثابت رنگی یا utility رنگی بدون جفتdark:اضافه شود، fail میشود. - ⚠️ مرزی ۱: تغییر brand hue (
setBrandHue، مثلاً هیوی «نارنجی» کهfixedدارد) در هر دو مود باید رنگ اصلی را عوض کند؛ هیچ جایی نباید#5559CEثابت بماند. - ⚠️ مرزی ۲:
density: compactو مرورگر قدیمی بدون پشتیبانیcolor-mix/oklch(بلوک@supportsدرstyles.css) — رنگها باید روی fallback sRGB هم درست باشند، نه اینکه به transparent بیفتند. - ⚠️ مرزی ۳: جدول انبار (
.inv-table) در دارکمود — thead، badgeها (in-stock/low-stock/out-of-stock) و tabها خوانا باشند.
فایلهای مرتبط
| فایل | نقش |
|---|---|
assets/admin/styles.css |
تعریف توکنها (:root, [data-theme="dark"], @supports) + کلاسهای .inv-* که هنوز hex ثابت دارند |
assets/admin/stores/uiStore.ts |
applyTheme() / applyBrand() — منبع کلاس dark و data-theme و --brand-h/--brand-c |
assets/admin/components/session/PaymentStep.tsx |
بیشترین inline style رنگی + dark:های مرده |
assets/admin/components/session/DetailsStep.tsx |
همان الگو |
assets/admin/components/session/CreateStep.tsx |
همان الگو |
assets/admin/components/SessionPaymentAccordion.tsx, SessionServiceCard.tsx, PatientCaseBanner.tsx, AppointmentTurnCard.tsx |
dark:های مرده کنار inline style |
assets/admin/pages/MyPatientsPage.tsx, PatientDetailPage.tsx, SmsWalletPage.tsx, SubscriptionPage.tsx, ClinicServicesPage.tsx, PatientsListPage.tsx, MySecretariesPage.tsx |
حجم بالای inline style رنگی |
assets/admin/pages/RepresentationDetailPage.tsx, AppointmentDetailPage.tsx, PaymentDetailPage.tsx |
utility روشن بدون dark: |
assets/admin/components/ImageCropModal.tsx |
جفت dark: ناقص |
assets/admin/components/icons/ |
SVGهای با stroke/fill ثابت |
docs/admin-ui/ui-design-spec.md |
سند UI — بخش ۱۶ «Dark Mode (اختیاری — فاز دوم)» کهنه است و با پیادهسازی فعلی نمیخواند |
وضعیت فعلی
الگوی مردهٔ dark: کنار inline style — components/session/PaymentStep.tsx
// خط ۳۳–۳۵ — استایلهای مشترک، همه hex ثابت
const fieldLabel: React.CSSProperties = { fontSize: 14, color: '#6B7280', marginBottom: 8, display: 'block' };
const primaryBtn: React.CSSProperties = { background: '#5559CE', color: '#fff', border: 'none', borderRadius: 4, height: 46, fontSize: 14, fontWeight: 500, cursor: 'pointer' };
const ghostBtn: React.CSSProperties = { background: 'transparent', color: '#5559CE', border: '1px solid #5559CE', borderRadius: 4, height: 46, fontSize: 14, fontWeight: 500, cursor: 'pointer' };
// خط ۱۵۰ — کلاس dark: هیچ اثری ندارد چون inline style غالب است
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 14, fontWeight: 700, color: '#525252' }}>{formatRial(finalPrice)}</span>
// خط ۱۵۵ — همان اشتباه روی border/background
<div className="dark:border-[#35343D]" style={{ border: '1px solid #E8EBFF', background: '#F7F8FF', borderRadius: 8, padding: 12, marginBottom: 16 }}>
utility روشن بدون جفت dark — pages/AppointmentDetailPage.tsx
// خط ۱۴۱–۱۴۲
<div className="bg-white rounded-2xl border border-gray-100 shadow-sm p-6">
<h3 className="font-semibold text-gray-800 mb-4">اطلاعات بیمار</h3>
utility روشن بدون جفت dark — pages/RepresentationDetailPage.tsx
// خط ۲۵۱
className="flex items-center gap-1.5 px-3 py-2 text-sm rounded-[10px] border border-gray-300 text-gray-700 hover:bg-gray-50 transition-colors"
// خط ۳۰۹
<p className="text-sm text-gray-400 text-center py-6">اطلاعات بانکی ثبت نشده</p>
CSS ثابت — assets/admin/styles.css خط ۹۵۸–۹۷۰
.inv-table { width: 100%; border-collapse: collapse; }
.inv-table thead tr { background: #e1e1e1; } /* بدون override دارک */
.inv-table th {
color: #616161; font-size: 14px; font-weight: 400; /* بدون override دارک */
padding: 10px 18px; text-align: start; white-space: nowrap;
}
.inv-table td {
padding: 12px 18px; text-align: start; white-space: nowrap;
font-size: 16px; font-weight: 500; color: var(--text-2);
border-bottom: 1px solid #DBDBDB;
}
.dark .inv-table td { border-color: var(--border); }
.inv-table tbody tr:hover { background: #f4f5fd; }
.dark .inv-table tbody tr:hover { background: var(--surface-2); }
الگوی درستِ موجود در پروژه (مرجع سبک) — components/FreeVisitPrice.tsx
<p style={{ fontSize: 12, color: 'var(--text-3)', margin: '0 0 12px', lineHeight: 1.7 }}>
<span style={{ color: 'var(--danger)' }}> *</span>
این همان الگویی است که باید همهجا اعمال شود: inline style میماند، فقط مقدار رنگ به توکن تبدیل میشود.
وظایف
۱. تثبیت جدول نگاشت رنگ → توکن
قبل از هر تغییر، این جدول را مبنا بگیر. hexها از شمارش واقعی فایلهای .tsx استخراج شدهاند (ستون «تعداد» = تکرار در سورس):
| hex فعلی (لایت) | تعداد | hex فعلی (دارک، در dark:ها) |
توکن مقصد |
|---|---|---|---|
#525252, #3b3b3b, #2f2f2f, #111827 |
۴۵+۱۳+۱۶+۱۱ | #d7d8ed (۷۶) |
var(--text) |
#616161, #7e7e7e, #6b7280 |
۵۱+۱۹+۳۱ | #a1a1a1 (۵۰) |
var(--text-2) |
#9ca3af |
۱۰ | — | var(--text-3) |
#5559ce |
۷۵ | — | var(--primary) |
#f17732, #f0753b |
۳۴+۴ | — | var(--accent) |
#ffffff (سطح کارت) |
۴ | #222433 (۲۵) |
var(--surface) |
#fafafa, #f1f1f1 (پسزمینهٔ صفحه/فیلد) |
۶+۴ | — | var(--bg) / var(--surface-2) |
#efefef, #ededed, #e7e7e7 |
۱۸+۴+۴ | #35343d (۲۲), #343645 (۱۱) |
var(--border) |
#e0e0e0, #e1e1e1, #dbdbdb, #d7d7d7 |
۱۴+۸+… | #404040 (۱۴) |
var(--border-2) |
#ef4444, #d32f2f |
۱۰+۹ | — | var(--danger) |
#2e7d32, #3c9a4f |
۸+۷ | — | var(--success) |
#f59e0b |
۵ | — | var(--warning) |
پسزمینهٔ نرم بنفش #f7f8ff, #f4f5fd, #e8ebff |
— | — | var(--primary-soft) / var(--primary-soft2) |
نکته: بعضی نگاشتها دقیقاً یکسان نیستند (#525252 در برابر --text: #3b3b3b). این اختلاف عمدی پذیرفته میشود چون هدف یکدستسازی است؛ اما اگر جایی اختلاف بصری محسوس شد (مثلاً متن اصلی کارت که واضحاً تیرهتر/روشنتر میشود)، همانجا را در گزارش پایانی لیست کن بهجای اینکه توکن جدید بسازی.
نحوه تست: جدول تصمیم است، نه کد. بعد از تعریف، در docs/admin-ui/ui-design-spec.md ثبتش کن (وظیفهٔ ۷).
۲. پاکسازی dark:های مرده (دستهٔ A، اولویت اول)
در ۱۰ فایلی که در بخش «مشکل» لیست شد: هر جا className شامل dark: کنار style={{ color|background|border|borderColor: '#…' }} است:
- کلاس
dark:مرده را حذف کن - مقدار hex داخل
styleرا طبق جدول وظیفهٔ ۱ بهvar(--token)تبدیل کن
// قبل
<span className="dark:text-[#D7D8ED]" style={{ fontSize: 14, fontWeight: 700, color: '#525252' }}>
// بعد
<span style={{ fontSize: 14, fontWeight: 700, color: 'var(--text)' }}>
// قبل
<div className="dark:border-[#35343D]" style={{ border: '1px solid #E8EBFF', background: '#F7F8FF', ... }}>
// بعد
<div style={{ border: '1px solid var(--border)', background: 'var(--primary-soft)', ... }}>
ثابتهای ماژولسطح (fieldLabel, primaryBtn, ghostBtn در PaymentStep.tsx) هم همینطور:
const fieldLabel: React.CSSProperties = { fontSize: 14, color: 'var(--text-2)', marginBottom: 8, display: 'block' };
const primaryBtn: React.CSSProperties = { background: 'var(--primary)', color: 'var(--on-primary)', ... };
const ghostBtn: React.CSSProperties = { background: 'transparent', color: 'var(--primary)', border: '1px solid var(--primary)', ... };
نحوه تست:
ddev exec npm run testسبز بماند (تستهای موجودPaymentStep/SessionPaymentAccordion/… نباید بشکنند)- تأیید صفر شدن الگو:
grep -rn "dark:" --include='*.tsx' assets/admin | grep -E "style=\{\{[^}]*(color|background)" | grep -v '\.test\.' | wc -l→ باید0شود - بصری:
/admin→ جلسه (session) → مراحل ایجاد/جزئیات/پرداخت، یکبار لایت و یکبار دارک
۳. تبدیل بقیهٔ inline styleهای رنگی به توکن (دستهٔ A، ادامه)
فایلبهفایل، به ترتیب حجم (MyPatientsPage → PatientDetailPage → SmsWalletPage → SubscriptionPage → ClinicServicesPage → PatientsListPage → MySecretariesPage → DoctorFormPage → DashboardPage → AdminSubscriptionPage → TurnsTimeline → …).
قواعد:
- رنگ ثابت داخل
style→var(--token) - کلاسهای arbitrary دوتایی مثل
className="text-[#525252] dark:text-[#D7D8ED]"→className="text-[var(--text)]"(یک کلاس، هر دو مود) bg-[#FAFAFA] dark:bg-[#222433]→bg-[var(--surface)]یاbg-[var(--bg)]بسته به اینکه سطح کارت است یا پسزمینهٔ فیلد- استثنا: hex داخل SVG که با prop رنگ میگیرد (مثل
<PatientsGridView color={...} />) — در وظیفهٔ ۶ - هر فایل یک commit/گام مستقل؛ فایل بعدی را قبل از تأیید بصری فایل قبلی شروع نکن
نحوه تست: بعد از هر فایل: ddev exec npm run test، سپس بازکردن صفحهٔ متناظر در /admin در هر دو مود و مقایسه با اسکرینشات قبلِ تغییر (لایت باید بدون تغییر باشد).
۴. اضافه کردن پوشش دارک به دستهٔ B
در pages/RepresentationDetailPage.tsx، pages/AppointmentDetailPage.tsx، pages/PaymentDetailPage.tsx، components/ImageCropModal.tsx:
utilityهای پالت ثابت را با کلاس توکنی جایگزین کن — نه اینکه جفت dark: اضافه کنی (جفتسازی بدهی را دو برابر میکند و با brand hue هم هماهنگ نمیشود):
// قبل
<div className="bg-white rounded-2xl border border-gray-100 shadow-sm p-6">
<h3 className="font-semibold text-gray-800 mb-4">اطلاعات بیمار</h3>
// بعد
<div className="bg-[var(--surface)] rounded-2xl border border-[var(--border)] shadow-sm p-6">
<h3 className="font-semibold text-[var(--text)] mb-4">اطلاعات بیمار</h3>
// قبل (RepresentationDetailPage خط ۲۵۱)
className="… border border-gray-300 text-gray-700 hover:bg-gray-50 …"
// بعد
className="… border border-[var(--border-2)] text-[var(--text)] hover:bg-[var(--surface-2)] …"
برای رنگهای وضعیتی (text-red-600, border-red-300, bg-red-50) → text-[var(--danger)], border-[var(--danger)]/30, bg-[var(--danger-bg)].
نحوه تست: /admin/representations/{id}، /admin/appointments/{id}، /admin/payments/{id} و مودال کراپ تصویر (آپلود آواتار پزشک) — هر کدام در دارک و لایت.
۵. پاکسازی styles.css
.inv-table thead tr→background: var(--surface-2).inv-table th→color: var(--text-2).inv-table td→border-bottom: 1px solid var(--border)و حذف.dark .inv-table td { border-color: … }که دیگر لازم نیست.inv-table tbody tr:hover→background: var(--surface-2)و حذف override.dark.inv-tabs→border-bottom: 1px solid var(--border)و حذف.dark .inv-tabs.inv-tab→color: var(--text-2)؛.inv-tab.active→color: var(--primary); border-bottom: 3px solid var(--primary)؛ حذف هر دو override.dark.inv-badge.in-stock|low-stock|out-of-stock→background: var(--success-bg)|var(--warning-bg)|var(--danger-bg)وcolor: var(--success)|var(--warning)|var(--danger)؛ حذف سه override.dark
color: #fff روی .btn/.avatar (خطوط ۲۶۳، ۴۱۱، ۵۹۸، ۶۷۱، ۷۷۵) → var(--on-primary) هر جا روی پسزمینهٔ برند است؛ rgba(8,13,22,.5) اسکریم مودال (خطوط ۶۹۶، ۷۹۸) عمداً در هر دو مود یکسان است و دست نمیخورد — در گزارش ذکرش کن.
نحوه تست: /admin → انبار (inventory): جدول، تبها و badgeهای موجودی در هر دو مود؛ ddev exec npm run build بدون خطا.
۶. آیکونهای SVG
آیکونهای inline با stroke="#616161" / #3B3B3B / fill="#7E7E7E" (مثلاً pages/MySecretariesPage.tsx خطوط ۲۶–۳۵ و فایلهای components/icons/) را به stroke="currentColor" تبدیل کن و رنگ را از کلاس والد بگیر (text-[var(--text-2)]).
استثنا: آیکونهای چندرنگ برند (stroke="#F17732" در components/icons/FilesServiceIcons.tsx، ۲۲ مورد) — اینها هویت رنگی دارند؛ به var(--accent) تبدیل کن، نه currentColor.
// قبل
<path d="…" stroke="#616161" strokeWidth="1.5" … />
// بعد — رنگ از والد
<span className="text-[var(--text-2)]">
<path d="…" stroke="currentColor" strokeWidth="1.5" … />
</span>
نحوه تست: صفحهٔ «منشیهای من» و «سرویسها» در دارکمود — آیکونها باید دیده شوند نه اینکه در پسزمینه گم شوند.
۷. تست گارد + بهروزرسانی سند
۷.۱ تست گارد — assets/admin/test/theme-tokens.test.ts (Vitest، همان setup موجود در assets/admin/test/):
// اسکن سورس؛ فایلهای پاکشده در فاز جاری در allowlist نیستند و باید تمیز بمانند.
const CLEANED = [ /* مسیر فایلهایی که در وظایف ۲–۴ پاک شدند */ ];
it('فایلهای پاکشده hex ثابت رنگی ندارند', () => { /* regex #rrggbb داخل style/className، بهجز SVG برند */ });
it('الگوی مردهٔ dark: کنار inline style رنگی وجود ندارد', () => { /* کل assets/admin */ });
تست دوم باید روی کل assets/admin اجرا شود (نه فقط allowlist) چون بعد از وظیفهٔ ۲ باید صفر باشد و هرگز برنگردد.
۷.۲ سند — docs/admin-ui/ui-design-spec.md:
- بخش ۱۶ فعلی («Dark Mode (اختیاری — فاز دوم)» با
.dark { }و پالت Tailwind) با پیادهسازی واقعی نمیخواند → بازنویسی شود: دارکمود پیادهشده است، از طریقdata-theme/کلاسdarkروی<html>توسطuiStore.applyTheme()، و منبع رنگ فقط توکنهایstyles.cssاست. - جدول نگاشت وظیفهٔ ۱ + قاعدهٔ الزامی: «رنگ ثابت (hex یا utility پالت Tailwind) در
assets/adminممنوع؛var(--token)یا*-[var(--token)]». - بخش ۱ (Color Palette) که هنوز
--color-bg-sidebar: #0f172aدارد با توکنهای واقعی همخوان شود.
نحوه تست: ddev exec npm run test — گارد جدید سبز؛ برای اطمینان از اینکه واقعاً گارد است، یکبار موقتاً color: '#525252' به یکی از فایلهای allowlist اضافه کن، ببین تست قرمز میشود، بعد برگردان.
۸. (فاز ۳ — فقط با تأیید صریح کاربر) مهاجرت سه فایل بزرگ
pages/DoctorDetailPage.tsx (۳۱۳ utility رنگی / ۱۴۲ dark:)، components/schedule/ScheduleSection.tsx (۲۶۰ / ۱۲۰)، pages/UserDetailPage.tsx (۱۹۸ / ۹۱).
اینها در دارکمود کار میکنند (جفت slate/gray + dark: دارند) ولی از design-system منحرفاند: با تغییر brand hue هماهنگ نمیشوند و رنگ خاکستریشان با --surface/--text مو نمیزند. مهاجرت ۷۷۱ نقطه ریسک رگرسیون بصری بالایی دارد و سود عملکردی فوری ندارد.
توصیه: این وظیفه را در همین پاس انجام نده. اگر کاربر تأیید کرد، فایلبهفایل و با اسکرینشات قبل/بعد در هر دو مود.
نکات مهم
- علت ریشهای، نه علامت: الگوی
className="dark:…"کنارstyle={{color:…}}نشان میدهد قبلاً تلاش شده دارکمود «وصله» شود بدون اینکه specificity در نظر گرفته شود. راهحل درست حذف رنگ ثابت است، نه اضافه کردن!importantیا جفتdark:بیشتر. اگر جایی واقعاً به override نیاز شد، اول ببین آیا میشود کلاً ازstyleبهclassNameرفت. - ترتیب اجرا اجباری است: وظیفهٔ ۲ (خرابی قطعی، ۹۰ نقطه) قبل از وظیفهٔ ۳ (حجیم). اگر بودجه/زمان تمام شد، وظایف ۲، ۴، ۵ حداقل قابل تحویل مستقلاند.
- لایتمود نباید تغییر کند. توکنهای لایت همان hexهای رایجاند؛ هر تغییر بصری محسوس در لایت یعنی نگاشت اشتباه انتخاب شده — گزارش کن، خودسرانه توکن جدید نساز.
- توکن جدید فقط با دلیل. اگر جایی هیچ توکن مناسبی نبود، اول بررسی کن آیا واقعاً رنگ جدید لازم است یا نزدیکترین توکن کافی است (guidelines §۵ — abstraction بیمصرف ممنوع). توکن جدید اگر اضافه شد باید در هر سه بلوک
:root،[data-theme="dark"]و در صورت لزوم@supportsتعریف شود. - سازگاری مرورگر قدیمی: بلوک
@supports (color: color-mix(in oklch, red, blue))عمداً fallback sRGB دارد (iPhone 8 / WebKit قدیمی). هیچ توکنی نباید فقط داخل@supportsتعریف شود. brandHue.fixed: هیوی «نارنجی» درuiStore.tsمقادیر--primary*را inline روی root میگذارد. یعنی هر جا#5559CEثابت مانده باشد با انتخاب این هیو ناهماهنگ میشود — این یک تست بصری مستقل است، نه فقط دارک/لایت.- بدون تغییر backend/API. این تسک صفر تغییر در
src/وdocs/api/دارد؛ تنها سند متأثرdocs/admin-ui/ui-design-spec.mdاست. - دستورها داخل ddev اجرا میشوند:
ddev exec npm run test،ddev exec npm run build. برای مشاهدهٔ زندهddev exec npm run watch. - حساب تست:
09390039833 / 09390039833رویhttps://clinic-pro.ddev.site/admin.