Style the body only on the error page
Plan step 36 review of a8c2d88f. error-page.css drew a bare `body`, which
components.css already bundles into every Workbench page and step 37's
all.css would put in every application page: each would take the error
page's background, margin and system font. The rule now matches
body:has(> [data-md-error-page]); the fallback stylesheet, inlined into
the error page alone, keeps its own. A test in the containment harness
and in ErrorPagesTest rejects an unscoped html, body, dialog or :root.
The body's system font stack is gone: the old `font-sans` was the brand
typeface (tokens/theme.css), which the page inherits from the
foundation's html rule, and the header's claim otherwise was wrong. The
shape's slow turn, which moved from the view's inline style into the
stylesheet, is back in the fallback so the no-build page still turns.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
co-authored by
Claude Opus 5
parent
cab8d804a5
commit
a764fddf27
@@ -5,7 +5,7 @@
|
||||
* (`resources/views/error-pages/errors/minimal.blade.php`'s header) — none of that is this file's
|
||||
* concern, only the geometry and colour of the parts that show them:
|
||||
*
|
||||
* body
|
||||
* body:has(> [data-md-error-page])
|
||||
* [data-md-error-page]
|
||||
* [data-md-error-art]
|
||||
* [data-md-error-shape] an <x-shape>, turning once a minute unless reduced motion asks
|
||||
@@ -17,17 +17,15 @@
|
||||
* section (otherwise `message` doubles as the headline)
|
||||
* [data-md-error-actions]
|
||||
*
|
||||
* `body` carries no hook of its own — `src/Support/ErrorPage.php`'s `fallbackStyles()`, the
|
||||
* stylesheet an application without a Vite build gets instead, styles the bare element the same
|
||||
* way, so this file matches it rather than inventing a hook the fallback has no equivalent of.
|
||||
* That fallback still needs updating by hand when this file changes, until step 40 replaces how
|
||||
* it is built.
|
||||
* The body is matched only when it holds the layout (`body:has(> [data-md-error-page])`): this
|
||||
* file sits in the application's bundle beside every other page, where a bare `body` rule would
|
||||
* restyle them all. `src/Support/ErrorPage.php`'s `fallbackStyles()`, the stylesheet an
|
||||
* application without a Vite build gets instead, is inlined into the error page alone, so it keeps
|
||||
* a bare `body`; it still needs updating by hand when this file changes, until step 40 replaces
|
||||
* how it is built.
|
||||
*
|
||||
* The page's own font is a literal system stack, not `var(--md-ref-typeface-brand)`: an error
|
||||
* page must read correctly before any webfont has had a chance to load (`@font-face` is what the
|
||||
* fallback path has none of, and this file matches it even on the path that does), and Tailwind's
|
||||
* `font-sans` this replaces never carried the brand font either
|
||||
* (`resources/css/tokens/theme.css`'s `--font-sans` is the only utility that does).
|
||||
* The page's font is the foundation's, `--md-ref-typeface-brand` on `html` (foundation/base.css),
|
||||
* as the old `font-sans` was; only the fallback, which has no `@font-face`, uses a system stack.
|
||||
*
|
||||
* Colours from the roles (`docs/reference/m3/styles.md` § Typography, "Accessibility
|
||||
* requirements": surface/on-surface); the display code over its primary-container shape is the
|
||||
@@ -45,12 +43,11 @@
|
||||
@import './shape.css';
|
||||
|
||||
@layer material.components {
|
||||
body {
|
||||
body:has(> [data-md-error-page]) {
|
||||
margin: 0;
|
||||
min-height: 100dvh;
|
||||
background-color: var(--md-sys-color-surface);
|
||||
color: var(--md-sys-color-on-surface);
|
||||
font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,8 @@ class ErrorPage
|
||||
/**
|
||||
* A stylesheet for a page without its build: the application's scheme in both themes, a
|
||||
* system font, and the layout's `data-md-error-*` hooks drawn to match the built version
|
||||
* (resources/css/components/error-page.css). Still hand-built, not `Stylesheets::bundle()` —
|
||||
* (resources/css/components/error-page.css), the shape's slow turn included. Inlined into the
|
||||
* error page alone, so its `body` rule needs no scope. Still hand-built, not `Stylesheets::bundle()` —
|
||||
* plan step 40 replaces this method's own body, once the design guard exists to catch a hook
|
||||
* the two drift apart on.
|
||||
*/
|
||||
@@ -90,6 +91,8 @@ class ErrorPage
|
||||
[data-md-error-actions] :is(a, button) { display: inline-flex; align-items: center; height: 3.5rem; padding: 0 1.5rem; border: 0; border-radius: 9999px; background: none; color: var(--md-sys-color-primary); font-family: inherit; font-size: 1rem; font-weight: 500; line-height: 1.5rem; text-decoration: none; cursor: pointer; }
|
||||
[data-md-error-actions] > :first-child { background-color: var(--md-sys-color-primary); color: var(--md-sys-color-on-primary); }
|
||||
[data-md-error-actions] :is(a, button):focus-visible { outline: 3px solid var(--md-sys-color-secondary); outline-offset: 2px; }
|
||||
@keyframes material-error-turn { to { transform: rotate(1turn); } }
|
||||
@media (prefers-reduced-motion: no-preference) { [data-md-error-shape] { animation: material-error-turn 60s linear infinite; } }
|
||||
CSS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,9 +11,9 @@ use NoNameWeb\LivewireMaterial\Tests\Support\ViewClasses;
|
||||
* the stylesheets of the components its view renders, writes its values from the tokens and its
|
||||
* breakpoints as px range queries, and is imported from the "Containment" block of components.css.
|
||||
*
|
||||
* The dataset grows by one name per component commit (`divider`, `collapse`, `card`, then `list`
|
||||
* and `list-item` together), the same rule InputStylesheetsTest.php and ActionStylesheetsTest.php
|
||||
* follow. It starts empty: this file lands before any containment component is rewritten.
|
||||
* The dataset grew by one name per component commit, the same rule InputStylesheetsTest.php and
|
||||
* ActionStylesheetsTest.php follow. The error layout, whose view is not a component, has the same
|
||||
* checks in tests/Feature/ErrorPagesTest.php.
|
||||
*/
|
||||
dataset('containment components', [
|
||||
'divider',
|
||||
@@ -115,3 +115,11 @@ it('is imported from the containment block of components.css', function (string
|
||||
|
||||
expect($block)->toContain("@import './components/{$name}.css';");
|
||||
})->with('containment components');
|
||||
|
||||
it('scopes every element-wide selector to a data-md hook', function (string $name) {
|
||||
// `all.css` bundles every component stylesheet into every page, so a bare `html`, `body`,
|
||||
// `dialog` or `:root` rule would restyle the application's own pages.
|
||||
$source = (string) preg_replace('~/\*.*?\*/~s', '', ComponentStylesheet::read($name)->css);
|
||||
|
||||
expect($source)->not->toMatch('/(?:^|[,{};]\s*)(?:html|body|dialog|:root)(?![\w-])(?!\[data-md-|:has\(> \[data-md-)/m');
|
||||
})->with('containment components');
|
||||
|
||||
@@ -6,6 +6,7 @@ use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Support\Facades\Vite;
|
||||
use Illuminate\Support\Str;
|
||||
use NoNameWeb\LivewireMaterial\LivewireMaterialServiceProvider;
|
||||
use NoNameWeb\LivewireMaterial\Support\ErrorPage;
|
||||
use NoNameWeb\LivewireMaterial\Support\Scheme;
|
||||
use NoNameWeb\LivewireMaterial\Tests\Support\ComponentStylesheet;
|
||||
use NoNameWeb\LivewireMaterial\Tests\Support\ViewClasses;
|
||||
@@ -279,3 +280,14 @@ it('is imported from the containment block of components.css', function () {
|
||||
|
||||
expect($block)->toContain("@import './components/error-page.css';");
|
||||
});
|
||||
|
||||
it('styles the body only when it holds the error layout, and turns the shape on both paths', function () {
|
||||
$source = (string) preg_replace('~/\*.*?\*/~s', '', ComponentStylesheet::read('error-page')->css);
|
||||
|
||||
// The stylesheet travels in the application's bundle, so a bare `body` would restyle every page.
|
||||
expect($source)->not->toMatch('/(?:^|[,{};]\s*)(?:html|body|dialog|:root)(?![\w-])(?!\[data-md-|:has\(> \[data-md-)/m')
|
||||
->and(ComponentStylesheet::read('error-page')->declarations('body:has(> [data-md-error-page])'))->not->toHaveKey('font-family')
|
||||
->and((string) ErrorPage::fallbackStyles())
|
||||
->toContain('@keyframes material-error-turn')
|
||||
->toContain('@media (prefers-reduced-motion: no-preference) { [data-md-error-shape] { animation: material-error-turn 60s linear infinite; } }');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user