Fix spotlight tile reattach and mobile meeting toolbar layout.
Deploy Ladill Meet / deploy (push) Successful in 1m5s
Deploy Ladill Meet / deploy (push) Successful in 1m5s
Recreate spotlight tiles with video on switch, limit regular meetings to four primary controls before More, and align mobile notification badge with desktop.
This commit is contained in:
+53
-13
@@ -979,23 +979,30 @@ function meetRoom() {
|
||||
if (room) {
|
||||
const all = [room.localParticipant, ...room.remoteParticipants.values()];
|
||||
all.forEach((participant) => {
|
||||
const tile = this.findParticipantTile(participant.identity);
|
||||
if (!tile) return;
|
||||
|
||||
const target = this.getTileContainerForIdentity(participant.identity);
|
||||
if (target) {
|
||||
if (tile.parentElement !== target) {
|
||||
target.appendChild(tile);
|
||||
}
|
||||
if (!target) {
|
||||
this.removeParticipantTile(participant.identity);
|
||||
return;
|
||||
}
|
||||
|
||||
const isSpotlightTile = target === spotlight;
|
||||
const existingTile = this.findParticipantTile(participant.identity);
|
||||
const previousParent = existingTile?.parentElement ?? null;
|
||||
const tile = this.getOrCreateParticipantTile(participant);
|
||||
if (!tile) {
|
||||
return;
|
||||
}
|
||||
|
||||
tile.classList.toggle('meet-stage-spotlight-tile', isSpotlightTile);
|
||||
tile.classList.toggle('meet-stage-panel-tile', target === grid && this.stageLayout === 'panel');
|
||||
tile.classList.toggle('aspect-video', !isSpotlightTile && !this.audioOnly);
|
||||
tile.classList.toggle('rounded-xl', !isSpotlightTile && !this.audioOnly);
|
||||
const isSpotlightTile = target === spotlight;
|
||||
|
||||
tile.classList.toggle('meet-stage-spotlight-tile', isSpotlightTile);
|
||||
tile.classList.toggle('meet-stage-panel-tile', target === grid && this.stageLayout === 'panel');
|
||||
tile.classList.toggle('aspect-video', !isSpotlightTile && !this.audioOnly);
|
||||
tile.classList.toggle('rounded-xl', !isSpotlightTile && !this.audioOnly);
|
||||
|
||||
if (!existingTile || previousParent !== target) {
|
||||
this.reattachParticipantVideo(participant);
|
||||
} else {
|
||||
tile.remove();
|
||||
this.updateParticipantTile(participant);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1353,6 +1360,14 @@ function meetRoom() {
|
||||
|
||||
if (hasVideo) {
|
||||
avatar.classList.add('hidden');
|
||||
if (!stage.querySelector('video')) {
|
||||
const publication = Array.from(participant.videoTrackPublications.values())
|
||||
.find((pub) => pub.source !== Track.Source.ScreenShare && pub.track && !pub.isMuted);
|
||||
if (publication?.track) {
|
||||
this.attachVideoToTile(participant, publication.track);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1379,6 +1394,22 @@ function meetRoom() {
|
||||
stage.appendChild(el);
|
||||
},
|
||||
|
||||
reattachParticipantVideo(participant) {
|
||||
if (this.audioOnly || !participant) {
|
||||
return;
|
||||
}
|
||||
|
||||
const publication = Array.from(participant.videoTrackPublications.values())
|
||||
.find((pub) => pub.source !== Track.Source.ScreenShare && pub.track && !pub.isMuted);
|
||||
|
||||
if (publication?.track) {
|
||||
this.attachVideoToTile(participant, publication.track);
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateParticipantTile(participant);
|
||||
},
|
||||
|
||||
setupCaptionPipeline() {
|
||||
if (!this.liveCaptions || !this.config.captionUrl) return;
|
||||
if (room?.localParticipant?.isMicrophoneEnabled) return;
|
||||
@@ -2019,6 +2050,15 @@ function meetRoom() {
|
||||
return !this.canPublish || this.audioOnlyPublish;
|
||||
},
|
||||
|
||||
/** Mobile primary toolbar — webinars/conferences only; meetings use More for extras. */
|
||||
showPrimaryToolbarAudienceControls() {
|
||||
if (!this.usesSpeakAccess) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.showAudienceControls();
|
||||
},
|
||||
|
||||
showStagePublisherControls() {
|
||||
return this.usesSpeakAccess && this.canPublish && !this.audioOnlyPublish;
|
||||
},
|
||||
|
||||
@@ -375,19 +375,19 @@
|
||||
@include('meet.room.partials.meet-icon', ['icon' => 'screen-share'])
|
||||
</button>
|
||||
<button @click="raiseHand()" type="button"
|
||||
x-show="showAudienceControls()"
|
||||
x-show="showPrimaryToolbarAudienceControls()"
|
||||
class="rounded-full bg-slate-700 p-3 hover:bg-slate-600"
|
||||
title="Raise hand">
|
||||
@include('meet.room.partials.meet-icon', ['icon' => 'raise-hand'])
|
||||
</button>
|
||||
<button @click="sendReaction('thumbs')" type="button"
|
||||
x-show="showAudienceControls()"
|
||||
x-show="showPrimaryToolbarAudienceControls()"
|
||||
class="rounded-full bg-slate-700 p-3 hover:bg-slate-600"
|
||||
title="Applause — sound plays when others join in">
|
||||
@include('meet.room.partials.meet-icon', ['icon' => 'applause'])
|
||||
</button>
|
||||
<button @click="sendReaction('heart')" type="button"
|
||||
x-show="showAudienceControls() && !(usesSpeakAccess && speakGranted && audioOnlyPublish)"
|
||||
x-show="showPrimaryToolbarAudienceControls() && !(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'])
|
||||
@@ -800,8 +800,14 @@
|
||||
<div class="space-y-1 sm:hidden" x-show="showAudienceControls()">
|
||||
<x-meet.room.menu-item icon="chat" title="Chat" subtitle="Open the {{ $sessionNoun }} chat"
|
||||
@click="toggleChat()" />
|
||||
<x-meet.room.menu-item icon="raise-hand" title="Raise hand" subtitle="Signal that you have something to share"
|
||||
x-show="!usesSpeakAccess"
|
||||
@click="raiseHand(); closeSidebar()" />
|
||||
<x-meet.room.menu-item icon="applause" title="Applause" subtitle="Send applause — sound plays when others join in"
|
||||
x-show="!usesSpeakAccess"
|
||||
@click="sendReaction('thumbs'); closeSidebar()" />
|
||||
<x-meet.room.menu-item icon="react" title="React" subtitle="Send a heart to the room"
|
||||
x-show="usesSpeakAccess && speakGranted && audioOnlyPublish"
|
||||
x-show="!usesSpeakAccess || (usesSpeakAccess && speakGranted && audioOnlyPublish)"
|
||||
@click="sendReaction('heart'); closeSidebar()" />
|
||||
<div class="my-1 border-t border-slate-800"></div>
|
||||
</div>
|
||||
|
||||
@@ -57,12 +57,14 @@
|
||||
},
|
||||
}"
|
||||
@endif
|
||||
class="relative flex flex-col items-center justify-center gap-1 px-2 py-2 transition hover:text-slate-900 {{ $navActive($notificationsActive ?? false) }}">
|
||||
<svg class="h-6 w-6" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M14.857 17.082a23.848 23.848 0 0 0 5.454-1.31A8.967 8.967 0 0 1 18 9.75V9a6 6 0 1 0-12 0v.75a8.967 8.967 0 0 1-2.312 6.022c1.733.64 3.56 1.08 5.455 1.31m5.714 0a24.255 24.255 0 0 1-5.714 0m5.714 0a3 3 0 1 1-5.714 0"/></svg>
|
||||
@if ($unreadUrl)
|
||||
<span x-show="unread > 0" x-cloak x-text="unread > 9 ? '9+' : unread"
|
||||
class="absolute right-3 top-1.5 inline-flex min-w-4 items-center justify-center rounded-full bg-rose-500 px-1 py-0.5 text-[9px] font-semibold text-white"></span>
|
||||
@endif
|
||||
class="flex flex-col items-center justify-center gap-1 px-2 py-2 transition hover:text-slate-900 {{ $navActive($notificationsActive ?? false) }}">
|
||||
<span class="relative inline-flex shrink-0">
|
||||
<svg class="h-6 w-6" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M14.857 17.082a23.848 23.848 0 0 0 5.454-1.31A8.967 8.967 0 0 1 18 9.75V9a6 6 0 1 0-12 0v.75a8.967 8.967 0 0 1-2.312 6.022c1.733.64 3.56 1.08 5.455 1.31m5.714 0a24.255 24.255 0 0 1-5.714 0m5.714 0a3 3 0 1 1-5.714 0"/></svg>
|
||||
@if ($unreadUrl)
|
||||
<span x-show="unread > 0" x-cloak x-text="unread > 9 ? '9+' : unread"
|
||||
class="absolute -right-1 -top-1 inline-flex min-w-5 items-center justify-center rounded-full bg-rose-500 px-1.5 py-0.5 text-[10px] font-semibold text-white"></span>
|
||||
@endif
|
||||
</span>
|
||||
<span class="text-[10px] font-medium">Notifications</span>
|
||||
</a>
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
$mobileClass = match ($variant) {
|
||||
'primary' => 'btn-fab h-10 w-10 lg:hidden',
|
||||
'outline' => 'inline-flex h-10 w-10 items-center justify-center rounded-full border border-slate-200 bg-white text-slate-700 shadow-sm transition hover:border-slate-300 hover:bg-slate-50 lg:hidden',
|
||||
'dark' => 'inline-flex h-10 w-10 items-center justify-center rounded-full bg-gray-900 text-white shadow-sm transition hover:bg-gray-800 lg:hidden',
|
||||
'indigo' => 'inline-flex h-10 w-10 items-center justify-center rounded-full bg-indigo-600 text-white shadow-sm transition hover:bg-indigo-700 lg:hidden',
|
||||
default => 'btn-fab h-10 w-10 lg:hidden',
|
||||
};
|
||||
@@ -16,6 +17,7 @@
|
||||
$desktopClass = match ($variant) {
|
||||
'primary' => 'btn-primary hidden items-center lg:inline-flex',
|
||||
'outline' => 'hidden items-center rounded-lg border border-gray-200 bg-white px-4 py-2 text-sm font-medium text-gray-700 shadow-sm transition hover:bg-gray-50 lg:inline-flex',
|
||||
'dark' => 'hidden items-center gap-1.5 rounded-lg bg-gray-900 px-3.5 py-2 text-sm font-medium text-white transition hover:bg-gray-800 lg:inline-flex',
|
||||
'indigo' => 'hidden items-center justify-center rounded-xl bg-indigo-600 px-4 py-2.5 text-sm font-semibold text-white transition hover:bg-indigo-700 lg:inline-flex',
|
||||
default => 'btn-primary hidden items-center lg:inline-flex',
|
||||
};
|
||||
|
||||
@@ -2,14 +2,20 @@
|
||||
$icon = $icon ?? 'arrow';
|
||||
$desktopClass = $desktopClass ?? 'text-xs font-medium text-indigo-600 hover:text-indigo-700';
|
||||
$label = $label ?? '';
|
||||
$extraAttributes = $attributes ?? '';
|
||||
@endphp
|
||||
|
||||
<a href="{{ $href }}"
|
||||
aria-label="{{ $label }}"
|
||||
title="{{ $label }}"
|
||||
@if ($extraAttributes !== '') {!! $extraAttributes !!} @endif
|
||||
class="inline-flex h-9 w-9 items-center justify-center rounded-full bg-indigo-50 text-indigo-600 ring-1 ring-indigo-100 transition hover:bg-indigo-100 lg:h-auto lg:w-auto lg:rounded-none lg:bg-transparent lg:ring-0 lg:hover:bg-transparent">
|
||||
<span class="lg:hidden">
|
||||
@if ($icon === 'shield')
|
||||
@if ($icon === 'plus')
|
||||
<svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15"/>
|
||||
</svg>
|
||||
@elseif ($icon === 'shield')
|
||||
<svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75 11.25 15 15 9.75m-3-7.036A11.959 11.959 0 0 1 3.598 6 11.99 11.99 0 0 0 3 9.749c0 5.592 3.824 10.29 9 11.623 5.176-1.332 9-6.03 9-11.622 0-1.31-.21-2.571-.598-3.751h-.152c-3.196 0-6.1-1.248-8.25-3.285Z"/>
|
||||
</svg>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@php
|
||||
$title = $heading ?? $mobileTopbarTitle ?? 'Ladill Meet';
|
||||
$title = $mobileTopbarTitle ?? 'Ladill';
|
||||
@endphp
|
||||
<div class="min-w-0 flex-1 lg:hidden">
|
||||
<h1 class="truncate text-base font-semibold text-slate-900">{{ $title }}</h1>
|
||||
|
||||
Reference in New Issue
Block a user