Tighten mobile meet room header and bottom toolbar layout.
Deploy Ladill Meet / deploy (push) Successful in 50s

Show participant count without labels on phones, cap the title at 40% width, and keep four bottom-nav icons by moving React into More only after speak access is granted.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-07-03 15:13:22 +00:00
co-authored by Cursor
parent 9943dc9e44
commit 08a1437b44
3 changed files with 60 additions and 20 deletions
+29 -4
View File
@@ -85,19 +85,44 @@ class ParticipantPresenter
* @param list<array<string, mixed>> $participants
* @param list<string> $presenterRefs
*/
public static function headerCountLabel(array $participants, bool $usesStageLayout, array $presenterRefs = []): string
public static function headerCountNumber(array $participants, bool $usesStageLayout, array $presenterRefs = []): string
{
$joined = array_values(array_filter($participants, fn ($p) => ($p['status'] ?? '') === 'joined'));
if ($usesStageLayout) {
$count = count(array_filter($joined, fn ($p) => self::isSpeakerPerson($p, $presenterRefs)));
} else {
$count = count($joined);
}
return (string) $count;
}
/**
* @param list<array<string, mixed>> $participants
* @param list<string> $presenterRefs
*/
public static function headerCountSuffix(array $participants, bool $usesStageLayout, array $presenterRefs = []): string
{
$joined = array_values(array_filter($participants, fn ($p) => ($p['status'] ?? '') === 'joined'));
if ($usesStageLayout) {
$count = count(array_filter($joined, fn ($p) => self::isSpeakerPerson($p, $presenterRefs)));
return $count === 1 ? '1 speaker' : "{$count} speakers";
return $count === 1 ? ' speaker' : ' speakers';
}
$count = count($joined);
return ' in call';
}
return "{$count} in call";
/**
* @param list<array<string, mixed>> $participants
* @param list<string> $presenterRefs
*/
public static function headerCountLabel(array $participants, bool $usesStageLayout, array $presenterRefs = []): string
{
return self::headerCountNumber($participants, $usesStageLayout, $presenterRefs)
.self::headerCountSuffix($participants, $usesStageLayout, $presenterRefs);
}
/**
+15 -3
View File
@@ -1087,14 +1087,26 @@ function meetRoom() {
return this.inCallParticipants().length;
},
headerParticipantLabel() {
headerParticipantCount() {
if (this.usesStageLayout) {
return String(this.speakerCount());
}
return String(this.participantCount());
},
headerParticipantSuffix() {
if (this.usesStageLayout) {
const count = this.speakerCount();
return count === 1 ? '1 speaker' : `${count} speakers`;
return count === 1 ? ' speaker' : ' speakers';
}
return `${this.participantCount()} in call`;
return ' in call';
},
headerParticipantLabel() {
return this.headerParticipantCount() + this.headerParticipantSuffix();
},
inCallParticipants() {
+16 -13
View File
@@ -34,7 +34,12 @@
$sessionNounTitle = ucfirst($sessionNoun);
$presenterRefsList = (array) ($presenterRefs ?? []);
$headerHostPerson = ParticipantPresenter::headerHost($joinedParticipants->all(), $roomHost);
$headerParticipantLabel = ParticipantPresenter::headerCountLabel(
$headerParticipantCount = ParticipantPresenter::headerCountNumber(
$joinedParticipants->all(),
(bool) ($usesStageLayout ?? false),
$presenterRefsList,
);
$headerParticipantSuffix = ParticipantPresenter::headerCountSuffix(
$joinedParticipants->all(),
(bool) ($usesStageLayout ?? false),
$presenterRefsList,
@@ -140,8 +145,8 @@
<div class="flex h-full min-w-0">
<div class="relative flex min-h-0 min-w-0 flex-1 flex-col">
<header class="flex shrink-0 items-center justify-between bg-slate-950 px-4 py-3">
<div class="min-w-0">
<header class="flex shrink-0 items-center justify-between gap-2 bg-slate-950 px-4 py-3">
<div class="min-w-0 max-w-[40%] sm:max-w-none">
<h1 class="truncate text-sm font-semibold">{{ $room->title }}</h1>
@if ($isAudioOnly ?? false)
<p class="text-[10px] font-medium uppercase tracking-wide text-emerald-400/90">Audio room</p>
@@ -172,9 +177,10 @@
</span>
<span x-show="isLocked" @unless($session->is_locked) style="display: none" @endunless class="rounded bg-amber-600 px-2 py-0.5 font-medium text-white">Locked</span>
<button @click="toggleParticipants()" type="button"
class="relative inline-flex items-center gap-2 rounded-lg bg-slate-900 px-2 py-1 text-xs font-medium text-slate-200 transition-colors hover:bg-slate-800"
class="relative inline-flex items-center gap-1 rounded-lg bg-slate-900 px-2 py-1 text-xs font-medium text-slate-200 transition-colors hover:bg-slate-800 sm:gap-2"
:class="isHost && waitingCount > 0 ? 'ring-2 ring-amber-400/60' : ''"
:title="usesStageLayout ? 'View speakers' : 'View participants'">
:title="usesStageLayout ? 'View speakers' : 'View participants'"
:aria-label="(usesStageLayout ? 'Speakers' : 'Participants') + ': ' + headerParticipantLabel()">
<span x-show="isHost && waitingCount > 0" x-cloak
x-text="waitingCount > 9 ? '9+' : waitingCount"
class="absolute -right-1 -top-1 flex h-4 min-w-4 items-center justify-center rounded-full bg-amber-500 px-1 text-[10px] font-bold text-amber-950"></span>
@@ -190,7 +196,7 @@
@endif
</span>
@endif
<span x-text="headerParticipantLabel()">{{ $headerParticipantLabel }}</span>
<span><span x-text="headerParticipantCount()">{{ $headerParticipantCount }}</span><span class="hidden sm:inline" x-text="headerParticipantSuffix()">{{ $headerParticipantSuffix }}</span></span>
</button>
</div>
</header>
@@ -381,7 +387,7 @@
@include('meet.room.partials.meet-icon', ['icon' => 'applause'])
</button>
<button @click="sendReaction('heart')" type="button"
x-show="showAudienceControls()"
x-show="showAudienceControls() && !(usesSpeakAccess && speakGranted && audioOnlyPublish)"
class="rounded-full bg-slate-700 p-3 hover:bg-slate-600"
title="React">
@include('meet.room.partials.meet-icon', ['icon' => 'react'])
@@ -773,14 +779,11 @@
<div class="flex min-h-0 flex-1 flex-col overflow-y-auto">
<div class="space-y-1">
<div class="space-y-1 sm:hidden" x-show="showAudienceControls()">
<x-meet.room.menu-item icon="raise-hand" title="Raise hand" subtitle="Let the host know you have a question"
@click="raiseHand(); closeSidebar()" />
<x-meet.room.menu-item icon="applause" title="Applause" subtitle="Send applause — sound plays when others join in"
@click="sendReaction('thumbs'); closeSidebar()" />
<x-meet.room.menu-item icon="react" title="React" subtitle="Send a heart to the room"
@click="sendReaction('heart'); closeSidebar()" />
<x-meet.room.menu-item icon="chat" title="Chat" subtitle="Open the {{ $sessionNoun }} chat"
@click="toggleChat()" />
<x-meet.room.menu-item icon="react" title="React" subtitle="Send a heart to the room"
x-show="usesSpeakAccess && speakGranted && audioOnlyPublish"
@click="sendReaction('heart'); closeSidebar()" />
<div class="my-1 border-t border-slate-800"></div>
</div>
<div class="space-y-1" x-show="usesSpeakAccess && !speakGranted && !speakRequested && showAudienceControls()">