Rewrite the showcase frame without Tailwind

Plan step 38 (first batch): layout.blade.php, index.blade.php,
section.blade.php, shell.blade.php and the example component now
lay out through the layout components (pane, stack, row, grid,
surface) and their props, text through the md-* classes, and
everything else through showcase.css's data-md-showcase-* hooks — no
Tailwind utility remains in any of them. The head links the new
stylesheet route after @vite(...), not before: that entry opens the
document's first @layer statement, and linking the showcase's own
bundle ahead of it re-anchors the material layer before Tailwind's
own and lets its preflight's `padding: 0` beat the search view's
padding-top (found by a failing browser test). @vite(...) stays, its
Tailwind CSS entry included, only for the section views (still
Tailwind until the next batches) and the JS runtime; the config
comment says so.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
Andreas Reinhold / reini
2026-09-15 03:55:25 +02:00
co-authored by Claude Sonnet 5
parent 62b09c45b5
commit 9c8b39600b
6 changed files with 167 additions and 107 deletions
+41 -23
View File
@@ -38,26 +38,37 @@
<x-livewire-material::theme-script />
{{-- Kept only for the section views (resources/views/showcase/sections/*), still Tailwind
until the next batches of step 38, and for the Livewire/Alpine runtime; its CSS entry
goes with them. It opens the document's first @layer statement (Workbench package.css's
header explains the trick), which the link below must follow, not precede — first would
re-anchor `material` ahead of Tailwind's own layers and let its preflight's `padding: 0`
beat the search view's padding-top. --}}
@vite(config('livewire-material.showcase.vite'))
@livewireStyles
{{-- The showcase's own chrome: does not depend on the build above. --}}
<link rel="stylesheet" href="{{ \NoNameWeb\LivewireMaterial\Http\Controllers\ShowcaseAssetController::url() }}" />
</head>
<body class="bg-surface font-sans text-on-surface antialiased">
<body data-md-showcase>
<x-livewire-material::scaffold :destinations="$destinations" label="Showcase" rail-width="17rem">
<x-slot:brand>
<a href="{{ route('livewire-material.showcase') }}" wire:navigate class="block truncate rounded-corner-xs type-title-lg focus-ring">Livewire Material</a>
<a href="{{ route('livewire-material.showcase') }}" wire:navigate class="md-type-title-lg md-truncate md-focus-ring" data-md-showcase-brand>Livewire Material</a>
</x-slot:brand>
<x-slot:top>
<x-livewire-material::app-bar variant="search">
<x-slot:navigation>
<span class="medium:hidden"><x-livewire-material::button icon="menu" tooltip="Open navigation" x-data x-on:click="$store.rail.show()" data-test="showcase-menu" /></span>
<x-livewire-material::stack as="span" hide-from="medium">
<x-livewire-material::button icon="menu" tooltip="Open navigation" x-data x-on:click="$store.rail.show()" data-test="showcase-menu" />
</x-livewire-material::stack>
</x-slot:navigation>
{{-- The search looks through every section, example and component: the index is
fetched on first focus, and / or Ctrl+K (⌘K) reaches it from anywhere. Its names
keep clear of <x-search>'s own (`results`, `open`), which the slot also sees. --}}
<div
class="w-full"
data-md-showcase-search
x-data="{
query: '',
entries: null,
@@ -111,42 +122,49 @@
x-on:focus.once="load()"
x-on:keydown.enter.prevent="go($event, matches[0])"
>
<p x-show="query.trim() === ''" class="px-4 py-3 type-body-md text-on-surface-variant">
Type a component (<code>datepicker</code>), an example or a section. Press <kbd class="rounded-corner-xs bg-surface-container-highest px-1.5 type-label-md">/</kbd> to search from anywhere.
<p x-show="query.trim() === ''" class="md-type-body-md md-ink-variant" data-md-showcase-search-hint>
Type a component (<code>datepicker</code>), an example or a section. Press <kbd class="md-type-label-md" data-md-showcase-kbd>/</kbd> to search from anywhere.
</p>
<p x-cloak x-show="query.trim() !== '' && entries !== null && matches.length === 0" class="px-4 py-3 type-body-md text-on-surface-variant">
<p x-cloak x-show="query.trim() !== '' && entries !== null && matches.length === 0" class="md-type-body-md md-ink-variant" data-md-showcase-search-hint>
Nothing matches <span x-text="query.trim()"></span>.
</p>
<template x-for="result in matches" x-bind:key="result.url + result.title">
<a
x-bind:href="result.url"
x-on:click="go($event, result)"
class="state-layer focus-ring flex min-h-14 flex-col justify-center px-4 py-2 outline-none"
class="md-state-layer md-focus-ring"
data-showcase-result
data-md-showcase-search-result
>
<span class="truncate type-body-lg text-on-surface" x-text="result.title"></span>
<span class="truncate type-body-sm text-on-surface-variant" x-text="`${result.kind} · ${result.context}`"></span>
<span class="md-type-body-lg md-ink md-truncate" x-text="result.title"></span>
<span class="md-type-body-sm md-ink-variant md-truncate" x-text="`${result.kind} · ${result.context}`"></span>
</a>
</template>
</x-livewire-material::search>
</div>
<x-slot:actions>
{{-- With colour profiles, a preview of each on this page; nothing is stored. --}}
@if (($profiles = \NoNameWeb\LivewireMaterial\Support\Scheme::profiles()) !== [])
<x-livewire-material::menu label="Colour profile" position="bottom-end" data-test="showcase-profiles">
<x-slot:trigger>
<x-livewire-material::button icon="palette" tooltip="Colour profile" />
</x-slot:trigger>
<x-livewire-material::row gap="space100" align="center">
{{-- With colour profiles, a preview of each on this page; nothing is stored. --}}
@if (($profiles = \NoNameWeb\LivewireMaterial\Support\Scheme::profiles()) !== [])
<x-livewire-material::menu label="Colour profile" position="bottom-end" data-test="showcase-profiles">
<x-slot:trigger>
<x-livewire-material::button icon="palette" tooltip="Colour profile" />
</x-slot:trigger>
@foreach ($profiles as $name => $profile)
<x-livewire-material::menu-item :label="$profile['label']" x-on:click="$store.theme.previewScheme('{{ $name }}')" data-scheme-preview="{{ $name }}" />
@endforeach
</x-livewire-material::menu>
@endif
@foreach ($profiles as $name => $profile)
<x-livewire-material::menu-item :label="$profile['label']" x-on:click="$store.theme.previewScheme('{{ $name }}')" data-scheme-preview="{{ $name }}" />
@endforeach
</x-livewire-material::menu>
@endif
<span class="ms-2 me-3 max-expanded:hidden"><x-livewire-material::theme-toggle mode="picker" /></span>
<span class="expanded:hidden"><x-livewire-material::theme-toggle mode="cycle" /></span>
<x-livewire-material::stack as="span" hide-below="expanded">
<x-livewire-material::theme-toggle mode="picker" />
</x-livewire-material::stack>
<x-livewire-material::stack as="span" hide-from="expanded">
<x-livewire-material::theme-toggle mode="cycle" />
</x-livewire-material::stack>
</x-livewire-material::row>
</x-slot:actions>
</x-livewire-material::app-bar>
</x-slot:top>