Follow up on the drawer polish, replacing things it hand-rolled with what
the codebase already provides.
Reuse
- The navigation toggles now use the Switch component instead of ~30 lines
of CSS mirroring it, which carried a comment admitting the metrics were
kept in sync by hand. base-ui renders Switch.Root as a span, so the row
can be a label wrapping a real control, the same shape the params editor
already uses. The row stays clickable across its full width
- Remove scrollbar-width and scrollbar-color from three drawers. index.scss
already sets both on the universal selector, so these were not only
redundant, they overrode the app wide thumb and track tokens with local
values
- Collect the user facing view names in one map in viewerConfig, and derive
the navigation entries and the URL preset targets from it. The same nine
labels had been written out in three places
Simplify
- NavigationMenuToggle composes NavigationMenuItem rather than repeating its
markup and key handling, so a row reacts to input in one place only
- ViewParamsSection consulted collapsible five times in a render. Absence of
a toggle handler now represents a section which cannot collapse, and the
header owns its two shapes
- Share the small uppercase group heading through an eyebrow-label mixin,
which was copied across four stylesheets
Tests
- Cover that a collapsed section keeps its values through apply. The form
reads from the DOM, so unmounting collapsed fields would silently drop
them, and no existing test caught that
Also drops a comment claiming rows avoid being buttons because Space is a
global hotkey. Measured against the app, the hotkey does not fire while the
menu is open regardless of focus, so the rationale did not hold.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014L7R2LgjMSH2WQbiSP4uRn
Bring both drawers onto the list and field patterns already used by the
settings panel, rather than each carrying its own treatment.
Navigation menu
- Rows adopt the PanelList styling: neutral idle colour with blue reserved
for the current view, which previously competed with a dozen other blue rows
- Group the list under named headings instead of bare separators
- Display options become toggle rows with a switch matching the Switch
component, replacing the inconsistent "Active" text notes
- Leading icons on a fixed box so labels line up, and an icon for Rename Client
- Swap :focus for :focus-visible so clicking no longer leaves an outline
- Show the client name in the header, next to the action that renames it
View params editor
- Compact fields (booleans, colours) sit beside their label instead of below
it, which removes a third of the scroll height and pairs control with label
- Restore the type hierarchy: option titles were dimmer than their section
header. Titles now read as primary with descriptions muted underneath
- Sections become cards with hairline separated rows
- Section headers are keyboard reachable and mark sections holding custom values
- Sticky header and footer with borders, so content no longer scrolls
visibly underneath the Apply button, dropping the 10vh padding workaround
- Give the presets block a heading and a tinted applied state
Collapsed and hidden fields stay mounted and hidden with CSS: the form reads
its values from the DOM, so unmounting them would drop them on Apply.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014L7R2LgjMSH2WQbiSP4uRn
* fix: issue where a count-to-end would lead to incorrect expected times
* fix: include add time in overtime when countToEnd
* fix: ui and server use same calculation for expected end
The server serves html/timer-legacy.html and html/login.html from disk
at runtime, relative to the bundled server. The Docker image copies
these files but the electron packaging did not, so the view 404ed in
all desktop distributions.
Additionally, AppImages mount at /tmp/.mount_*, a hidden directory.
Express sendFile refuses paths containing dot-segments by default
(returns 404 without touching disk), so the view failed on Linux even
with the file packaged. Allow dotfiles for this route; the request
path is fixed so no user input is affected.
The Stage Timer and PiP Timer views relied on `align-content: center` to
vertically center the timer digits inside `.timer-container`, which is a
plain block element. Aligning children of a block container via
`align-content` only works in Chromium 123+ (Firefox 125+, Safari 17.4+).
Embedded browsers such as vMix Browser Input (CEF V115) and other older
CEF/Chromium-based production tools ignore the property, so the digits
fall back to the top of the container while every other element renders
correctly.
Make `.timer-container` a real flex column and center with
`justify-content: center`, which is universally supported and matches the
centering approach used elsewhere in the codebase. The removed
`justify-self`/`align-self` were no-ops on a full-width flex item.
Fixes#2126
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014T6ENZ3r6JXZb1fpYw2oNY
Surface {{groupNow.*}} template variables (title, note, colour, times,
custom fields) in the automation template autocomplete so events inside a
group can reference their group. The runtime store already carries
groupNow, so substitution and filters worked already; this makes it
discoverable.
Extend the message-secondary action with an optional text field so an
automation can set the secondary message content, not just its source.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LZYPZVdZLWowU7DyzGkWyy