Files
ERP/docs/mobile-responsive.md
T
whqreza 9e2089e853 feat(mobile): mobile-responsive UI — bottom tab bar, bottom-sheet dialogs, PWA
All changes are gated behind max-md:/md:hidden so the >=768px desktop layout is untouched (verified with lint + build + live checks at 375px).

- globals.css: one mobile block — 16px inputs (no iOS auto-zoom), units sidebar stacks above content, wizard item rows become 2-col (text fields full-width, delete button full-width), dd-panels / flow diagram / conv-form stack, larger touch targets
- ui/dialog.tsx: dialogs become full-width bottom sheets on mobile (all modals inherit it); desktop keeps the centered dialog
- Header: sticky on mobile only + PageLayout bottom clearance
- New MobileTabBar: role-aware bottom tabs (office admin/manager, inventory PM, inventory admin); hidden on /wizard
- Wizard step 4: TouchSensor (150ms delay) so touch drag works without stealing scroll
- JalaliDatePicker: dropdown capped to viewport; bigger day cells and time inputs on mobile
- PWA: manifest.webmanifest + 192/512 icons (scripts/gen-pwa-icons.ps1) + theme-color/manifest links in index.html
- New docs/mobile-responsive.md documenting the full change set
2026-09-03 19:26:40 +03:30

109 lines
8.3 KiB
Markdown

# Mobile-Responsive UI — Change Log (v1.4)
هدف: تجربه‌ی کاربری قابل‌استفاده برای کاربران موبایل (اکثریت کاربران)، بدون اینکه
ظاهر دسکتاپ هیچ تغییری بکند. هیچ بک‌اند، nginx، docker-compose یا ساختار جدیدی
اضافه نشده — همه‌چیز داخل همان اپ React است.
## Core principle
یک کدبیس، دو نمایش. همه‌ی تغییرات «فقط موبایل» هستند و پشت بریک‌پوینت
Tailwind `max-md:` (زیر 768px) یا `md:hidden` (فقط روی موبایل نمایش داده می‌شود)
قفل شده‌اند. دسکتاپ (≥768px) همان استایل‌های قبلی را می‌خواند و بنابراین
پیکسل‌به‌پیکسل بدون تغییر می‌ماند — به‌ساختار.
## What changed
### 1. `frontend/src/styles/globals.css` — consolidated mobile block (new)
یک بلوک `@media (max-width: 767.98px)` در انتهای فایل اضافه شد:
| Rule | Effect (mobile only) |
|---|---|
| `input/select/textarea { font-size: 16px !important }` | جلوگیری از زوم خودکار iOS روی فوکوس (فونت‌های ۱۲–۱۴px زوم می‌شدند) |
| `.units-layout { grid-template-columns: 1fr }` | سایدبار ۲۲۰px دسته‌ها روی موبایل بالای پنل محتوا قرار می‌گیرد |
| `.item-row-head { display: none }` + `.wizard-item-row` دوستونه | ردیف اقلام ویزارد (گرید ۸ ستونه) روی موبایل می‌شود: فیلدهای متنی تمام‌عرض، عددها دوستونه؛ placeholderها نقش برچسب را دارند |
| `.wizard-item-row > :last-child` تمام‌عرض + حداقل ۴۴×۴۰px | دکمه‌ی حذف قلم بزرگ و قابل لمس |
| `.dd-panels { grid-template-columns: 1fr }` | پنل‌های درگ‌اندروپ مرحله‌ی ۴ تک‌ستونه |
| `.flow-cols` تک‌ستونه + `.flow-lines { display: none }` | نمودار جریان باکس‌ها روی هم؛ خطوط SVG اتصال که فقط در چیدمان دوستونه معنی داشتند روی موبایل مخفی می‌شوند |
| `.conv-form` تک‌ستونه، `.conv-row` wrap | فرم تبدیل واحد (گرید ۵ ستونه) روی موبایل ستونی |
| touch targets بزرگ‌تر (`.chip`, `.quick-chip`, `.spec-chip`, `.dd-item`, `.ut-cat`, `.btn-line-file`, دکمه‌های × و ...) | ارتفاع هدف لمسی به ~۴۰px رسید |
### 2. `frontend/src/components/ui/dialog.tsx` — dialogs become bottom sheets
`DialogContent` با کلاس‌های `max-md:` به bottom-sheet تمام‌عرض تبدیل شد
(`inset-x-0 bottom-0`، گوشه‌های گرد فقط بالا، `max-h-[85dvh]`، padding با
`safe-area-inset-bottom`). چون همه‌ی مودال‌ها (ویرایش، پذیرش، تایید حذف) از همین
کامپوننت استفاده می‌کنند، همه یک‌جا درست شدند. دکمه‌ی بستن هم بزرگ‌تر شد.
### 3. Form grids stacked — one-line additions each
- `EditModal.tsx` — گرید تأمین‌کننده/پروژه و گرید تاریخ‌ها: `max-md:grid-cols-1`
- `Wizard/Step1TopicSupplier.tsx` — فرم تأمین‌کننده‌ی جدید: `max-md:grid-cols-1`
- `Wizard/Step5Review.tsx` — گرید تاریخ‌ها: `max-md:grid-cols-1`
- `Suppliers/CategoryPage.tsx` — فرم افزودن تأمین‌کننده: `max-md:grid-cols-1`
### 4. `frontend/src/components/layout/Header.tsx` — sticky header + clearance
- هدر فقط روی موبایل `sticky top-0 z-40` شد (`max-md:`)
- دکمه‌ی بازگشت بزرگ‌تر شد
- `PageLayout` روی موبایل `pb-24` گرفت تا نوار تب پایین روی محتوا نیفتد
### 5. `frontend/src/components/layout/MobileTabBar.tsx` — NEW mobile bottom tab bar
نوار تب پایین (فقط `<768px` با `md:hidden`):
- **ادمین / مدیر تدارکات در دفتر:** داشبورد / تأمین‌کننده‌ها / پروژه‌ها / ضرایب
- **ادمین / مدیر تدارکات در پنل انبار:** انبار / کنترل روزانه / کالاهای در راه / سازمان‌دهی (آینه‌ی ناوبری دسکتاپ)
- **مدیر پروژه:** انبار / تغییر موجودی / کنترل روزانه / کالاهای در راه
- هدف لمسی ≥۵۶px، padding برای `safe-area-inset-bottom`، هایلایت تب فعال
- در `/wizard` نمایش داده نمی‌شود (تا با جابه‌جایی تصادفی کارِ کاربر از بین نرود)
### 6. `frontend/src/App.tsx` — renders `<MobileTabBar />`
### 7. `frontend/src/pages/Wizard/Step4Projects.tsx` — touch drag & drop
`TouchSensor` با `{ delay: 150, tolerance: 8 }` به سنسورهای dnd-kit اضافه شد:
درگ لمسی کار می‌کند بدون اینکه اسکرول صفحه را بدزدد. مسیر کلیک-قلم-بعد-کلیک-پروژه
هم‌چنان مسیر جایگزین است. دسکتاپ همان `PointerSensor` قبلی را دارد.
### 8. `frontend/src/components/JalaliDatePicker.tsx` — dropdown width + targets
- داپداون تقویم: `max-w-[calc(100vw-2rem)]` (در صفحه‌های باریک سرریز نمی‌شود)
- سلول‌های روز و ورودی‌های ساعت/دقیقه روی موبایل بزرگ‌تر شدند
### 9. PWA layer (optional installability)
- `frontend/public/manifest.webmanifest` — NEW (name فارسی، `dir: rtl`،
`display: standalone`، theme `#4f46e5`، آیکون 192/512 + maskable)
- `frontend/public/icons/icon-192.png`, `icon-512.png` — NEW
(تولیدشده با `frontend/scripts/gen-pwa-icons.ps1` — NEW، بدون وابستگی)
- `frontend/index.html` — `theme-color` + لینک manifest + آیکون‌ها اضافه شد
- روی HTTP مثل میان‌بر صفحه‌ی اصلی کار می‌کند؛ پرامپت نصب رسمی PWA به HTTPS
نیاز دارد (بعداً با پروکسی/Let's Encrypt — بدون تغییر کد).
## Deliberately NOT changed
- **`SpecDrawer.tsx`**: کد مرده است (هیچ‌جا import نمی‌شود) — تصمیم تیم: دست نمی‌زنیم، فایل می‌ماند.
- **`.e-item-row` / `.spec-drawer` در CSS**: کلاس‌های بلااستفاده — دست‌نخورده ماندند.
- هیچ کلاس/استایل دسکتاپی ویرایش نشد؛ تمام تغییرات داخل `max-md:` یا کامپوننت‌های `md:hidden` است.
## Verification performed
- `npm run lint` (oxlint) → 0 errors (4 هشدار از قبل موجود)
- `npm run build` (tsc + vite) → موفق
- تست مرورگر روی Vite dev (viewport واقعی 375px):
- نوار تب: `fixed bottom-0`، قابل‌مشاهده، ۴ تب با برچسب درست، ارتفاع ≥56px
- هدر `sticky`، ورودی‌ها 16px، padding پایین صفحه 96px (جای نوار تب)
- صفحات ضرایب/ویزارد چیدمان تک‌ستونه (`.units-layout` فقط بعد از انتخاب موضوع رندر می‌شود)
- رگرسیون دسکتاپ: کلاس‌های دسکتاپ دست‌نخورده‌اند (بریک‌پوینت‌گیت)؛
`npm run build` سلامت باندل را تایید می‌کند.
## How to test manually
```powershell
cd C:\Users\Reza\Desktop\v1.4
docker compose up -d --build # بازسازی ایمیج فرانت
```
سپس در مرورگر دسکتاپ DevTools → device toolbar (مثلاً iPhone SE 375px) یا
مستقیم با گوشی (بخش «دیدن روی گوشی» در README/جواب نهایی). دسکتاپ را هم در
1280px چک کنید — باید دقیقاً مثل قبل باشد.
## Notes / known considerations
- خطوط اتصال نمودار جریان (SVG) روی موبایل عمداً مخفی شد — فقط باکس‌ها روی هم
قرار می‌گیرند؛ اگر روزی خواستید اتصال‌ها را روی موبایل هم ببینید باید
`FlowDiagram` برای حالت تک‌ستونه بازنویسی شود.
- نوار تب موبایل «انبارها» را ندارد (PMها از منوی همبرگری به آن می‌رسند).