diff --git a/web/hwlab-cloud-web/scripts/check.mjs b/web/hwlab-cloud-web/scripts/check.mjs index aa9f0034..06e4eaab 100644 --- a/web/hwlab-cloud-web/scripts/check.mjs +++ b/web/hwlab-cloud-web/scripts/check.mjs @@ -26,6 +26,7 @@ for (const file of requiredFiles) { } const html = fs.readFileSync(path.resolve(rootDir, "index.html"), "utf8"); +const styles = fs.readFileSync(path.resolve(rootDir, "styles.css"), "utf8"); const app = fs.readFileSync(path.resolve(rootDir, "app.mjs"), "utf8"); const artifactPublisher = fs.readFileSync(path.resolve(repoRoot, "scripts/dev-artifact-publish.mjs"), "utf8"); const frontendSource = `${html}\n${app}\n${artifactPublisher}`; @@ -61,6 +62,11 @@ assert.match(html, /DRY-RUN loading/); assert.match(html, /DEV-LIVE probing/); assert.match(html, /BLOCKED pending/); assert.doesNotMatch(html, /M3 Diagnostics Console/); +assert.match(styles, /html,\s*\nbody\s*{[^}]*height:\s*100%;[^}]*overflow:\s*hidden;/s); +assert.match(styles, /body\s*>\s*\[data-app-shell\]\s*{[^}]*min-height:\s*0;/s); +assert.match(styles, /\.workbench-shell\s*{[^}]*height:\s*100(?:d)?vh;[^}]*overflow:\s*hidden;/s); +assert.match(styles, /\.view\s*{[^}]*min-height:\s*0;[^}]*overflow:\s*auto;/s); +assert.match(styles, /\.(?:resource-tree|compact-list|conversation-list|trace-list|hardware-list)[^{]*{[^}]*min-height:\s*0;[^}]*overflow:\s*auto;/s); assert.match(app, /fetchJson\("\/v1"\)/); assert.match(app, /fetchJson\("\/health\/live"\)/); assert.match(app, /callRpc\("system\.health"\)/); diff --git a/web/hwlab-cloud-web/styles.css b/web/hwlab-cloud-web/styles.css index 68190ba1..8736c3a6 100644 --- a/web/hwlab-cloud-web/styles.css +++ b/web/hwlab-cloud-web/styles.css @@ -28,7 +28,10 @@ html, body { margin: 0; - min-height: 100%; + width: 100%; + height: 100%; + min-height: 0; + overflow: hidden; background: linear-gradient(90deg, rgba(212, 173, 67, 0.055) 1px, transparent 1px), linear-gradient(0deg, rgba(111, 183, 169, 0.04) 1px, transparent 1px), @@ -38,6 +41,10 @@ body { font: 12px/1.4 var(--body); } +body > [data-app-shell] { + min-height: 0; +} + button, input { font: inherit; @@ -57,10 +64,13 @@ ul { } .workbench-shell { - min-height: 100vh; + height: 100vh; + height: 100dvh; + min-height: 0; display: grid; grid-template-columns: 48px 292px minmax(460px, 1fr) 366px; grid-template-rows: 1fr; + overflow: hidden; background: rgba(15, 17, 16, 0.88); } @@ -79,6 +89,7 @@ ul { padding: 8px 6px; background: var(--rail); border-right: 1px solid var(--line); + overflow: auto; } .rail-spacer { @@ -537,7 +548,7 @@ h3 { .right-sidebar { display: grid; - grid-template-rows: auto minmax(0, 1fr); + grid-template-rows: minmax(0, 0.45fr) minmax(0, 1fr); gap: 10px; padding: 10px; background: rgba(18, 20, 18, 0.98); @@ -546,9 +557,12 @@ h3 { } .hardware-status { + min-height: 0; display: grid; + grid-template-rows: auto minmax(0, 1fr); gap: 10px; padding: 12px; + overflow: hidden; } .hardware-list { @@ -847,12 +861,17 @@ tbody tr:last-child td { @media (max-width: 1240px) { .workbench-shell { grid-template-columns: 48px 260px minmax(420px, 1fr); + grid-template-rows: minmax(0, 1fr) clamp(220px, 36dvh, 360px); + } + + .explorer-collapsed { + grid-template-columns: 48px 0 minmax(0, 1fr); } .right-sidebar { grid-column: 2 / 4; grid-row: 2; - min-height: 420px; + min-height: 0; border-top: 1px solid var(--line); border-left: 0; } @@ -866,10 +885,12 @@ tbody tr:last-child td { .workbench-shell, .explorer-collapsed { grid-template-columns: 44px minmax(0, 1fr); + grid-template-rows: clamp(150px, 26dvh, 240px) minmax(0, 1fr) clamp(180px, 32dvh, 280px); } .explorer { grid-column: 2; + overflow: auto; } .center-workspace,