From 25015442e5094e968ed8fb00d6db6119491c70a9 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Thu, 12 Nov 2026 11:27:01 -0500 Subject: [PATCH] feat(centralui): adopt Theme 0.5.3 ScrollNav rail scroll pane (#61) Bump ZB.MOM.WW.Theme 0.5.0 -> 0.5.3, set ThemeShell ScrollNav=true, drop NavMenu's own .rail-scroll wrapper and the site.css rail scroll block (keeps .rail-updates*). NavMenu test now asserts no local wrapper. Claude-Session: https://claude.ai/code/session_01GT67ACmpMR7b9LGRPLijMi --- Directory.Packages.props | 2 +- .../Components/Layout/MainLayout.razor | 2 +- .../Components/Layout/NavMenu.razor | 7 ++----- .../wwwroot/css/site.css | 21 ------------------- .../Layout/NavMenuTests.cs | 16 ++++++-------- 5 files changed, 10 insertions(+), 38 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 1ce69f90..49f7f2ed 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -114,7 +114,7 @@ - + diff --git a/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Layout/MainLayout.razor b/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Layout/MainLayout.razor index cfd5c550..f090404b 100644 --- a/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Layout/MainLayout.razor +++ b/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Layout/MainLayout.razor @@ -8,7 +8,7 @@ style="--accent: …" on the shell root, which outranks the dark-mode token override on and silently killed the dark accent app-wide. The accent is declared as a :root token in site.css instead. *@ - + diff --git a/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Layout/NavMenu.razor b/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Layout/NavMenu.razor index 85a70b8d..8c63e19c 100644 --- a/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Layout/NavMenu.razor +++ b/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Layout/NavMenu.razor @@ -6,11 +6,9 @@ contributes only the nav items. Collapsible sections use the kit's NavRailSection (
); their open/closed state is persisted client-side by the kit's nav-state.js (localStorage, keyed by Key) — no JS interop here. - Everything below is wrapped in .rail-scroll, the scroll pane defined in - site.css: a long nav scrolls under the brand bar while the rail footer - stays pinned, and the kit itself is untouched. *@ + The scroll pane (long nav scrolls, footer pinned) is provided by the kit's + ThemeShell ScrollNav="true" (Theme 0.5.3). *@ -
@@ -157,4 +155,3 @@ -
diff --git a/src/ZB.MOM.WW.ScadaBridge.CentralUI/wwwroot/css/site.css b/src/ZB.MOM.WW.ScadaBridge.CentralUI/wwwroot/css/site.css index 0f3d2986..7f1b1fef 100644 --- a/src/ZB.MOM.WW.ScadaBridge.CentralUI/wwwroot/css/site.css +++ b/src/ZB.MOM.WW.ScadaBridge.CentralUI/wwwroot/css/site.css @@ -171,27 +171,6 @@ --sb-backdrop: rgba(0, 0, 0, 0.6); } -/* ── Rail nav scroll pane ──────────────────────────────────────────────── - ThemeShell's nav.side-rail is a flex column inside the sticky 100vh - #theme-rail (lg+), but it never fills that height and nothing inside it - scrolls, so a long nav grows past the viewport and carries the footer - with it. Fill the rail and let the nav items (NavMenu's .rail-scroll - wrapper) scroll while the brand bar and .rail-foot stay put. Below lg the - rail is inline and scrolls with the page, so the rule is scoped to lg+. - The kit is untouched (deferred-work register: upstream into - ZB.MOM.WW.Theme so the other consumers get it too). */ -@media (min-width: 992px) { - #theme-rail > .side-rail { - height: 100%; - } - .rail-scroll { - flex: 1 1 auto; - min-height: 0; - overflow-y: auto; - overscroll-behavior: contain; - } -} - /* ── Rail pending-updates indicator ────────────────────────────────────── Sits in .rail-foot just above .rail-user. One line when quiet, two when something is pending; tokens only so dark mode follows for free. */ diff --git a/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Layout/NavMenuTests.cs b/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Layout/NavMenuTests.cs index cb7d18e8..98fde411 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Layout/NavMenuTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Layout/NavMenuTests.cs @@ -254,23 +254,19 @@ public class NavMenuTests : BunitContext } /// - /// ThemeShell's nav.side-rail never fills the sticky 100vh rail, so - /// a long expanded nav grows past the viewport and pushes - /// .rail-foot off-screen. NavMenu wraps its items in a - /// div.rail-scroll pane that site.css makes scroll on its - /// own (lg+), leaving the brand bar and rail footer pinned. This asserts - /// the wrapper exists and actually contains the nav sections, not just - /// that the class string appears somewhere in the markup. + /// The rail scroll pane is owned by the kit (ThemeShell ScrollNav="true", + /// Theme 0.5.3). NavMenu must not add its own .rail-scroll wrapper, + /// or the rail gets two nested scroll panes. /// [Fact] - public void NavItems_RenderInsideTheRailScrollPane() + public void NavItems_DoNotCarryTheirOwnRailScrollWrapper() { var cut = RenderWithRoles("Administrator", "Designer", "Deployer"); cut.WaitForAssertion(() => { - Assert.Contains("class=\"rail-scroll\"", cut.Markup); - Assert.NotEmpty(cut.FindAll("div.rail-scroll details.rail-section")); + Assert.NotEmpty(cut.FindAll("details.rail-section")); + Assert.DoesNotContain("rail-scroll", cut.Markup); }); } }