The phone picker of <x-section-nav> drew the current section as a checked menuitemcheckbox in tertiary-container, which a screen reader announces as a choice rather than where you are, and it dropped the sections' badges, so an open support count showed on the tabs but not on a phone. <x-menu-item> gains current (aria-current="page", the selected shape in secondary-container, the navigation indicator's colour) and badge (a dot or a count at the end of the row), and the picker uses both. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RHoXZSHc8gGpZjFmA5fPc2
87 lines
4.2 KiB
PHP
87 lines
4.2 KiB
PHP
{{-- The navigation inside one area of an app — the sections of settings, of an admin — which is a
|
|
single destination in the app's own navigation.
|
|
|
|
`items`, a list of `['title' => …, 'url' => …]` with an optional `icon`, `active` and `badge`
|
|
(an item is current when `active` is true, or when its `url` is the page's). From `sm` they
|
|
are M3's secondary tabs as links, the current one underlined; below `sm`, where a row of them
|
|
never fits, a button naming the current section opens a menu of all of them, the current one
|
|
marked `aria-current="page"` and each with its badge. The same list is
|
|
rendered for both, and CSS shows one.
|
|
|
|
The page's URL is `Livewire::originalUrl()`: while a Livewire component on the page updates, the
|
|
request is Livewire's update endpoint, and comparing with it left no section lit.
|
|
|
|
A row too long for its column wraps onto a grid rather than scrolling: below `xl` five or six
|
|
sections go 3 + 3 and seven or more go four to a row — tabs that scroll hid the last sections on
|
|
a tablet. `label` names the navigation ("Sections"). Links use `wire:navigate` unless
|
|
`no-wire-navigate`. --}}
|
|
|
|
@props([
|
|
'items' => [],
|
|
'label' => null,
|
|
'noWireNavigate' => false,
|
|
])
|
|
|
|
@php
|
|
$label ??= __('Sections');
|
|
$page = \Livewire\Livewire::originalUrl();
|
|
$isCurrent = fn (array $item): bool => ($item['active'] ?? false) || (filled($item['url'] ?? null) && $page === url($item['url']));
|
|
$current = collect($items)->first($isCurrent) ?? ($items[0] ?? null);
|
|
|
|
$layout = match (true) {
|
|
count($items) < 5 => 'sm:flex',
|
|
count($items) < 7 => 'sm:grid sm:grid-cols-3 xl:flex',
|
|
default => 'sm:grid sm:grid-cols-4 xl:flex',
|
|
};
|
|
@endphp
|
|
|
|
<div {{ $attributes->class(['min-w-0']) }} data-section-nav>
|
|
@if ($current)
|
|
<div class="sm:hidden" data-section-picker>
|
|
<x-livewire-material::menu :$label position="bottom-start">
|
|
<x-slot:trigger>
|
|
<button type="button" class="focus-ring flex h-12 w-[min(20rem,calc(100vw-2rem))] cursor-pointer items-center gap-3 rounded-corner-xs border border-outline px-4 text-start type-body-lg text-on-surface">
|
|
@isset($current['icon'])
|
|
<x-livewire-material::icon :name="$current['icon']" class="size-5 text-on-surface-variant" />
|
|
@endisset
|
|
<span class="min-w-0 flex-1 truncate">{{ $current['title'] }}</span>
|
|
<x-livewire-material::icon name="arrow_drop_down" class="size-6 text-on-surface-variant" />
|
|
</button>
|
|
</x-slot:trigger>
|
|
|
|
@foreach ($items as $item)
|
|
<x-livewire-material::menu-item :label="$item['title']" :icon="$item['icon'] ?? null" :link="$item['url']" :current="$isCurrent($item)" :badge="$item['badge'] ?? null" :no-wire-navigate="$noWireNavigate" />
|
|
@endforeach
|
|
</x-livewire-material::menu>
|
|
</div>
|
|
@endif
|
|
|
|
<nav aria-label="{{ $label }}" class="max-sm:hidden">
|
|
<ul data-tabs-bar data-variant="secondary" class="{{ $layout }}">
|
|
@foreach ($items as $item)
|
|
@php($on = $isCurrent($item))
|
|
|
|
<li class="flex min-w-0">
|
|
<a
|
|
href="{{ $item['url'] }}"
|
|
data-tab
|
|
@if ($on) aria-current="page" @endif
|
|
@unless ($noWireNavigate) wire:navigate @endunless
|
|
>
|
|
<span data-tab-content>
|
|
@isset($item['icon'])
|
|
<x-livewire-material::icon :name="$item['icon']" :filled="$on" class="size-5" />
|
|
@endisset
|
|
<span class="truncate">{{ $item['title'] }}</span>
|
|
@if (filled($item['badge'] ?? null))
|
|
<x-livewire-material::badge :value="$item['badge']" />
|
|
@endif
|
|
<span data-tab-indicator aria-hidden="true"></span>
|
|
</span>
|
|
</a>
|
|
</li>
|
|
@endforeach
|
|
</ul>
|
|
</nav>
|
|
</div>
|