9.2 KiB
name, description
| name | description |
|---|---|
| redesign-page | بازطراحی UI/UX یک صفحه از پنل ادمین ClinicPro از روی URL آن — اسکرینشات گرفتن از صفحه، نگاشت URL به فایل سورس، آدیت انحرافها از دیزاینسیستم، و بازنویسی صفحه با کامپوننتها و توکنهای موجود. استفاده کن وقتی کاربر یک URL از /admin میدهد و میگوید «این صفحه ui/ux خوبی ندارد»، «این صفحه را بازطراحی کن»، «redesign this page»، «این قسمت را درست کن»، یا «screenshot این صفحه». |
بازطراحی صفحه پنل ادمین ClinicPro
پنل ادمین یک SPA کلاینتساید است (React 19 + Webpack Encore، سرو شده از /admin/*).
یعنی curl و فلگ --screenshot کروم به درد نمیخورند: هر دو روی فرم لاگین مینشینند،
چون توکن JWT در localStorage['clinicpro-auth'] است.
درایور این skill آن کار را انجام میدهد: با API لاگین میکند، localStorage را seed
میکند، بعد ناوبری و اسکرینشات میگیرد — با CDP روی WebSocket نیتیو Node 22،
بدون هیچ وابستگی npm (نه playwright، نه puppeteer).
مسیرها نسبت به clinicpro/ هستند.
پیشنیازها
هیچ نصبی لازم نیست. فقط این دو:
ddev describe | head -3 # باید بالا باشد: https://clinic-pro.ddev.site
ls "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
کروم در مسیر دیگری است؟ CHROME_BIN را ست کن.
گردش کار
۱. اسکرینشات صفحه فعلی
node .claude/skills/redesign-page/driver.mjs shot \
"https://clinic-pro.ddev.site/admin/appointments" --out /tmp/before.png
بعد حتماً تصویر را با ابزار Read باز کن و نگاه کن. بدون دیدنِ صفحه، بازطراحی یعنی حدس زدن.
فلگها: --w 1440 --h 900 (سایز ویوپورت)، --wait 4000 (میلیثانیه صبر برای رندر)،
--full (کل صفحه، نه فقط ویوپورت).
موبایل هم ببین — این پنل RTL و پرجدول است و بیشتر مشکلات ریسپانسیو آنجاست:
node .claude/skills/redesign-page/driver.mjs shot \
"https://clinic-pro.ddev.site/admin/appointments" --w 390 --h 844 --out /tmp/mobile.png
۲. نگاشت URL به سورس + آدیت
node .claude/skills/redesign-page/driver.mjs inspect \
"https://clinic-pro.ddev.site/admin/clinics/41e325c4-e825-4067-8438-5d828ecaee09"
خروجی واقعی:
route clinics/:uuid
component ClinicDetailPage
file assets/admin/pages/ClinicDetailPage.tsx
components ConfirmDialog, Modal, PageHeader, SearchableSelect, NotificationMobileCard
lines 1035
AUDIT
assets/admin/pages/ClinicDetailPage.tsx:242 hand-rolled overlay — use the shared <Modal>
روی هر فایل دلخواه هم مستقیم:
node .claude/skills/redesign-page/driver.mjs audit assets/admin/pages/AppointmentsPage.tsx
۳. قبل از نوشتن کد، دیزاینسیستم را بخوان
منبع حقیقتِ توکنها assets/admin/styles.css است — نه docs/admin-ui/ui-design-spec.md
(آن سند قدیمی و پالت بنفشش با کد شیپشده نمیخواند).
sed -n '/^:root/,/^}/p' assets/admin/styles.css | head -60 # توکنها
ls assets/admin/components/ui/ # کامپوننتهای آماده
قانون: اول کامپوننت موجود، بعد توسعهاش، در آخر ساخت کامپوننت جدید — و دلیلش را بنویس.
۴. بازنویسی، سپس مقایسه
بعد از ادیت، دوباره اسکرینشات بگیر و با before.png مقایسه کن:
yarn dev # یا: yarn watch
node .claude/skills/redesign-page/driver.mjs shot "<همان url>" --out /tmp/after.png
۵. تست + تایپچک (بدون این، تسک تمام نیست)
npx tsc --noEmit -p tsconfig.json
npx vitest run assets/admin/pages/<YourPage>.test.tsx
توجه: سوییت کامل همین الان ۲۱ تست از پیش شکسته دارد (api.test.ts، LoginPage،
PatientDetailPage، …) که ربطی به کار تو ندارند. قبل از شروع یکبار npx vitest run
بگیر و عدد پایه را یادداشت کن، وگرنه خطاهای موجود را به گردن تغییر خودت میاندازی.
چکلیست بازطراحی
درایور موارد گرپشدنی را میگیرد؛ اینها را باید خودت با چشم ببینی:
.fieldدر مقابل.field-block—.fieldیک باکس افقی بوردردار است که لیبل داخلش مینشیند. اگر<label>داخل.fieldبگذاری، لیبل کنار اینپوت میچسبد؛ و اگرSearchableSelectداخلش بگذاری، دو باکس تودرتو میشود. برای «لیبل بالای فیلد» از.field-blockاستفاده کن.className="btn"بدون واریانت بیرنگ و بدون بوردر رندر میشود — عملاً نامرئی. همیشهbtn primary/btn ghost/btn soft/btn danger.- دکمههای فقط-آیکون →
mini-btn، نهbtn ghost smبا پدینگ دستی. - توکن مرده — مثلاً
var(--error)وجود ندارد (--dangerدرست است). درایور این را میگیرد. - سلسلهمراتب — عنوان صفحه در
PageHeaderبیاید و در کارت زیرش تکرار نشود. - RTL/جلالی — رشتههای جدید فارسی، تاریخها جلالی، اعداد با
formatNumber/formatRial. - دارکمود — چون توکن استفاده میکنی خودکار درست است؛ هگز هاردکد آن را میشکند.
Gotchas
-
ریدایرکت خاموش نقشها.
RoleRouteکاربری که نقشش اجازه ندارد را بیصدا به/admin/dashboardمیبرد. یعنی یک اسکرینشات کاملاً سالم از صفحهٔ اشتباه میگیری. درایور مسیر نهایی را با مسیر درخواستی مقایسه میکند و هشدار میدهد:⚠ WRONG PAGE: asked for /admin/clinics/…, landed on /admin/dashboardکاربر پیشفرض (
09390039833) نقش doctor دارد. صفحات ادمین/کلینیک با آن باز نمیشوند. برای آنهاCLINICPRO_USER/CLINICPRO_PASSرا ست کن. -
کاربران تستی ممکن است seed نشده باشند.
TEST_USERS.mdادمین09100000001با رمزTest@1234را مستند میکند، ولی روی این دیتابیس وجود نداشت و لاگینERR_AUTH_005داد. ساختنشان:ddev exec php create_test_users.php(دیتابیس را مینویسد — اول بپرس). -
مودال نصب PWA جلوی صفحه را میگیرد. درایور
localStorage['pwa-dismissed']='1'را seed میکند. اگر با کروم خام اسکرینشات بگیری، این مودال وسط تصویر است. -
کپچا (altcha) لوکال اجباری نیست.
POST /api/v1/user/loginبدون فیلدaltchaهم توکن میدهد؛ درایور به همین تکیه میکند. اگر روی محیطی که کپچا را اجبار میکند اجرا شود، میشکند. -
سرت ddev را Node رد میکند (
UNABLE_TO_VERIFY_LEAF_SIGNATURE). درایور فقط برای هاستهای*.ddev.site/localhostتأیید TLS را خاموش میکند، نه برای هر مبدأ. -
صفحهٔ نوبتها خودش اسکرول میشود به ساعت جاری، پس ویوپورت وسط تایملاین میافتد. برای دیدن هدر از
--fullاستفاده کن. -
بیلد CSS داخل ddev خطای نیتیو
lightningcssمیدهد — از قبل وجود دارد و جلوی کامپایل JS/TS را نمیگیرد. خطاهای TypeScript همچنان در خروجیtscمیآیند.
Troubleshooting
| علامت | علت / راهحل |
|---|---|
Chrome did not expose CDP on :9333 |
نمونهٔ کروم قبلی زنده مانده. CDP_PORT=9444 بده یا پروسه را بکش. |
login failed: … ERR_AUTH_005 |
کاربر seed نشده یا رمز فرق دارد. TEST_USERS.md را ببین. |
⚠ redirected to /login |
توکن رد شد؛ معمولاً یعنی JWT منقضی شده — دوباره اجرا کن. |
⚠ page text is only N chars |
صفحه خالی رندر شده. --wait 8000 بده یا کنسول را چک کن. |
| اسکرینشات تغییرات را نشان نمیدهد | باندل قدیمی است. yarn dev بزن (یا yarn watch روشن باشد). |