diff --git a/app/igneum-app/ui/app.css b/app/igneum-app/ui/app.css index 27805a21b..82434f427 100644 --- a/app/igneum-app/ui/app.css +++ b/app/igneum-app/ui/app.css @@ -885,4 +885,11 @@ body.drawer-open .toast{bottom:calc(var(--drawer-h) + 16px)} #page-overview #dag-live{height:184px} #page-overview .legend{margin-top:8px} #page-overview .wait-card{padding:12px 20px} -#page-overview .node-card{padding-top:18px} \ No newline at end of file +#page-overview .node-card{padding-top:18px} +/* dash-24 (7 October 2026, main's order after the screenshots: gutters inside the app at its 1440p and 4K opening sizes): the + dashboard's cap scales with the window above 1080p (1080 px to 1699, 1280 px at a 1440p-class window from 1700, 1440 px at + a 4K-class window from 2500); Settings gains a second column at the wide cap, its cards never past 640 px, their design + width; the Overview, Cards, Earnings and Prove rows are lists and read at the full cap. fold.test.mjs measures the width at + 1920 by 1080 and 1920 by 1200 on build-2 (known-failed first at 1080); view.test.mjs checks these rules. */ +@media (min-width:1700px){.screen{max-width:1280px}#page-settings{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--gap);align-items:start}#page-settings>.card{max-width:640px;width:100%}#page-settings>.card.wide,#page-settings>#s-interface-card{grid-column:1/-1;max-width:none}} +@media (min-width:2500px){.screen{max-width:1440px}} diff --git a/app/igneum-app/ui/fold.test.mjs b/app/igneum-app/ui/fold.test.mjs index a250b6b36..0162f92c7 100644 --- a/app/igneum-app/ui/fold.test.mjs +++ b/app/igneum-app/ui/fold.test.mjs @@ -14,7 +14,9 @@ const here = dirname(fileURLToPath(import.meta.url)), root = join(here, '../../. const require = createRequire(import.meta.url); let chromium = null; try { if (process.env.IGNEUM_PLAYWRIGHT_DIR) chromium = require(join(process.env.IGNEUM_PLAYWRIGHT_DIR, 'node_modules/playwright')).chromium; } catch (e) { chromium = null; } -const SIZES = [[1280, 800], [1440, 900], [1920, 1080]]; +const SIZES = [[1280, 800], [1440, 900], [1920, 1080], [1920, 1200]]; +// dash-24: the dashboard's content width the cap must allow at each window (1080 up to 1080p, 1280 at a 1440p-class window) +const MIN_DASH_W = { 1280: 1000, 1440: 1080, 1920: 1280 }; // at 1280 the window itself (less the rail and gutters) is the limit, not the cap const ROW = 48; // the first row of a card: its head line with the padding above it test('the first screen: the Overview above the fold at 1280 by 800, 1440 by 900 and 1920 by 1080; Cards, Earnings and Prove show their first object', { skip: chromium ? false : 'no Playwright env (IGNEUM_PLAYWRIGHT_DIR); runs on build-2' }, async () => { @@ -30,6 +32,7 @@ test('the first screen: the Overview above the fold at 1280 by 800, 1440 by 900 const open = async (scenario, p) => { await page.goto(`http://127.0.0.1:${port}/t/mock/?scenario=${scenario}&page=${p}&theme=dark`, { waitUntil: 'load' }); await page.waitForTimeout(1200); }; const fits = async (sel, label, rowOnly) => { const r = await rect(page, sel); if (!r) { bad.push(`${w}x${h} ${label}: not found`); return; } const end = rowOnly ? r.top + ROW : r.bottom; if (!(r.top >= 0 && end <= r.inner)) bad.push(`${w}x${h} ${label}: ${rowOnly ? 'row ends at ' + end : 'ends at ' + r.bottom} of ${r.inner}`); }; await open('live', 'overview'); + { const r = await page.evaluate(() => { const el = document.querySelector('#screen-dashboard'); return el ? Math.round(el.getBoundingClientRect().width) : 0; }); if (r < (MIN_DASH_W[w] || 0)) bad.push(`${w}x${h} dashboard width ${r}, the cap must allow ${MIN_DASH_W[w]} (dash-24)`); } await fits('#totals', 'Overview rate band'); await fits('#btn-toggle', 'Overview big button'); await fits('#ladder-strip', 'Overview ladder strip'); await fits('#dag-card', 'Overview chain card'); await fits('#node-card', 'Overview node card first row', true); if (h >= 1080) await fits('#node-card', 'Overview node card whole at 1080'); await open('rig', 'cards'); await fits('#tune-card', 'Cards tune strip'); await fits('#d-cards .gpu-line:first-child', 'Cards first card row'); diff --git a/app/igneum-app/ui/view.test.mjs b/app/igneum-app/ui/view.test.mjs index b1e0a9bb0..ab81ec0f5 100644 --- a/app/igneum-app/ui/view.test.mjs +++ b/app/igneum-app/ui/view.test.mjs @@ -1111,3 +1111,18 @@ test('the switch is refused without the confirm, and the confirm names what rese assert.equal((idx.match(/step [1-4] of 4/g) || []).length, 4, 'four steps'); assert.ok(idx.includes('id="s-network-cards"') && idx.includes('id="ask-network"'), 'the Settings card and its confirm'); }); + +// ---------- the dashboard's width cap (dash-24, 7 October 2026: gutters inside the app at its 1440p and 4K opening sizes) ---------- +// .screen capped the dashboard at 1080 px at every window width; above 1080p the cap scales (1280 at a 1440p-class window, +// 1440 at a 4K-class one) and Settings gains a second column where its cards allow, never stretching a card past 640 px. +test('the dashboard cap scales with the window above 1080p and Settings gains a column (known-failed on the 1080 px cap)', () => { + const rules = cssRules(css); + const base = rules.filter((r) => r.sel === '.screen').map((r) => r.body).join(';'); + assert.match(base, /max-width:\s*1080px/, 'the 1080p cap stays the base'); + const block = css.slice(css.indexOf('/* dash-24')); + assert.ok(block.length > 0, 'the dash-24 block exists'); + assert.match(block, /@media \(min-width:1700px\)\{[^}]*\.screen\{max-width:1280px\}/, '1440p-class window: 1280'); + assert.match(block, /@media \(min-width:2500px\)\{[^}]*\.screen\{max-width:1440px\}/, '4K-class window: 1440'); + assert.match(block, /#page-settings\{display:grid;grid-template-columns:repeat\(2,minmax\(0,1fr\)\)/, 'Settings two columns at the wide cap'); + assert.match(block, /#page-settings>\.card\{max-width:640px/, 'a Settings card never past its design width'); +});