# قواعد UI — هر صفحه و بخش جدید عیناً مطابق سیستم موجود

**الزامی برای همهٔ تسک‌ها.** هیچ طراحی جدید، هیچ تم جدید، هیچ کامپوننت موازی.
منبع حقیقت: کدِ موجود، نه سلیقه و نه `docs/admin-ui/ui-design-spec.md` (که draft قدیمی
با پالت بنفش است و با کد شیپ‌شده نمی‌خواند).

---

## پنل ادمین `clinicpro` — React 19 + Webpack Encore + Tailwind v4

### توکن‌ها — هرگز مقدار hard-code

منبع: `assets/admin/styles.css`، بلوک `:root`.

```tsx
// ❌
<div style={{ background: '#5559CE', borderRadius: 14 }}>

// ✅
<div className="bg-[var(--primary)] rounded-[var(--r)]">
```

| گروه | توکن |
|---|---|
| برند | `--primary` `#5559CE` · `--primary-600/700` · `--primary-soft/soft2` · `--on-primary` |
| اکسنت | `--accent` `#f0682a` · `--accent-600` · `--accent-bg` |
| سطوح | `--bg` `--bg-2` `--surface` `--surface-2/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}` |
| شعاع | `--r-xs:7` `--r-sm:8` `--r:14` `--r-lg:18` `--r-xl:24` `--r-pill:999` |
| سایه | `--shadow-sm` `--shadow` `--shadow-lg` |
| چیدمان | `--sidebar-w:243` `--collapsed-w:90` `--topbar-h:64` `--gap:20` `--card-pad:22` `--row-h:56` |
| حرکت | `--ease: cubic-bezier(.22,.61,.36,1)` |

دارک‌مود با `[data-theme="dark"]` و حالت فشرده با `[data-density="compact"]` خودکار
اعمال می‌شوند — **اگر** از توکن استفاده کرده باشی. مقدار hard-code در دارک‌مود می‌شکند.

### کامپوننت‌ها — اول جست‌وجو، بعد ساخت

`assets/admin/components/ui/` این‌ها را دارد. ساختن نسخهٔ موازی از هر کدام **رد** می‌شود:

```
DataTable (مرتب‌سازی، جستجو، skeleton، empty state، bulk) · Modal · ConfirmDialog
PageHeader (عنوان + breadcrumb + action + backTo) · BackButton · StatCard · StatusBadge
Pagination · SearchableSelect · AppointmentStatusDropdown
PersianDateInput / PersianDatePicker / PersianCalendar
MobileInput · PriceInput · Portal · FeatureGate · Altcha
```

### پنج قاعدهٔ غیرقابل‌مذاکره

1. **`SearchableSelect`، هرگز `<select>` بومی.** بی‌استثنا.
2. **دکمهٔ بازگشت در هر زیرصفحه.** صفحه‌ای که از دل صفحهٔ دیگر باز می‌شود:
   - با `PageHeader` → فقط `backTo="/admin/…"` بده
   - بی `PageHeader` → `<BackButton fallback="/admin/…" />` بالای هدر
   - دکمهٔ دست‌ساز نساز. رفتار در `hooks/useGoBack.ts` متمرکز است.
3. **وضعیت لیست در URL، نه در `useState`.** جستجو، فیلتر، شمارهٔ صفحه، نما — همه با
   `hooks/useUrlState.ts`:
   ```tsx
   const [urlState, setUrlState] = useUrlState({ page: '1', search: '', status: '' });
   const setSearch = (v: string) => setUrlState({ search: v, page: '1' });
   ```
   دلیلش «بازگشت» است: `navigate(-1)` همان URL را برمی‌گرداند. فیلد جستجوی debounce‌شده
   local می‌ماند، فقط مقدار نهایی به URL می‌رود.
4. **داده فقط با TanStack Query.** `useQuery`/`useMutation`، کلید `['resource', page, filters]`،
   همهٔ HTTP از `lib/api.ts`. استخراج: paginated → `data?.data` + `data?.meta?.totalRecords`؛
   single → `data?.data`؛ Category → `data?.data?.data ?? []`.
5. **فرم با React Hook Form + Zod.** `z.object({...})` و تایپ با `z.infer`.

### فارسی، RTL، شمسی

- همهٔ رشته‌های UI فارسی — از فایل i18n، نه inline
- تاریخ‌ها شمسی با `formatDate`/`formatDateTime` از `lib/utils.ts` (پشت‌صحنه `jalaali-js`)
- مبالغ با `formatRial`/`formatNumber`
- جهت RTL — `ms-*`/`me-*` به‌جای `ml-*`/`mr-*`
- فونت `Vazirmatn` از `@fontsource/vazirmatn`
- آیکن‌ها Heroicons v2 · نمودار Recharts · تُست `sonner`

### نام‌گذاری و مسیر

- صفحه: `assets/admin/pages/XxxPage.tsx` · کامپوننت PascalCase · هوک `useXxx.ts`
- کامپوننت عمومی → `components/ui/` · کامپوزیت مخصوص فیچر → `components/*.tsx`
- تایپ‌های مشترک → `types/index.ts`
- مسیر در `App.tsx` (React Router v7)، زیر `/admin/*`

---

## سایت عمومی `nobat724_front` — Next.js 15 App Router + MUI v5 + Tailwind

- تم MUI در `mui/index.js` با `direction: rtl` و فونت Vazir — تم جدید نساز
- Tailwind با `darkMode: "class"`؛ صفحات عمومی `data-theme`، پنل `class`
  (`next-themes` در `app/Providers.js`)
- **فونت فقط Vazir** — در `app/globals.css` با `@font-face`. فونت دیگر اضافه نکن.
- هر صفحه باید `generateMetadata` صادر کند · همیشه `await params`
- شهر از subdomain: server-side `lib/getStateInfo.js` · client-side `useProvince()`
- فراخوانی API: `services/response.js` → `request.*`؛ برای auth `{ requireAuth: true }`
- داده server-side: `lib/req.js` → `fetchReq(url)`
- slug پزشک/کلینیک = `uuid`
- JSON-LD مستقیم در JSX صفحات doctor/clinic/blog
- تاریخ شمسی با `jalali-moment` / `dayjs`
- کامپوننت‌های موجود `components/appointment/*` را توسعه بده، مسیر موازی نساز

---

## چک‌لیست UI — در `checklist.md` هر تسکی که صفحه یا کامپوننت می‌سازد

هر ردیف باید یکی از ✅ / 🔄 / ⏳ / ⚠️ بگیرد:

```
□ هیچ رنگ/شعاع/سایهٔ hard-code نیست — همه از توکن‌های styles.css
□ دارک‌مود بررسی شد (data-theme="dark") و چیزی نمی‌شکند
□ حالت فشرده بررسی شد (data-density="compact")
□ همهٔ select ها SearchableSelect اند، هیچ <select> بومی نیست
□ زیرصفحه‌ها backTo یا <BackButton /> دارند
□ وضعیت لیست (جستجو/فیلتر/صفحه) در URL است با useUrlState
□ لیست‌ها از DataTable استفاده می‌کنند با skeleton و empty state فارسی
□ هیچ کامپوننت موازیِ چیزی که در components/ui/ هست ساخته نشد
□ همهٔ رشته‌ها فارسی و از i18n
□ تاریخ‌ها شمسی با formatDate · مبالغ با formatRial
□ RTL بررسی شد (ms/me نه ml/mr)
□ موبایل بررسی شد (بدون اسکرول افقی)
□ فرم‌ها با React Hook Form + Zod
□ داده با TanStack Query و استخراج envelope درست
□ خطاها با پیام فارسی از ErrorCodes نمایش داده می‌شوند
```
