feat(statistics-deck): deck shell — zero-scroll frame, top bar, period picker, profiles, keyboard, data-quality marker #133

Closed
opened 2026-09-26 11:28:43 +00:00 by gabogg · 0 comments
Owner

Part of the statistics deck UI, implementing the accepted RFC docs/architecture/rfc-statistics-deck-display-model.md (#80). This issue is the shell shared by the three period views; the views themselves are split by period (Day, Week, Month issues, each blocked by this one).

Scope

Replace the #content-statistics placeholder in app/static/index.html with the deck shell, as its own module under app/static/js/src/ui/ (not more code in app.js), with frontend tests under tests/frontend/.

  • Zero-scroll frame (RFC §3.1, §3.5): deck root height: 100dvh; overflow: hidden, minmax(0, Nfr) rows, min-height: 0 panels; the per-profile row splits (Room 12/55/33, Desk 17/50/33, Laptop 26/74). Below 760 CSS px the deck stacks into one column and scrolls, the only exception.

  • Top bar, 38 px (RFC §3.4): it replaces the app header, HUD ribbon and deck selector while the deck is shown. It holds:

    • the period button (kind and range, e.g. WEEK MON 14 – SUN 20 SEP 2026 ▾) and the Day / Week / Month tabs;
    • the data-quality badge slot;
    • the layout profile switch (Room / Desk / Laptop);
    • the language switch;
    • the Fullscreen button (a refused request is handled quietly);
    • a "back to ops" control, hidden for the viewer role;
    • the ? help.
  • Period picker (RFC §5.1) from GET /api/statistics/periods?granularity=: a calendar for Day, a list for Week and Month, the covered-days count for Partial Periods. It marks periods with marked days. Numpad - / + step to the previous / next period. Each tab keeps its own choice and opens on the latest complete period; a reload returns to the latest; the deep link (URL) carries the chosen period.

  • Layout profiles (RFC §3.3): the choice is stored per browser (localStorage, wrapped in try/catch) and defaults to Room. Never inferred from resolution.

  • Language (RFC §5.2): the deck's own switch, stored per browser and defaulting to the app's current language. All deck copy goes through i18n.js. Period labels are formatted on the client from the structured fields (start, end, iso_week, …).

  • Keyboard (RFC §3.4), matched by KeyboardEvent.code:

    • 7 / 8 / 9: period;
    • 4 / 5 / 6: profile;
    • 0: fullscreen;
    • .: picker;
    • - / +: previous / next period;
    • *: data-quality detail;
    • /: help.

    The / help shows the numpad diagram and the marker legend.

  • Data-quality marker frame (RFC §4.1):

    • the top-bar badge: full text in Room and Desk, glyphs and counts in Laptop;
    • the * / click detail panel, with plain-language lines and no internal codes;
    • a shared helper that classifies a day into OK / Estimate / Unreliable, which the period views reuse to mark their graphs.

    Always on, amber only. The counts come from the period quality (#129).

  • Graph plumbing: Chart.js (vendored, chart.umd.min.js) instances that redraw to their box and thin out axis labels instead of overflowing. There are shared styles for the Estimate dashed outline and the Unreliable grey hatching. No confidence-margin bands.

  • Navigation:

    • a viewer lands on the deck (already wired by #121);
    • operators get it as a tab (F8);
    • for admins, the deck replaces the analytics tab and F5 goes to the deck. Do the swap together with #130, which moves the calibration tools first, so no admin tool becomes unreachable.

Acceptance

  • No scrollbar at 1920×1080 and 1920×960 in any profile, and at the Laptop profile's 760 px minimum. Stacking and scrolling below 760 px.
  • Every numpad shortcut works with NumLock on and off. The deep link restores period and tab. Profile and language survive a reload.
  • The badge and detail render from fixture data in both tiers. There is no way to hide them.
  • A viewer sees only the deck; the "back to ops" control is hidden. Admin and operator navigation work as described.
  • Frontend tests cover the day classification, period-label formatting in both languages, and the keyboard map.

Depends on #129 (tier counts) for live badge data. The UI can be built against fixtures first. Admin tab swap: with #130. Refs #80, #121.

🤖 Generated with Claude Code

Part of the statistics deck UI, implementing the accepted RFC [`docs/architecture/rfc-statistics-deck-display-model.md`](https://git.gaboggamer.online/gabogg/hikcentral/src/branch/master/docs/architecture/rfc-statistics-deck-display-model.md) (#80). This issue is the **shell** shared by the three period views; the views themselves are split by period (Day, Week, Month issues, each blocked by this one). ## Scope Replace the `#content-statistics` placeholder in `app/static/index.html` with the deck shell, as its own module under `app/static/js/src/ui/` (not more code in `app.js`), with frontend tests under `tests/frontend/`. - **Zero-scroll frame (RFC §3.1, §3.5):** deck root `height: 100dvh; overflow: hidden`, `minmax(0, Nfr)` rows, `min-height: 0` panels; the per-profile row splits (Room 12/55/33, Desk 17/50/33, Laptop 26/74). Below 760 CSS px the deck stacks into one column and scrolls, the only exception. - **Top bar, 38 px (RFC §3.4):** it replaces the app header, HUD ribbon and deck selector while the deck is shown. It holds: - the period button (kind and range, e.g. `WEEK MON 14 – SUN 20 SEP 2026 ▾`) and the Day / Week / Month tabs; - the data-quality badge slot; - the layout profile switch (Room / Desk / Laptop); - the language switch; - the Fullscreen button (a refused request is handled quietly); - a "back to ops" control, hidden for the `viewer` role; - the `?` help. - **Period picker (RFC §5.1)** from `GET /api/statistics/periods?granularity=`: a calendar for Day, a list for Week and Month, the covered-days count for Partial Periods. It marks periods with marked days. Numpad `-` / `+` step to the previous / next period. Each tab keeps its own choice and opens on the latest complete period; a reload returns to the latest; the deep link (URL) carries the chosen period. - **Layout profiles (RFC §3.3):** the choice is stored per browser (`localStorage`, wrapped in try/catch) and defaults to **Room**. Never inferred from resolution. - **Language (RFC §5.2):** the deck's own switch, stored per browser and defaulting to the app's current language. All deck copy goes through `i18n.js`. Period labels are formatted on the client from the structured fields (`start`, `end`, `iso_week`, …). - **Keyboard (RFC §3.4), matched by `KeyboardEvent.code`:** - 7 / 8 / 9: period; - 4 / 5 / 6: profile; - 0: fullscreen; - `.`: picker; - `-` / `+`: previous / next period; - `*`: data-quality detail; - `/`: help. The `/` help shows the numpad diagram and the marker legend. - **Data-quality marker frame (RFC §4.1):** - the top-bar badge: full text in Room and Desk, glyphs and counts in Laptop; - the `*` / click detail panel, with plain-language lines and no internal codes; - a shared helper that classifies a day into OK / Estimate / Unreliable, which the period views reuse to mark their graphs. Always on, amber only. The counts come from the period quality (#129). - **Graph plumbing:** Chart.js (vendored, `chart.umd.min.js`) instances that redraw to their box and thin out axis labels instead of overflowing. There are shared styles for the Estimate dashed outline and the Unreliable grey hatching. No confidence-margin bands. - **Navigation:** - a viewer lands on the deck (already wired by #121); - operators get it as a tab (F8); - for admins, the deck replaces the `analytics` tab and F5 goes to the deck. Do the swap together with #130, which moves the calibration tools first, so no admin tool becomes unreachable. ## Acceptance - No scrollbar at 1920×1080 and 1920×960 in any profile, and at the Laptop profile's 760 px minimum. Stacking and scrolling below 760 px. - Every numpad shortcut works with NumLock on and off. The deep link restores period and tab. Profile and language survive a reload. - The badge and detail render from fixture data in both tiers. There is no way to hide them. - A viewer sees only the deck; the "back to ops" control is hidden. Admin and operator navigation work as described. - Frontend tests cover the day classification, period-label formatting in both languages, and the keyboard map. Depends on #129 (tier counts) for live badge data. The UI can be built against fixtures first. Admin tab swap: with #130. Refs #80, #121. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gabogg/hikcentral#133
No description provided.