trainlog/docs/design/web_dashboard_grid_v1.md

4.5 KiB
Raw Blame History

Web Dashboard grid V1

Status: WEB_DASHBOARD_GRID_V1=PASS/FROZEN

Library spike

The spike was performed on 2026-09-16 against React 19.3.0, TypeScript 7 and Vite 8.3.0. Package metadata and upstream documentation were checked before installation.

Candidate Version checked Fit Decision
react-grid-layout 2.2.4 MIT; React peer >=16.3; TypeScript v2 implementation; 12-column layouts, drag, two-axis resize, per-item min/max, configurable enablement, vertical compaction, responsive primitives and serializable layouts. Active 2026 releases. Mouse interaction is mature but has no complete keyboard grid editor. Selected, with a Trainlog keyboard layer and independent model/validator.
gridstack 13.3.0 MIT; active maintenance; framework-neutral drag, resize, responsive columns and constraints. Its package is substantially larger and React integration remains an imperative wrapper around a DOM engine rather than a native typed React state boundary. Rejected for this React-owned surface.
@dnd-kit/core 6.3.1 MIT; strong sensors and keyboard support, but it is a drag/drop toolkit rather than a heterogeneous dashboard-grid engine. It supplies neither resize nor the required collision/compaction policy; upstream guidance requires a custom sorting strategy for mixed grid sizes. Rejected because Trainlog would have to build the missing engine.

react-grid-layout has no external service, runtime telemetry, CDN or backend dependency. Trainlog imports the v2 API directly and does not expose the library's {i,w,h} representation outside its adapter.

Trainlog model and invariants

The authoritative frontend shape is:

TileLayout { id, x, y, width, height }

The seven stable IDs are next-session, activity, progression, last-session, max-records, muscle-distribution, and cardio-recovery. The desktop layout alone is canonical and uses 12 columns. The adapter maps it to and from the library shape. A separate Trainlog validator requires exactly those IDs, integral coordinates and dimensions, each tile's min/max bounds, x >= 0, y >= 0, x + width <= 12, y <= 200, and no overlap.

The deterministic default is:

Tile x y width height min/max width min/max height
Prochaine séance 0 0 5 4 4–8 3–7
Activité 5 0 7 4 5–12 3–7
Progression 0 4 8 5 6–12 4–9
Dernière séance 8 4 4 3 3–7 3–6
Records / MAX 8 7 4 3 3–8 3–7
Répartition musculaire 0 9 6 5 5–12 4–9
Cardio / récupération 6 10 6 4 5–12 4–8

Vertical compaction is deterministic; overlap is forbidden and collisions push/reflow other items. Library output is accepted into React state only after conversion and Trainlog validation.

Interaction and responsive contract

Normal mode disables drag and resize and emits no resize handles. Explicit Modifier l'agencement mode enables them on desktop. Annuler restores the entry snapshot, Réinitialiser restores the Trainlog default in the edit draft, and Enregistrer pour cette session accepts the draft only in current React memory. Reload deliberately restores the default: persistence belongs to WEB_DASHBOARD_LAYOUT_V1.

Focused tiles support Arrow keys for movement and Shift+Arrow keys for resize. Focus is visible and a polite live region announces logical coordinates and dimensions. Mouse resize exposes east, south and south-east handles. Reduced motion disables grid transitions.

Widths below 1100 px derive a six-column projection; widths below 700 px derive a stable one-column projection. These projections preserve canonical ordering, remain non-authoritative and never update the desktop layout. Editing at those breakpoints is deliberately disabled with an explicit explanation.

The existing /api/v1/dashboard fetch and factual Footer remain unchanged. Tile bodies retain placeholders; logical compact, medium, and large presentation levels depend only on tile dimensions and add no business facts.

Bundle impact

Vite production output before the dependency was 229.07 kB JavaScript and 7.14 kB CSS. V1 output is 301.61 kB JavaScript and 13.42 kB CSS: an increase of 72.54 kB JavaScript and 6.28 kB CSS before transport compression. This is accepted for the complete drag, resize, constraint and compaction engine.

Upstream references: