feat(ui): voice drawer replaces full-screen call UI

Discord-style bottom drawer for voice instead of navigating away:

- "Join Voice" hides the FAB, slides up a persistent bottom bar
- Drawer shows: room name, timer, P2P/Relay badge, level meter
- Controls: mic, speaker, end call — all in the drawer
- Direct call info (identicon, name, P2P badge) shown inline
- Lobby stays visible above the drawer at all times
- Stats line shows codec/packet/FEC info
- Leave voice = drawer slides away, FAB returns

Removed: full-screen call-screen, back button, old participant
list, old mic/speaker/hangup buttons. All voice interaction
happens in the 15% bottom drawer while the lobby stays live.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Siavash Sameni
2026-04-14 18:47:40 +04:00
parent a058a83c91
commit 25471c694f
3 changed files with 189 additions and 144 deletions

View File

@@ -238,6 +238,74 @@ body {
.fab-icon { font-size: 18px; }
/* ── Voice Drawer (bottom bar) ── */
.voice-drawer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: var(--surface);
border-top: 1px solid var(--surface2);
padding: 0 16px;
padding-bottom: env(safe-area-inset-bottom, 8px);
z-index: 50;
animation: drawerUp 0.25s ease-out;
box-shadow: 0 -4px 20px rgba(0,0,0,0.4);
}
@keyframes drawerUp {
from { transform: translateY(100%); }
to { transform: translateY(0); }
}
.voice-drawer-bar {
display: flex; flex-direction: column; gap: 6px; padding: 10px 0 6px;
}
.vd-info {
display: flex; align-items: center; gap: 8px; font-size: 13px;
}
.vd-status-dot {
width: 8px; height: 8px; border-radius: 50%; background: var(--green); flex-shrink: 0;
}
.vd-room { color: var(--green); font-weight: 600; }
.vd-timer { color: var(--text-dim); font-family: ui-monospace, monospace; font-size: 12px; }
.vd-badge {
font-size: 10px; padding: 1px 6px; border-radius: 6px; font-weight: 500;
}
.vd-badge.direct { background: rgba(74,222,128,0.15); color: var(--green); }
.vd-badge.relay { background: rgba(96,165,250,0.15); color: #60a5fa; }
.vd-level { height: 3px; background: var(--surface2); border-radius: 2px; overflow: hidden; }
.vd-level-fill {
height: 100%; width: 0%; background: var(--green); border-radius: 2px; transition: width 0.1s;
}
.vd-controls {
display: flex; align-items: center; justify-content: center; gap: 12px; padding: 4px 0;
}
.vd-btn {
width: 44px; height: 44px; border-radius: 50%; border: none;
background: var(--surface2); color: var(--text); font-size: 18px;
cursor: pointer; display: flex; align-items: center; justify-content: center;
transition: background 0.15s;
}
.vd-btn:hover { background: var(--primary); }
.vd-btn.muted { background: var(--red); color: white; }
.vd-end { background: var(--red); color: white; }
.vd-end:hover { background: #dc2626; }
.vd-direct-info {
display: flex; align-items: center; gap: 10px; padding: 8px 0 4px;
border-top: 1px solid var(--surface2); margin-top: 4px;
}
.vd-dc-identicon { width: 32px; height: 32px; border-radius: 50%; flex-shrink: 0; }
.vd-dc-name { font-size: 13px; font-weight: 600; }
.vd-dc-badge {
font-size: 10px; padding: 1px 6px; border-radius: 6px;
}
.vd-dc-badge.direct { background: rgba(74,222,128,0.15); color: var(--green); }
.vd-dc-badge.relay { background: rgba(96,165,250,0.15); color: #60a5fa; }
.vd-dc-badge.connecting { background: rgba(250,204,21,0.15); color: var(--yellow); }
.vd-stats {
font-size: 10px; color: var(--text-dim); font-family: ui-monospace, monospace;
padding: 2px 0 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Incoming call banner */
.incoming-banner {
position: fixed;