M3 Expressive's flexible navigation bar, the collapsed, expanded and modal navigation rail with its state applied before the first paint, and an adaptive app shell composing them. The head script now restores the theme and rail attributes that wire:navigate strips from <html>. Completes Phase 8. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V9NnLxnPp8vaaurb3Z1MFy
70 lines
2.7 KiB
PHP
70 lines
2.7 KiB
PHP
{{-- One destination in an `<x-navigation-bar>`.
|
|
|
|
<x-navigation-bar-item label="Inbox" icon="inbox" link="{{ route('inbox') }}" :active="request()->routeIs('inbox')" badge="12" />
|
|
|
|
`link` renders an anchor with `wire:navigate` (unless `external` or `no-wire-navigate`);
|
|
without one it is a button, for a destination a Livewire action switches to. `active` marks
|
|
the current destination: `aria-current="page"`, the filled icon in on-secondary-container on
|
|
the secondary-container indicator, and the label in secondary (on-secondary-container inside
|
|
the medium bar's pill).
|
|
|
|
`badge` puts M3's badge on the icon: `true` for the small dot, a number or a few characters
|
|
for the large one (999+ at most). Screen readers hear a count after the label (", 12");
|
|
`badge-label` replaces it with words ("12 unread") and gives a dot something to say.
|
|
|
|
Values from NavigationBarTokens.kt and NavigationBarVerticalItemTokens.kt (androidx Compose
|
|
Material 3, Apache-2.0); see `<x-navigation-bar>`. --}}
|
|
|
|
@props([
|
|
'label' => null,
|
|
'icon' => null,
|
|
'link' => null,
|
|
'external' => false,
|
|
'noWireNavigate' => false,
|
|
'active' => false,
|
|
'badge' => null,
|
|
'badgeLabel' => null,
|
|
])
|
|
|
|
@php
|
|
$isLink = filled($link);
|
|
$tag = $isLink ? 'a' : 'button';
|
|
$dot = $badge === true;
|
|
$count = ! $dot && $badge !== null && $badge !== false && $badge !== '';
|
|
$spoken = $badgeLabel ?? ($count ? $badge : null);
|
|
|
|
$attributes = $attributes->merge(array_filter([
|
|
'href' => $isLink ? $link : null,
|
|
'target' => $isLink && $external ? '_blank' : null,
|
|
'rel' => $isLink && $external ? 'noopener' : null,
|
|
'wire:navigate' => $isLink && ! $external && ! $noWireNavigate && ! $attributes->has('wire:navigate') ? true : null,
|
|
'type' => $isLink ? null : 'button',
|
|
'aria-current' => $active ? 'page' : null,
|
|
'data-active' => $active ? true : null,
|
|
], fn ($value): bool => $value !== null));
|
|
@endphp
|
|
|
|
<{{ $tag }} data-navigation-bar-item {{ $attributes }}>
|
|
<span data-navigation-pill>
|
|
<span data-navigation-indicator>
|
|
<span class="relative inline-flex">
|
|
@if ($icon)
|
|
<x-icon :name="$icon" :filled="$active" class="size-6" />
|
|
@endif
|
|
|
|
@if ($dot)
|
|
<x-badge floating />
|
|
@elseif ($count)
|
|
<x-badge :value="$badge" max="999" floating />
|
|
@endif
|
|
</span>
|
|
</span>
|
|
|
|
<span data-navigation-label>{{ $label ?? $slot }}</span>
|
|
</span>
|
|
|
|
@if ($spoken !== null)
|
|
<span class="sr-only">, {{ $spoken }}</span>
|
|
@endif
|
|
</{{ $tag }}>
|