Commit Graph

20 Commits

Author SHA1 Message Date
aaverbitskiy
77a36a22d9 Датапикер: открытый диапазон через пилюли-концы «С» / «По»
Над календарём — две пилюли-конца в стиле чипсов фильтров (accent-weak
заливка, индиго-текст, скруглённые). Активная пилюля (куда пишется следующий
клик) с индиго-рамкой; клик по дню пишет в активный конец, фокус авто-переходит
ко второму. У каждой пилюли × — очистить именно этот конец, что даёт ОТКРЫТЫЙ
диапазон: «с X» (без конца) или «по Y» (без начала). «Применить» активна, если
задан хотя бы один конец. Нативные #date-start/#date-end по-прежнему источник
истины, любой из них может быть пустым; фильтр и URL уже читают from/to по
отдельности.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-17 08:14:45 +00:00
aaverbitskiy
147529c20f Унификация ширины полей-фильтров: все 195px, короткий год в «Период»
- .hgroup-fields: колонки 170→195px (все фильтры одинаковой ширины)
- «Период» (.dr-field) 333→195px, вровень с остальными
- Формат даты в поле «Период» — 2-значный год (05.08.26 — 20.08.26), чтобы диапазон целиком помещался в 195px; в чипсах год остался полным

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-17 05:13:35 +00:00
aaverbitskiy
5ba5a77f97 UI-доработки: выравнивание тогглов, датапикер с «Применить», степперы 80px, поле поиска, автозакрытие балуна карты
- Тогглы: Бренд+Компания в одну строку, блок выровнен ровно по полосе контролов (верх = верх полей, низ = низ «Поиска»), равномерные зазоры
- Датапикер: выбор диапазона больше не применяется автоматически по второму клику — только кнопкой «Применить» (+ «Сбросить» для незавершённого выбора)
- Степперы «Оформления»: ровно 80px по ширине
- Поле поиска в дропдаунах: равномерная рамка 1px по всем сторонам вместо разноцветных краёв
- Балун на карте: клик по пустой карте закрывает балун (guard от самозакрытия по «своему» клику, клик по другому кластеру открывает новый)
- Полоса фильтров: поля сужены на 10px, «Период» до 333px

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-15 20:39:12 +00:00
aaverbitskiy
e9eee60dab ui: toasts, icon segmented mode switch, steppers, date-range picker (v0.2.13)
Second modernization batch (reference: easystudy ui_elements):
- Toast/snackbar notifications (dark, green check) for actions — copy link.
- Mode switch: icons (horizontal bars / pin / columns) + a sliding active
  indicator; fixed width so the bold active label never resizes the block.
- Appearance number fields became steppers: an editable field with centred −/+
  buttons, ~20% narrower.
- Date filter: the two native date inputs are replaced by a custom range picker
  — one field "Период (даты)" + a calendar popup with month nav and range
  selection (circle endpoints, light band between). The native inputs stay hidden
  as the source of truth so all filter/URL/chip wiring is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-15 19:02:45 +00:00
aaverbitskiy
f5166b888a ui: toggles, stat tiles, dropdown search, bubble scale slider (v0.2.12)
Modernised several controls (reference: easystudy ui_elements catalogue):
- Display checkboxes (Бренд/Компания/Коллизии/Все поверхности) are now toggle
  switches; the option checkboxes inside filter dropdowns stay normal.
- Counters became stat tiles: header "Поверхности N" (accent) and the map
  legend (свободно/занято/всего + dashed "без координат").
- Filter dropdowns gained an in-panel search that filters the option list
  (shown for lists >7, auto-focused on open).
- Timeline scale control restyled as a filled slider with a value bubble, moved
  out of the header to float over the top-right of the chart just below the time
  axis (5px gap), bubble pointing up.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-15 14:46:04 +00:00
aaverbitskiy
d7c1ce7b77 ui: fresh panel per cluster click, 5-step scale, unified column resizer (v0.2.11)
- Map panel: every marker/cluster click reopens a fresh panel repositioned next
  to the just-clicked cluster (with a pop-in), instead of leaving it in place and
  only swapping the content.
- Timeline scale slider: 5 fixed stops — 6/12/18/24/30 months; label is now
  "Масштаб графика: <6М|12М|18М|24М|30М>" (default 12М).
- Address-column resizer now matches the timeline/map splitter: a 6px solid bar
  that turns accent on hover/drag, so both dividers look identical.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-15 13:40:10 +00:00
aaverbitskiy
f4c1de70b4 feat: timeline label -> fly map to surface; keep panel inside the window (v0.2.10)
Timeline: clicking a surface in the left column now flies the map to it — it
switches to the combined "Карта и график" view when only the timeline is open,
then centres+zooms on the surface's cluster (deferred focus waits for the map to
render; works for anonymous and manager users). Replaces the old manager-only
board detail panel on that click (the map card already shows photos + bookings).

Map panel: for clusters with many surfaces it now widens (tabs flow into 3-4
columns) and its height is capped to the space available in the window, so it
never overflows the browser window and scrolls inside instead.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-15 09:59:52 +00:00
aaverbitskiy
78d62ae36c ui: render lone surfaces as donut clusters of 1 for a unified map (v0.2.9)
Set minClusterSize:1 so a solitary surface is drawn with the same donut icon
(showing "1", green when free / red when busy) instead of a small dot, and every
click flows through the single cluster handler into our panel. A cluster of one
keeps the rich single-surface hover tooltip.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-15 09:04:27 +00:00
aaverbitskiy
e83bb5ad49 feat: custom map surface panel (fits content, resizable, smart-positioned) (v0.2.8)
Replace the Yandex balloon with our own floating card, opened on marker/cluster
click. It fits its content (no forced scroll), is draggable by the header and
resizable from the bottom-right corner, and — for clusters — carries tabs to
switch between the co-located surfaces. Photo gallery + lightbox are preserved.

On open it positions itself next to the clicked cluster and offsets toward the
free side of the map (the map half the cluster sits in picks the direction, e.g.
bottom-left cluster -> panel opens up and to the right), clamped inside the map.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-15 08:40:48 +00:00
aaverbitskiy
8e6c19e9a4 feat: surface photos in the map balloon + fullscreen lightbox (v0.2.7)
Photos live on disk as photos/<board_key>/<file>.{jpg,jpeg,png} (a read-only
volume). A cached directory index (60s TTL) attaches a `photos` URL list to each
surface in /api/map; a /photos StaticFiles mount serves the files. Photos are
public — shown to anonymous visitors and managers alike.

The balloon renders a gallery (main image + thumbnail strip + "1 / N" counter);
clicking a thumbnail swaps the main image, and clicking the main image / "+N"
opens a fullscreen lightbox over the map (prev/next, Esc, backdrop close).
Surfaces without photos render exactly as before.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-15 08:00:10 +00:00
aaverbitskiy
dec639581b ui: green "Размещено" default + green circle favicon (v0.2.6)
- default colour for status "РК. Размещено" is now green #26c04c (was indigo)
- add a #26c04c circle favicon (inline SVG data URI) for the browser tab

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-14 20:14:01 +00:00
aaverbitskiy
de4cf1743b polish: flip overflowing bar label to the left when it would hit the next bar (v0.2.5)
Extends the bar-label overflow handling: an oversized label defaults to the
right of the bar, but if it would collide with the next bar on the same row it
is placed to the left instead (whichever side has room; larger gap wins when
neither fits). Also make the trigger a debounce (was a throttle) so the layout
runs after a zoom/redraw burst settles, once bar widths are final.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-14 19:31:26 +00:00
aaverbitskiy
9b6ca6f848 polish: appearance menu offsets, anon map badge, bar label overflow (v0.2.4)
- appearance menu opens 20px below the header/chips and 58px from the right edge
- map "no coordinates" badge is manager-only (hidden for anonymous visitors)
- timeline bar label that is wider than its bar now renders just past the bar's
  right edge as dark text on the track, instead of being clipped; labels that
  fit still sit inside the bar in white. Applied post-render (measure overflow),
  re-run on changed/rangechanged with a double rAF so bar widths are settled.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-14 19:09:47 +00:00
aaverbitskiy
159590d62e analytics: add Yandex.Metrika counter 111613184 (v0.2.3)
Counter snippet at the top of <body> (webvisor, clickmap, trackLinks).
Lives in index.html only — no change to the JS/CSS bundle.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-14 18:32:11 +00:00
aaverbitskiy
b4d56d0540 polish: chips bar + appearance menu placement + brand title (v0.2.2)
- appearance menu drops below the active-filter chips row when it is shown,
  and sits 10px further from the right edge
- "Скопировать ссылку" moved to the left of the chips, separated by a divider
- enlarge "Green Media" title so it is flush with the "Адресная программа"
  line below it

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-14 16:00:47 +00:00
aaverbitskiy
aeb4651f6f polish: appearance menu + clean status names everywhere (v0.2.1)
Appearance ("Оформление") menu:
- add missing status "РК. Предварительное бронирование" (8 statuses total)
- strip the systemic "РК. " prefix from status names in the UI (menu,
  tooltip, status filter dropdown, active-filter chips); raw values stay
  intact for filtering/URLs
- fixed-position menu: opens 25px below the header, ends >=30px above the
  window bottom, scrolls inside — never overflows the viewport
- drop the "Прочие статусы" row
- per-status grey reset glyph (circular arrows) restoring its default colour

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-14 15:37:03 +00:00
aaverbitskiy
5cabad9c33 feat: all-surfaces timeline + UI polish (v0.2.0)
Timeline can now list the entire inventory (occupied + free + never
booked), not just booked surfaces. New manager-only "Все поверхности"
checkbox (on by default; forced on and hidden for anonymous visitors so
they can spot what is currently free with no future bookings).

/api/boards gains all_surfaces: sources rows from board_info and unions
pf_board so a just-booked surface not yet in the inventory snapshot still
gets a row. Surface facets (city/dimension/search) narrow rows; booking
facets (brand/manager/status) narrow to booked surfaces; dates are a
window that narrows bars, not the surface set.

UI polish:
- timeline tooltip flips up/left near viewport edges
- anonymous "Войти" button filled accent, inverts to white-on-accent hover
- appearance button uses a gear icon instead of "+"
- header counter shows only "Поверхности: N"
- map "всего" counter includes surfaces without coordinates

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-14 14:48:25 +00:00
aaverbitskiy
b6b9c27cb0 auth: Keycloak OIDC — anonymous (truncated) vs manager (full) tiers
Backend (main.py + auth.py):
- Validate Bearer JWT against the intense-sale realm JWKS (RS256, issuer
  checked, aud skipped). Missing/invalid token = anonymous, never an error,
  so the public map keeps working when Keycloak is down.
- Anonymous truncation: /api/meta hides brand/manager/status facets;
  /api/bookings blanks brand/company_name/manager/task_id/task_status
  (bars stay, one neutral colour); /api/map keeps occupied_now but empties
  booking details. Hidden facet filters are ignored for anonymous callers.
- boards stay visible to all (physical inventory: address/city/dimension).

Frontend (keycloak-js):
- Silent SSO (check-sso) — anonymous by default, Войти/Выйти button.
- Bearer token attached + refreshed on every API call.
- Anonymous UI hides Brand/Manager/Status filters, Brand/Company toggles,
  appearance menu, collisions and labels; board detail panel (Planfix
  deep-links) gated to managers.

Test manager: user / 1234567890 (realm role `manager`).
2026-08-14 11:05:47 +00:00
aaverbitskiy
17c54db501 design: adopt Open Props tokens, indigo accent + IBM Plex Sans, collision colour
- Add Open Props as the token foundation (@import "open-props/style"). Our
  semantic tokens (--bg/--surface/--border/--text/--shadow-*/--transition) are
  now backed by its gray ramp, shadows and easing; the rest of the CSS is
  untouched since it already references var(--…).
- Accent → indigo #4f46e5 (--accent + derived rings / month-hover), and the
  timeline bar default colours (appearance.ts) move to the same indigo so the
  content and UI share one palette.
- Font → IBM Plex Sans, self-hosted via @fontsource (latin + cyrillic, weights
  400/500/600/700) so there is no runtime Google Fonts dependency. Backed into
  --font-sans (overrides Open Props' :where() default). Tabular figures on the
  counters and map legend.
- Collision default colour → warm amber-orange #e8590c: distinct from the indigo
  bars and from the green/red map status, reads as a conflict warning.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-06 21:15:50 +00:00
aaverbitskiy
c6363cd8cf frontend: Vite+TypeScript scaffold (types, api) — not wired to static yet 2026-07-17 15:41:13 +00:00