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:
@@ -979,13 +979,17 @@ function meetRoom() {
|
|||||||
if (room) {
|
if (room) {
|
||||||
const all = [room.localParticipant, ...room.remoteParticipants.values()];
|
const all = [room.localParticipant, ...room.remoteParticipants.values()];
|
||||||
all.forEach((participant) => {
|
all.forEach((participant) => {
|
||||||
const tile = this.findParticipantTile(participant.identity);
|
|
||||||
if (!tile) return;
|
|
||||||
|
|
||||||
const target = this.getTileContainerForIdentity(participant.identity);
|
const target = this.getTileContainerForIdentity(participant.identity);
|
||||||
if (target) {
|
if (!target) {
|
||||||
if (tile.parentElement !== target) {
|
this.removeParticipantTile(participant.identity);
|
||||||
target.appendChild(tile);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const existingTile = this.findParticipantTile(participant.identity);
|
||||||
|
const previousParent = existingTile?.parentElement ?? null;
|
||||||
|
const tile = this.getOrCreateParticipantTile(participant);
|
||||||
|
if (!tile) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isSpotlightTile = target === spotlight;
|
const isSpotlightTile = target === spotlight;
|
||||||
@@ -994,8 +998,11 @@ function meetRoom() {
|
|||||||
tile.classList.toggle('meet-stage-panel-tile', target === grid && this.stageLayout === 'panel');
|
tile.classList.toggle('meet-stage-panel-tile', target === grid && this.stageLayout === 'panel');
|
||||||
tile.classList.toggle('aspect-video', !isSpotlightTile && !this.audioOnly);
|
tile.classList.toggle('aspect-video', !isSpotlightTile && !this.audioOnly);
|
||||||
tile.classList.toggle('rounded-xl', !isSpotlightTile && !this.audioOnly);
|
tile.classList.toggle('rounded-xl', !isSpotlightTile && !this.audioOnly);
|
||||||
|
|
||||||
|
if (!existingTile || previousParent !== target) {
|
||||||
|
this.reattachParticipantVideo(participant);
|
||||||
} else {
|
} else {
|
||||||
tile.remove();
|
this.updateParticipantTile(participant);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1353,6 +1360,14 @@ function meetRoom() {
|
|||||||
|
|
||||||
if (hasVideo) {
|
if (hasVideo) {
|
||||||
avatar.classList.add('hidden');
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1379,6 +1394,22 @@ function meetRoom() {
|
|||||||
stage.appendChild(el);
|
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() {
|
setupCaptionPipeline() {
|
||||||
if (!this.liveCaptions || !this.config.captionUrl) return;
|
if (!this.liveCaptions || !this.config.captionUrl) return;
|
||||||
if (room?.localParticipant?.isMicrophoneEnabled) return;
|
if (room?.localParticipant?.isMicrophoneEnabled) return;
|
||||||
@@ -2019,6 +2050,15 @@ function meetRoom() {
|
|||||||
return !this.canPublish || this.audioOnlyPublish;
|
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() {
|
showStagePublisherControls() {
|
||||||
return this.usesSpeakAccess && this.canPublish && !this.audioOnlyPublish;
|
return this.usesSpeakAccess && this.canPublish && !this.audioOnlyPublish;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -375,19 +375,19 @@
|
|||||||
@include('meet.room.partials.meet-icon', ['icon' => 'screen-share'])
|
@include('meet.room.partials.meet-icon', ['icon' => 'screen-share'])
|
||||||
</button>
|
</button>
|
||||||
<button @click="raiseHand()" type="button"
|
<button @click="raiseHand()" type="button"
|
||||||
x-show="showAudienceControls()"
|
x-show="showPrimaryToolbarAudienceControls()"
|
||||||
class="rounded-full bg-slate-700 p-3 hover:bg-slate-600"
|
class="rounded-full bg-slate-700 p-3 hover:bg-slate-600"
|
||||||
title="Raise hand">
|
title="Raise hand">
|
||||||
@include('meet.room.partials.meet-icon', ['icon' => 'raise-hand'])
|
@include('meet.room.partials.meet-icon', ['icon' => 'raise-hand'])
|
||||||
</button>
|
</button>
|
||||||
<button @click="sendReaction('thumbs')" type="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"
|
class="rounded-full bg-slate-700 p-3 hover:bg-slate-600"
|
||||||
title="Applause — sound plays when others join in">
|
title="Applause — sound plays when others join in">
|
||||||
@include('meet.room.partials.meet-icon', ['icon' => 'applause'])
|
@include('meet.room.partials.meet-icon', ['icon' => 'applause'])
|
||||||
</button>
|
</button>
|
||||||
<button @click="sendReaction('heart')" type="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"
|
class="rounded-full bg-slate-700 p-3 hover:bg-slate-600"
|
||||||
title="React">
|
title="React">
|
||||||
@include('meet.room.partials.meet-icon', ['icon' => 'react'])
|
@include('meet.room.partials.meet-icon', ['icon' => 'react'])
|
||||||
@@ -800,8 +800,14 @@
|
|||||||
<div class="space-y-1 sm:hidden" x-show="showAudienceControls()">
|
<div class="space-y-1 sm:hidden" x-show="showAudienceControls()">
|
||||||
<x-meet.room.menu-item icon="chat" title="Chat" subtitle="Open the {{ $sessionNoun }} chat"
|
<x-meet.room.menu-item icon="chat" title="Chat" subtitle="Open the {{ $sessionNoun }} chat"
|
||||||
@click="toggleChat()" />
|
@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-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()" />
|
@click="sendReaction('heart'); closeSidebar()" />
|
||||||
<div class="my-1 border-t border-slate-800"></div>
|
<div class="my-1 border-t border-slate-800"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -57,12 +57,14 @@
|
|||||||
},
|
},
|
||||||
}"
|
}"
|
||||||
@endif
|
@endif
|
||||||
class="relative flex flex-col items-center justify-center gap-1 px-2 py-2 transition hover:text-slate-900 {{ $navActive($notificationsActive ?? false) }}">
|
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>
|
<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)
|
@if ($unreadUrl)
|
||||||
<span x-show="unread > 0" x-cloak x-text="unread > 9 ? '9+' : unread"
|
<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>
|
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
|
@endif
|
||||||
|
</span>
|
||||||
<span class="text-[10px] font-medium">Notifications</span>
|
<span class="text-[10px] font-medium">Notifications</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
$mobileClass = match ($variant) {
|
$mobileClass = match ($variant) {
|
||||||
'primary' => 'btn-fab h-10 w-10 lg:hidden',
|
'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',
|
'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',
|
'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',
|
default => 'btn-fab h-10 w-10 lg:hidden',
|
||||||
};
|
};
|
||||||
@@ -16,6 +17,7 @@
|
|||||||
$desktopClass = match ($variant) {
|
$desktopClass = match ($variant) {
|
||||||
'primary' => 'btn-primary hidden items-center lg:inline-flex',
|
'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',
|
'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',
|
'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',
|
default => 'btn-primary hidden items-center lg:inline-flex',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,14 +2,20 @@
|
|||||||
$icon = $icon ?? 'arrow';
|
$icon = $icon ?? 'arrow';
|
||||||
$desktopClass = $desktopClass ?? 'text-xs font-medium text-indigo-600 hover:text-indigo-700';
|
$desktopClass = $desktopClass ?? 'text-xs font-medium text-indigo-600 hover:text-indigo-700';
|
||||||
$label = $label ?? '';
|
$label = $label ?? '';
|
||||||
|
$extraAttributes = $attributes ?? '';
|
||||||
@endphp
|
@endphp
|
||||||
|
|
||||||
<a href="{{ $href }}"
|
<a href="{{ $href }}"
|
||||||
aria-label="{{ $label }}"
|
aria-label="{{ $label }}"
|
||||||
title="{{ $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">
|
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">
|
<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">
|
<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"/>
|
<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>
|
</svg>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@php
|
@php
|
||||||
$title = $heading ?? $mobileTopbarTitle ?? 'Ladill Meet';
|
$title = $mobileTopbarTitle ?? 'Ladill';
|
||||||
@endphp
|
@endphp
|
||||||
<div class="min-w-0 flex-1 lg:hidden">
|
<div class="min-w-0 flex-1 lg:hidden">
|
||||||
<h1 class="truncate text-base font-semibold text-slate-900">{{ $title }}</h1>
|
<h1 class="truncate text-base font-semibold text-slate-900">{{ $title }}</h1>
|
||||||
|
|||||||
Reference in New Issue
Block a user