Fix participant card layout and add meeting video pop-out.
Deploy Ladill Meet / deploy (push) Successful in 56s

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-07-11 16:41:43 +00:00
co-authored by Cursor
parent 86d5b43607
commit aa16b31fe1
3 changed files with 166 additions and 12 deletions
+108 -3
View File
@@ -177,6 +177,8 @@ function meetRoom() {
activeSpeakerIds: [],
floatingReactions: [],
reactionsInitialized: false,
pictureInPictureActive: false,
pictureInPictureSupported: false,
pollTimer: null,
config: {},
@@ -313,6 +315,8 @@ function meetRoom() {
this.syncToolbarConditionalVisibility();
document.querySelector('.meet-toolbar__track')?.classList.add('is-ready');
});
this.setupPictureInPicture();
},
connectionErrorMessage(error) {
@@ -1054,8 +1058,8 @@ function meetRoom() {
participantTileShellHtml() {
return `
<div data-tile-body class="relative min-h-0 flex-1">
<div data-tile-stage class="absolute inset-0 flex items-center justify-center"></div>
<div data-tile-body class="relative min-h-0 flex-1 overflow-hidden">
<div data-tile-stage class="absolute inset-0 overflow-hidden"></div>
<div data-tile-avatar class="absolute inset-0 flex items-center justify-center">
<div data-tile-avatar-circle class="flex h-20 w-20 shrink-0 items-center justify-center rounded-full text-2xl font-semibold text-white shadow-lg"></div>
</div>
@@ -1682,7 +1686,7 @@ function meetRoom() {
stage.innerHTML = '';
const el = track.attach();
el.className = 'h-full w-full object-cover';
el.className = 'meet-tile-video';
el.dataset.participant = participant.identity;
stage.appendChild(el);
},
@@ -2488,6 +2492,107 @@ function meetRoom() {
}
},
setupPictureInPicture() {
this.pictureInPictureSupported = typeof document !== 'undefined'
&& 'pictureInPictureEnabled' in document
&& document.pictureInPictureEnabled !== false;
if (!this.pictureInPictureSupported) {
return;
}
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
this.maybeAutoEnterPictureInPicture();
}
});
document.addEventListener('leavepictureinpicture', () => {
this.pictureInPictureActive = false;
});
},
showPictureInPictureControl() {
return this.pictureInPictureSupported && !this.audioOnly;
},
findPictureInPictureVideo() {
if (this.isScreenSharing) {
const screenVideo = document.querySelector('#screen-share video');
if (screenVideo) {
return screenVideo;
}
}
const localId = this.config.participantUuid;
const priorities = [];
if (room?.localParticipant?.isCameraEnabled) {
priorities.push(localId);
}
this.activeSpeakerIds.forEach((id) => {
if (!priorities.includes(id)) {
priorities.push(id);
}
});
for (const id of priorities) {
const video = this.findParticipantTile(id)?.querySelector('[data-tile-stage] video');
if (video) {
return video;
}
}
return document.querySelector('[data-participant-tile] [data-tile-stage] video');
},
async maybeAutoEnterPictureInPicture() {
if (!this.pictureInPictureSupported || this.pictureInPictureActive || this.audioOnly) {
return;
}
if (document.pictureInPictureElement) {
return;
}
await this.enterPictureInPicture({ silent: true });
},
async togglePictureInPicture() {
if (!this.pictureInPictureSupported) {
return;
}
if (document.pictureInPictureElement) {
await document.exitPictureInPicture();
this.pictureInPictureActive = false;
return;
}
await this.enterPictureInPicture();
},
async enterPictureInPicture({ silent = false } = {}) {
const video = this.findPictureInPictureVideo();
if (!video) {
if (!silent) {
this.connectionStatus = 'No video available to pop out';
}
return;
}
try {
await video.requestPictureInPicture();
this.pictureInPictureActive = true;
} catch {
if (!silent) {
this.connectionStatus = 'Pop-out blocked — try again from the toolbar';
}
}
},
async raiseHand() {
await fetch(this.config.raiseHandUrl, {
method: 'POST',