From 86e53b5f0bdaa9467f0052af971468fc2835f5df Mon Sep 17 00:00:00 2001 From: Aleksey Sabilin Date: Tue, 28 Jul 2026 21:22:03 +0300 Subject: [PATCH] Docs: sync Front#39 Mood chip + Lens strip. Fixes EventHub/EventHubSpec#16 Refs EventHub/EventHubFront#39 (c2cb754 / d38a927). --- EventHubFrontSpec.md | 36 ++++++++++++++++++++++++++---------- UX-BACKLOG.md | 9 +++++++++ WORKFLOW.md | 1 + design/front/UI-PARITY.md | 22 +++++++++++++++++++++- 4 files changed, 57 insertions(+), 11 deletions(-) diff --git a/EventHubFrontSpec.md b/EventHubFrontSpec.md index 27692d8..7491d00 100644 --- a/EventHubFrontSpec.md +++ b/EventHubFrontSpec.md @@ -38,7 +38,7 @@ Deep-link на календарь, владельцем которого явл - Сборщик: Vite - UI: React 19 + Tailwind CSS 4 + shadcn/Radix - Типографика: Syne (display) + Manrope (UI) -- Состояние: Zustand (auth + mood + calendar context), TanStack React Query v5 (сервер) +- Состояние: Zustand (auth + mood + lens + calendar context), TanStack React Query v5 (сервер) - HTTP: Axios с интерсепторами - Формы: React Hook Form + Zod - Дата/время: dayjs (ru locale) @@ -55,8 +55,14 @@ Deep-link на календарь, владельцем которого явл и «Мои записи» (participant); пустые группы скрывать. Confirm на карточке события остаётся. Past/expired: бейдж `expired` («истекла»), Cancel скрыт; empty-state с CTA Discover / календари. Время на list-карточках — вторичное к title (`.eh-book-list-time`). -- В **Ещё**: пункт входящих specialist invites скрыт при `pending=0`; при `pending > 0` — - badge со счётчиком (deep-link `/invites` работает). +- В **Ещё**: язык (`LanguageSwitcher`); пункт входящих specialist invites скрыт при + `pending=0`; при `pending > 0` — badge со счётчиком (deep-link `/invites` работает). + **Mood в Ещё нет** — только chip в chrome workspace календаря (Front#39). +- **Mood + Lens (workspace, Front#39):** в chrome календаря — mood chip (FLOW/MOMENTUM/ + CONTROL → sheet picker); отдельно lens «Обзор / Сегодня / Записи» (desktop segment / + mobile sheet); над сеткой — collapsible lens strip (Front-only derive из уже + загруженных events/bookings). Без flip календаря; без 4-го CREATOR. Strip по + умолчанию раскрыт на desktop, свёрнут на mobile. Нет на HTML-архиве месяца. - Контекст виджета: свой календарь (селектор) или чужой (browse после поиска). Чужой `personal` — только просмотр; чужой `commercial` с `booking_open=true` — запись; при `booking_open=false` (restricted / нет подписки владельца) — просмотр + сообщение «Запись временно недоступна». @@ -89,7 +95,7 @@ Deep-link на календарь, владельцем которого явл ## 3.2. Настроения (mood themes) / режимы CalenTIQ -Публичный бренд UI: **CalenTIQ** (см. [BRANDING.md](BRANDING.md)). Внутренние ключи API/preferences без изменений. +Публичный бренд UI: **CalenTIQ** (см. [BRANDING.md](BRANDING.md)). Внутренние ключи API/preferences без изменений. Три mood только — **без CREATOR**, без flip календаря. Пользователь переключает визуальный режим; атрибут `html[data-mood]`. Для гостя и при отсутствии `preferences.mood` — дефолт `calm` (в профиль при логине не пишется). После входа смена mood сохраняется в `preferences.mood` через `PATCH /v1/user/me`. @@ -99,9 +105,19 @@ Deep-link на календарь, владельцем которого явл | MOMENTUM | `energetic` | тёмный ink + coral `#FF6A3D` | | CONTROL | `business` | charcoal + steel `#324A5F`, более жёсткие радиусы | -Переключатели mood и языка: на экранах auth (`/login`, `/register`, `/verify`) и в `/more`. В шапке workspace — wordmark CalenTIQ (Time Arc), **nickname** (не raw email) и выход (без mood/lang). Desktop chrome — одна строка: logo | nav | logout. +**Где mood:** +- Auth (`/login`, `/register`, `/verify`, forgot/reset) — compact `MoodSwitcher` (+ language). +- Calendar workspace — primary control: **mood chip** → dialog/sheet (не в `/more`). +- App shell header — wordmark + nickname + logout (**без** mood/lang). Desktop: logo \| nav \| logout. -Язык UI (`ru`/`en`): до логина — `navigator.language`; после входа — поле `language` профиля (`PATCH /v1/user/me`). Если в профиле язык пуст — при логине записывается текущий (браузерный/выбранный на экране входа). Язык также можно сменить в форме `/profile`. +**Lens** (отдельно от mood и от view month/week/day): `overview` / `today` / `bookings` +(UI: Обзор / Сегодня / Записи). Persist только `localStorage` (`eh.calendar.lens` + +`eh.calendar.lens.pinned`); **не** поле профиля / Back API. Soft-default при смене mood, +если lens не pinned пользователем: FLOW→overview, MOMENTUM→today, CONTROL→bookings. +Strip над сеткой: free gaps сегодня / события сегодня / upcoming bookings (derive +на клиенте из уже загруженных данных). + +Язык UI (`ru`/`en`): до логина — `navigator.language`; после входа — поле `language` профиля (`PATCH /v1/user/me`). Если в профиле язык пуст — при логине записывается текущий (браузерный/выбранный на экране входа). Язык также в `/more` и в форме `/profile`. ## 4. Маршруты @@ -116,8 +132,8 @@ Deep-link на календарь, владельцем которого явл - `/bookings` — grouped inbox: (A) к подтверждению (owner/specialist pending) + (B) мои записи участника; deep-link в `/c/.../e/...` - `/calendars` — управление своими календарями (CRUD) -- `/more` — вторичное меню + mood switcher; пункт specialist invites **скрыт**, - если входящих pending = 0; при pending > 0 — badge со счётчиком +- `/more` — вторичное меню + language switcher (**без** mood); пункт specialist + invites **скрыт**, если входящих pending = 0; при pending > 0 — badge со счётчиком (deep-link `/invites?token=` работает) - `/invites` — inbox входящих specialist invites (не смешивать с `/bookings`) - `/following` — отслеживаемые чужие календари (follow; не платная Подписка) @@ -125,7 +141,7 @@ Deep-link на календарь, владельцем которого явл Redirects: `/discover` → `/search`; `/calendars/:id` → `/c/:id`; `/calendars/:id/events/:eventId` → `/c/:id/e/:eventId`. -Состояние вида: Zustand `calendarContextStore` (`view`, `cursorDate`, last own `calendarId` в `localStorage`). +Состояние вида: Zustand `calendarContextStore` (`view`, `cursorDate`, last own `calendarId` в `localStorage`); lens — `lensStore` + `localStorage` (см. §3.2). ## 5. Модули @@ -133,7 +149,7 @@ Redirects: `/discover` → `/search`; `/calendars/:id` → `/c/:id`; `/calendars Регистрация, верификация, вход, восстановление сессии. ### 5.2. Профиль -`GET /v1/user/me` + форма на `/profile`. Редактируемые через `PATCH /v1/user/me`: `nickname`, `phone`, `timezone`, `avatar_url`, `language`; смена пароля — `current_password` + `password`. Read-only в UI: `id`, `email`, `role`, `status`. Mood — отдельно в `/more` (`preferences.mood`). Язык при первом визите — из браузера; при первом логине без `language` — пишется в профиль. Mood по умолчанию `calm`, при логине не сидится. +`GET /v1/user/me` + форма на `/profile`. Редактируемые через `PATCH /v1/user/me`: `nickname`, `phone`, `timezone`, `avatar_url`, `language`; смена пароля — `current_password` + `password`. Read-only в UI: `id`, `email`, `role`, `status`. Mood — chip в calendar workspace (+ compact на auth); persist `preferences.mood` через `PATCH /v1/user/me` (**не** в `/more`). Язык при первом визите — из браузера; при первом логине без `language` — пишется в профиль. Mood по умолчанию `calm`, при логине не сидится. Lens — только localStorage (не профиль). ### 5.3. Поиск (участник) `GET /v1/search` — фильтры (`type`, `q`, `tags`, даты, `lat`/`lon`/`radius`, sort, order, пагинация). Без `q`/дат/tags/geo/sort — топы календарей и событий; иначе — поиск. В списке бейдж типа — `calendar`|`event` (не `personal`/`commercial`). Даты, теги, geo и сортировка свёрнуты по умолчанию. Переход к `/c/:id` или `/c/:id/e/:eventId`. diff --git a/UX-BACKLOG.md b/UX-BACKLOG.md index 465a076..5f7027e 100644 --- a/UX-BACKLOG.md +++ b/UX-BACKLOG.md @@ -81,6 +81,15 @@ Canvas: `eventhub-front-ux-review` → `eventhub-front-ux-rewalk` → **`eventhu Трекер: [EventHubFront#35](https://git.sabilin.com/EventHub/EventHubFront/issues/35). +## Mood + Lens workspace (Front#39, Jul 2026) — shipped + +- [x] Mood chip в chrome календаря (sheet); убран из Ещё; 3 moods, без flip/CREATOR +- [x] Lens Обзор / Сегодня / Записи отдельно от mood и view modes +- [x] Strip над сеткой (Front-derive); mobile collapsed; desktop expanded +- [x] Persist: mood → `preferences.mood`; language → `user.language`; lens → localStorage + +Трекер: [EventHubFront#39](https://git.sabilin.com/EventHub/EventHubFront/issues/39) (`c2cb754` / `d38a927`). + ## Future (не блокер 10) - [x] Swipe month/week + long-press create в календаре ([EventHubFront#24](https://git.sabilin.com/EventHub/EventHubFront/issues/24)) diff --git a/WORKFLOW.md b/WORKFLOW.md index 7c69ff4..0256187 100644 --- a/WORKFLOW.md +++ b/WORKFLOW.md @@ -393,6 +393,7 @@ error rate > 1% **или** mean request > 500 ms (hold ≥2 мин в фазе) | Дата | Изменение | |------|-----------| +| 2026-07-28 | Spec sync Front#39: Mood chip в workspace (не Ещё); Lens Обзор/Сегодня/Записи + strip; mood→DB, lens→localStorage | | 2026-07-28 | Spec sync Front#35: D9 B guest specialist schedule; confirmed overlay на personal; SpecialistsPanel density; F6 EventActionCard | | 2026-07-27 | Spec sync Back#61: `specialist_id` на POST event; commercial без active sub → 402; trial только `start_trial` | | 2026-07-27 | `agent-pitfalls.mdc` §6: экономия токенов (чат, scope, subagents, режимы) | diff --git a/design/front/UI-PARITY.md b/design/front/UI-PARITY.md index 3e20d12..0fa4d2d 100644 --- a/design/front/UI-PARITY.md +++ b/design/front/UI-PARITY.md @@ -18,7 +18,9 @@ SoT: [`boards/calentiq-ui-board-final.png`](boards/calentiq-ui-board-final.png). | 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; mood switcher на login (иконки); taglines mood cards — на `/more`; **без** Google OAuth | +| Login §D phone chrome | три phone frames + (на борде) Google CTA | brand-first hero + mood `--auth-*`; email/password only; compact mood на auth; taglines — в mood sheet workspace (не в `/more`); **без** Google OAuth | +| Mood placement | board §C switcher cards | **Front#39:** mood chip в chrome calendar workspace (+ compact auth); **не** в `/more`; 3 moods, без flip / CREATOR | +| Lens + strip | board Today/Upcoming rail only | **Front#39:** отдельный lens Обзор/Сегодня/Записи + strip над сеткой (Front-derive); localStorage only; soft-default по mood | | Favicon set | 3 отдельных favicon файла на борде | mood appicon через `applyMood` | | Desktop nav | phone bottom tabs на борде | desktop: **одна строка** chrome — logo \| nav (Календарь / Найти / Записи / Ещё) \| nickname + logout; bottom nav — mobile | | Header identity | — | nickname primary (не raw email); email только в `title` tooltip | @@ -43,6 +45,8 @@ IA без sidebar / без Creator mood — совпадает с non-goals (п **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 только в calendar workspace (убран из Ещё); Lens Обзор/Сегодня/Записи + strip над сеткой во всех 3 moods; mobile sheets + strip collapsed; mood→DB, lens→localStorage; без flip / CREATOR. + **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) @@ -79,6 +83,20 @@ API: `GET /v1/user/booking-requests` (Back) + существующий `PUT /v1/ изменений. 3. **SpecialistsPanel density (mobile):** имя/теги сверху, actions снизу full-width. +### Mood + Lens (locked Front#39) + +1. **Mood** = визуальная атмосфера (`html[data-mood]`, FLOW/MOMENTUM/CONTROL). Primary UX — + chip → sheet в chrome **calendar workspace**; compact на auth. **Нет** в `/more`. + Persist: `preferences.mood` через `PATCH /v1/user/me`. Без flip; без CREATOR. +2. **Lens** = отдельный контентный режим (`overview` / `today` / `bookings`), не mood и не + view month/week/day. Desktop — segment; mobile — chip → sheet. Soft-default при смене + mood, если lens не pinned: FLOW→overview, MOMENTUM→today, CONTROL→bookings. +3. **Strip** над сеткой (не на HTML-архиве месяца): Front-only derive — free gaps / + события сегодня / upcoming bookings. Desktop раскрыт по умолчанию; mobile свёрнут + (tap раскрывает). Сетка всегда видна. +4. **Persistence:** mood → DB; language → `user.language`; lens → `localStorage` + (`eh.calendar.lens` + pinned). Без нового Back API. + ### Follow-ups (вне этого fix-pass или частично) | Тема | Статус | @@ -88,6 +106,7 @@ API: `GET /v1/user/booking-requests` (Back) + существующий `PUT /v1/ | §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 — logo \| nav \| nickname+logout | | D9 B + confirmed personal overlay | **done** Front#35 (`57cfcf3`) | +| Mood chip + Lens strip | **done** Front#39 (`c2cb754` / `d38a927`) | ## Mood concept = product surface @@ -215,6 +234,7 @@ CSS-токены и chrome на mood beyond primary hex: surfaces, gradients, ev | — | 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) | Эпик: [Spec#10](https://git.sabilin.com/EventHub/EventHubSpec/issues/10).