From 6b566831a2fddaf672ba65e4b478818c55a72fe9 Mon Sep 17 00:00:00 2001 From: Cyril Date: Wed, 8 Apr 2026 10:19:25 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B(frontend)=20align=20pip=20layout?= =?UTF-8?q?=20with=20google=20meet?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Show a main tile with a bottom-right thumbnail in PiP, like Google Meet. --- .../src/features/pip/components/PipView.tsx | 57 ++++++++++++++----- 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/src/frontend/src/features/pip/components/PipView.tsx b/src/frontend/src/features/pip/components/PipView.tsx index 5e86a731..975ffb10 100644 --- a/src/frontend/src/features/pip/components/PipView.tsx +++ b/src/frontend/src/features/pip/components/PipView.tsx @@ -7,7 +7,6 @@ import { import { useTracks } from '@livekit/components-react' import { Track } from 'livekit-client' import { ParticipantTile } from '@/features/rooms/livekit/components/ParticipantTile' -import { GridLayout } from '@/features/layout/components/GridLayout' import { SidePanel } from '@/features/rooms/livekit/components/SidePanel' import { pipLayoutStore } from '../stores/pipLayoutStore' import { PipControlBar } from './PipControlBar' @@ -24,6 +23,22 @@ const pickTrackForPip = ( return tracks[0] } +const pickLocalCameraTrack = ( + tracks: TrackReferenceOrPlaceholder[] +): TrackReferenceOrPlaceholder | undefined => + tracks.find( + (track) => + track.source === Track.Source.Camera && track.participant?.isLocal + ) + +const pickRemoteCameraTrack = ( + tracks: TrackReferenceOrPlaceholder[] +): TrackReferenceOrPlaceholder | undefined => + tracks.find( + (track) => + track.source === Track.Source.Camera && !track.participant?.isLocal + ) + /** * Main view component for the Picture-in-Picture window. * Handles track selection (prioritizes screen share), layout switching (grid for multiple participants), @@ -41,6 +56,13 @@ export const PipView = () => { const trackRef = pickTrackForPip(tracks) const browserSupportsScreenSharing = supportsScreenSharing() const hasMultipleTiles = tracks.length > 1 + const localCameraTrack = pickLocalCameraTrack(tracks) + const remoteCameraTrack = pickRemoteCameraTrack(tracks) + const mainTrackRef = remoteCameraTrack ?? trackRef + const thumbnailTrackRef = + mainTrackRef && localCameraTrack && localCameraTrack !== mainTrackRef + ? localCameraTrack + : tracks.find((track) => track !== mainTrackRef) if (!trackRef && !hasMultipleTiles) return null @@ -49,11 +71,14 @@ export const PipView = () => { {/* Keep stage height stable to avoid layout shifting on track changes. */} {hasMultipleTiles ? ( - - - - - + <> + {mainTrackRef && } + {thumbnailTrackRef && ( + + + + )} + ) : ( )} @@ -97,14 +122,18 @@ const PipStage = styled('div', { }, }) -const PipGridWrapper = styled('div', { +const PipThumbnail = styled('div', { base: { - position: 'relative', - display: 'flex', - flexDirection: 'column', - alignItems: 'center', - justifyContent: 'center', - width: '100%', - height: '100%', + position: 'absolute', + right: '1rem', + bottom: '1rem', + width: '42%', + maxWidth: '220px', + minWidth: '140px', + aspectRatio: '16 / 9', + borderRadius: 'md', + overflow: 'hidden', + boxShadow: 'md', + zIndex: 2, }, })