5.7 KiB
| phase | slug | status | shadcn_initialized | preset | created |
|---|---|---|---|---|---|
| 6 | renderer-architecture | draft | false | none | 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
16pxgap, wrapping - SVG month/day labels:
10pxsans-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