tests / lint (push) Failing after 2m6s
tests / feature (8.4) (push) Successful in 1m3s
tests / feature (8.5) (push) Successful in 1m7s
tests / browser (safari, webkit) (push) Successful in 3m14s
tests / browser (chrome, chromium) (push) Successful in 2m9s
tests / browser (firefox, firefox) (push) Successful in 2m29s
<x-card> (filled, elevated, outlined), <x-list> and <x-list-item> (plain or M3 Expressive's segmented list), <x-divider>, <x-collapse> on <details>, <x-modal> on the native <dialog>, <x-drawer> as a side sheet or list-detail pane, and <x-bottom-sheet> with drag to dismiss. Dialogs and sheets bind to a Livewire flag or id and write back false or null on close, or use the surrounding Alpine scope. Rows open from anywhere on them through data-list-row and data-list-open. DesignGuard now also reports Blade directives written inside a component tag, where they do not compile. Browser test helpers wait for a complete document with Alpine and Livewire running: in Firefox, networkidle alone could return before a repeated visit had loaded. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V9NnLxnPp8vaaurb3Z1MFy
100 lines
4.1 KiB
PHP
100 lines
4.1 KiB
PHP
{{-- One M3 list item: a headline with what leads it, what supports it and what trails it.
|
|
|
|
<x-list-item title="holiday-photos.zip" description="248 MB · expires in 3 days" icon="folder_zip" trailing="3 files" />
|
|
<x-list-item title="Settings" icon="settings" icon-right="chevron_right" link="/settings" />
|
|
|
|
`title` (or the slot) is the body-large headline; `overline` sits above it (label-small),
|
|
`description` under it (body-medium, up to two lines). The leading element is one of `icon`,
|
|
`avatar` (an image URL, or initials in primary-container) or `image` (a 56px thumbnail), or a
|
|
`leading` slot (a checkbox, a switch). The trailing element is `trailing` text (label-small),
|
|
`icon-right`, or an `end` slot for controls (a menu, a switch). One-, two- and three-line
|
|
heights (56, 72, 88px) follow from what is given (ListTokens, androidx Compose Material 3, Apache-2.0).
|
|
|
|
`link` makes the whole item the link. Otherwise, to make it open something while its trailing
|
|
controls keep their own presses, give it `data-list-row` and put `data-list-open` on the one
|
|
control that opens — see resources/js/list-rows.js. `selected` (true) is M3's selected item,
|
|
in secondary-container; `disabled` greys it. --}}
|
|
|
|
@props([
|
|
'title' => null,
|
|
'overline' => null,
|
|
'description' => null,
|
|
'icon' => null,
|
|
'avatar' => null,
|
|
'image' => null,
|
|
'trailing' => null,
|
|
'iconRight' => null,
|
|
'link' => null,
|
|
'external' => false,
|
|
'noWireNavigate' => false,
|
|
'selected' => false,
|
|
'disabled' => false,
|
|
])
|
|
|
|
@php
|
|
$isLink = filled($link);
|
|
$lines = (filled($overline) ? 1 : 0) + (filled($description) ? 1 : 0);
|
|
$initials = filled($avatar) && ! str_contains((string) $avatar, '/') && ! str_contains((string) $avatar, '.');
|
|
@endphp
|
|
|
|
<div
|
|
role="listitem"
|
|
data-list-item
|
|
@if ($isLink) data-list-row @endif
|
|
@if ($selected) data-selected @endif
|
|
{{ $attributes->class([
|
|
'relative flex items-center gap-3 px-4 text-on-surface',
|
|
'min-h-14 py-2' => $lines === 0,
|
|
'min-h-18 py-2.5' => $lines === 1,
|
|
'min-h-22 py-2.5' => $lines === 2,
|
|
'pointer-events-none text-on-surface/38' => $disabled,
|
|
]) }}
|
|
>
|
|
@isset($leading)
|
|
<div class="flex shrink-0 items-center">{{ $leading }}</div>
|
|
@elseif ($avatar)
|
|
@if ($initials)
|
|
<span class="grid size-10 shrink-0 place-items-center rounded-corner-full bg-primary-container type-title-md text-on-primary-container" aria-hidden="true">{{ $avatar }}</span>
|
|
@else
|
|
<img src="{{ $avatar }}" alt="" class="size-10 shrink-0 rounded-corner-full object-cover" />
|
|
@endif
|
|
@elseif ($image)
|
|
<img src="{{ $image }}" alt="" class="size-14 shrink-0 rounded-corner-sm object-cover" />
|
|
@elseif ($icon)
|
|
<x-icon :name="$icon" :class="\Illuminate\Support\Arr::toCssClasses(['size-6', 'text-on-surface-variant' => ! $selected && ! $disabled])" />
|
|
@endif
|
|
|
|
<div class="min-w-0 flex-1">
|
|
@if ($overline)
|
|
<p @class(['type-label-sm', 'text-on-surface-variant' => ! $selected])>{{ $overline }}</p>
|
|
@endif
|
|
|
|
@if ($isLink)
|
|
<a
|
|
href="{{ $link }}"
|
|
data-list-open
|
|
@if ($external) target="_blank" rel="noopener" @elseif (! $noWireNavigate) wire:navigate @endif
|
|
class="block truncate type-body-lg outline-none"
|
|
>{{ $title ?? $slot }}</a>
|
|
@else
|
|
<p class="truncate type-body-lg">{{ $title ?? $slot }}</p>
|
|
@endif
|
|
|
|
@if ($description)
|
|
<p @class(['line-clamp-2 type-body-md', 'text-on-surface-variant' => ! $selected])>{{ $description }}</p>
|
|
@endif
|
|
</div>
|
|
|
|
@isset($end)
|
|
<div class="flex shrink-0 items-center gap-1">{{ $end }}</div>
|
|
@endisset
|
|
|
|
@if ($trailing)
|
|
<span @class(['shrink-0 type-label-sm', 'text-on-surface-variant' => ! $selected])>{{ $trailing }}</span>
|
|
@endif
|
|
|
|
@if ($iconRight)
|
|
<x-icon :name="$iconRight" :class="\Illuminate\Support\Arr::toCssClasses(['size-6', 'text-on-surface-variant' => ! $selected && ! $disabled])" />
|
|
@endif
|
|
</div>
|