Plan step 15. Every `sm:`/`md:`/`lg:`/`xl:` in the components, the showcase (sections, layout, shell) and the pagination and error views becomes the M3 window size class the audits' breakpoint maps prescribe: the full-screen dialog, the FAB, the snackbar's width, `radio inline`, the section picker and the page numbers move from 640px to `medium` (600px, M3's compact boundary, N-07 / C-07 / IN-28); `button responsive` moves from 1024px to `expanded` (840px); `section-nav`'s grid-to-row switch from 1280px to `large` (1200px, N-07); and `drawer pane` from 1280px to `expanded`, where M3 shows two panes for list-detail (C-07). The pane's default width is now 360dp, M3's fixed supporting pane at expanded. Showcase example grids take two columns from `medium` and three or more from `expanded`; the showcase's own theme picker swaps at `expanded`, the nearest class boundary to the 768px it used (no M3 rule applies to it). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
80 lines
4.3 KiB
PHP
80 lines
4.3 KiB
PHP
{{-- A choice of colour profile: one swatch per profile `material:scheme` generated from
|
|
`livewire-material.profiles`, each its name and its primary, secondary and tertiary colour.
|
|
|
|
<x-scheme-picker label="Colour profile" wire:model="colorProfile" hint="Applies to every page after saving" />
|
|
|
|
Native radios under the swatches, so `wire:model` and `x-model` bind as on any input and the
|
|
arrow keys move the choice. Choosing one shows it on the page at once
|
|
(`$store.theme.previewScheme`); storing it — and telling `Scheme::resolveProfileUsing()` — is
|
|
the application's. The dots are the only colours not drawn from tokens: they show other
|
|
profiles than the page's, so they are custom properties set inline from the scheme file's
|
|
checked hexes, light or dark with the page. Without profiles it renders nothing.
|
|
|
|
Props: `label`, `hint`, `name` (needed with `x-model`), `profiles` (default: every generated
|
|
profile). A validation message for the bound property replaces the hint. --}}
|
|
|
|
@props([
|
|
'label' => null,
|
|
'hint' => null,
|
|
'name' => null,
|
|
'profiles' => null,
|
|
])
|
|
|
|
@php
|
|
$profiles ??= \NoNameWeb\LivewireMaterial\Support\Scheme::profiles();
|
|
$model = $attributes->whereStartsWith('wire:model')->first();
|
|
$name ??= $model ?: 'scheme';
|
|
$errorKey = $model ?: (filled($attributes->get('name')) ? (string) $attributes->get('name') : null);
|
|
$messages = $errorKey !== null && isset($errors) ? \Illuminate\Support\Arr::flatten($errors->get($errorKey)) : [];
|
|
@endphp
|
|
|
|
@if ($profiles !== [])
|
|
<fieldset x-data data-scheme-picker {{ $attributes->whereDoesntStartWith(['wire:model', 'x-model'])->except('name')->class('min-w-0') }}>
|
|
@if (filled($label))
|
|
<legend class="mb-2 type-label-lg text-on-surface-variant">{{ $label }}</legend>
|
|
@endif
|
|
|
|
<div class="grid grid-cols-2 gap-2 medium:grid-cols-4">
|
|
@foreach ($profiles as $profile => $scheme)
|
|
<label
|
|
data-scheme-option="{{ $profile }}"
|
|
class="state-layer flex min-w-0 cursor-pointer select-none flex-col items-start gap-2 rounded-corner-lg border border-outline-variant bg-surface-container-low p-3 text-on-surface transition-[background-color,border-color] duration-(--md-sys-motion-effects-fast-duration) ease-effects-fast has-checked:border-transparent has-checked:bg-secondary-container has-checked:text-on-secondary-container has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-secondary"
|
|
>
|
|
<input
|
|
{{ $attributes->whereStartsWith(['wire:model', 'x-model']) }}
|
|
type="radio"
|
|
name="{{ $name }}"
|
|
value="{{ $profile }}"
|
|
x-on:change="$store.theme.previewScheme($event.target.value)"
|
|
class="peer sr-only"
|
|
/>
|
|
|
|
<span class="flex shrink-0 -space-x-1.5" aria-hidden="true">
|
|
@foreach (['primary', 'secondary', 'tertiary'] as $role)
|
|
<span
|
|
style="--swatch-light: {{ $scheme['light'][$role] }}; --swatch-dark: {{ $scheme['dark'][$role] }}"
|
|
class="size-5 rounded-corner-full bg-(--swatch-light) ring-2 ring-surface-container-low in-has-checked:ring-secondary-container dark:bg-(--swatch-dark)"
|
|
></span>
|
|
@endforeach
|
|
</span>
|
|
|
|
<span class="w-full truncate pe-6 type-label-lg">{{ __($scheme['label']) }}</span>
|
|
|
|
{{-- In the corner, so a long name keeps its room. The wrapper carries the position. --}}
|
|
<span class="pointer-events-none absolute end-2 top-2 hidden peer-checked:block">
|
|
<x-livewire-material::icon name="check" class="size-5" />
|
|
</span>
|
|
</label>
|
|
@endforeach
|
|
</div>
|
|
|
|
@if ($messages !== [])
|
|
@foreach ($messages as $message)
|
|
<p class="mt-1 type-body-sm text-error">{{ $message }}</p>
|
|
@endforeach
|
|
@elseif (filled($hint))
|
|
<p class="mt-1 type-body-sm text-on-surface-variant">{{ $hint }}</p>
|
|
@endif
|
|
</fieldset>
|
|
@endif
|