admin/docs/consumer-ui-guidelines.md
alisaza e1eaf5eff5 feat: initial ghabilee-admin backoffice app
Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js
app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
2026-09-05 13:12:59 +03:30

162 lines
6.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Consumer UI guidelines
Hard constraints for the end-user app under `frontend/app/(consumer)/` and
shared consumer surfaces (`components/consumer/*`, PWA/auth overlays used
there, event/review/booking flows).
Agents must follow the always-on Cursor rules
`consumer-modals`, `consumer-input`, `consumer-button`, and `consumer-mobile-first`. This doc is the longer
companion.
## 1. Overlays: ConsumerModal only
Any modal / dialog in the consumer app must use
`components/consumer/ConsumerModal`.
```tsx
// ❌ BAD — admin/shared Modal in consumer UI
import Modal from '@/components/modals/Modal'
// ✅ GOOD
import ConsumerModal from '@/components/consumer/ConsumerModal'
```
Do not use `components/modals/Modal`, HeroUI `Drawer`, or ad-hoc fixed
banners for consumer dialogs. Admin stays on `components/modals/Modal`
(see `admin-ui-guidelines.md`).
`ConsumerModal` is always a **bottom sheet** (phone and desktop). There is no
centered / top / auto placement.
## 3. Form fields: ConsumerInput only
Any text field, select, textarea, OTP, radio, checkbox, switch, or number
input in the consumer app must use `components/consumer/ConsumerInput`.
```tsx
// ❌ BAD — admin/shared Input in consumer UI
import Input from '@/components/formElements/Input'
// ✅ GOOD
import ConsumerInput from '@/components/consumer/ConsumerInput'
```
Do not use `components/formElements/Input` in consumer surfaces.
**Props:** use `size` (`sm` | `md` | `lg`), `radius`
(`full` | `control`, 10px), and `tone` (`muted` | `bordered`). `muted` applies
`#E2E2E280` fill; `bordered` is white surface + border. **Select is always
`muted`.** Do not pass HeroUI
`size`, `radius`, or `variant`.
**Standalone mode:** when the parent is not wrapped in `react-hook-form`, pass
`value` and `onValueChange``ConsumerInput` creates an internal form bridge.
**Custom wrappers:** pass `inputWrapper` to merge classes (auth full-radius
fields, host contact section).
**OTP styling:** pass `otpClassNames={{ segment, segmentWrapper }}` when the
default consumer OTP look is not enough (e.g. auth gate).
**Temporary exception:** `birthDatePicker`, `combobox`, and other admin-only
field kinds not yet in ConsumerInput v1 may keep `formElements/Input` for that
single field until support is added.
Implementation lives under `components/consumer/input/` (`ConsumerFieldShell`,
`consumerInputStyles.ts`, per-kind controls). Admin panel and event-create wizard
stay on `formElements/Input`.
## 4. Actions: ConsumerButton only
Any button, submit control, or link-styled action in the consumer app must use
`components/consumer/ConsumerButton`.
```tsx
// ❌ BAD — admin/shared Button in consumer UI
import Button from '@/components/formElements/Button'
// ✅ GOOD
import ConsumerButton from '@/components/consumer/ConsumerButton'
```
Do not use `components/formElements/Button` in consumer surfaces.
**Props:** use `fill` (`orange` | `navy` | `gray` | `none`), `size`
(`xs` | `sm` | `md` | `lg` | `xl`), `radius` (`full` | `control`), `textColor`,
`fontSize`, `align`, and icon props (`iconStart` / `iconEnd` / `iconOnly`). Do not
pass HeroUI `size`, `radius`, `variant`, or `color`.
**Size tokens (button heights):**
| `size` | height |
| ------ | ----------------------: |
| `xs` | 40px |
| `sm` | 44px |
| `md` | 48px |
| `lg` | 52px (default text CTA) |
| `xl` | 60px |
Default: `lg` for text buttons, `sm` for `iconOnly`.
**هم‌نام بودن ≠ هم‌اندازه بودن:** `ConsumerButton` `size` and `ConsumerInput`
`size` reuse labels (`sm`, `md`, `lg`) but map to **different pixel
heights**. Do not assume a field and a button with the same token name share
one height.
| token | `ConsumerButton` `size` | `ConsumerInput` `size` |
| ----- | ----------------------: | ---------------------: |
| `xs` | 40px | — |
| `sm` | 44px | 32px |
| `md` | 48px | 48px |
| `lg` | 52px | 52px |
| `xl` | 60px | — |
**Four button roles (+ icon chrome):**
| Role | API | Typical use |
| ------------------- | ----------------------------------------- | --------------------------------- |
| Conversion CTA | `fill="orange"` (default) | login, book, continue |
| Dark primary | `fill="navy"` | modal confirm, host CTAs |
| Inline / card pill | `fill="gray"` | cancel booking, nav chips, follow |
| Text / ghost action | `fill="none"` + `textColor` | change mobile, resend code, links |
| Destructive | `fill="none"` + `textColor="text-fourth-900"` | delete, cancel reservation |
| Icon-only | `iconOnly` + `size="sm"` | bookmark, share, edit on cards |
**Dual cancel/primary rows:** `ConsumerActionButtons` (modal footers,
`ConsumerFormActionBar`). Do not duplicate that layout.
**No ad-hoc visual `className`:** if Figma needs a look this component cannot
express via `fill`, `size`, `radius`, `textColor`, `fontSize`, or `align`, stop
and ask the product owner — do not patch with `bg-*`, `text-*`, `rounded-*`, etc.
Extend `ConsumerButton` only after explicit approval. Layout-only classes
(`flex-1`, `mt-5`, `shrink-0`, …) are fine.
Admin panel stays on `formElements/Button`.
## 5. Mobile excellence; desktop does not matter
The consumer app is a **mobile product**.
- Target phone widths (~360430px) first and last.
- No horizontal scroll, clipped content, overlapping BottomNav, or ignored
safe-area insets.
- Touch targets ≥ 44px; primary CTAs reachable with one thumb when practical.
- Fix mobile layout bugs before any other visual work.
**Non-goal:** desktop / wide-viewport polish. Do not invest in multi-column
desktop layouts or large-screen aesthetics unless explicitly requested. A
correct phone layout always wins over a polished desktop layout.
Design tokens and patterns: [`docs/frontend/consumer-design-system.md`](../../docs/frontend/consumer-design-system.md).
Copy catalog: [`consumer-texts.md`](./consumer-texts.md).
## 6. Event cards
Use the single medium card `components/consumer/EventCard` everywhere.
- Fixed top: poster + date / time / category / location + title.
- Variable bottom: pass page-specific UI via `children` (inline `div`s).
- Optional helper: `EventCapacityBadge` for remaining-seat chips in discovery/host footers.
- Loading state: `EventCardSkeleton` / `EventCardSkeletonList`.
- Dense lists: `CompactEventCard` or `ConsumerEventThumbRow` when the medium card is too tall.