feat(calls): pin screen-share to a stage tile (LC-408) #421
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/lc-408-screenshare-pinned-tile"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Implements LC-408 (subtask of the LC-402 call redesign): pin an active screen share to a large stage tile instead of letting it sit as an equal grid cell.
What
While any participant is sharing their screen, the participant grid reshapes into a stage:
object-fit: containon a neutral-dark background so the shared content is never cropped),When sharing ends it reverts to the even responsive grid. Multiple simultaneous shares stack as full-width stages with the filmstrip below.
How
A receiver cannot distinguish a screen track from a camera track, so the discrete share state is propagated over the WS exactly like mute (LC-407):
ClientFrame::voice_screen { room_id, sharing }; gated byis_in_voice_room, broadcastsChatEvent::VoiceScreenChanged { room_id, user_id, sharing }to the room, rendered to#lc-voice-busaskind="screen"(payload"1"/"0").render_eventreturnsNonefor it (handled per recipient).toggleScreen) and stop (endScreenShare, which also fires for the browser's own "Stop sharing"), appliesdata-screento the peer's tile, and re-announces on a late join so a newcomer pins correctly.selfSharingresets on join/leave..lc-voice-grid:has(.lc-voice-tile[data-screen])rule does the stage/filmstrip reshape - no JS layout code, and the DOM (flat tiles) is unchanged.Scope
ws/events.rs(1 variant),routes/ws.rs(frame + handler + render + dispatch),views/ws_fragments.rs(None arm),assets/voice.js,assets/main.css,templates/base.html+locales/{en,es}/js.ftl(one "Presenting" string). No template-page or schema change.Tests
just check(standalone + saas compile, clippy, fmt),just test,just test-saasall pass.voice.jssyntax-checked;just build-cssregenerated.A shared screen previously sat as an equal cell in the participant grid. Now, while anyone is sharing, the grid reshapes into a "stage": the sharing tile spans the full width (letterboxed, object-fit: contain on a neutral-dark background) and the other participants flow below as a centered filmstrip of small tiles. A "Presenting" badge marks the sharer's tile. The receiver cannot tell a screen track from a camera track, so screen-share state is propagated over the WS exactly like mute (LC-407): a new voice_screen { room_id, sharing } client frame broadcasts ChatEvent::VoiceScreenChanged to the room (gated by is_in_voice_room), rendered to the voice bus as kind="screen". voice.js announces on share start (toggleScreen) and stop (endScreenShare, including the browser's own "Stop sharing"), applies data-screen to the peer's tile, and re-announces on a late join so newcomers pin correctly. The whole stage layout is a CSS :has([data-screen]) rule, so no JS layout code and it reverts to the even grid when sharing ends. selfSharing resets on join/leave. Server: one event variant + frame + handler + render arm + the render_event None arm. Frontend: voice.js + main.css + one i18n string (en/es). No schema change. just check, just test, just test-saas all pass; voice.js syntax-checked. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>