Files
livewire-material/resources/views/components/alert.blade.php
T
Andreas Reinhold / reiniandClaude Opus 5 648ad8efaf
tests / lint (push) Successful in 1m3s
tests / feature (8.4) (push) Failing after 1m5s
tests / feature (8.5) (push) Failing after 1m4s
tests / browser (chrome, chromium) (push) Failing after 1m5s
tests / browser (firefox, firefox) (push) Failing after 1m1s
tests / browser (safari, webkit) (push) Failing after 1m1s
Add the snackbar, badges, rich tooltips, alerts, stats and empty states
<x-toast> hosts the snackbar queue for the Toasts concern and
window.materialToast(), one at a time, paused on hover and focus, with
an optional action; it listens from the moment its script loads, so a
toast dispatched before Alpine starts is shown rather than lost.
<x-badge> is M3's dot and count, plus a tonal or outlined status label;
<x-rich-tooltip> is transient or persistent; <x-alert>, <x-stat> and
<x-empty-state> are built from M3's parts.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9NnLxnPp8vaaurb3Z1MFy
2026-09-13 06:59:40 +02:00

66 lines
2.9 KiB
PHP

{{-- A notice in the page: a state that needs saying storage is full, the link has expired.
Not an M3 component (M3's banner is gone); drawn in M3's terms: the state's container colour
(tinted, never filled), a medium corner, the state's icon, a title-small `title`, body-medium
text from `description` or the slot, and an `actions` slot for one or two text buttons.
`color` (alias `tone`): `info` (the default), `success`, `warning`, `error`, `primary`,
`secondary`, `tertiary`, or `neutral` for surface-container-high. `icon` replaces the state's
icon; `:icon="false"` drops it. `dismissible` adds a close button that hides it in the browser.
Errors and warnings are `role="alert"` and announced at once; the rest are `role="status"`. --}}
@props([
'title' => null,
'description' => null,
'color' => null,
'tone' => null,
'icon' => null,
'dismissible' => false,
])
@php
$color = in_array($color ?? $tone, ['info', 'success', 'warning', 'error', 'primary', 'secondary', 'tertiary', 'neutral'], true) ? ($color ?? $tone) : 'info';
$icon = $icon === false ? null : ($icon ?? [
'info' => 'info', 'success' => 'check_circle', 'warning' => 'warning', 'error' => 'error',
'primary' => 'info', 'secondary' => 'info', 'tertiary' => 'info', 'neutral' => 'info',
][$color]);
$colours = [
'info' => 'bg-info-container text-on-info-container', 'success' => 'bg-success-container text-on-success-container',
'warning' => 'bg-warning-container text-on-warning-container', 'error' => 'bg-error-container text-on-error-container',
'primary' => 'bg-primary-container text-on-primary-container', 'secondary' => 'bg-secondary-container text-on-secondary-container',
'tertiary' => 'bg-tertiary-container text-on-tertiary-container', 'neutral' => 'bg-surface-container-high text-on-surface',
][$color];
@endphp
<div
role="{{ in_array($color, ['error', 'warning'], true) ? 'alert' : 'status' }}"
@if ($dismissible) x-data="{ shown: true }" x-show="shown" x-transition.opacity @endif
{{ $attributes->class(['flex items-start gap-3 rounded-corner-md p-4', $colours]) }}
>
@if ($icon)
<x-icon :name="$icon" filled class="size-6" />
@endif
<div class="min-w-0 flex-1 space-y-1 self-center">
@if ($title)
<p class="type-title-sm">{{ $title }}</p>
@endif
@if ($description || $slot->isNotEmpty())
<div class="type-body-md">{{ $description ?? $slot }}</div>
@endif
@isset($actions)
<div class="-ms-3 flex flex-wrap gap-2 pt-1">{{ $actions }}</div>
@endisset
</div>
@if ($dismissible)
<button type="button" class="state-layer focus-ring -m-2 inline-flex size-10 shrink-0 items-center justify-center rounded-corner-full" aria-label="{{ __('Dismiss') }}" x-on:click="shown = false">
<x-icon name="close" class="size-5" />
</button>
@endif
</div>