fix(central-ui): rail nav scrolls in its own pane so the footer stays pinned
NavMenu wraps its items in .rail-scroll; site.css fills the sticky rail on lg+ and lets that wrapper scroll. Kit untouched. Claude-Session: https://claude.ai/code/session_01Y5ef34iUUMjmwnMpL9xgmB
This commit is contained in:
@@ -5,8 +5,12 @@
|
|||||||
(brand bar + responsive hamburger) belongs to ThemeShell; this component
|
(brand bar + responsive hamburger) belongs to ThemeShell; this component
|
||||||
contributes only the nav items. Collapsible sections use the kit's
|
contributes only the nav items. Collapsible sections use the kit's
|
||||||
NavRailSection (<details>); their open/closed state is persisted client-side
|
NavRailSection (<details>); their open/closed state is persisted client-side
|
||||||
by the kit's nav-state.js (localStorage, keyed by Key) — no JS interop here. *@
|
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. *@
|
||||||
|
|
||||||
|
<div class="rail-scroll">
|
||||||
<NavRailItem Href="/" Text="Dashboard" Match="NavLinkMatch.All" />
|
<NavRailItem Href="/" Text="Dashboard" Match="NavLinkMatch.All" />
|
||||||
|
|
||||||
<AuthorizeView>
|
<AuthorizeView>
|
||||||
@@ -153,3 +157,4 @@
|
|||||||
</AuthorizeView>
|
</AuthorizeView>
|
||||||
</Authorized>
|
</Authorized>
|
||||||
</AuthorizeView>
|
</AuthorizeView>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -170,3 +170,24 @@
|
|||||||
/* Backdrop — slightly darker overlay in dark mode */
|
/* Backdrop — slightly darker overlay in dark mode */
|
||||||
--sb-backdrop: rgba(0, 0, 0, 0.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -241,4 +241,25 @@ public class NavMenuTests : BunitContext
|
|||||||
Assert.DoesNotContain("/audit/log", cut.Markup);
|
Assert.DoesNotContain("/audit/log", cut.Markup);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ThemeShell's <c>nav.side-rail</c> never fills the sticky 100vh rail, so
|
||||||
|
/// a long expanded nav grows past the viewport and pushes
|
||||||
|
/// <c>.rail-foot</c> off-screen. <c>NavMenu</c> wraps its items in a
|
||||||
|
/// <c>div.rail-scroll</c> pane that <c>site.css</c> 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.
|
||||||
|
/// </summary>
|
||||||
|
[Fact]
|
||||||
|
public void NavItems_RenderInsideTheRailScrollPane()
|
||||||
|
{
|
||||||
|
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"));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user