Frontend: gradient day swatches and a real month backdrop bar (#48) #96

Merged
claude-bot merged 1 commit from feat/gradient-swatches-and-backdrop into main 2026-09-01 00:36:25 +00:00
Contributor

Batch C items 3 and 4 — both visual fidelity against spec §10.1.

Gradient swatches

Each segment strip rendered seg.colors[0] and threw away slots 1 and 2, so a three-colour scheme looked identical to a one-colour scheme. The spec asks for "one horizontal gradient strip per themed segment, blending that segment's colour slots (matches WLED's own preset thumbnails)".

The non-obvious part is black. WLED pads unused colour slots with pure black, and 7 of the 98 colour blocks in schemes/builtin.yaml end that way — e.g. [[180,0,0],[0,120,45],[255,215,0],[0,0,0]]. Blending naively would drag those swatches to black at the right edge and read as a rendering bug.

So trailing pure-black slots are dropped. Interior blacks are kept — a black between two colours may be deliberate — and [20,20,20] is a real dark rather than padding, so only exact [0,0,0] counts.

I checked that against the actual library rather than assuming; the dev database has zero scheme_segments rows (that instance was never configured past scheme generation), so builtin.yaml was the honest source.

The logic lives in segmentGradient() in utils.ts rather than inline in the component, so it's directly testable.

Month backdrop

The backdrop rendered as a tint on the month header plus a left border. The spec asks for "a full-width coloured bar behind each month's row".

It now sits behind the day grid, which is where it belongs: day cells carry no background of their own, so the colour shows through and around them — and that's the point, since the backdrop is what those days fall back to. The header keeps a small colour chip so the event stays identifiable beside its name.

Verification

In a node:22 container matching CI:

tsc -b --noEmit    exit 0
eslint             exit 0  (--max-warnings 0)
vitest             56 passed  (was 47)
npm run build      succeeded

9 new tests — 7 on segmentGradient (blending, single slot, trailing padding, several trailing blacks, interior black, near-black, empty fallback) and 2 asserting DayCell actually renders a gradient for multi-slot segments and a solid for single-slot.

One test caught me out honestly: my first assertion expected rgb(0, 255, 0) with spaces, but jsdom preserves the exact emitted string, which has none. The implementation was right; the expectation was wrong. Worth mentioning because it's the sort of thing that gets "fixed" in the wrong direction.

Note

This branch was cut before #95 merged, so I rebased it onto the updated main before pushing — DayCell.tsx now carries both the icon work and the gradient change, and they merged cleanly (different regions of the file).

Batch C after this: items 7 (browsable import panel) and 8 (quick-push arbitrary colour) remain.

Batch C items **3 and 4** — both visual fidelity against spec §10.1. ## Gradient swatches Each segment strip rendered `seg.colors[0]` and threw away slots 1 and 2, so **a three-colour scheme looked identical to a one-colour scheme**. The spec asks for *"one horizontal gradient strip per themed segment, blending that segment's colour slots (matches WLED's own preset thumbnails)"*. **The non-obvious part is black.** WLED pads unused colour slots with pure black, and **7 of the 98 colour blocks in `schemes/builtin.yaml` end that way** — e.g. `[[180,0,0],[0,120,45],[255,215,0],[0,0,0]]`. Blending naively would drag those swatches to black at the right edge and read as a rendering bug. So trailing pure-black slots are dropped. Interior blacks are **kept** — a black between two colours may be deliberate — and `[20,20,20]` is a real dark rather than padding, so only exact `[0,0,0]` counts. I checked that against the actual library rather than assuming; the dev database has zero `scheme_segments` rows (that instance was never configured past scheme generation), so `builtin.yaml` was the honest source. The logic lives in `segmentGradient()` in `utils.ts` rather than inline in the component, so it's directly testable. ## Month backdrop The backdrop rendered as a **tint on the month header** plus a left border. The spec asks for *"a full-width coloured bar behind each month's row"*. It now sits behind the day grid, which is where it belongs: day cells carry no background of their own, so the colour shows through and around them — and that's the point, since the backdrop is what those days fall back to. The header keeps a small colour chip so the event stays identifiable beside its name. ## Verification In a `node:22` container matching CI: ``` tsc -b --noEmit exit 0 eslint exit 0 (--max-warnings 0) vitest 56 passed (was 47) npm run build succeeded ``` 9 new tests — 7 on `segmentGradient` (blending, single slot, trailing padding, several trailing blacks, interior black, near-black, empty fallback) and 2 asserting `DayCell` actually renders a gradient for multi-slot segments and a solid for single-slot. **One test caught me out honestly:** my first assertion expected `rgb(0, 255, 0)` with spaces, but jsdom preserves the exact emitted string, which has none. The implementation was right; the expectation was wrong. Worth mentioning because it's the sort of thing that gets "fixed" in the wrong direction. ## Note This branch was cut before #95 merged, so I rebased it onto the updated `main` before pushing — `DayCell.tsx` now carries both the icon work and the gradient change, and they merged cleanly (different regions of the file). **Batch C after this:** items **7** (browsable import panel) and **8** (quick-push arbitrary colour) remain.
Frontend: gradient day swatches and a real month backdrop bar (#48)
Some checks failed
CI / Alembic migration check (pull_request) Successful in 35s
CI / Python lint & type-check (pull_request) Successful in 1m18s
CI / Python tests (pull_request) Successful in 1m58s
CI / Frontend lint, test & build (pull_request) Successful in 1m38s
CI / Docker build, health smoke & E2E (pull_request) Failing after 1s
4f9ec63b6f
Batch C items 3 and 4, both purely visual fidelity against spec 10.1.

Gradient swatches. Each segment strip rendered seg.colors[0] and discarded
slots 1 and 2, so a three-colour scheme looked identical to a one-colour one.
The spec asks for "one horizontal gradient strip per themed segment, blending
that segment's colour slots (matches WLED's own preset thumbnails)".

The non-obvious part is black. WLED pads unused colour slots with pure black,
and 7 of the 98 colour blocks in schemes/builtin.yaml end that way -- for
instance [[180,0,0],[0,120,45],[255,215,0],[0,0,0]]. Blending naively would
drag those swatches to black at the right edge and read as a rendering bug, so
trailing pure-black slots are dropped. Interior blacks are kept, since a black
between two colours may well be deliberate, and [20,20,20] is a real dark, not
padding -- only exact [0,0,0] counts.

The logic lives in segmentGradient() in utils.ts rather than inline in the
component, so it is directly testable; 7 tests cover blending, single slots,
trailing padding, interior black, near-black, and the empty fallback.

Month backdrop. The backdrop rendered as a tint on the month HEADER plus a left
border. The spec asks for "a full-width coloured bar behind each month's row".
It now sits behind the day grid, where it belongs: day cells carry no background
of their own, so it shows through and around them -- which is the point, since
the backdrop is what those days fall back to. The header keeps a small colour
chip so the event stays identifiable next to its name.

Verified in a node:22 container matching CI:

  tsc -b --noEmit   exit 0
  eslint            exit 0 (--max-warnings 0)
  vitest            56 passed, up from 47
  npm run build     succeeded

One test caught me out honestly: the first gradient assertion expected
"rgb(0, 255, 0)" with spaces, but jsdom preserves the exact string, which has
none. The implementation was right and the expectation was wrong.

Refs #48.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
rbrooks force-pushed feat/gradient-swatches-and-backdrop from 4f9ec63b6f
Some checks failed
CI / Alembic migration check (pull_request) Successful in 35s
CI / Python lint & type-check (pull_request) Successful in 1m18s
CI / Python tests (pull_request) Successful in 1m58s
CI / Frontend lint, test & build (pull_request) Successful in 1m38s
CI / Docker build, health smoke & E2E (pull_request) Failing after 1s
to 7875b10f86
All checks were successful
CI / Python lint & type-check (pull_request) Successful in 1m4s
CI / Frontend lint, test & build (pull_request) Successful in 1m12s
CI / Alembic migration check (pull_request) Successful in 1m50s
CI / Python tests (pull_request) Successful in 5m4s
CI / Docker build, health smoke & E2E (pull_request) Successful in 3m9s
2026-09-01 00:11:29 +00:00
Compare
claude-bot deleted branch feat/gradient-swatches-and-backdrop 2026-09-01 00:36:26 +00:00
Sign in to join this conversation.
No description provided.