feat(calls): redesign the in-call voice UI (LC-402) #419
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/lc-402-voice-call-redesign"
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 the core of the LC-402 epic (subtasks LC-403/404/405/406). See data/liveT.png for the before state. Stack unchanged: Askama + HTMX + Tailwind, server-rendered, WebSocket-driven, no client framework.
What changed
Layout regions + theme (LC-403). The enclave voice page now has clear regions: control bar / participant grid (primary) / transcript drawer (secondary). The voice page, the shared recording pill, and the transcript panel are migrated off hardcoded slate/green/red/indigo onto the semantic theme tokens (
--surface,--content,--accent,--danger,--success,--border), so the call UI follows light/dark/high-contrast. New.lc-call* / .lc-voice* / .lc-transcript*design system inmain.css.Participant grid (LC-404). Responsive CSS grid for 1 / 2 / many (a lone tile is sized instead of ballooning; "Waiting for others to join" shows when alone). Tiles rebuilt in
voice.js: video-vs-avatar, name + YOU badge, a self mute indicator, and an active-speaker ring driven by a self-contained, feature-detected Web Audio analyser loop. Participant-count chip in the header.Control bar (LC-405). Two clusters - media controls (Mute / Start video / Share screen) and session actions (Transcribe / Transcript / Leave) - split by a divider. Mute / video / screen show aria-pressed on/off state; Leave is danger-styled; Transcribe is the danger-tinted "recording" toggle with a pulsing dot tied to the pill + drawer.
Transcript panel (LC-406). The bottom scrim becomes a themed right-hand drawer (toggle + close, own scroll). Lines render as speaker + timestamp + text, grouped by consecutive speaker; auto-scroll to latest with a "Jump to live" affordance when scrolled up. The pill, toggle, and drawer header share one obvious recording state. On the voice page the root reserves space for the drawer so tiles are never covered; over the 1:1 modal it overlays.
Safety
Every
data-lc-*attribute and element id the JS relies on is preserved, so the WebRTC mesh + signaling state machines are untouched - only tile structure, control state, and caption presentation changed. The 1:1 DM call modal shares the new transcript drawer + tokened pill. CSS.hiddenoverrides are added wheremain.css(loaded after tailwind-built.css) would otherwise beat the.hiddentoggle the JS uses (the LC-391 gotcha).Brainstorm captured as follow-ups (sub-issues on LC-402)
Remote mute/speaking propagation over WS (only local mute is known today), screen-share pinned tile, full mobile pass, connection-quality indicator, transcript consent/export-link, and 1:1 modal control-bar parity (it gets the drawer but no panel-toggle button yet). Noted in the epic.
Scope
Frontend only:
templates/voice/page.html,templates/layout.html(caption/drawer),templates/ws/transcript_segment.html,templates/base.html(2 JS strings),assets/voice.js,assets/transcribe.js,assets/main.css,locales/{en,es}/{misc,js}.ftl. No Rust, route, or schema change.Tests
just check(standalone + saas compile, clippy, fmt),just test,just test-saasall pass.voice.js+transcribe.jssyntax-checked (node + bun).just build-cssregenerated. prefers-reduced-motion respected.