Desktop viewport layout, plus a dead-code and duplication pass - #6
Open
ameesme wants to merge 3 commits into
Open
Desktop viewport layout, plus a dead-code and duplication pass#6ameesme wants to merge 3 commits into
ameesme wants to merge 3 commits into
Conversation
An over-engineering pass across the integration and the panel. No user-facing behaviour changes. Backend: - Drop the status payload fields nothing renders (per-light manual_since, last_applied*, settling, supports, supported_color_modes, config; the sun's position/drive/coordinates/sources; eight global settings echoes; local_hour), plus the runtime state and coordinator accessors that existed only to feed them. - Replace the twelve repetitions of the "is the integration ready" guard in the WebSocket handlers with one decorator. - Fold the private/public accessor pairs on the coordinator into single public methods, and drop the unused supports_rgb. - Track our own service-call contexts in one bounded insertion-ordered map instead of a deque plus a parallel set. - The tanh ramp is only ever fitted through (0, 0.05) and (1, 0.95), so bake its two coefficients in rather than solving per call. Values are bit-identical. - One round-to-5 helper instead of three copies; dataclasses.asdict instead of five hand-written to_dict bodies; one device_info shared by the select and switch platforms. Panel: - Share the 24-cell chart styling and fill-colour rule between the timeline rows and the row-preview strip. - Trim the status types to the fields the panel reads, use the existing _lightInfo lookup, drop a duplicated .grow rule and the identical label.field/div.field blocks, and fold _load into _run. Dev harness: - Delete frontend/dev/engine.ts. It was a second implementation of the lighting math kept in sync by hand, and an approximate one (fixed sunrise/sunset), so it never verified anything. The mock backend now serves a sun-row fixture captured from engine.py with explicit hour cells laid over it: the timeline, cell editing, overrides, RGB and status all still work; editing the sun config no longer moves the curve in the harness. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012UavT5bm5ZN2f1tNd7Yz1H
The desktop panel grew the page: a tall timeline pushed the whole thing down and the schema header scrolled out of reach. It now behaves like the small-screen layout — the panel is exactly as tall as the viewport, the header stays put, and the timeline and side sheet each scroll in their own column. - The host is a viewport-height flex column with overflow hidden, so the page itself never scrolls; the layout grid takes the remaining height and both columns get min-height: 0 to scroll rather than stretch. - The timeline card fills its column with the rows scrolling inside it, and the hour header is sticky — otherwise the 00-23 labels scroll away and the chart can't be read. - The side sheet keeps its title, subtitle and close button in place and scrolls only the form under them, in a new .side-body wrapper. This is the split the mobile drawer already used; scrolling the whole sheet would drag the close button off-screen. - Most of this was already in the small-screen media query, so it moves to the shared base and mobile keeps only its own deltas: the fixed host, edge-to-edge padding, and the flattened card's header colour. Version 2.3.0 rather than a patch: this changes how the panel behaves. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012UavT5bm5ZN2f1tNd7Yz1H
The timeline's drag row sat above the grid at all times, offering a control that does nothing unless preview is on. Gate it on previewActive like the small-screen scrub bar already is, so both layouts show a scrubber only when dragging it has an effect. Its clock readout and "jump to now" button go with it; the playhead still marks the current time, as it does on mobile. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012UavT5bm5ZN2f1tNd7Yz1H
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two commits: a cleanup pass with no behaviour change, then a desktop layout change on top. Version 2.3.0.
1. Fill the viewport on desktop, scroll each column internally (
cbec0e8)The desktop panel grew the page — a tall timeline pushed everything down and the schema header scrolled out of reach. It now behaves like the small-screen layout: the panel is exactly as tall as the viewport, the header stays put, and the timeline and side sheet each scroll in their own column.
overflow: hidden, so the page itself never scrolls. Measured at 1400×900 and 1280×620: page overflow 0px in both; at 620px the timeline pane has 28px of internal scroll and the sheet 122px.--surfaceon desktop (mobile keeps--bg, its card being flattened)..side-bodywrapper — the same split the mobile drawer already used. Scrolling the whole sheet drags the ✕ off-screen.2. Cut dead code and duplication; drop the JS engine port (
f435cec)No user-facing behaviour changes. Net −460 lines of source.
Dev harness:
frontend/dev/engine.tsis goneIt was a 250-line second implementation of the lighting math, kept in sync with
engine.pyby hand — and an approximate one (sunrise/sunset faked at fixed clock hours, fractional-hour space instead of datetimes), so it could never actually catch a divergence.tests/test_engine.pyis what does that.mock-backend.tsnow serves aSUN_ROWfixture captured from the realengine.pyunder the default sun config, with each light's explicit hour cells laid over it. The timeline, cell editor, overrides, RGB swatches, colourless rows, selection and status all still work innpm run dev; the one thing lost is that editing the sun config no longer moves the curve in the harness.CLAUDE.mdupdated to say so, including how to regenerate the fixture.Backend
sundial/statusshipped ~23 fields nothing renders: per-lightmanual_since,last_applied,last_applied_at,settling,supports,supported_color_modes,config; the sun'sposition,drive, coordinates and*_source; eight globals that echo settings the panel already has;local_hour. Deleted, along with theLightRuntimefields and coordinator accessors (is_settling,last_pass_at,supports_rgb) that existed only to feed them.@_with_coordinatordecorator, same error code and message._supported_modes/supported_modesand_compute_target/compute_targetwere private methods plus public passthroughs. One public method each.dequeplus a parallelsetto bound our own service-call context ids → one insertion-ordered dict, same bound, same O(1).(0, 0.05)and(1, 0.95), sofind_a_bsolved the same two coefficients on every call. Baked in at full double precision — verified bit-identical across the domain.engine.round5; five hand-writtento_dictbodies →dataclasses.asdict; the identicaldevice_infoinselect.pyandswitch.py→ one shared helper.Panel
cellStylesandcellColor(); each keeps its own cell height, so the drawer strip stays 42px and the grid keeps its 52px mobile rows.config.lights.find(...)calls now use the existing_lightInfo(); dropped a.growrule already inbaseStylesand the byte-identicallabel.field/div.fieldblocks;_load()was_run(getConfig())written out.Deliberately not done
_apply_external— flagged as speculative, but removing it would actually change behaviour:sundial.applyon a light Sundial doesn't control currently applies the sun default to it. Left alone.targetbranch ininterceptor.py— likely dead (HA mergestargetintoservice_databefore firingEVENT_CALL_SERVICE), but I couldn't verify against a real instance, and being wrong means explicit-colour calls stop flagging manual control. Left alone.<dialog>close animation (@starting-style/allow-discrete) — doesn't work here: the drawer is conditionally rendered, so@close→_sel = nullremoves the node before any CSS transition can run. The existing 30 lines stay.Verification
ruff check,pytest(33 passed),tsc --noEmitandvite buildall clean; bundle regenerated and committed.Drove the dev harness in Chromium, no console errors in any layout:
Group — 3 lights · 1 onplus the group warning) and the sun sheet (Adaptation,Sun — night · up 08:23 · down 17:36,Sun now,Next run,Lights — 7 controlled · 1 manual).🤖 Generated with Claude Code
https://claude.ai/code/session_012UavT5bm5ZN2f1tNd7Yz1H