Plan step 36 (navigation group, third batch): <x-account-menu>'s class lists move into resources/css/components/account-menu.css, keyed on data-md-account-menu (the avatar trigger), data-md-account-menu-avatar and data-md-account-menu-header. The trigger already carried the target-extension and state-layer fixes from an earlier pass (N-01, N-15); this rewrite only moves them onto the shared md-state-layer/ md-touch-target/md-focus-ring classes and their z-index-ordering comment into the stylesheet. The header's name and email keep their type and ink as the fixed text classes on the view (md-type-title-sm/md-ink, md-type-body-sm/md-ink-variant), since they are the caller's own prose. Hooks renamed: data-account-menu to data-md-account-menu, data-account-theme to data-md-account-menu-theme, updated in AppBarTest.php, which carries account-menu's render tests. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
82 lines
3.1 KiB
PHP
82 lines
3.1 KiB
PHP
{{-- Who is signed in, and what belongs to them rather than to a page: an avatar that opens a menu.
|
|
|
|
`name` and `email` head the menu; `avatar` is an image URL or, by default, the initials of the
|
|
name. The slot holds the items (`<x-menu-item>`: settings, billing…), a theme item follows unless
|
|
`:theme="false"`, and the `footer` slot comes last, after a separator — the place for signing
|
|
out, furthest from the thumb:
|
|
|
|
<x-account-menu :name="$user->name" :email="$user->email">
|
|
<x-menu-item label="Settings" icon="settings" :link="route('settings')" />
|
|
<x-slot:footer>
|
|
<form method="POST" action="{{ route('logout') }}">
|
|
@csrf
|
|
<x-menu-item label="Sign out" icon="logout" type="submit" />
|
|
</form>
|
|
</x-slot:footer>
|
|
</x-account-menu>
|
|
|
|
`label` names the button and the menu ("Account"). `position` as on `<x-menu>` (`bottom-end`). --}}
|
|
|
|
@props([
|
|
'name' => null,
|
|
'email' => null,
|
|
'avatar' => null,
|
|
'label' => null,
|
|
'theme' => true,
|
|
'position' => 'bottom-end',
|
|
])
|
|
|
|
@php
|
|
$label ??= __('Account');
|
|
$image = filled($avatar) && (str_contains((string) $avatar, '/') || str_contains((string) $avatar, '.'));
|
|
$initials = $image ? null : ($avatar ?? \Illuminate\Support\Str::of((string) $name)->explode(' ')->filter()->take(2)->map(fn (string $word): string => mb_strtoupper(mb_substr($word, 0, 1)))->join(''));
|
|
@endphp
|
|
|
|
<x-livewire-material::menu :$label :$position {{ $attributes }}>
|
|
<x-slot:trigger>
|
|
<button
|
|
type="button"
|
|
aria-label="{{ $label }}"
|
|
data-md-account-menu
|
|
class="md-state-layer md-touch-target md-focus-ring"
|
|
>
|
|
@if ($image)
|
|
{{-- Behind the state layer (md-state-layer paints its ::before at z-index -1), so
|
|
an avatar image still shows the hover and pressed states over it. --}}
|
|
<img src="{{ $avatar }}" alt="" data-md-account-menu-avatar />
|
|
@elseif (filled($initials))
|
|
{{ $initials }}
|
|
@else
|
|
<x-livewire-material::icon name="person" />
|
|
@endif
|
|
</button>
|
|
</x-slot:trigger>
|
|
|
|
@if (filled($name) || filled($email))
|
|
<div data-md-account-menu-header>
|
|
@if (filled($name))
|
|
<p class="md-truncate md-type-title-sm md-ink">{{ $name }}</p>
|
|
@endif
|
|
@if (filled($email))
|
|
<p class="md-truncate md-type-body-sm md-ink-variant">{{ $email }}</p>
|
|
@endif
|
|
</div>
|
|
|
|
<x-livewire-material::menu-separator />
|
|
@endif
|
|
|
|
{{ $slot }}
|
|
|
|
@if ($theme)
|
|
<x-livewire-material::menu-item icon="contrast" x-on:click="$store.theme.toggle()" data-md-account-menu-theme>
|
|
<span x-text="$store.theme.resolved === 'dark' ? @js(__('Light theme')) : @js(__('Dark theme'))">{{ __('Theme') }}</span>
|
|
</x-livewire-material::menu-item>
|
|
@endif
|
|
|
|
@isset($footer)
|
|
<x-livewire-material::menu-separator />
|
|
|
|
{{ $footer }}
|
|
@endisset
|
|
</x-livewire-material::menu>
|