{{-- The adaptive app shell: navigation that changes shape with the window, around the page. SealShare …the page's app bar… …the page… - Below `sm`: a navigation bar with the destinations marked `bar`, pinned to the bottom. Everything else is in the modal rail, which slides in when something calls `$store.rail.show()` — put a menu button in the app bar for it, hidden from `sm`: ``. - `sm` to `lg`: the collapsed rail, whose menu button opens it expanded, as a modal. - From `lg`: the expanded rail, collapsed and expanded again by its menu button; the choice is remembered and applied before the first paint (`$store.rail`, ). `destinations` is a list of arrays: `title`, `icon` (a Material Symbol), `url`, and optionally `active` (by default: the URL is the current one), `badge` (`true` for a dot, or a count), `section` (a heading the destination is grouped under in the rail; only an expanded rail shows it), `bar` (`false` keeps it out of the bottom bar; M3 wants three to five there) and `navigate` (`false` for a full page load instead of `wire:navigate`). Slots, each rendered once: `brand` (beside the rail's menu button while it is expanded), `rail-header` (under it: a FAB — see `` for its two shapes), `rail-footer` (at the foot of the rail: footer destinations, an account), `actions` (a row of icon buttons at the very foot, stacked when the rail is collapsed: a theme toggle, sign out), `top` (the app bar, above the page at every width) and the page itself. The rail is one element at every width, so what is in it is also in the modal rail a phone opens. `label` names both navigation landmarks ("Main"); `rail-width` is the expanded rail's width. The page is `
` with `wire:transition.navigate`, behind a skip link that is the first thing a keyboard reaches. The snackbar host (``) is part of the shell; below `sm` it, and a `fab` button, sit above the bottom bar through `--material-bottom-bar`: the bar's 64px, the bottom safe area (`--material-safe-bottom`, else the device's inset) and `--material-bottom-extra` (0px unless the application docks something, an offline banner, on top of the bar). `max-lg:overflow-x-clip` on the content region is the backstop under every page, and it stays `clip`: `overflow-x: hidden` would force `overflow-y` to `auto`, turn the region into a scroll container and break every `position: sticky` inside it (an app bar, a list-detail pane). Below `lg` only, so a wide window never clips what overhangs on purpose. Nothing application-specific belongs in here: an app's destinations and chrome come in through the props and slots. --}} @props([ 'destinations' => [], 'label' => null, 'railWidth' => '16rem', ]) @php $label ??= __('Main'); $current = request()->url(); $items = collect($destinations) ->filter(fn ($item): bool => is_array($item) && filled($item['title'] ?? null)) ->map(fn (array $item): array => [ 'title' => (string) $item['title'], 'icon' => $item['icon'] ?? null, 'url' => $item['url'] ?? null, 'active' => (bool) ($item['active'] ?? (filled($item['url'] ?? null) && rtrim(url($item['url']), '/') === rtrim($current, '/'))), 'badge' => $item['badge'] ?? null, 'section' => filled($item['section'] ?? null) ? (string) $item['section'] : null, 'bar' => ($item['bar'] ?? true) !== false, 'navigate' => ($item['navigate'] ?? true) !== false, ]) ->values(); $barItems = $items->where('bar', true)->values(); // Consecutive destinations under the same heading form one group, in the order given. $groups = $items->chunkWhile(fn (array $item, int $key, $chunk): bool => $item['section'] === $chunk->last()['section']); @endphp
$barItems->isNotEmpty(), ]) > {{ __('Skip to content') }} @isset($brand) {{ $brand }} @endisset @isset($railHeader) {{ $railHeader }} @endisset @foreach ($groups as $group) @if ($group->first()['section'] !== null) @foreach ($group as $item) @endforeach @else @foreach ($group as $item) @endforeach @endif @endforeach @if (isset($railFooter) || isset($actions)) {{ $railFooter ?? '' }} @isset($actions)
{{ $actions }}
@endisset
@endif
{{ $top ?? '' }}
{{ $slot }}
@if ($barItems->isNotEmpty())
@foreach ($barItems as $item) @endforeach
@endif