Draw the scaffold without Tailwind
Plan step 36 (navigation group, third batch): <x-scaffold>'s own styling moves into resources/css/layout/scaffold.css (the content region, the bar and rail row, the banner, the actions row and its rail-collapsed column layout, --material-bottom-bar and --material-margin publishing, the skip link) alongside step 35's FAB and content-margin rules already there. Every data-app-shell* hook becomes data-md-scaffold-* (data-app-shell-bar, -actions, -banner); the skip link is data-md-skip-link; data-app-shell itself is dropped, data-md-scaffold already named the root. The actions row's rail-collapsed:flex-col is written out branch for branch as the navigation rail's own rewrite did for its internal parts: the three width-independent conditions in one :where() group, the four width-gated ones each in their own @media block. With that gone, resources/css/tailwind.css's rail-collapsed custom-variant shim (its last use) is removed; tailwind.css now carries only tokens/theme.css and tokens/utilities.css, which the showcase still needs until step 38. navigation-bar.css's hide-on-scroll rule reading --material-bottom-bar stayed unlayered only because <x-scaffold> published that variable through a Tailwind utility, which no layered rule could outrank; now scaffold.css sets it itself in material.layout, a layer navigation-bar.css's own material.components always beats, so the rule moves into the layer and the file fits one @layer material.components block like every other navigation stylesheet. navigation-bar rejoins NavigationStylesheetsTest.php's dataset and NavigationBarTest.php's own duplicate shape test is retired in favour of it. Browser tests added (docs/plans/material-3-browser-tests.md): the scaffold's FAB dropping the bar's own height once hide-bar-on-scroll slides it away, at the trailing edge in a right-to-left document, and clearing a safe area an application sets on its inline-end and bottom edges. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
20b062846d
commit
ed93222d22
@@ -408,7 +408,7 @@ it('lays a feed out in one column below medium and in columns of its minimum wid
|
||||
->assertScript(layoutRect('#item-5', 'left').' === '.layoutRect('#item-1', 'left'));
|
||||
});
|
||||
|
||||
function scaffoldFabPage(int $width): mixed
|
||||
function scaffoldFabPage(int $width, string $dir = 'ltr'): mixed
|
||||
{
|
||||
$body = <<<'BLADE'
|
||||
<x-scaffold :destinations="[
|
||||
@@ -421,7 +421,7 @@ function scaffoldFabPage(int $width): mixed
|
||||
</x-scaffold>
|
||||
BLADE;
|
||||
|
||||
return layoutPage($body, $width, 800);
|
||||
return layoutPage($body, $width, 800, $dir);
|
||||
}
|
||||
|
||||
const SCAFFOLD_FAB = '[data-md-scaffold-fab]';
|
||||
@@ -451,6 +451,54 @@ it('places the scaffold\'s FAB at the bottom-end corner, clear of the navigation
|
||||
->assertNoJavaScriptErrors();
|
||||
});
|
||||
|
||||
it('drops the bar\'s own height from the FAB\'s offset once hide-bar-on-scroll slides it away', function () {
|
||||
$body = <<<'BLADE'
|
||||
<x-scaffold hide-bar-on-scroll :destinations="[
|
||||
['title' => 'Inbox', 'icon' => 'inbox', 'url' => '/inbox', 'active' => true],
|
||||
['title' => 'Sent', 'icon' => 'send', 'url' => '/sent'],
|
||||
]">
|
||||
<x-slot:fab><x-fab icon="edit" tooltip="Compose" /></x-slot:fab>
|
||||
<p style="block-size: 2000px">The page</p>
|
||||
</x-scaffold>
|
||||
BLADE;
|
||||
|
||||
$page = layoutPage($body, 599, 800);
|
||||
$shown = (int) $page->script(layoutRect(SCAFFOLD_FAB, 'bottom'));
|
||||
|
||||
$page->script('window.scrollTo(0, 400)')
|
||||
->assertScript("document.querySelector('[data-md-navigation-bar]').hasAttribute('data-md-hidden')")
|
||||
// The bar's own 64px is what --material-bottom-bar drops once the bar has slid off, so the
|
||||
// FAB moves down by exactly that much (navigation-bar.css, layout/scaffold.css).
|
||||
->assertScript(layoutRect(SCAFFOLD_FAB, 'bottom')." === {$shown} + 64")
|
||||
->assertNoJavaScriptErrors();
|
||||
});
|
||||
|
||||
it('places the FAB at the trailing edge, the left in a right-to-left document', function () {
|
||||
scaffoldFabPage(599, 'rtl')
|
||||
->assertScript(layoutRect(SCAFFOLD_FAB, 'left').' === 16')
|
||||
->assertScript(layoutRect(SCAFFOLD_FAB, 'right').' < window.innerWidth - 16')
|
||||
->assertNoJavaScriptErrors();
|
||||
});
|
||||
|
||||
it('clears a safe area an application sets on the FAB\'s inline-end and bottom edges', function () {
|
||||
$body = <<<'BLADE'
|
||||
<x-scaffold :destinations="[['title' => 'Inbox', 'icon' => 'inbox', 'url' => '/inbox', 'active' => true, 'bar' => false]]">
|
||||
<x-slot:fab><x-fab icon="edit" tooltip="Compose" /></x-slot:fab>
|
||||
</x-scaffold>
|
||||
BLADE;
|
||||
|
||||
$page = layoutPage($body, 599, 800);
|
||||
$right = (int) $page->script('window.innerWidth - '.layoutRect(SCAFFOLD_FAB, 'right'));
|
||||
$bottom = (int) $page->script('window.innerHeight - '.layoutRect(SCAFFOLD_FAB, 'bottom'));
|
||||
|
||||
$page->script("document.documentElement.style.setProperty('--material-safe-right', '20px')")
|
||||
->assertScript('window.innerWidth - '.layoutRect(SCAFFOLD_FAB, 'right')." === {$right} + 20");
|
||||
|
||||
$page->script("document.documentElement.style.setProperty('--material-safe-bottom', '30px')")
|
||||
->assertScript('window.innerHeight - '.layoutRect(SCAFFOLD_FAB, 'bottom')." === {$bottom} + 30")
|
||||
->assertNoJavaScriptErrors();
|
||||
});
|
||||
|
||||
it('draws no second margin for a pane or a canonical layout inside the scaffold\'s content region', function () {
|
||||
$body = <<<'BLADE'
|
||||
<x-scaffold :destinations="[['title' => 'Inbox', 'icon' => 'inbox', 'url' => '/inbox', 'active' => true]]">
|
||||
|
||||
Reference in New Issue
Block a user