From e7d12719ed28630804d73d919dc717d985163116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christopher=20M=C3=BChl?= Date: Thu, 9 Apr 2026 00:25:52 +0200 Subject: [PATCH] docs(phase-6): UI design contract for renderer architecture refactor Co-Authored-By: Claude Opus 4.6 --- .../06-renderer-architecture/06-UI-SPEC.md | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 .planning/phases/06-renderer-architecture/06-UI-SPEC.md diff --git a/.planning/phases/06-renderer-architecture/06-UI-SPEC.md b/.planning/phases/06-renderer-architecture/06-UI-SPEC.md new file mode 100644 index 0000000..c661e2f --- /dev/null +++ b/.planning/phases/06-renderer-architecture/06-UI-SPEC.md @@ -0,0 +1,150 @@ +--- +phase: 6 +slug: renderer-architecture +status: draft +shadcn_initialized: false +preset: none +created: 2026-04-09 +--- + +# Phase 6 — UI Design Contract + +> Visual and interaction contract for the renderer architecture refactor. This phase ships zero visual changes -- the contract documents the existing v1.0 visual baseline as a regression guard. + +--- + +## Design System + +| Property | Value | +|----------|-------| +| Tool | none | +| Preset | not applicable | +| Component library | Tabler (Kimai host app) | +| Icon library | not applicable (no icons in this phase) | +| Font | `var(--tblr-font-sans-serif)` (inherited from Kimai/Tabler) | + +**Note:** This plugin renders inside a Kimai dashboard card (`@theme/embeds/card.html.twig`). All surface colors, fonts, and border styles inherit from Tabler CSS custom properties. No standalone design system is used or needed. + +--- + +## Spacing Scale + +Declared values from existing v1.0 CSS (must remain unchanged after refactor): + +| Token | Value | Usage | +|-------|-------|-------| +| cell-gap | 2px | Gap between heatmap cells (SVG attribute, not CSS) | +| tooltip-pad | 6px 10px | Tooltip internal padding | +| wrapper-gap | 16px | Gap between heatmap SVG area and filter dropdown | +| stats-gap | 16px | Gap between stat items in footer row | +| stats-top | 12px | Padding above stats row | +| filter-top | 20px | Padding above filter dropdown (desktop) | + +Exceptions: Cell size and margins are controlled by `HeatmapConfig` in TypeScript (not CSS). These values must transfer unchanged to `DEFAULT_CONFIG` in the refactored code. + +--- + +## Typography + +All typography inherits from Kimai/Tabler. The plugin declares only two overrides: + +| Role | Size | Weight | Line Height | Source | +|------|------|--------|-------------|--------| +| SVG label | 10px | 400 (normal) | default | `.heatmap-label` in heatmap.css | +| Tooltip / Stats | 0.8125rem (13px) | 400 (normal) | default | `.heatmap-tooltip`, `.heatmap-stats` | +| Stat value | 0.8125rem (13px) | 600 (semibold) | default | `.heatmap-stats .stat-value` | + +No new typography tokens in this phase. + +--- + +## Color + +All colors use Tabler CSS custom properties. The plugin does not declare its own palette. + +| Role | Value | Usage | +|------|-------|-------| +| Body text | `var(--tblr-body-color)` | SVG labels, stat values, tooltip text | +| Surface | `var(--tblr-bg-surface)` | Tooltip background | +| Surface secondary | `var(--tblr-bg-surface-secondary)` | Empty heatmap cells | +| Border | `var(--tblr-border-color)` | Tooltip border | +| Secondary text | `var(--tblr-secondary, #6c757d)` | Stat labels | +| Heatmap scale | `['#9be9a8', '#40c463', '#30a14e', '#216e39']` | Cell fill intensity (4-step quantize) | + +**Regression constraint:** The 4-color heatmap scale array must remain identical in `shared/color-scale.ts` after extraction. These are hardcoded GitHub-green values, not Tabler variables. + +Accent reserved for: not applicable (no accent color in this phase). + +--- + +## Copywriting Contract + +Phase 6 introduces no new copy. Existing copy must survive the refactor unchanged: + +| Element | Copy | Location after refactor | +|---------|------|------------------------| +| Tooltip: date line | `{formatted date}` | `shared/tooltip.ts` | +| Tooltip: hours line | `{N}h {M}m` | `shared/tooltip.ts` | +| Tooltip: entries line | `{N} entries` | `shared/tooltip.ts` | +| Stats: streak | `Current streak: {N} days` | `shared/stats.ts` | +| Stats: total | `Total: {N}h` | `shared/stats.ts` | +| Stats: average | `Daily avg: {N}h` | `shared/stats.ts` | +| Stats: busiest | `Busiest: {date}` | `shared/stats.ts` | +| Empty state | No explicit empty state (heatmap renders with all-empty cells) | `renderers/year.ts` | +| Error state | No explicit error state (console.error only) | `heatmap.ts` orchestrator | +| Primary CTA | not applicable (no user actions beyond hover/click) | -- | +| Destructive confirmation | not applicable (no destructive actions) | -- | + +--- + +## Interaction Contract + +No new interactions. Existing interactions must work identically after refactor: + +| Interaction | Behavior | Must survive in | +|-------------|----------|-----------------| +| Cell hover | Show tooltip with date, hours, entry count | `shared/tooltip.ts` + renderer | +| Cell click | Navigate to Kimai timesheet filtered by date | `RenderContext.onCellClick` callback | +| Cell hover (weekend) | Same tooltip, slightly reduced opacity (0.65 vs 0.75) | `.heatmap-weekend:hover` CSS (unchanged) | +| Filter select change | Re-render heatmap with filtered project data | `heatmap.ts` orchestrator via `HeatmapState.filters` | +| Window resize | Re-render to fit container width | `heatmap.ts` orchestrator (resize listener) | + +--- + +## Regression Checklist + +These visual properties must be pixel-identical before and after the refactor: + +- [ ] Cell border-radius: `rx=2 ry=2` +- [ ] Cell hover opacity: `0.75` (normal), `0.65` (weekend) +- [ ] Tooltip shadow: `0 2px 8px rgba(0,0,0,0.12)` +- [ ] Tooltip border-radius: `4px` +- [ ] Empty cell fill: `var(--tblr-bg-surface-secondary)` +- [ ] Heatmap color scale: 4 greens `#9be9a8 #40c463 #30a14e #216e39` +- [ ] Stats layout: flex row with `16px` gap, wrapping +- [ ] SVG month/day labels: `10px` sans-serif +- [ ] Filter dropdown position: right side on desktop, above on mobile (<1330px) +- [ ] Scroll behavior: horizontal scroll on `.heatmap-svg-area` + +--- + +## Registry Safety + +| Registry | Blocks Used | Safety Gate | +|----------|-------------|-------------| +| not applicable | none | not applicable | + +No component registries or third-party blocks in this phase. + +--- + +## Checker Sign-Off + +- [ ] Dimension 1 Copywriting: PASS +- [ ] Dimension 2 Visuals: PASS +- [ ] Dimension 3 Color: PASS +- [ ] Dimension 4 Typography: PASS +- [ ] Dimension 5 Spacing: PASS +- [ ] Dimension 6 Registry Safety: PASS + +**Approval:** pending