feat(web,api): lobby signage, speaker view polish, force-stop reliability#6
Merged
Merged
Conversation
…lity
Lobby (audience-facing signage)
- Rewrite LobbyView as a state-driven layout: 1 live → big hero card;
2-3 live → grid; 0 live + upcoming → next-up hero; 0 live + nothing →
quiet "Programme has ended" / "No sessions yet". No countdown digits
on the public screen — only scheduled times and a capped progress
bar (overrun caps at 100%; host stops the session). Up Next list is
chronological, filters out items whose scheduled start has passed
(between-session buffer is invisible to the audience). 24h wall
clock + date in the event timezone, minutes only.
- PublicInfoController.GetLobby now returns the event window
(start/end/timezone) plus the per-room schedule items needed to
build the upcoming list. publicInfo.ts types updated to match.
- PublicAccessCodeAuthHandler accepts a `surface=lobby` query param
and falls back to lobby-code lookup so the lobby's hub negotiate
is authorised without a room context. TimerHub rehydrates the
PublicAccessContext from connection claims and lets a lobby code
resync any room in its own event.
Speaker view polish
- Adopt a speaker display state machine (idle / pre-roll / running /
final / overrun) with options driven by query params (chrome,
contrast, progress, scale, margin). Adds ring/line progress modes,
a calm IdleState ("Standing by" / "Up next ..."), and a re-styled
message overlay. Countdown gains `scale`, `label`, and `pulse` props
so the parent can drive emphasis without the timer guessing.
- Message overlay: anchored at the bottom, full-bleed-ish width,
large readable type for the back of the room.
Force-stop reliability
- useEventRoomSnapshots wraps the initial hub.start() in a single
short-delay retry. SignalR's auto-reconnect only fires after an
*established* connection drops; if the initial start races with
StrictMode's double-mount the hub stays disconnected forever
otherwise. `stopRoom` throws if the hub isn't connected and gives
the dashboard a 3s grace window during reconnect.
- EventDashboardPage wires the new `onForceStop` on the room panel
through the shared hub instead of opening a new connection.
Operator dashboard
- EventIdentity: a live room trumps the configured event window in
the status pill, so the header no longer says "Ended 18h ago" while
a room tile next to it is still live.
- RoomTile: drop `nextItem` from the idle-upcoming view when its
scheduled start is in the past — fixes the "Up next 10:15 ·
starting now" line on stale snapshots.
- ScheduleEditor: linked programme-slot label rendered as a chip on
schedule items bound to a programme slot.
Audit + theming
- New `lib/auditHumanise.ts` maps verbs to human-readable labels for
the audit log; AuditPage uses it. Speaker display options + state
derivation extracted to `lib/speakerDisplay.ts` with unit tests.
- Countdown: per-variant sizing now scales by string length so long
overrun strings ("+HH:MM:SS") no longer overflow the viewport or
the compact tile.
- globals.css: `.countdown-pulse-once` one-shot emphasis (replaces
the continuous alarm); new `.speaker-stage` background + high-
contrast modifier. Theme default `--primary` is now near-white
(`#f5f5f7`) — color is reserved for state, normal time is calm.
Verification
- dotnet build: clean (8 pre-existing dependency warnings).
- web build: clean, 1927 modules.
Co-Authored-By: Claude Opus 4.7 (1M context) <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.
Summary
LobbyViewrewritten: 1 live → big hero, 2-3 live → grid, 0 live + upcoming → next-up hero, 0 live + nothing → quiet "Programme has ended". No countdown digits on the public screen — only scheduled times and a progress bar (capped at 100% on overrun; host stops the session). Lobby info endpoint now returns the event window + per-room schedule items; auth handler + hub updated so the lobby code is recognised on the negotiate path and can resync any room in its event.IdleState, ring/line progress modes, larger message overlay.Countdowngainsscale/label/pulseprops plus length-aware sizing so long "+HH:MM:SS" overruns no longer overflow.useEventRoomSnapshotsretries the initialhub.start()once (covers the StrictMode double-mount race that left the dashboard hub permanently disconnected) andstopRoomwaits up to 3s for reconnect before failing.EventDashboardPage.onForceStopgoes through the shared hub.EventIdentity's status pill; stalenextItemwhose start is in the past is dropped from the idle-upcoming tile view; linked programme-slot chip on schedule items.lib/auditHumanise.ts); speaker display logic extracted tolib/speakerDisplay.tswith unit tests;.countdown-pulse-onceone-shot emphasis replaces the continuous alarm; theme default--primaryis near-white — colour is reserved for state.Test plan
dotnet test(Docker-backed integration tests)npm run build— passes locally (1927 modules, 0 errors)/e/<code>/lobbyon a wide display: 1 live → big hero card; stop the live session → switches to "Next" hero; verify progress bar caps at 100% on overrun, scheduled times stay correct in the event timezone/r/<code>/speaker?chrome=minimal&progress=ringand verify the minimal speaker variantEventIdentitywhile a room is still live🤖 Generated with Claude Code