|
| 1 | +--- |
| 2 | +name: restyle-color-metric-popover |
| 3 | +issue: "" |
| 4 | +state: complete |
| 5 | +version: 1 |
| 6 | +date: 2026-06-11 |
| 7 | +tags: [plan, visualization, metricsBar, colorSettingsPopover, markedPackages, restyle] |
| 8 | +--- |
| 9 | + |
| 10 | +# Restyle the Color settings popover to the new mockup |
| 11 | + |
| 12 | +Mockup: `plans/color_metric_popover/restyle_color_metric.png` |
| 13 | +Supersedes: `plans/2026-05-13-redesign-color-settings-popover.md` |
| 14 | + |
| 15 | +## Goal |
| 16 | + |
| 17 | +Migrate the Color settings popover to the mockup's single-column layout: header with metric name, slider row, distribution chart, segmented gradient mode, bands list with node counts, a folder-overrides section (backed by markedPackages), and an invert/reset footer. |
| 18 | + |
| 19 | +Decisions (clarified with user): |
| 20 | + |
| 21 | +- **Styling**: structure only — adopt the mockup's layout/sections/controls but use existing DaisyUI/Tailwind theme tokens (no cream/mono theme). |
| 22 | +- **Gradient modes**: keep all 4 `ColorMode` values as a segmented control (Absolute / Focused / Weighted / Relative). No behavior change. |
| 23 | +- **Folder overrides**: reuse the markedPackages state (shared with sidebar). Swatch click recolors with arbitrary colors, × unmarks, "Pin a folder color…" opens a folder search that marks a new package. |
| 24 | +- **Scope**: phased — restyle first, folder overrides second. The 2026-05-22 metrics-bar distributions plan stays separate. |
| 25 | + |
| 26 | +## Tasks |
| 27 | + |
| 28 | +### 1. Restyle existing controls into the mockup layout |
| 29 | + |
| 30 | +- Fixed narrow popover width (~420px), single column; drop the `w-[640px]`/`w-80` dynamic width logic |
| 31 | +- Header row: swatch dot + "Color by <metric>" + reset-thresholds icon button (right) — replaces the inline "Reset thresholds" button |
| 32 | +- Slider row: min input — slider rail with value labels above — max input |
| 33 | +- DISTRIBUTION section: section label, "<metric> × quantile %" caption, quantile diagram resized to fit the column (replace hardcoded 550×250 SVG size) |
| 34 | +- GRADIENT MODE: segmented control (DaisyUI join) for all 4 modes |
| 35 | +- BANDS section: one row per band — swatch + value range + node count; swatch opens the existing color picker (replaces the labelled picker rows); keep the "selected" row |
| 36 | +- Footer: Invert colors toggle (left) + Reset colors button (right) |
| 37 | +- Delta mode / unary metric: keep the simplified narrow variant (delta pickers + selected + footer), as today |
| 38 | + |
| 39 | +### 2. Folder overrides section (markedPackages) |
| 40 | + |
| 41 | +- Selector providing marked packages with descendant file counts |
| 42 | +- Section: "FOLDER OVERRIDES" label + "<n> pinned" + helper text ("These folders use a fixed color instead of the metric. Click a swatch to recolor.") |
| 43 | +- Row: swatch (click → color picker, dispatch `markPackages` with new color) + path + file count + × (`unmarkPackage`) |
| 44 | +- "Pin a folder color…": inline folder search (autocomplete over folder paths) that marks the chosen folder |
| 45 | +- Section always shows the pin button; list renders only when packages exist |
| 46 | + |
| 47 | +### 3. Tests + changelog |
| 48 | + |
| 49 | +- Unit tests for new selector(s), band counts, and folder-override interactions |
| 50 | +- `Changed` entry in `visualization/CHANGELOG.md` |
| 51 | + |
| 52 | +## Steps |
| 53 | + |
| 54 | +- [x] Complete Task 1: restyle existing controls into the mockup layout |
| 55 | +- [x] Complete Task 2: folder overrides section |
| 56 | +- [x] Complete Task 3: tests + changelog |
| 57 | + |
| 58 | +## Review Feedback Addressed |
| 59 | + |
| 60 | +1. **Invert/Reset placement**: Moved the Invert colors toggle + Reset colors row from the popover footer to between the Bands section and Folder Overrides. |
| 61 | +2. **Reset scope**: `Reset colors` now also resets the gradient mode (`dynamicSettings.colorMode`) — outside delta mode only, since the control is not visible there. |
| 62 | +3. **Picker light-dismiss bug**: Choosing a color closed the popover because the mat-menu picker rendered in a CDK overlay on `document.body`, outside the native `[popover]`, triggering light dismiss. Replaced with `cc-inline-color-picker`, which renders the `color-chrome` panel inside the popover DOM (fixed-positioned so it escapes the scrollable override list). |
| 63 | +4. **Override list density**: Rows sit in a `gap-0.5` container capped at `max-h-36` (~5 rows) with `overflow-y-auto`; full path shown as tooltip on each row and each search suggestion. |
| 64 | +5. **Folder search auto-close**: The search closes on blur when empty (typed terms keep it open); the suggestion list prevents the input blur on mousedown so clicking a suggestion with an empty term still pins it. |
| 65 | +6. **Invert/Reset row sizing**: The row looked oversized next to the dense column — "Invert colors" now uses `text-sm` and the Reset colors button renders as `btn-sm` via a new opt-in `small` input on `cc-reset-settings-button` (other popovers keep the full-size default). |
| 66 | +7. **Sub-agent review findings (all 12 fixed)**: inline picker closes on `pointerdown` instead of `click` so a drag released outside the panel keeps the picked color (pending `(onChange)` value is emitted if the close races the 100ms `onChangeComplete` debounce); panel also closes on container scroll, window resize, and popover close; Escape cancels the folder search without light-dismissing the popover (`preventDefault`); `mousedown` preventDefault moved from the suggestion `<ul>` (broke scrollbar dragging) to the buttons; helper copy corrected (marking colors tint folder floors, not buildings) with an "n files" tooltip on counts; both selectors skip excluded nodes; count attribution rewritten as an O(leaves×depth) path walk-up; `rounded-btn` (removed in DaisyUI 5) replaced with `rounded-md`; nested pins avoid their marked parent's color (reducer would drop them); gradient radio group got `role="radiogroup"` and a per-popover `name`; reset tooltip is delta-aware; new tests for all of the above plus the header threshold reset and the diagram size inputs. Components were also rewired through feature stores/services (`FolderOverridesStore/Service`, `MapColorsStore.setMapColors`) to satisfy the dependency-cruiser rule `feature-only-stores-can-import-ngrx-store`. |
| 67 | + |
| 68 | +## Notes |
| 69 | + |
| 70 | +- Band counts: `colorCategoryCounts$` (`ui/codeMap/codeMap.render.service.ts`) already tracks positive/neutral/negative node counts — reuse or derive a selector from `metricDataSelector` + `colorRangeSelector` |
| 71 | +- Marked-package recoloring is no longer limited to the 5 `markingColors` — verify rendering and sidebar handle arbitrary hex colors |
| 72 | +- Header reset icon resets thresholds only; footer "Reset colors" keeps its current behavior (colors + invert checkbox) |
| 73 | +- Verified headless via Electron + Playwright (`xvfb-run`): popover layout, segmented gradient mode, band counts, pin/recolor/unpin folder overrides (pinned `/root` → count 8 across both sample maps), invert toggle, threshold reset. Delta-mode variant covered by unit tests only. |
| 74 | +- New files: `colorBandRow.component.*`, `folderOverrides.component.*`, `markedPackagesWithCounts.selector.*`, `markableFolderPaths.selector.*` (all under `features/metricsBar/`); diagram got `diagramWidth`/`diagramHeight`/`showAxisLabels` inputs |
| 75 | +- `npm run build`, full `npm test` (367 suites), and `npm run format:check` all pass |
0 commit comments