223 lines
14 KiB
Markdown
223 lines
14 KiB
Markdown
---
|
|
name: redesign-page
|
|
description: نقد و بازطراحی حرفهای UI/UX یک صفحه از پنل ادمین ClinicPro از روی URL آن — اسکرینشات در چهار نما (روشن، تیره، فشرده، موبایل)، پروبِ دسترسیپذیری روی DOM زنده، نگاشت URL به فایل سورس، آدیت انحراف از دیزاینسیستم، و بازنویسی با کامپوننتها و توکنهای موجود. استفاده کن وقتی کاربر یک URL از /admin میدهد و میگوید «این صفحه ui/ux خوبی ندارد»، «این صفحه را بازطراحی کن»، «این صفحه را نقد کن»، «redesign this page»، «UI/UX review»، «این قسمت را درست کن»، یا «screenshot این صفحه».
|
|
---
|
|
|
|
> **قبل از شروع، فایل `clinicpro/.claude/guidelines.md` را بخوان و همهٔ بخشهای آن را اعمال کن — از جمله `§۰ Grill` که قبل از هر تغییر اجباری است.**
|
|
|
|
# نقد و بازطراحی صفحهٔ پنل ادمین ClinicPro
|
|
|
|
نقش: متخصص ارشد UI/UX. هدف **بهبود تجربهٔ کاربری در چهارچوب تم فعلی** است، نه ساختن
|
|
هویت بصری جدید. هر تغییری که با دیزاینسیستم فعلی ناسازگار باشد، رد است.
|
|
|
|
پنل ادمین یک SPA کلاینتساید است (React 19 + Webpack Encore، سرو شده از `/admin/*`).
|
|
یعنی `curl` و فلگ `--screenshot` کروم به درد نمیخورند: هر دو روی فرم لاگین مینشینند،
|
|
چون توکن JWT در `localStorage['clinicpro-auth']` است. درایور این skill آن کار را
|
|
میکند: با API لاگین میکند، `localStorage` را seed میکند، تم/تراکم را مینشاند، بعد
|
|
ناوبری و اسکرینشات میگیرد — با CDP روی `WebSocket` نیتیو Node 22، **بدون هیچ وابستگی
|
|
npm** (نه playwright، نه puppeteer).
|
|
|
|
مسیرها نسبت به `clinicpro/` هستند.
|
|
|
|
## پیشنیازها
|
|
|
|
هیچ نصبی لازم نیست:
|
|
|
|
```bash
|
|
ddev describe | head -3 # باید بالا باشد: https://clinic-pro.ddev.site
|
|
ls "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
|
```
|
|
|
|
کروم جای دیگری است؟ `CHROME_BIN` را ست کن.
|
|
|
|
## گردش کار
|
|
|
|
### ۰. اول دیزاینسیستم را بخوان — قبل از هر چیز
|
|
|
|
**منبع حقیقتِ توکنها `assets/admin/styles.css` است**، نه `docs/admin-ui/ui-design-spec.md`
|
|
(آن سند قدیمی است و پالت بنفشش با کد شیپشده نمیخواند).
|
|
|
|
```bash
|
|
node .claude/skills/redesign-page/driver.mjs ds # توکنها + کلاسها + کامپوننتها
|
|
node .claude/skills/redesign-page/driver.mjs ds tokens # فقط توکنها
|
|
node .claude/skills/redesign-page/driver.mjs ds components # فقط کامپوننتهای مشترک با Props
|
|
```
|
|
|
|
خروجی واقعی: `TOKENS (57)` و `SHARED COMPONENTS (26)`. قانون ترتیب:
|
|
**اول کامپوننت موجود، بعد توسعه/عمومیکردنش، در آخر ساخت کامپوننت جدید** — و دلیلش را بنویس.
|
|
|
|
### ۱. چهار نمای اجباری
|
|
|
|
```bash
|
|
node .claude/skills/redesign-page/driver.mjs variants \
|
|
"https://clinic-pro.ddev.site/admin/resources" --dir /tmp/clinicpro-review
|
|
```
|
|
|
|
چهار فایل میسازد: `-light` · `-dark` · `-compact` · `-mobile`. **هر چهار را با ابزار
|
|
Read باز کن و نگاه کن.** قضاوت با یک اسکرینشات یعنی صفحهای که در سه نمای دیگر خراب است.
|
|
تم تیره و تراکم فشرده در این پنل تنظیمات واقعی کاربرند، نه فرض.
|
|
|
|
تکنما:
|
|
|
|
```bash
|
|
node .claude/skills/redesign-page/driver.mjs shot "<url>" --out /tmp/x.png \
|
|
--theme dark --density compact --w 390 --h 844 --full --wait 6000
|
|
```
|
|
|
|
فلگها: `--w/--h` ویوپورت · `--wait` میلیثانیه · `--full` کل صفحه ·
|
|
`--theme light|dark` · `--density comfortable|compact` · `--context clinic|personal` ·
|
|
`--no-probe`.
|
|
|
|
هر `shot` یک **پروب رانتایم** هم میزند که فقط روی DOM رندرشده دیدنی است:
|
|
|
|
```
|
|
RUNTIME
|
|
⚠ 2 form field(s) with no label
|
|
```
|
|
|
|
چه چیزهایی میگیرد: سرریز افقی، دکمهٔ آیکونیِ بینام (بدون `aria-label`/`title`)،
|
|
فیلد بدون لیبل، و کنترل کوتاهتر از ۳۲px (هدف لمسی ۴۴px است).
|
|
|
|
### ۲. نگاشت URL به سورس + آدیت ایستا
|
|
|
|
```bash
|
|
node .claude/skills/redesign-page/driver.mjs inspect "https://clinic-pro.ddev.site/admin/resources"
|
|
```
|
|
|
|
خروجی واقعی:
|
|
|
|
```
|
|
route resources
|
|
component ResourcesPage
|
|
file assets/admin/pages/ResourcesPage.tsx
|
|
components PageHeader, DataTable, ResourceBlocksModal, ConfirmDialog, SearchableSelect, …
|
|
lines 278
|
|
test assets/admin/pages/ResourcesPage.test.tsx
|
|
|
|
AUDIT clean
|
|
```
|
|
|
|
روی هر فایل مستقیم:
|
|
|
|
```bash
|
|
node .claude/skills/redesign-page/driver.mjs audit assets/admin/pages/ClinicDetailPage.tsx
|
|
# AUDIT
|
|
# assets/admin/pages/ClinicDetailPage.tsx:242 hand-rolled overlay — use the shared <Modal>
|
|
```
|
|
|
|
آدیت اینها را میگیرد: `<select>` نیتیو، `.btn` بدون واریانت، هگز هاردکد، overlay دستی،
|
|
`<label>` داخل `.field`، تاریخ میلادی، `type="date"`، دکمهٔ آیکونی بدون `aria-label`،
|
|
توکن تعریفنشده، و `.seg` بدون کلاس `on/active`.
|
|
|
|
### ۳. گزارش — همیشه با این ۹ بخش
|
|
|
|
```
|
|
۱. تحلیل صفحه چه کاری برای چه کاربری؛ جریان اصلی
|
|
۲. مشکلات UI سلسلهمراتب بصری، فاصله، تایپوگرافی، رنگ، انحراف از DS
|
|
۳. مشکلات UX جریان کار، تعداد کلیک، حالتهای Loading/Empty/Error، ریسپانسیو، دسترسیپذیری
|
|
۴. پیشنهادهای بهبود برای هر مشکل، یک راهحل مشخص و قابل اجرا
|
|
۵. ساختار جدید صفحه چیدمان پیشنهادی، در چهارچوب همین تم
|
|
۶. کامپوننتهای قابل استفادهٔ مجدد از components/ui که همین حالا جواب میدهند
|
|
۷. کامپوننتهای نیازمند بهبود کدام Props/API باید عمومیتر شود و چرا
|
|
۸. کامپوننتهای جدید فقط در صورت ضرورت، با دلیل نبودِ جایگزین
|
|
۹. دلیل هر تغییر چرا این تغییر تجربه را بهتر میکند
|
|
```
|
|
|
|
هر یافته باید به `file:line` وصل باشد یا به یکی از اسکرینشاتها. یافتهٔ بیارجاع، حدس است.
|
|
|
|
### ۴. بازنویسی، سپس مقایسه
|
|
|
|
```bash
|
|
ddev exec yarn dev
|
|
node .claude/skills/redesign-page/driver.mjs variants "<همان url>" --dir /tmp/clinicpro-review-after
|
|
```
|
|
|
|
before/after را کنار هم بگذار. اگر تفاوتی دیده نمیشود، باندل قدیمی است.
|
|
|
|
### ۵. تست + تایپچک (بدون این، تسک تمام نیست)
|
|
|
|
```bash
|
|
ddev exec npx tsc --noEmit --project tsconfig.json
|
|
npx vitest run # روی هاست، نه داخل ddev
|
|
```
|
|
|
|
خط پایه در ۲۰۲۶-۰۸-۰۲: **۱۰۰ فایل، ۶۶۰ تست، همه سبز.** هر شکستی مالِ توست.
|
|
(نسخهٔ قبلی این سند از «۲۱ تست از پیش شکسته» میگفت — دیگر درست نیست.)
|
|
|
|
## چکلیست بازطراحی
|
|
|
|
درایور موارد گرپشدنی و DOMی را میگیرد؛ اینها را باید خودت با چشم ببینی:
|
|
|
|
- **`.field` در مقابل `.field-block`** — `.field` خودش باکسِ بوردردار اینپوت است. لیبل
|
|
داخلش یعنی لیبل چسبیده به اینپوت؛ `SearchableSelect` داخلش یعنی دو باکس تودرتو.
|
|
«لیبل بالای فیلد» → `.field-block`.
|
|
- **`.card` پدینگ ندارد** — `card-pad` آن را میدهد.
|
|
- **`className="btn"` بدون واریانت** بیرنگ و بیبوردر رندر میشود، عملاً نامرئی.
|
|
همیشه `btn primary` / `btn secondary` / `btn ghost` / `btn danger`.
|
|
- **دکمهٔ فقط-آیکون** → `mini-btn`، نه `btn ghost sm` با پدینگ دستی.
|
|
- **`.seg`** فقط `button` و `a` را میشناسد و کلاس فعالش `on` است (`active` هم alias شد).
|
|
تبِ فعالِ بیکلاس یعنی هیچ نشانهای ندارد.
|
|
- **سلسلهمراتب** — عنوان در `PageHeader` بیاید و در کارت زیرش تکرار نشود.
|
|
- **صفحهٔ زیرمجموعه** حتماً `backTo` یا `<BackButton fallback=…>` دارد.
|
|
- **وضعیت لیست در URL** — جستجو/فیلتر/صفحه با `useUrlState`، نه `useState`؛ وگرنه
|
|
«بازگشت» نما را میپراند.
|
|
- **RTL/جلالی** — رشتههای جدید فارسی، تاریخها جلالی، اعداد با `formatNumber`/`formatRial`.
|
|
- **دارکمود** — با توکن خودکار درست است؛ یک هگز هاردکد آن را میشکند.
|
|
- **سه حالت داده** — Loading / Empty / Error هر سه باید طراحی داشته باشند، نه فقط حالت پر.
|
|
|
|
## Gotchas
|
|
|
|
- **کاربر پیشفرض درایور با دیتابیس فعلی هماهنگ است، ولی دیتابیس عوض میشود.**
|
|
پیشفرض `0912000201` / `QaTest@1234` (پزشکِ مالک کلینیک) است. اگر لاگین `ERR_AUTH_005`
|
|
داد، دیتابیس دوباره seed شده: `ddev exec php bin/console app:seed-scenarios --reset -n`.
|
|
در اجرای ۲۰۲۶-۰۸-۰۲ کاربر `0912000301` (مالک غیرپزشک) **رمز نداشت** و لاگینش رد شد؛
|
|
از `0912000201` یا `0912000101` استفاده کن.
|
|
|
|
- **ریدایرکت خاموش نقشها.** `RoleRoute` کاربرِ بیمجوز را بیصدا به `/admin/dashboard`
|
|
میبرد — یعنی یک اسکرینشات کاملاً سالم از **صفحهٔ اشتباه**. درایور مقایسه میکند:
|
|
|
|
```
|
|
⚠ WRONG PAGE: asked for /admin/clinics/…, landed on /admin/dashboard
|
|
```
|
|
|
|
- **محیط کاری، نه نقش.** کاربری که هم مطب شخصی دارد هم کلینیک، پیشفرض روی مطب مینشیند و
|
|
صفحهٔ منابع/سرویسهای کلینیک **خالی** میآید. این باگ نیست: `--context clinic` بده.
|
|
|
|
- **مودال نصب PWA جلوی صفحه را میگیرد.** درایور `pwa-dismissed=1` را seed میکند. با
|
|
کروم خام، این مودال وسط تصویر است.
|
|
|
|
- **تم فقط با صفت `data-theme` نمیماند** — بعد از hydrate از `localStorage['clinicpro-ui']`
|
|
دوباره خوانده میشود. درایور هر دو را مینویسد و بعد از رندر یک بار دیگر صفت را میگذارد.
|
|
|
|
- **موبایل بدون `Emulation.setDeviceMetricsOverride` فقط «پنجرهٔ باریک» است** — مدیا
|
|
کوئریهای `pointer: coarse` خاموش میمانند و ارتفاع لمسی ۴۴px دیده نمیشود. درایور برای
|
|
عرض ≤۴۸۰ خودش این را روشن میکند.
|
|
|
|
- **کپچا (altcha) لوکال اجباری نیست.** `POST /api/v1/user/login` بدون فیلد `altcha` هم
|
|
توکن میدهد؛ درایور به همین تکیه میکند و روی محیطی که کپچا را اجبار کند میشکند.
|
|
|
|
- **سرت ddev را Node رد میکند** (`UNABLE_TO_VERIFY_LEAF_SIGNATURE`). درایور فقط برای
|
|
`*.ddev.site` / `localhost` تأیید TLS را خاموش میکند، نه برای هر مبدأ.
|
|
|
|
- **صفحهٔ نوبتها خودش تا ساعت جاری اسکرول میکند**، پس ویوپورت وسط تایملاین میافتد.
|
|
برای دیدن هدر `--full` بده.
|
|
|
|
- **منوی تنظیمات دو مصرفکننده دارد** — `settingsMenu.ts` منبع واحد است؛ سایدبار دسکتاپ و
|
|
فهرست موبایل هر دو از آن میخوانند. در موبایل کل منو **بالای** محتوا مینشیند، پس صفحهٔ
|
|
تنظیماتی در نمای ۳۹۰px یعنی ۱۵ آیتم منو قبل از رسیدن به محتوا. در نقد موبایل حتماً ببینش.
|
|
|
|
- **بیلد CSS داخل ddev خطای نیتیو `lightningcss` میدهد** — از قبل هست و جلوی کامپایل
|
|
JS/TS را نمیگیرد؛ خطاهای TypeScript همچنان در خروجی `tsc` میآیند.
|
|
|
|
## Troubleshooting
|
|
|
|
| علامت | علت / راهحل |
|
|
|---|---|
|
|
| `login failed for 0912000201: … ERR_AUTH_005` | دیتابیس دوباره seed شده. `ddev exec php bin/console app:seed-scenarios --reset -n` یا `CLINICPRO_USER`/`CLINICPRO_PASS` را ست کن. |
|
|
| `Chrome did not expose CDP on :9333` | نمونهٔ کروم قبلی زنده مانده. `CDP_PORT=9444` بده یا پروسه را بکش. |
|
|
| `⚠ redirected to /login` | توکن رد شد؛ معمولاً JWT منقضی شده — دوباره اجرا کن. |
|
|
| `⚠ WRONG PAGE` | نقشِ کاربر اجازه ندارد، یا محیط اشتباه است (`--context clinic`). |
|
|
| `⚠ page text is only N chars` | صفحه خالی رندر شده. `--wait 8000` بده یا کنسول را چک کن. |
|
|
| اسکرینشات تغییرات را نشان نمیدهد | باندل قدیمی است. `ddev exec yarn dev` (یا `yarn watch` روشن). |
|
|
| صفحهٔ کلینیک خالی است ولی خطا ندارد | محیط روی مطب شخصی است. `--context clinic`. |
|