Files
EventHubSpec/design/front/UI-PARITY.md
T
aleksey 4d8f4db284 docs(spec): Front#45 mood chip mobile icon-only chrome
Sync EventHubFrontSpec and UI-PARITY with mark-only logo + icon-only chip on mobile.

Refs EventHub/EventHubFront#45
2026-07-29 23:46:07 +03:00

261 lines
20 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.
# UI parity: EventHubFront ↔ CalenTIQ board
План визуального выравнивания клиентского фронта с утверждённым бордом.
SoT: [`boards/calentiq-ui-board-final.png`](boards/calentiq-ui-board-final.png).
Эпик: [EventHubSpec#10](https://git.sabilin.com/EventHub/EventHubSpec/issues/10).
**Статус:** workstreams 15 закрыты в коде Front (Refs Front#25#29). Stage smoke на `https://stage.calentiq.com`**done** (UI `0.2.29` / `79dadfb21f98`, API `0.2.158`).
---
## Known deviations from board (Front#29)
Зафиксировано осознанно / пока не делаем (после visual pass ×3 moods + stage):
| Зона | Борд | Сейчас |
|------|------|--------|
| Pixel-perfect calendar | denser board mock + Today/Upcoming rail | Agenda rail (§B): title-case Сегодня/Предстоящие + count, time-first rows; month chips/cell wash (§B/D) по mood; не 1:1 Figma |
| Discover cards | soft cards + media thumb + CTA | mood media plane (wash/initials + `image_url` when present) + soft-card rhythm + CTA; без full photo-hero grid |
| CONTROL booking §E | отдельные mock-карточки «слот/специалист» | `EventActionCard` / specialists / bookings: steel rail (усилен), avatar, available label, Confirm/Decline; не pixel-perfect board mocks |
| Bookings list §D | список заявок с Confirm/Decline на `/bookings` | `/bookings` = **grouped inbox**: (A) К подтверждению — pending owner/specialist + Confirm/Decline; (B) Мои записи — participant upcoming/past + Cancel; empty groups hidden. Event card Confirm/Decline **остаётся** обязательным |
| Login §D phone chrome | три phone frames + (на борде) Google CTA | brand-first hero + mood `--auth-*`; email/password only; compact mood на auth; taglines — в mood sheet AppShell (не в `/more`); **без** Google OAuth |
| Mood placement | board §C switcher cards | **Front#40/#45:** mood chip в AppShell рядом с BrandWordmark (+ compact auth); mobile icon-only chip + mark-only logo; **не** в `/more`, **не** в toolbar Month/Week/Day; 3 moods, без flip / CREATOR |
| Lens + strip | board Today/Upcoming rail only | **Front#39 + controls IA:** lens Обзор/На сегодня/Заявки в **шапке strip** (underline tabs / mobile sheet); view Месяц/Неделя/День рядом с периодом; owner schedule actions отдельным рядом; localStorage only; soft-default по mood |
| Week view headers | — | **Front#40:** одна строка day-headers (без дубля `WeekDayColumn`); scroll `.eh-cal-week-scroll` (mobile ~390) |
| Favicon set | 3 отдельных favicon файла на борде | mood appicon через `applyMood` |
| Desktop nav | phone bottom tabs на борде | desktop: **одна строка** chrome — logo + mood \| nav (Календарь / Найти / Записи / Ещё) \| nickname + logout; bottom nav — mobile |
| Header identity | — | nickname primary (не raw email); email только в `title` tooltip |
| Bookings past/expired | — | `expired` бейдж + Cancel скрыт; empty-state с CTA Discover / календари; soft list time |
| Agenda empty copy | — | personal «Нет событий»; commercial «Нет слотов» |
| More invites | пункт меню | скрыт при pending=0; badge счётчика при pending > 0 |
| D9 guest specialist schedule | — | **модель B (Front#35):** roster карточек → тап → фильтр слотов по `event.specialist_id`; «Все слоты студии»; book без specialist в body; **не** chip-filter |
| Confirmed на personal | — | Front-only overlay confirmed чужих commercial на default personal; title `событие · студия · спец`; клик → `/c/:foreignCalId/e/:eventId` |
| SpecialistsPanel density | — | mobile: имя/теги сверху, actions снизу full-width (Front#33/#35) |
| Stage | полный smoke на stage | **done** 2026-07-27: Login×3 / Calendar×3 + agenda / Discover / CONTROL commercial + Confirm·Decline / More moods |
| Домены calentiq.* | — | публичный stage: `stage.calentiq.com` / `admin.stage.calentiq.com` (канон STAGE-BROWSER.md) |
IA без sidebar / без Creator mood — совпадает с non-goals (проверено на stage).
### Visual pass ×3 moods (local + stage)
**Checked (vite preview + Playwright shots + stage HTTPS):** Login §D, Calendar grid+agenda, Discover media, CONTROL slot/bookings (Confirm/Decline на event card), More mood cards — FLOW / MOMENTUM / CONTROL.
**Polish in this pass:** agenda copy/casing/counts + time-first rows; CONTROL steel rail emphasis; neutral Discover cover in mock (не flow-appicon во всех moods).
**Front#31 (2026-07-27):** desktop one-row chrome (logo|nav|logout); header nickname; bookings `expired` + soft list time + empty CTA; agenda personal vs commercial empty copy; Discover cover photo/fallback; More invites badge.
**Front#35 (2026-07-28, SHA `57cfcf3`):** D9 модель B (guest roster → schedule filter); confirmed foreign overlay на personal; SpecialistsPanel mobile density; F6 EventActionCard past+pending → expired / no Cancel, Book скрыт на past.
**Front#39 (2026-07-28, SHA `c2cb754` / `d38a927`):** Mood chip убран из Ещё; Lens Обзор/Сегодня/Записи + strip над сеткой во всех 3 moods; mobile sheets + strip collapsed; mood→DB, lens→localStorage; без flip / CREATOR. (Placement chip уточнён в Front#40.) **Controls IA (2026-07-29):** lens перенесён в шапку strip (labels: Обзор / На сегодня / Заявки); view рядом с периодом; owner schedule actions отдельным рядом.
**Front#40 (2026-07-28, SHA mood `7c092d1` / week `db11c41`):** Mood chip в AppShell рядом с BrandWordmark (**не** в calendar toolbar Month/Week/Day); 3 moods; `PATCH preferences.mood`; без дубля в Ещё. Week view: одна строка day-headers + `.eh-cal-week-scroll` для mobile ~390.
**Front#45 (2026-07-29):** Mobile mood chrome — chip icon-only (без truncate label) + BrandWordmark mark-only; `sm+` полный label + wordmark; sheet без изменений; `aria-label` на chip.
**Remaining intentional:** no pixel-perfect phone chrome; Discover без photo-hero grid (cover via `image_url` when API returns it; broken URL → wash+initials); §E specialist schedule card vs panel — не pixel-perfect board mocks (follow-up). Product flow D9 B — documented; board pixel mock — Future.
### Bookings inbox + More invites (locked 2026-07-27)
Продуктовые решения (не deviation — канон):
1. **Event card Confirm/Decline** остаётся обязательным (quick approve на слоте).
2. **`/bookings`** — grouped inbox, не только participant:
- **Группа A — К подтверждению:** pending bookings, где пользователь calendar **owner** или **assigned specialist** (`event.specialist_id` = user). Confirm/Decline те же, что на `EventActionCard`.
- **Группа B — Мои записи:** participant bookings (upcoming/past + Cancel) как раньше.
- Пустые группы скрывать (`count=0`).
- Опционально подпись owner vs specialist внутри A; иначе одна секция «К подтверждению».
3. **`specialist_invite` в More:** скрывать пункт меню, если **0 pending** входящих; при
pending > 0 — **badge** со счётчиком. Deep-link `/invites?token=` работает. Исходящие
invite остаются в `SpecialistsPanel`.
4. **Не** класть строки `specialist_invite` в `/bookings`.
5. **Past-pending / `expired`:** Back#60 помечает past-pending → `expired` и исключает из
`booking-requests`; Confirm/Decline → `409`. UI: бейдж «истекла», Cancel скрыт
(Bookings + EventActionCard); defensive map past+pending → expired badge.
Front#35 F6: на past Book скрыт; past+pending на карточке → expired label.
API: `GET /v1/user/booking-requests` (Back) + существующий `PUT /v1/bookings/:id`
(`409` на expired / full).
### Guest specialist schedule + confirmed overlay (locked Front#35)
1. **D9 модель B (guest на commercial):** roster активных специалистов (карточки) →
тап → сетка только со слотами выбранного `event.specialist_id`; CTA «Все слоты
студии» сбрасывает фильтр. **Не** chip-filter на shared grid. Book body без
specialist. Owner `SpecialistsPanel` (invite/CRUD) не менять этим флоу.
2. **Confirmed на personal (Front-only):** `GET /v1/user/bookings` (confirmed) +
догрузка events/calendars → overlay на **default personal** grid; title
`event · studio · specialist`; клик → `/c/:foreignCalId/e/:eventId`. Back без
изменений.
3. **SpecialistsPanel density (mobile):** имя/теги сверху, actions снизу full-width.
### Mood + Lens (locked Front#39 / placement Front#40)
1. **Mood** = визуальная атмосфера (`html[data-mood]`, FLOW/MOMENTUM/CONTROL). Primary UX —
chip → sheet в **AppShell** рядом с BrandWordmark (Front#40); compact на auth.
**Нет** в `/more`; **не** в toolbar Month/Week/Day. Persist: `preferences.mood`
через `PATCH /v1/user/me`. Без flip; без CREATOR. Front#45: mobile chip icon-only +
mark-only logo; desktop — полный label/wordmark; sheet — icon + label + tagline.
2. **Lens** = отдельный контентный режим (`overview` / `today` / `bookings`), не mood и не
view month/week/day. UI: Обзор / На сегодня / Заявки. Переключатель — в шапке strip
(underline/text tabs на desktop; chip → sheet на mobile), **не** рядом с ViewMode.
Soft-default при смене mood, если lens не pinned: FLOW→overview, MOMENTUM→today,
CONTROL→bookings.
3. **Strip** над сеткой (не на HTML-архиве месяца): Front-only derive — free gaps /
события сегодня / upcoming bookings. Desktop раскрыт по умолчанию; mobile свёрнут
(tap раскрывает). Сетка всегда видна. Workspace toolbar: контекст (селектор) /
виджет (период + view) / owner schedule actions (отдельный ряд).
4. **Persistence:** mood → DB; language → `user.language`; lens → `localStorage`
(`eh.calendar.lens` + pinned). Без нового Back API.
5. **Week view (Front#40):** одна строка day-headers (без дубля `WeekDayColumn`);
горизонтальный скролл `.eh-cal-week-scroll` (mobile ~390).
### Follow-ups (вне этого fix-pass или частично)
| Тема | Статус |
|------|--------|
| Discover `image_url` в search serialization | Back отдаёт поле; upload API **нет** — только URL field / seed; Front#31: photo vs fallback media classes + onError fallback |
| Stage Popular clutter (e2e calendars) | filter notes: см. `EventHubSpec/STAGE-POPULAR-CLEANUP.md`; не трогать реальные smoke данные без фильтра по e2e-паттернам |
| §E specialist schedule card vs panel | deviation: EventActionCard + SpecialistsPanel; pixel mock — Future; **product D9 B** — done Front#35 |
| Desktop one-row chrome | **done** Front#31; mood chip у logo — Front#40 (`7c092d1`) |
| D9 B + confirmed personal overlay | **done** Front#35 (`57cfcf3`) |
| Mood chip + Lens strip | **done** Front#39 (`c2cb754` / `d38a927`); chip → AppShell Front#40; mobile icon-only Front#45 |
| Week view single header + scroll | **done** Front#40 (`db11c41`) |
## Mood concept = product surface
Mood — не переименование `calm|energetic|business` и не смена primary hex.
Каждый mood — **отдельная атмосфера продукта** при той же IA:
| Mood | Ощущение | Chrome / surfaces | Discover / booking feel |
|------|----------|-------------------|-------------------------|
| **FLOW** (`calm`) | спокойствие, баланс | soft sage panels, light wash, soft chips | мягкие карточки, спокойный CTA |
| **MOMENTUM** (`energetic`) | энергия, скорость | ink `#111820`, coral `#FF6A3D`, denser chips | тёмный discover, яркий CTA |
| **CONTROL** (`business`) | бизнес, доступность | steel `#324A5F`, cool neutrals | коммерческие карточки слот/специалист/CTA |
Референс на борде: секции **B Mood Overview**, **C Mood Switcher**, **D Core Screens**, **NEW Discover**, **E Booking / Commercial**.
Switcher — **branded cards** (иконка + короткий tagline), не plain list/tabs:
- FLOW — *Find balance*
- MOMENTUM — *Get more done*
- CONTROL — *Grow the business*
Опционально: mood-aware favicon из [`boards/calentiq-icon-system-final.png`](boards/calentiq-icon-system-final.png) / `mood-icons/`.
Токены сейчас узкие ([`tokens/colors.json`](tokens/colors.json)); для parity нужны surfaces, gradients, chip/event styles, chrome — не только primary.
---
## Workstreams (mood-first)
Порядок важен: сначала атмосфера и токены, затем экраны поверх них.
### 1. Mood system / atmosphere — **P0 / first** ✅
CSS-токены и chrome на mood beyond primary hex: surfaces, gradients, event chip styles; switcher как branded cards (icon + tagline); опционально mood favicon.
**Acceptance**
- [x] Per-mood token set: surface / wash / chip / border / CTA (не только primary)
- [x] Mood switcher = 3 branded cards с иконкой и tagline с борда
- [x] Смена mood меняет атмосферу chrome (не только accent button)
- [x] API keys остаются `calm|energetic|business`
- [x] Опционально: favicon следует активному mood
**Design:** board §B, §C, §F; `mood-icons/`; `tokens/`
**Done:** EventHubFront#25`index.css` mood tokens + `MoodSwitcher` cards + favicon via `applyMood`.
### 2. Calendar mood-chrome — **P0** ✅
Та же сетка/IA; soft panels (FLOW), denser chips (MOMENTUM), mood-tinted cells (CONTROL) — как на борде §B / §D Calendar.
**Acceptance**
- [x] Month/week выглядят различно по mood при той же навигации
- [x] Event chips / cells тонированы mood-токенами
- [x] Нет sidebar / смены layout ради «красоты»
**Design:** board §B Mood Overview, §D Calendar
**Done:** EventHubFront#26`--cal-*` tokens + `.eh-cal` / `.eh-chip` в `CalendarWidget`; IA без изменений.
**Follow-up:** month grid §B/D — FLOW sage cell wash + chip limit 2; MOMENTUM denser/hotter chips limit 5; CONTROL steel cells + sharper chips limit 3; split time/title chips.
### 3. Discover mood variants — **P1** ✅
Визуальная дифференциация FLOW vs MOMENTUM vs CONTROL: soft cards + CTA; соответствие борду (NEW Discover / §D Discover), не as-is скринам.
**Acceptance**
- [x] Discover в трёх moods визуально различим (фон, карточки, CTA)
- [x] Soft card + CTA pattern с борда (не плоский as-is list-only)
- [x] IA и фильтры без смены модели; только presentation
**Design:** board NEW Discover, §D Discover; as-is refs: `eventhub-discover-{flow,momentum,control}.png`
**Done:** EventHubFront#27`--disc-*` + `.eh-discover-card` / `.eh-discover-cta`; list → card grid.
**Follow-up:** media hierarchy — `.eh-discover-media` with per-mood size/radius/washes (FLOW air / MOMENTUM energy / CONTROL steel), optional cover via `image_url`, display title + soft-card rhythm.
### 4. CONTROL booking surfaces — **P1** ✅
Коммерческие карточки: слот, специалист, CTA — только Control-specific (§E).
**Acceptance**
- [x] Slot card + specialist card + primary CTA в CONTROL
- [x] Specialists остаются внутри Control (не 4-й mood)
- [x] FLOW/MOMENTUM не получают Control commercial chrome
**Design:** board §E Booking / Commercial
**Done:** EventHubFront#28`.eh-book-slot` / `.eh-book-specialist` / `.eh-book-request`; steel chrome только под `data-mood=business`.
**Follow-up:** §E polish — `--book-*` tokens; CONTROL steel left-rail + sharper radii; slot duration/available label; specialist/request avatars; mood-token CTA/Decline.
### 5. Polish + stage smoke — **P2** ✅
Мелкие расхождения с бордом, wordmark/lockup consistency, stage smoke трёх moods.
**Acceptance**
- [x] Mock smoke: calendar → discover → bookings в 3 moods (+ IA без sidebar)
- [x] Нет регрессий IA (top + bottom nav) — покрыто mock e2e
- [x] Известные отклонения от борда зафиксированы в UI-PARITY (Known deviations)
- [x] Visual pass ×3 moods (local preview / Playwright shots) — Login / Calendar / Discover / CONTROL booking
- [x] Stage smoke на живом стенде — UI `0.2.29` (`79dadfb21f98`) @ `https://stage.calentiq.com` (2026-07-27)
**Done:** EventHubFront#29`e2e/tests/mood-parity-smoke.spec.ts`, brand meta, CONTROL tagline polish.
**Follow-up:** visual pass polish — agenda Предстоящие + counts/time-first; CONTROL steel rail; mock Discover cover neutral. Stage: seed commercial + slots + pending booking для §E Confirm/Decline.
## Non-goals
- Left sidebar / смена IA
- 4-й Creator mood / AI-assistant home
- Rename API keys (`calm|energetic|business` остаются)
- Покупка доменов / DNS cutover
- Админский UI (`design/admin/`) — не трогать Front-бордами
- Полный pixel-perfect каждого пикселя борда (направление + mood atmosphere)
---
## Mapping → issues
| # | Workstream | Issue |
|---|------------|-------|
| — | Story (родитель) | [Spec#11](https://git.sabilin.com/EventHub/EventHubSpec/issues/11) |
| 1 | Mood system / atmosphere | [Front#25](https://git.sabilin.com/EventHub/EventHubFront/issues/25) |
| 2 | Calendar mood-chrome | [Front#26](https://git.sabilin.com/EventHub/EventHubFront/issues/26) |
| 3 | Discover mood variants | [Front#27](https://git.sabilin.com/EventHub/EventHubFront/issues/27) |
| 4 | CONTROL booking surfaces | [Front#28](https://git.sabilin.com/EventHub/EventHubFront/issues/28) |
| 5 | Polish + stage smoke | [Front#29](https://git.sabilin.com/EventHub/EventHubFront/issues/29) |
| — | P1/P2 UX polish + expired + desktop chrome | [Front#31](https://git.sabilin.com/EventHub/EventHubFront/issues/31) |
| — | Past-pending → `expired` | [Back#60](https://git.sabilin.com/EventHub/EventHubBack/issues/60) |
| — | P2: D9 B + confirmed personal + density/F6 | [Front#35](https://git.sabilin.com/EventHub/EventHubFront/issues/35) |
| — | Mood chip + Lens strip (workspace) | [Front#39](https://git.sabilin.com/EventHub/EventHubFront/issues/39) |
| — | Mood chip → AppShell + week scroll | [Front#40](https://git.sabilin.com/EventHub/EventHubFront/issues/40) |
| — | Mood chip icon-only mobile + mark-only logo | [Front#45](https://git.sabilin.com/EventHub/EventHubFront/issues/45) |
Эпик: [Spec#10](https://git.sabilin.com/EventHub/EventHubSpec/issues/10).
---
## Suggested start
Кодить с **Task 1 (Mood system / atmosphere)**: без токенов и switcher-as-cards остальные экраны будут «перекраской primary», а не mood product surface.