Rewrite the showcase's App bars and tabs section without Tailwind

Plan step 38 (last batch): the app-bar/toolbar row becomes <x-stack>/
<x-row>, each bordered demo box a data-md-showcase-bar-frame hook
(`visible` for the search bar, whose docked suggestions must not clip;
`rounded` for the large-screen docked toolbar, which only gains its
edge and padding from `expanded`, 840px), and the search bar's own
avatar reuses the existing data-md-showcase-avatar hook. The
scrollable-tabs demo's forced-narrow box is
data-md-showcase-tabs-narrow, and the "Open the scaffold" link uses
the shared md-link/md-ink-primary classes in place of the old
Tailwind-era link/text-primary utilities.

Every #bars id and visible label/tooltip the Chromium BarsTest
(against its own probes) and the search index rely on is unchanged.

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 05:32:31 +02:00
co-authored by Claude Sonnet 5
parent 295673554e
commit 7b7e7279f5
2 changed files with 60 additions and 28 deletions
+32
View File
@@ -476,6 +476,38 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
/* Bars: a bordered frame around one app-bar or docked-toolbar demo, matching the rounding a
real scaffold would clip its bar to. `visible` lets the search bar's docked suggestions
overflow it instead of clipping; `rounded` is the large-screen docked toolbar, which has no
edge of its own and only gains its padding from `expanded` (840px), M3's own condition for
the rounded (rather than square) docked toolbar. */
[data-md-showcase-bar-frame] {
width: 100%;
overflow: hidden;
border-radius: var(--md-sys-shape-corner-lg);
border: 1px solid var(--md-sys-color-outline-variant);
}
[data-md-showcase-bar-frame='visible'] {
overflow: visible;
}
[data-md-showcase-bar-frame='rounded'] {
border: 0;
background-color: var(--md-sys-color-surface);
}
@media (width >= 840px) {
[data-md-showcase-bar-frame='rounded'] {
padding: var(--md-sys-measurement-space200);
}
}
/* Bars: the scrollable-tabs demo needs a width narrow enough to force its own scroll. */
[data-md-showcase-tabs-narrow] {
max-width: 384px;
}
} }
/* A handful of call sites (<x-input>, <x-datepicker>, <x-slider>) forward only `class` and /* A handful of call sites (<x-input>, <x-datepicker>, <x-slider>) forward only `class` and
@@ -1,8 +1,8 @@
@php @php
$examples = [ $examples = [
'Top app bars' => <<<'BLADE' 'Top app bars' => <<<'BLADE'
<div class="grid w-full gap-4 [&>*]:overflow-hidden [&>*]:rounded-corner-lg [&>*]:border [&>*]:border-outline-variant"> <x-stack gap="space200" style="width: 100%;">
<div> <div data-md-showcase-bar-frame>
<x-app-bar title="Shares" :sticky="false"> <x-app-bar title="Shares" :sticky="false">
<x-slot:navigation><x-button icon="menu" tooltip="Open navigation" /></x-slot:navigation> <x-slot:navigation><x-button icon="menu" tooltip="Open navigation" /></x-slot:navigation>
<x-slot:actions> <x-slot:actions>
@@ -13,7 +13,7 @@
</div> </div>
{{-- Resize the window: two icon buttons below 600px, four from there, the rest in "More options". --}} {{-- Resize the window: two icon buttons below 600px, four from there, the rest in "More options". --}}
<div> <div data-md-showcase-bar-frame>
<x-app-bar title="holiday-photos" :sticky="false" :actions="[ <x-app-bar title="holiday-photos" :sticky="false" :actions="[
['label' => 'Share', 'icon' => 'share'], ['label' => 'Share', 'icon' => 'share'],
['label' => 'Download', 'icon' => 'download'], ['label' => 'Download', 'icon' => 'download'],
@@ -25,39 +25,39 @@
</x-app-bar> </x-app-bar>
</div> </div>
<div> <div data-md-showcase-bar-frame>
<x-app-bar variant="center" title="holiday-photos.zip" subtitle="248 MB · expires in 3 days" :sticky="false"> <x-app-bar variant="center" title="holiday-photos.zip" subtitle="248 MB · expires in 3 days" :sticky="false">
<x-slot:navigation><x-button icon="arrow_back" tooltip="Back" /></x-slot:navigation> <x-slot:navigation><x-button icon="arrow_back" tooltip="Back" /></x-slot:navigation>
<x-slot:actions><x-button icon="share" tooltip="Share" /></x-slot:actions> <x-slot:actions><x-button icon="share" tooltip="Share" /></x-slot:actions>
</x-app-bar> </x-app-bar>
</div> </div>
<div> <div data-md-showcase-bar-frame>
<x-app-bar variant="medium" title="Recipients" subtitle="3 people" :sticky="false"> <x-app-bar variant="medium" title="Recipients" subtitle="3 people" :sticky="false">
<x-slot:navigation><x-button icon="arrow_back" tooltip="Back" /></x-slot:navigation> <x-slot:navigation><x-button icon="arrow_back" tooltip="Back" /></x-slot:navigation>
<x-slot:actions><x-button icon="person_add" tooltip="Add recipient" /></x-slot:actions> <x-slot:actions><x-button icon="person_add" tooltip="Add recipient" /></x-slot:actions>
</x-app-bar> </x-app-bar>
</div> </div>
<div> <div data-md-showcase-bar-frame>
<x-app-bar variant="large" title="Settings" :sticky="false"> <x-app-bar variant="large" title="Settings" :sticky="false">
<x-slot:navigation><x-button icon="arrow_back" tooltip="Back" /></x-slot:navigation> <x-slot:navigation><x-button icon="arrow_back" tooltip="Back" /></x-slot:navigation>
</x-app-bar> </x-app-bar>
</div> </div>
<div class="!overflow-visible"> <div data-md-showcase-bar-frame="visible">
<x-app-bar variant="search" :sticky="false" class="rounded-corner-lg"> <x-app-bar variant="search" :sticky="false" style="border-radius: var(--md-sys-shape-corner-lg);">
<x-slot:navigation><x-button icon="menu" tooltip="Open navigation" /></x-slot:navigation> <x-slot:navigation><x-button icon="menu" tooltip="Open navigation" /></x-slot:navigation>
<x-search placeholder="Search shares" docked /> <x-search placeholder="Search shares" docked />
<x-slot:actions> <x-slot:actions>
<span class="mx-2 grid size-8 place-items-center rounded-corner-full bg-primary-container type-label-lg text-on-primary-container">AR</span> <span data-md-showcase-avatar class="md-type-label-lg">AR</span>
</x-slot:actions> </x-slot:actions>
</x-app-bar> </x-app-bar>
</div> </div>
</div> </x-stack>
BLADE, BLADE,
'Toolbars' => <<<'BLADE' 'Toolbars' => <<<'BLADE'
<div class="flex w-full flex-wrap items-center gap-6"> <x-row gap="space300" wrap align="center" style="width: 100%;">
<x-toolbar label="Formatting"> <x-toolbar label="Formatting">
<x-button icon="format_bold" tooltip="Bold" :selected="true" /> <x-button icon="format_bold" tooltip="Bold" :selected="true" />
<x-button icon="format_italic" tooltip="Italic" :selected="false" /> <x-button icon="format_italic" tooltip="Italic" :selected="false" />
@@ -78,7 +78,7 @@
<x-button icon="zoom_in" tooltip-right="Zoom in" /> <x-button icon="zoom_in" tooltip-right="Zoom in" />
</x-toolbar> </x-toolbar>
<div class="w-full overflow-hidden rounded-corner-lg border border-outline-variant"> <div data-md-showcase-bar-frame>
<x-toolbar variant="docked" label="Selection"> <x-toolbar variant="docked" label="Selection">
<x-button icon="download" tooltip="Download" /> <x-button icon="download" tooltip="Download" />
<x-button icon="share" tooltip="Share" /> <x-button icon="share" tooltip="Share" />
@@ -87,7 +87,7 @@
</x-toolbar> </x-toolbar>
</div> </div>
<div class="w-full overflow-hidden rounded-corner-lg border border-outline-variant"> <div data-md-showcase-bar-frame>
<x-toolbar variant="docked" label="Editing"> <x-toolbar variant="docked" label="Editing">
<x-button icon="check_box" tooltip="Select" /> <x-button icon="check_box" tooltip="Select" />
<x-button icon="brush" tooltip="Draw" /> <x-button icon="brush" tooltip="Draw" />
@@ -98,7 +98,7 @@
</div> </div>
{{-- M3's docked toolbar on a large screen: rounded from 840px, its groups of controls divided. Narrower, it is the square docked bar. --}} {{-- M3's docked toolbar on a large screen: rounded from 840px, its groups of controls divided. Narrower, it is the square docked bar. --}}
<div class="w-full overflow-hidden rounded-corner-lg bg-surface expanded:p-4"> <div data-md-showcase-bar-frame="rounded">
<x-toolbar variant="docked" rounded label="Text formatting"> <x-toolbar variant="docked" rounded label="Text formatting">
<x-button icon="undo" tooltip="Undo" /> <x-button icon="undo" tooltip="Undo" />
<x-button icon="redo" tooltip="Redo" /> <x-button icon="redo" tooltip="Redo" />
@@ -109,10 +109,10 @@
<x-button icon="link" tooltip="Insert link" /> <x-button icon="link" tooltip="Insert link" />
</x-toolbar> </x-toolbar>
</div> </div>
</div> </x-row>
BLADE, BLADE,
'Primary tabs' => <<<'BLADE' 'Primary tabs' => <<<'BLADE'
<div class="w-full space-y-8"> <x-stack gap="space400" style="width: 100%;">
<x-tabs :tabs="[['name' => 'files', 'label' => 'Files'], ['name' => 'recipients', 'label' => 'Recipients', 'badge' => 3], ['name' => 'activity', 'label' => 'Activity'], ['name' => 'settings', 'label' => 'Settings', 'disabled' => true]]"> <x-tabs :tabs="[['name' => 'files', 'label' => 'Files'], ['name' => 'recipients', 'label' => 'Recipients', 'badge' => 3], ['name' => 'activity', 'label' => 'Activity'], ['name' => 'settings', 'label' => 'Settings', 'disabled' => true]]">
<x-tab name="files">Three files, 248 MB.</x-tab> <x-tab name="files">Three files, 248 MB.</x-tab>
<x-tab name="recipients">Anna, Ben and Chiara.</x-tab> <x-tab name="recipients">Anna, Ben and Chiara.</x-tab>
@@ -124,25 +124,25 @@
<x-tab name="photos">Only photos.</x-tab> <x-tab name="photos">Only photos.</x-tab>
<x-tab name="videos">Only videos.</x-tab> <x-tab name="videos">Only videos.</x-tab>
</x-tabs> </x-tabs>
</div> </x-stack>
BLADE, BLADE,
'Secondary and scrollable tabs' => <<<'BLADE' 'Secondary and scrollable tabs' => <<<'BLADE'
<div class="w-full space-y-8"> <x-stack gap="space400" style="width: 100%;">
<x-tabs variant="secondary" :tabs="[['name' => 'overview', 'label' => 'Overview'], ['name' => 'security', 'label' => 'Security', 'icon' => 'lock'], ['name' => 'billing', 'label' => 'Billing']]"> <x-tabs variant="secondary" :tabs="[['name' => 'overview', 'label' => 'Overview'], ['name' => 'security', 'label' => 'Security', 'icon' => 'lock'], ['name' => 'billing', 'label' => 'Billing']]">
<x-tab name="overview">An overview of the account.</x-tab> <x-tab name="overview">An overview of the account.</x-tab>
<x-tab name="security">Passwords and two-factor sign-in.</x-tab> <x-tab name="security">Passwords and two-factor sign-in.</x-tab>
<x-tab name="billing">Plan and invoices.</x-tab> <x-tab name="billing">Plan and invoices.</x-tab>
</x-tabs> </x-tabs>
<div class="max-w-sm"> <div data-md-showcase-tabs-narrow>
<x-tabs scrollable :tabs="collect(['January', 'February', 'March', 'April', 'May', 'June', 'July'])->map(fn ($month) => ['name' => strtolower($month), 'label' => $month])->all()"> <x-tabs scrollable :tabs="collect(['January', 'February', 'March', 'April', 'May', 'June', 'July'])->map(fn ($month) => ['name' => strtolower($month), 'label' => $month])->all()">
<x-tab name="january">January's shares.</x-tab> <x-tab name="january">January's shares.</x-tab>
</x-tabs> </x-tabs>
</div> </div>
</div> </x-stack>
BLADE, BLADE,
'Section navigation, account menu and theme toggles' => <<<'BLADE' 'Section navigation, account menu and theme toggles' => <<<'BLADE'
<div class="w-full space-y-8"> <x-stack gap="space400" style="width: 100%;">
<x-section-nav :items="[ <x-section-nav :items="[
['title' => 'Profile', 'icon' => 'person', 'url' => '#bars', 'active' => true], ['title' => 'Profile', 'icon' => 'person', 'url' => '#bars', 'active' => true],
['title' => 'Security', 'icon' => 'lock', 'url' => '#bars'], ['title' => 'Security', 'icon' => 'lock', 'url' => '#bars'],
@@ -150,7 +150,7 @@
['title' => 'Billing', 'icon' => 'credit_card', 'url' => '#bars'], ['title' => 'Billing', 'icon' => 'credit_card', 'url' => '#bars'],
]" no-wire-navigate /> ]" no-wire-navigate />
<div class="flex flex-wrap items-center gap-4"> <x-row wrap align="center" gap="space200">
<x-account-menu name="Andreas Reinhold" email="andreas@example.com"> <x-account-menu name="Andreas Reinhold" email="andreas@example.com">
<x-menu-item label="Settings" icon="settings" link="#bars" no-wire-navigate /> <x-menu-item label="Settings" icon="settings" link="#bars" no-wire-navigate />
<x-slot:footer> <x-slot:footer>
@@ -161,20 +161,20 @@
<x-theme-toggle /> <x-theme-toggle />
<x-theme-toggle mode="cycle" /> <x-theme-toggle mode="cycle" />
<x-theme-toggle mode="picker" /> <x-theme-toggle mode="picker" />
</div> </x-row>
</div> </x-stack>
BLADE, BLADE,
]; ];
@endphp @endphp
<section id="bars" class="scroll-mt-24 space-y-6"> <x-livewire-material::stack as="section" id="bars" gap="space300">
<h2 class="type-headline-md">App bars, toolbars and tabs</h2> <h2 class="md-type-headline-md">App bars, toolbars and tabs</h2>
<p class="max-w-3xl type-body-md text-on-surface-variant"> <p class="md-type-body-md md-ink-variant">
<code>&lt;x-app-bar&gt;</code>, <code>&lt;x-toolbar&gt;</code>, <code>&lt;x-tabs&gt;</code>, <code>&lt;x-tab&gt;</code>, <code>&lt;x-section-nav&gt;</code>, <code>&lt;x-account-menu&gt;</code> and <code>&lt;x-theme-toggle&gt;</code>. <code>&lt;x-app-bar&gt;</code>, <code>&lt;x-toolbar&gt;</code>, <code>&lt;x-tabs&gt;</code>, <code>&lt;x-tab&gt;</code>, <code>&lt;x-section-nav&gt;</code>, <code>&lt;x-account-menu&gt;</code> and <code>&lt;x-theme-toggle&gt;</code>.
</p> </p>
@foreach ($examples as $title => $code) @foreach ($examples as $title => $code)
<x-showcase::example :$title :$code /> <x-showcase::example :$title :$code />
@endforeach @endforeach
</section> </x-livewire-material::stack>