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.
133 lines
8.0 KiB
PHP
133 lines
8.0 KiB
PHP
@php
|
|
$showSearch = isset($searchUrl) && $searchUrl !== null && $searchUrl !== '#';
|
|
$gridCols = match (true) {
|
|
! empty($centerCompose) => $showSearch ? 'grid-cols-5' : 'grid-cols-4',
|
|
default => $showSearch ? 'grid-cols-4' : 'grid-cols-3',
|
|
};
|
|
$avatarUrl = $avatarUrl ?? null;
|
|
$initials = $initials ?? 'U';
|
|
$notificationsUrl = $notificationsUrl ?? '#';
|
|
$unreadUrl = $unreadUrl ?? null;
|
|
$profileUrl = $profileUrl ?? '#';
|
|
$profileName = trim((string) ($profileName ?? ''));
|
|
$profileSubtitle = trim((string) ($profileSubtitle ?? ''));
|
|
$profileMenuItems = $profileMenuItems ?? [];
|
|
if ($profileMenuItems === [] && $profileUrl !== '#') {
|
|
$profileMenuItems = [['type' => 'link', 'label' => 'Profile', 'href' => $profileUrl]];
|
|
}
|
|
$navActive = fn (bool $active) => $active ? 'text-indigo-600' : 'text-slate-600';
|
|
@endphp
|
|
<div x-data="{ profileOpen: false }" class="lg:hidden">
|
|
<nav class="fixed inset-x-0 bottom-0 z-40 border-t border-slate-200 bg-white"
|
|
style="padding-bottom: env(safe-area-inset-bottom, 0px)">
|
|
<div class="grid h-16 {{ $gridCols }}">
|
|
<a href="{{ $homeUrl }}"
|
|
class="flex flex-col items-center justify-center gap-1 px-2 py-2 transition hover:text-slate-900 {{ $navActive($homeActive ?? 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="m2.25 12 8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25"/></svg>
|
|
<span class="text-[10px] font-medium">Home</span>
|
|
</a>
|
|
|
|
@if ($showSearch)
|
|
<a href="{{ $searchUrl }}"
|
|
class="flex flex-col items-center justify-center gap-1 px-2 py-2 transition hover:text-slate-900 {{ $navActive($searchActive ?? 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="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z"/></svg>
|
|
<span class="text-[10px] font-medium">Search</span>
|
|
</a>
|
|
@endif
|
|
|
|
@if (!empty($centerCompose))
|
|
<div class="flex items-center justify-center">
|
|
<button type="button"
|
|
@click="$dispatch('compose-open')"
|
|
class="btn-fab -translate-y-1 ring-4 ring-white shadow-md"
|
|
aria-label="Compose">
|
|
<svg class="h-5 w-5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Z"/></svg>
|
|
</button>
|
|
</div>
|
|
@endif
|
|
|
|
<a href="{{ $notificationsUrl }}"
|
|
@if ($unreadUrl)
|
|
x-data="{
|
|
unread: 0,
|
|
init() {
|
|
fetch({{ \Illuminate\Support\Js::from($unreadUrl) }}, {
|
|
headers: { Accept: 'application/json', 'X-Requested-With': 'XMLHttpRequest' },
|
|
}).then(r => r.json()).then(d => this.unread = d.unread_count || 0).catch(() => {});
|
|
},
|
|
}"
|
|
@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>
|
|
|
|
<button type="button"
|
|
@click="profileOpen = true"
|
|
class="flex flex-col items-center justify-center gap-1 px-2 py-2 transition hover:text-slate-900 {{ $navActive($profileActive ?? false) }}"
|
|
:class="profileOpen ? 'text-indigo-600' : ''"
|
|
aria-label="Open profile menu">
|
|
@if ($avatarUrl)
|
|
<img src="{{ $avatarUrl }}" alt="" class="h-7 w-7 rounded-full object-cover ring-1 ring-slate-200">
|
|
@else
|
|
<span class="inline-flex h-7 w-7 items-center justify-center rounded-full bg-slate-900 text-[10px] font-semibold text-white">{{ $initials }}</span>
|
|
@endif
|
|
<span class="text-[10px] font-medium">Profile</span>
|
|
</button>
|
|
</div>
|
|
</nav>
|
|
|
|
{{-- Profile menu bottom sheet (matches desktop avatar dropdown) --}}
|
|
<div x-show="profileOpen" x-cloak class="fixed inset-0 z-50" @keydown.escape.window="profileOpen = false">
|
|
<div x-show="profileOpen" x-transition.opacity.duration.200ms
|
|
@click="profileOpen = false"
|
|
class="absolute inset-0 bg-slate-900/40 backdrop-blur-[1px]"></div>
|
|
|
|
<div x-show="profileOpen"
|
|
x-effect="profileOpen && window.dispatchEvent(new CustomEvent('wallet-balance-refresh'))"
|
|
x-transition:enter="transition ease-out duration-300"
|
|
x-transition:enter-start="translate-y-full"
|
|
x-transition:enter-end="translate-y-0"
|
|
x-transition:leave="transition ease-in duration-200"
|
|
x-transition:leave-start="translate-y-0"
|
|
x-transition:leave-end="translate-y-full"
|
|
class="absolute inset-x-0 bottom-0 rounded-t-2xl border-t border-slate-200 bg-white shadow-2xl"
|
|
style="padding-bottom: env(safe-area-inset-bottom, 0px)"
|
|
@click.outside="profileOpen = false">
|
|
<div class="flex justify-center pt-3">
|
|
<span class="h-1 w-10 rounded-full bg-slate-200" aria-hidden="true"></span>
|
|
</div>
|
|
|
|
@if ($profileName !== '' || $profileSubtitle !== '')
|
|
<div class="flex items-center gap-3 border-b border-slate-100 px-5 py-4">
|
|
@if ($avatarUrl)
|
|
<img src="{{ $avatarUrl }}" alt="" class="h-12 w-12 rounded-full object-cover ring-1 ring-slate-200">
|
|
@else
|
|
<span class="inline-flex h-12 w-12 items-center justify-center rounded-full bg-slate-900 text-sm font-semibold text-white">{{ $initials }}</span>
|
|
@endif
|
|
<div class="min-w-0">
|
|
@if ($profileName !== '')
|
|
<p class="truncate text-sm font-semibold text-slate-900">{{ $profileName }}</p>
|
|
@endif
|
|
@if ($profileSubtitle !== '')
|
|
<p class="truncate text-xs text-slate-500">{{ $profileSubtitle }}</p>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
@include('partials.user-profile-menu', [
|
|
'items' => $profileMenuItems,
|
|
'variant' => 'sheet',
|
|
'onNavigate' => 'profileOpen = false',
|
|
])
|
|
</div>
|
|
</div>
|
|
</div>
|