From 29fa6ad547e1d46b900693f823099621de499bbf Mon Sep 17 00:00:00 2001 From: isaacclad Date: Sat, 4 Jul 2026 01:14:21 +0000 Subject: [PATCH] Show all joined participants on the audio room stage grid. Include attendees alongside host, co-hosts, and speakers so everyone in the call gets a card with role and muted state, not just speakers. Co-authored-by: Cursor --- resources/css/app.css | 4 ++++ resources/js/meet-room.js | 31 ++++++++++++++++++++++++------- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/resources/css/app.css b/resources/css/app.css index 458734e..dafdcd2 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -403,6 +403,10 @@ html.meet-room-page { box-shadow: 0 0 0 2px rgb(56 189 248 / 0.85); } +.meet-room-page .meet-space-tile--listener [data-tile-avatar-circle] { + opacity: 0.88; +} + .meet-room-page .meet-space-tile [data-tile-name] { width: 100%; padding-inline: 0.125rem; diff --git a/resources/js/meet-room.js b/resources/js/meet-room.js index 356efc5..021e1be 100644 --- a/resources/js/meet-room.js +++ b/resources/js/meet-room.js @@ -997,9 +997,23 @@ function meetRoom() { host: 'Host', co_host: 'Co-host', panelist: 'Speaker', + attendee: 'Attendee', }[role] || ''; }, + spaceStageParticipantsSorted() { + const order = { host: 0, co_host: 1, panelist: 2, attendee: 3, guest: 4, participant: 5 }; + + return [...this.inCallParticipants()].sort((a, b) => { + const roleDiff = (order[a.role] ?? 9) - (order[b.role] ?? 9); + if (roleDiff !== 0) { + return roleDiff; + } + + return a.display_name.localeCompare(b.display_name); + }); + }, + spaceSpeakerTileShellHtml() { return `
@@ -1091,11 +1105,13 @@ function meetRoom() { : Boolean(person.is_muted); if (tile.classList.contains('meet-space-tile')) { + const isListener = person.role === 'attendee'; tile.querySelector('[data-tile-name]').textContent = person.display_name; tile.querySelector('[data-tile-role]').textContent = this.spaceRoleLabel(person.role); - tile.classList.toggle('meet-tile-speaking', speaking); - tile.querySelector('[data-tile-speaking]')?.classList.toggle('hidden', !speaking); - tile.querySelector('[data-tile-mic]')?.classList.toggle('hidden', !muted || speaking); + tile.classList.toggle('meet-tile-speaking', speaking && !isListener); + tile.classList.toggle('meet-space-tile--listener', isListener); + tile.querySelector('[data-tile-speaking]')?.classList.toggle('hidden', !speaking || isListener); + tile.querySelector('[data-tile-mic]')?.classList.toggle('hidden', isListener ? false : (!muted || speaking)); return; } @@ -1116,10 +1132,10 @@ function meetRoom() { return; } - const speakers = this.speakerParticipantsSorted(); - const speakerIds = new Set(speakers.map((person) => person.uuid)); + const people = this.spaceStageParticipantsSorted(); + const peopleIds = new Set(people.map((person) => person.uuid)); - speakers.forEach((person) => { + people.forEach((person) => { const liveParticipant = this.liveKitParticipantForIdentity(person.uuid); const tile = this.ensureParticipantTileShell(person.uuid); @@ -1131,7 +1147,7 @@ function meetRoom() { }); grid.querySelectorAll('[data-participant-tile]').forEach((tile) => { - if (!speakerIds.has(tile.dataset.participantTile)) { + if (!peopleIds.has(tile.dataset.participantTile)) { tile.remove(); } }); @@ -2289,6 +2305,7 @@ function meetRoom() { const count = grid.querySelectorAll('[data-participant-tile]').length; grid.classList.toggle('meet-audio-grid--solo', count === 1); + grid.classList.toggle('meet-space-grid--few', count > 1 && count <= 3); }, updateGalleryGridLayout() {