From 7172091159390f7e8d5606c8b9c16a63d5e544f4 Mon Sep 17 00:00:00 2001 From: Jannis Braun <151788261+TheZwiss@users.noreply.github.com> Date: Sun, 1 Mar 2026 23:36:10 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20Phase=203=20Aether=20Drift=20=E2=80=94?= =?UTF-8?q?=20voice=20&=20video=20component=20token=20migration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Migrate all 10 voice/video components from Discord visual language to Aether Drift design system. Zero discord-* classes or hardcoded hex values remain in components/voice/. Key changes: - Status indicators use pastel accents: mint (connected/speaking), amber (connecting/idle), rose (muted/deafened/error) - VoiceControlBar converted to frosted glass-bubble material - ConnectionInfoPopover and ScreenShareSettingsPopover use glass popovers - Speaking ring glow changed from Discord green to mint (#86efac) - Slider accents use lavender instead of blurple - All bg/text/border tokens mapped to surface-*/txt-*/interactive-* system --- .../voice/ConnectionInfoPopover.tsx | 52 +++++++++---------- .../components/voice/IncomingCallModal.tsx | 18 +++---- .../src/components/voice/PictureInPicture.tsx | 12 ++--- .../voice/ScreenShareSettingsPopover.tsx | 28 +++++----- .../web/src/components/voice/StreamTile.tsx | 50 +++++++++--------- .../web/src/components/voice/VoiceChannel.tsx | 16 +++--- .../src/components/voice/VoiceChatPanel.tsx | 6 +-- .../src/components/voice/VoiceControlBar.tsx | 18 +++---- .../web/src/components/voice/VoiceGrid.tsx | 6 +-- .../web/src/components/voice/VoiceUser.tsx | 22 ++++---- 10 files changed, 114 insertions(+), 114 deletions(-) diff --git a/packages/web/src/components/voice/ConnectionInfoPopover.tsx b/packages/web/src/components/voice/ConnectionInfoPopover.tsx index 6ac20936..765a9da5 100644 --- a/packages/web/src/components/voice/ConnectionInfoPopover.tsx +++ b/packages/web/src/components/voice/ConnectionInfoPopover.tsx @@ -13,21 +13,21 @@ function formatBitrate(kbps: number): string { } function pingColor(ms: number): string { - if (ms <= 80) return 'text-discord-green'; - if (ms <= 200) return 'text-discord-yellow'; - return 'text-discord-red'; + if (ms <= 80) return 'text-status-online'; + if (ms <= 200) return 'text-status-idle'; + return 'text-txt-danger'; } function lossColor(pct: number): string { - if (pct <= 1) return 'text-discord-green'; - if (pct <= 5) return 'text-discord-yellow'; - return 'text-discord-red'; + if (pct <= 1) return 'text-status-online'; + if (pct <= 5) return 'text-status-idle'; + return 'text-txt-danger'; } function jitterColor(ms: number): string { - if (ms <= 30) return 'text-discord-green'; - if (ms <= 80) return 'text-discord-yellow'; - return 'text-discord-red'; + if (ms <= 30) return 'text-status-online'; + if (ms <= 80) return 'text-status-idle'; + return 'text-txt-danger'; } function sourceLabel(source: string): string { @@ -51,15 +51,15 @@ function trackLabel(direction: 'send' | 'recv', source: string, participantName: const Row = ({ label, value, colorClass }: { label: string; value: string; colorClass?: string }) => (
- {label} - {value} + {label} + {value}
); -const Divider = () =>
; +const Divider = () =>
; const SectionHeader = ({ title }: { title: string }) => ( -
+
{title}
); @@ -68,10 +68,10 @@ function AudioTrackRow({ track }: { track: AudioTrackStat }) { const label = trackLabel(track.direction, track.source, track.participantName); return (
- {label} - + {label} + {formatBitrate(track.bitrate)} - {track.codec && {track.codec}} + {track.codec && {track.codec}}
); @@ -84,19 +84,19 @@ function VideoTrackRow({ track }: { track: VideoTrackStat }) { return (
- {label} - + {label} + {formatBitrate(track.bitrate)} - {track.codec && {track.codec}} + {track.codec && {track.codec}}
{(resolution || track.fps !== null || track.qualityLimitation || track.simulcastLayer) && (
- + {resolution && `${resolution}`} {track.fps !== null && ` @${track.fps}`} - + {track.direction === 'send' && track.qualityLimitation && track.qualityLimitation !== 'none' ? track.qualityLimitation : ''} @@ -133,17 +133,17 @@ export function ConnectionInfoPopover({ open, onClose }: ConnectionInfoPopoverPr return (
-
- Connection Info +
+ Connection Info
{!room ? ( -
Not connected
+
Not connected
) : !stats ? ( -
Gathering stats...
+
Gathering stats...
) : ( <> {/* Network */} diff --git a/packages/web/src/components/voice/IncomingCallModal.tsx b/packages/web/src/components/voice/IncomingCallModal.tsx index 981576f2..6a83d9d9 100644 --- a/packages/web/src/components/voice/IncomingCallModal.tsx +++ b/packages/web/src/components/voice/IncomingCallModal.tsx @@ -43,22 +43,22 @@ export function IncomingCallModal() {
{/* Call card */} -
+
{/* Ring animation background */}
-
-
+
+
{/* Content */}
{/* Caller avatar */}
-
+
{incomingCall.callerName.charAt(0).toUpperCase()}
{/* Ringing phone icon */} -
+
@@ -67,8 +67,8 @@ export function IncomingCallModal() { {/* Caller info */}
-

{incomingCall.callerName}

-

Incoming Voice Call...

+

{incomingCall.callerName}

+

Incoming Voice Call...

{/* Action buttons */} @@ -76,7 +76,7 @@ export function IncomingCallModal() { {/* Decline */} @@ -191,7 +191,7 @@ export function ScreenShareSettingsPopover({ open, onClose }: ScreenShareSetting step={BITRATE_STEP} value={config.customBitrateKbps ?? Math.round(result.publish.videoEncoding.maxBitrate / 1000)} onChange={(e) => setConfig({ customBitrateKbps: Number(e.target.value) })} - className="flex-1 h-1.5 accent-discord-blurple cursor-pointer appearance-none bg-[#4e5058] rounded-full + className="flex-1 h-1.5 accent-accent-primary cursor-pointer appearance-none bg-interactive-muted rounded-full [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-3.5 [&::-webkit-slider-thumb]:h-3.5 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-white [&::-webkit-slider-thumb]:shadow-md [&::-webkit-slider-thumb]:cursor-pointer [&::-webkit-slider-thumb]:border-0 @@ -199,7 +199,7 @@ export function ScreenShareSettingsPopover({ open, onClose }: ScreenShareSetting [&::-moz-range-thumb]:bg-white [&::-moz-range-thumb]:border-0 [&::-moz-range-thumb]:cursor-pointer" /> {config.customBitrateKbps != null ? formatKbps(config.customBitrateKbps) @@ -210,8 +210,8 @@ export function ScreenShareSettingsPopover({ open, onClose }: ScreenShareSetting
{/* Footer — computed stats */} -
- +
+ {formatBitrate(result.publish.videoEncoding.maxBitrate)} · {formatDegradation(result.overdrive.degradationPreference)}
diff --git a/packages/web/src/components/voice/StreamTile.tsx b/packages/web/src/components/voice/StreamTile.tsx index b4236887..2f2ba951 100644 --- a/packages/web/src/components/voice/StreamTile.tsx +++ b/packages/web/src/components/voice/StreamTile.tsx @@ -130,7 +130,7 @@ export function StreamTile({ tile, large }: StreamTileProps) { return (
) : ( -
+
-

+

{participant.username} is streaming

{!isLocal && ( @@ -165,7 +165,7 @@ export function StreamTile({ tile, large }: StreamTileProps) { )} {/* LIVE badge — top left */} -
+
LIVE
@@ -203,7 +203,7 @@ export function StreamTile({ tile, large }: StreamTileProps) { {/* Context Menu */} {contextMenu && (
e.stopPropagation()} > @@ -215,7 +215,7 @@ export function StreamTile({ tile, large }: StreamTileProps) { handleStopStreaming(); setContextMenu(null); }} - className="w-full flex items-center gap-2 px-3 py-2 text-discord-red hover:bg-discord-red/10 rounded text-sm transition-colors" + className="w-full flex items-center gap-2 px-3 py-2 text-txt-danger hover:bg-accent-rose/10 rounded text-sm transition-colors" >
-
+
Stream Quality
{/* Stream Volume slider */}
-
+
Stream Volume
@@ -360,7 +360,7 @@ export function StreamTile({ tile, large }: StreamTileProps) { height="16" viewBox="0 0 24 24" fill="currentColor" - className="text-discord-text-muted flex-shrink-0" + className="text-txt-tertiary flex-shrink-0" > @@ -372,9 +372,9 @@ export function StreamTile({ tile, large }: StreamTileProps) { onChange={(e) => setStreamVolumeAction(userId, parseInt(e.target.value)) } - className="flex-1 accent-discord-blurple h-1" + className="flex-1 accent-accent-primary h-1" /> - + {streamVolume}%
@@ -385,14 +385,14 @@ export function StreamTile({ tile, large }: StreamTileProps) { onClick={() => setAttenuationEnabled(!streamAttenuationEnabled) } - className="w-full flex items-center justify-between px-3 py-2 text-discord-text-secondary hover:bg-discord-modifier-hover rounded text-sm transition-colors" + className="w-full flex items-center justify-between px-3 py-2 text-txt-secondary hover:bg-interactive-hover rounded text-sm transition-colors" > Stream Attenuation
{streamAttenuationEnabled && ( @@ -410,7 +410,7 @@ export function StreamTile({ tile, large }: StreamTileProps) { {/* Attenuation Strength slider */} {streamAttenuationEnabled && (
-
+
Attenuation Strength
@@ -422,9 +422,9 @@ export function StreamTile({ tile, large }: StreamTileProps) { onChange={(e) => setAttenuationStrength(parseInt(e.target.value)) } - className="flex-1 accent-discord-blurple h-1" + className="flex-1 accent-accent-primary h-1" /> - + {streamAttenuationStrength}%
diff --git a/packages/web/src/components/voice/VoiceChannel.tsx b/packages/web/src/components/voice/VoiceChannel.tsx index bbaf4b75..e66c9ba2 100644 --- a/packages/web/src/components/voice/VoiceChannel.tsx +++ b/packages/web/src/components/voice/VoiceChannel.tsx @@ -29,8 +29,8 @@ export function VoiceChannel({ channelId, channelName, onClick }: VoiceChannelPr onClick={onClick} className={`w-full flex items-center gap-1.5 px-2 h-8 rounded-[4px] group transition-colors ${ isActive - ? 'bg-discord-modifier-selected text-white' - : 'text-discord-text-muted hover:text-discord-text-secondary hover:bg-discord-modifier-hover' + ? 'bg-interactive-selected text-white' + : 'text-txt-tertiary hover:text-txt-secondary hover:bg-interactive-hover' }`} > @@ -61,36 +61,36 @@ export function VoiceChannel({ channelId, channelName, onClick }: VoiceChannelPr const isScreenSharing = participant?.isScreenSharing ?? wsStatus?.isScreenSharing ?? false; return ( -
+
- {displayName} + {displayName} {/* Status badges */}
{isMuted && ( - + )} {isParticipantDeafened && ( - + )} {hasCamera && ( - + )} {isScreenSharing && ( - LIVE + LIVE )}
diff --git a/packages/web/src/components/voice/VoiceChatPanel.tsx b/packages/web/src/components/voice/VoiceChatPanel.tsx index 4d5e88ab..243b63f0 100644 --- a/packages/web/src/components/voice/VoiceChatPanel.tsx +++ b/packages/web/src/components/voice/VoiceChatPanel.tsx @@ -13,13 +13,13 @@ export function VoiceChatPanel({ channelId, channelName }: VoiceChatPanelProps) const toggleVoiceChat = useUIStore((s) => s.toggleVoiceChat); return ( -
+
{/* Chat header */}
- Chat + Chat
@@ -134,7 +134,7 @@ export function VoiceGrid({ participants }: VoiceGridProps) { {/* Bottom strip of other tiles */} {!stripHidden && otherTiles.length > 0 && ( -
+
{otherTiles.map((t) => (
) : ( -
+
{isSpeaking && ( -
+
)}
@@ -119,7 +119,7 @@ export function VoiceUser({ tile, large }: VoiceUserProps) {
{participant.isMuted && ( -
+
)} {(isLocal ? isDeafened : participant.isDeafened) && ( -
+
e.stopPropagation()} > -
+
User Volume
@@ -167,7 +167,7 @@ export function VoiceUser({ tile, large }: VoiceUserProps) { height="16" viewBox="0 0 24 24" fill="currentColor" - className="text-discord-text-muted flex-shrink-0" + className="text-txt-tertiary flex-shrink-0" > @@ -182,9 +182,9 @@ export function VoiceUser({ tile, large }: VoiceUserProps) { parseInt(e.target.value), ) } - className="flex-1 accent-discord-blurple h-1" + className="flex-1 accent-accent-primary h-1" /> - + {perUserVolume}%