Docs: sync Front#39 Mood chip + Lens strip. Fixes EventHub/EventHubSpec#16
Refs EventHub/EventHubFront#39 (c2cb754 / d38a927).
This commit is contained in:
+26
-10
@@ -38,7 +38,7 @@ Deep-link на календарь, владельцем которого явл
|
|||||||
- Сборщик: Vite
|
- Сборщик: Vite
|
||||||
- UI: React 19 + Tailwind CSS 4 + shadcn/Radix
|
- UI: React 19 + Tailwind CSS 4 + shadcn/Radix
|
||||||
- Типографика: Syne (display) + Manrope (UI)
|
- Типографика: 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 с интерсепторами
|
- HTTP: Axios с интерсепторами
|
||||||
- Формы: React Hook Form + Zod
|
- Формы: React Hook Form + Zod
|
||||||
- Дата/время: dayjs (ru locale)
|
- Дата/время: dayjs (ru locale)
|
||||||
@@ -55,8 +55,14 @@ Deep-link на календарь, владельцем которого явл
|
|||||||
и «Мои записи» (participant); пустые группы скрывать. Confirm на карточке события остаётся.
|
и «Мои записи» (participant); пустые группы скрывать. Confirm на карточке события остаётся.
|
||||||
Past/expired: бейдж `expired` («истекла»), Cancel скрыт; empty-state с CTA Discover / календари.
|
Past/expired: бейдж `expired` («истекла»), Cancel скрыт; empty-state с CTA Discover / календари.
|
||||||
Время на list-карточках — вторичное к title (`.eh-book-list-time`).
|
Время на list-карточках — вторичное к title (`.eh-book-list-time`).
|
||||||
- В **Ещё**: пункт входящих specialist invites скрыт при `pending=0`; при `pending > 0` —
|
- В **Ещё**: язык (`LanguageSwitcher`); пункт входящих specialist invites скрыт при
|
||||||
badge со счётчиком (deep-link `/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` —
|
- Контекст виджета: свой календарь (селектор) или чужой (browse после поиска). Чужой `personal` —
|
||||||
только просмотр; чужой `commercial` с `booking_open=true` — запись; при `booking_open=false`
|
только просмотр; чужой `commercial` с `booking_open=true` — запись; при `booking_open=false`
|
||||||
(restricted / нет подписки владельца) — просмотр + сообщение «Запись временно недоступна».
|
(restricted / нет подписки владельца) — просмотр + сообщение «Запись временно недоступна».
|
||||||
@@ -89,7 +95,7 @@ Deep-link на календарь, владельцем которого явл
|
|||||||
|
|
||||||
## 3.2. Настроения (mood themes) / режимы CalenTIQ
|
## 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`.
|
Пользователь переключает визуальный режим; атрибут `html[data-mood]`. Для гостя и при отсутствии `preferences.mood` — дефолт `calm` (в профиль при логине не пишется). После входа смена mood сохраняется в `preferences.mood` через `PATCH /v1/user/me`.
|
||||||
|
|
||||||
@@ -99,9 +105,19 @@ Deep-link на календарь, владельцем которого явл
|
|||||||
| MOMENTUM | `energetic` | тёмный ink + coral `#FF6A3D` |
|
| MOMENTUM | `energetic` | тёмный ink + coral `#FF6A3D` |
|
||||||
| CONTROL | `business` | charcoal + steel `#324A5F`, более жёсткие радиусы |
|
| 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. Маршруты
|
## 4. Маршруты
|
||||||
|
|
||||||
@@ -116,8 +132,8 @@ Deep-link на календарь, владельцем которого явл
|
|||||||
- `/bookings` — grouped inbox: (A) к подтверждению (owner/specialist pending) +
|
- `/bookings` — grouped inbox: (A) к подтверждению (owner/specialist pending) +
|
||||||
(B) мои записи участника; deep-link в `/c/.../e/...`
|
(B) мои записи участника; deep-link в `/c/.../e/...`
|
||||||
- `/calendars` — управление своими календарями (CRUD)
|
- `/calendars` — управление своими календарями (CRUD)
|
||||||
- `/more` — вторичное меню + mood switcher; пункт specialist invites **скрыт**,
|
- `/more` — вторичное меню + language switcher (**без** mood); пункт specialist
|
||||||
если входящих pending = 0; при pending > 0 — badge со счётчиком
|
invites **скрыт**, если входящих pending = 0; при pending > 0 — badge со счётчиком
|
||||||
(deep-link `/invites?token=` работает)
|
(deep-link `/invites?token=` работает)
|
||||||
- `/invites` — inbox входящих specialist invites (не смешивать с `/bookings`)
|
- `/invites` — inbox входящих specialist invites (не смешивать с `/bookings`)
|
||||||
- `/following` — отслеживаемые чужие календари (follow; не платная Подписка)
|
- `/following` — отслеживаемые чужие календари (follow; не платная Подписка)
|
||||||
@@ -125,7 +141,7 @@ Deep-link на календарь, владельцем которого явл
|
|||||||
|
|
||||||
Redirects: `/discover` → `/search`; `/calendars/:id` → `/c/:id`; `/calendars/:id/events/:eventId` → `/c/:id/e/:eventId`.
|
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. Модули
|
## 5. Модули
|
||||||
|
|
||||||
@@ -133,7 +149,7 @@ Redirects: `/discover` → `/search`; `/calendars/:id` → `/c/:id`; `/calendars
|
|||||||
Регистрация, верификация, вход, восстановление сессии.
|
Регистрация, верификация, вход, восстановление сессии.
|
||||||
|
|
||||||
### 5.2. Профиль
|
### 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. Поиск (участник)
|
### 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`.
|
`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`.
|
||||||
|
|||||||
@@ -81,6 +81,15 @@ Canvas: `eventhub-front-ux-review` → `eventhub-front-ux-rewalk` → **`eventhu
|
|||||||
|
|
||||||
Трекер: [EventHubFront#35](https://git.sabilin.com/EventHub/EventHubFront/issues/35).
|
Трекер: [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)
|
## Future (не блокер 10)
|
||||||
|
|
||||||
- [x] Swipe month/week + long-press create в календаре ([EventHubFront#24](https://git.sabilin.com/EventHub/EventHubFront/issues/24))
|
- [x] Swipe month/week + long-press create в календаре ([EventHubFront#24](https://git.sabilin.com/EventHub/EventHubFront/issues/24))
|
||||||
|
|||||||
@@ -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-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 | Spec sync Back#61: `specialist_id` на POST event; commercial без active sub → 402; trial только `start_trial` |
|
||||||
| 2026-07-27 | `agent-pitfalls.mdc` §6: экономия токенов (чат, scope, subagents, режимы) |
|
| 2026-07-27 | `agent-pitfalls.mdc` §6: экономия токенов (чат, scope, subagents, режимы) |
|
||||||
|
|||||||
@@ -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 |
|
| 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 |
|
| 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 **остаётся** обязательным |
|
| 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` |
|
| Favicon set | 3 отдельных favicon файла на борде | mood appicon через `applyMood` |
|
||||||
| Desktop nav | phone bottom tabs на борде | desktop: **одна строка** chrome — logo \| nav (Календарь / Найти / Записи / Ещё) \| nickname + logout; bottom nav — mobile |
|
| Desktop nav | phone bottom tabs на борде | desktop: **одна строка** chrome — logo \| nav (Календарь / Найти / Записи / Ещё) \| nickname + logout; bottom nav — mobile |
|
||||||
| Header identity | — | nickname primary (не raw email); email только в `title` tooltip |
|
| 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#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.
|
**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)
|
### 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.
|
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 или частично)
|
### 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 |
|
| §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 |
|
| Desktop one-row chrome | **done** Front#31 — logo \| nav \| nickname+logout |
|
||||||
| D9 B + confirmed personal overlay | **done** Front#35 (`57cfcf3`) |
|
| D9 B + confirmed personal overlay | **done** Front#35 (`57cfcf3`) |
|
||||||
|
| Mood chip + Lens strip | **done** Front#39 (`c2cb754` / `d38a927`) |
|
||||||
|
|
||||||
## Mood concept = product surface
|
## 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) |
|
| — | 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) |
|
| — | 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) |
|
| — | 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).
|
Эпик: [Spec#10](https://git.sabilin.com/EventHub/EventHubSpec/issues/10).
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user