Plan step 15. Every `sm:`/`md:`/`lg:`/`xl:` in the components, the showcase (sections, layout, shell) and the pagination and error views becomes the M3 window size class the audits' breakpoint maps prescribe: the full-screen dialog, the FAB, the snackbar's width, `radio inline`, the section picker and the page numbers move from 640px to `medium` (600px, M3's compact boundary, N-07 / C-07 / IN-28); `button responsive` moves from 1024px to `expanded` (840px); `section-nav`'s grid-to-row switch from 1280px to `large` (1200px, N-07); and `drawer pane` from 1280px to `expanded`, where M3 shows two panes for list-detail (C-07). The pane's default width is now 360dp, M3's fixed supporting pane at expanded. Showcase example grids take two columns from `medium` and three or more from `expanded`; the showcase's own theme picker swaps at `expanded`, the nearest class boundary to the 768px it used (no M3 rule applies to it). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
90 lines
4.3 KiB
PHP
90 lines
4.3 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 `medium`
|
|
(600px) they
|
|
are M3's secondary tabs as links, the current one underlined; on a compact window, 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 `large` (1200px)
|
|
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 => 'medium:flex',
|
|
count($items) < 7 => 'medium:grid medium:grid-cols-3 large:flex',
|
|
default => 'medium:grid medium:grid-cols-4 large:flex',
|
|
};
|
|
@endphp
|
|
|
|
<div {{ $attributes->class(['min-w-0']) }} data-section-nav>
|
|
@if ($current)
|
|
<div class="medium: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-medium: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>
|