From baa1ed4d8d3379e43eb9a219b313af8903beeaff Mon Sep 17 00:00:00 2001 From: librelad Date: Sat, 4 Jul 2026 21:24:42 +0100 Subject: [PATCH] fix(webui/overview): uniform tab rhythm + rounded sub-tab strip corners MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - .tabs-list now rounds its own top corners (12px, matching .tab-navigation); the first/last .tab-button radii were invisible against the bar's square background on the Backups/Migrate/Config sub-tab strips. - All five fleet tabs share one rhythm under the header divider: a single 16px gap, no extra inset — .ov-tab-body drops its recessed margin/padding box, and the Backups/Migrate sub-tab strips gain the matching gap. - The Peers list keeps its recessed panel via .peers-body (in-card recipe), no longer riding the flattened .ov-tab-body. Co-Authored-By: Claude Fable 5 Signed-off-by: librelad --- .../components/apps/overview/css/overview.css | 26 ++++++++++++------- .../apps/overview/js/overview-manager.js | 6 +++-- .../frontend/core/theme/css/base.css | 4 +++ 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/containers/libreportal/frontend/components/apps/overview/css/overview.css b/containers/libreportal/frontend/components/apps/overview/css/overview.css index cd09236..cfe6ed1 100644 --- a/containers/libreportal/frontend/components/apps/overview/css/overview.css +++ b/containers/libreportal/frontend/components/apps/overview/css/overview.css @@ -60,15 +60,12 @@ flex-shrink: 0; } -/* Recessed dark panel holding each tab's body — same recipe as the per-app - .tasks-container / .backup-snapshots-container / .updater-detail-container, - so the fleet tabs read exactly like the app-detail tabs. */ -#overview-view .ov-tab-body { - margin: 16px; - padding: 16px; - background: rgba(var(--bg-rgb), 0.2); - border-radius: 8px; -} +/* Each tab's content sits flush under the header divider with one shared + 16px gap — the same rhythm on all five tabs (the Backups/Migrate sub-tab + strips get the identical gap below), so no tab carries extra inset. */ +#overview-view .tab-pane > .ov-tab-body { margin: 16px 0 0; } +#overview-view .tab-pane > .tabs-wrapper, +#overview-view .tab-pane > .backup-layout > .tabs-wrapper { margin-top: 16px; } /* ---- Overview: health hero + action board -------------------------------- */ /* The hero is the tab's "status circle": one glance answers "anything to do?". @@ -233,9 +230,18 @@ #overview-view .ov-subtabs-content .tab-panel { display: none; } #overview-view .ov-subtabs-content .tab-panel.active { display: block; } +/* Peers sub-tab: the peer list keeps its recessed panel INSIDE the sub-tab + card (the in-card recipe of the per-app .tasks-container et al) — distinct + from .ov-tab-body, which is now a flush whole-tab body. */ +#overview-view .peers-body { + padding: 16px; + background: rgba(var(--bg-rgb), 0.2); + border-radius: 8px; +} + /* Peers sub-tab: actions footer at the bottom left, mirroring the app-detail tabs' .config-actions row. Left padding lines the buttons up with the - .ov-tab-body container's 16px inset above. */ + .peers-body container's 16px inset above. */ #overview-view .peers-actions { display: flex; gap: 10px; diff --git a/containers/libreportal/frontend/components/apps/overview/js/overview-manager.js b/containers/libreportal/frontend/components/apps/overview/js/overview-manager.js index f076cab..919d536 100644 --- a/containers/libreportal/frontend/components/apps/overview/js/overview-manager.js +++ b/containers/libreportal/frontend/components/apps/overview/js/overview-manager.js @@ -173,8 +173,10 @@ class OverviewManager { if (!pane) return; // Every string-rendered tab follows the per-app detail tab idiom: the // shared header (title + actions + divider) on top, then the body inside - // the recessed .ov-tab-body container — so the renderers below only ever - // produce the body (never a heading or its action buttons). + // the flush .ov-tab-body container (one 16px gap under the divider, no + // extra inset — same rhythm as the Backups/Migrate sub-tab strips) — so + // the renderers below only ever produce the body (never a heading or its + // action buttons). const checkBtn = (label) => ``; const body = (html) => `
${html}
`; switch (id) { diff --git a/containers/libreportal/frontend/core/theme/css/base.css b/containers/libreportal/frontend/core/theme/css/base.css index 6f11de2..2e14cc2 100755 --- a/containers/libreportal/frontend/core/theme/css/base.css +++ b/containers/libreportal/frontend/core/theme/css/base.css @@ -514,6 +514,10 @@ html[data-theme="nebula"]::after { width: 100%; overflow-x: auto; scrollbar-color: rgba(var(--text-rgb), 0.4) rgba(var(--text-rgb), 0.08); + /* Rounded top corners on the strip itself — the first/last .tab-button + carry matching radii, but the bar's own background squares them off + without this. Mirrors .tab-navigation's 12px chrome. */ + border-radius: 12px 12px 0 0; } /* Tabs inside .tabs-wrapper or .tab-navigation share the row evenly so