Refine client panel layout and bump Harbor versions
This commit is contained in:
62
test/web/responsive-layout-contract.test.js
Normal file
62
test/web/responsive-layout-contract.test.js
Normal file
@@ -0,0 +1,62 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import test from 'node:test';
|
||||
|
||||
const root = path.resolve(import.meta.dirname, '../..');
|
||||
const styles = fs.readFileSync(path.join(root, 'src/web/styles.css'), 'utf8');
|
||||
|
||||
function rule(selector, source = styles) {
|
||||
const escaped = selector.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
return new RegExp(`^${escaped}\\s*\\{([\\s\\S]*?)\\n\\}`, 'm').exec(source)?.[1] || '';
|
||||
}
|
||||
|
||||
test('desktop layout keeps the power control on a symmetric center axis', () => {
|
||||
const panel = rule('.client-panel');
|
||||
const power = rule('.client-power-section');
|
||||
const form = rule('.client-form');
|
||||
|
||||
assert.match(panel, /grid-template-columns:\s*minmax\(0, 1fr\) minmax\(240px, 280px\) minmax\(0, 1fr\)/);
|
||||
assert.match(power, /grid-column:\s*2/);
|
||||
assert.match(form, /grid-column:\s*3/);
|
||||
assert.match(form, /position:\s*static/);
|
||||
assert.doesNotMatch(form, /\bleft\s*:|translateX|transition:[^;]*(?:left|width|transform)/);
|
||||
});
|
||||
|
||||
test('tablet and mobile regions use normal flow with viewport-safe widths', () => {
|
||||
const responsive = /@media \(max-width: 920px\) \{([\s\S]*?)\n\}\n\n@media \(max-width: 560px\)/.exec(styles)?.[1] || '';
|
||||
|
||||
assert.match(responsive, /grid-template-columns:\s*minmax\(0, 1fr\)/);
|
||||
assert.match(responsive, /\.client-power-section,[\s\S]*\.client-form,[\s\S]*grid-column:\s*1/);
|
||||
assert.match(responsive, /width:\s*min\(100%, 380px\)/);
|
||||
assert.match(responsive, /max-height:\s*none/);
|
||||
assert.match(responsive, /overflow-y:\s*visible/);
|
||||
assert.match(responsive, /\.harbor-brand,[\s\S]*position:\s*absolute/);
|
||||
assert.match(responsive, /\.client-inline-error\.is-connection,[\s\S]*position:\s*static/);
|
||||
|
||||
assert.match(rule('.client-duration-toggle'), /width:\s*min\(290px, 100%\)/);
|
||||
assert.match(styles, /\.client-instructions\s*\{[\s\S]*width:\s*min\(470px, 100vw\)/);
|
||||
assert.match(styles, /\.client-local-rules\s*\{[\s\S]*width:\s*min\(480px, 100vw\)/);
|
||||
assert.match(styles, /\.client-confirmation-dialog\s*\{[\s\S]*width:\s*min\(430px, calc\(100vw - 48px\)\)/);
|
||||
|
||||
for (const viewport of [320, 390, 768]) {
|
||||
const pagePadding = viewport <= 560 ? 28 : 48;
|
||||
const panelPadding = 12;
|
||||
const available = viewport - pagePadding - panelPadding;
|
||||
assert.ok(Math.min(380, available) <= viewport, `form fits ${viewport}px viewport`);
|
||||
assert.ok(Math.min(290, available) <= viewport, `duration control fits ${viewport}px viewport`);
|
||||
}
|
||||
|
||||
const desktopOuterColumn = (1100 - 280) / 2;
|
||||
assert.ok(Math.min(360, desktopOuterColumn) <= desktopOuterColumn, 'details fit the 1440px desktop grid');
|
||||
});
|
||||
|
||||
test('responsive motion has a reduced-motion fallback', () => {
|
||||
const reducedMotion = /@media \(prefers-reduced-motion: reduce\) \{([\s\S]*)\n\}/.exec(styles)?.[1] || '';
|
||||
|
||||
assert.match(reducedMotion, /\.client-power-section/);
|
||||
assert.match(reducedMotion, /\.client-form/);
|
||||
assert.match(reducedMotion, /\.harbor-brand/);
|
||||
assert.match(reducedMotion, /transition:\s*none/);
|
||||
assert.match(reducedMotion, /animation:\s*none/);
|
||||
});
|
||||
Reference in New Issue
Block a user