feat: lay the input controls over the wall and rebuild Settings - #334
Merged
Merged
Conversation
Implements the dropdown 2b ("Over the wall") and Settings handoff.
Dropdown: no panel any more. Opening it puts a picker over each half
(current input, a strip of 128x72 snapshot tiles, that half's volume),
a capsule at the top (Dual/Single, Output, Settings) and a Close pill
at the bottom. It closes with Close, Esc, or after 30s idle.
Multi-view (new `multiView` setting, default on): off makes dual view
show one input on both halves, with a single strip that sets both.
Settings: a 920x680 side-nav modal with Inputs, Layout, Remote keyboard
and Art-Net panes, each with a status in the nav. Capture moved into
each input's No-signal panel; the shortcut table and the separate
No-Signal Detection section are gone (the legend has the shortcuts).
Inputs gain a Key column, a hardware-label placeholder, a clearable
Startup pill and an inline capture result. Layout gets a to-scale wall
diagram. Remote keyboard and Art-Net get status lines; the API key a
Show/Hide toggle.
Fixes along the way:
- remote keyboard never added .local to a bare hostname
- remote keyboard presses now go through main (CORS from file://)
- shortcuts fired with a <select> focused (Q quit the app)
- one Esc closed Settings and left fullscreen
- names were interpolated into innerHTML in Settings and volume rows
- the orphaned-reference banner said "1 reference belong"
- the input-name toast timer was never cleared on rapid switching
- the presenter debug overlay outlived Remote Keyboard being turned off
- the Art-Net catalogue was fetched on every keystroke of the URL
System fonts only: the handoff's brand face is licensed for internal
use and this repo and its installers are public.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Same surface, hairline and corner rule as the capsule and Settings, a mono title, the new key chips, and a fade instead of a slide. It floats just above the bottom edge, overlapping its tab so a hover can move from the tab into the panel without crossing a gap. The tab gets the same keyboard and ARIA handling as the top one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The custom track was one flat grey, so a slider's value only showed as the thumb's position. The track is now a gradient that reads --fill, which paintRangeFill() keeps in step on input and after any render that sets a value programmatically. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The placeholder was a circle with eight thin rays, which reads as a sun. It is now an eight-tooth gear outline with a centre hole, until the design's settings-gear.svg is exported. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ets louder Muted shows a cross; then one, two or three waves past each third. A wave arriving draws itself in from the speaker outwards, staggered so a jump from silent to loud ripples out; one leaving fades. On the picker volumes and the Output slider, driven by paintRangeFill so it follows the slider however its value changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replaces the Close pill. Past the lowest picker row plus 48px, moving the pointer closes the controls; the line is the volume slider rather than the thumbnails, so reaching for the slider does not. On touch a tap in the same area closes them. Esc and the 30s idle close are unchanged. The legend tab is no longer hidden while the controls are open, since the pill that sat on top of it is gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Implements the Claude Design handoff
HANDOFF-2b.md: dropdown 2b "Over the wall" and the new Settings (1e). Behaviour follows the functional spec for v3.3.4 (2e26017).Dropdown 2b
Multi-view (
multiView, defaulttrue)defaultSettings. Turning it off brings the right half in line with the left, and startup enforces the same.Settings
getStatus(), a count of customised screensavers, and a two-column grid of per-screensaver modes.Fixes
.localto a bare hostname (http://was prepended first). The URL logic is now insettings-status.jsand unit tested.remote-key-send), for the same CORS reason Art-Net does.<select>focused, Q used to quit the app. Escape still gets through.textContentis used instead ofinnerHTMLfor names in Settings and the volume rows.After review in the dev instance
--fillCSS variable set bypaintRangeFill().Where this differs from the handoff
settings-gear.svgare exported. The square corner of the containers (--radius-container) is a guess.For design review
At 6000×1200 everything is the handoff's size (128×72 tiles, 22px names), but it fills only the top-left of each ~3000px half. It probably wants scaling on the wall.
Testing
npm run lintpasses, andnpm testpasses 933 tests, 47 of them new:settings-status.test.jscovers the pure status logic.settings-panel.test.jsruns against the realindex.html, and checks that the page contains every idrenderer.jslooks up.electron-vite buildsucceeds.--mockand--mock=8:🤖 Generated with Claude Code