diff --git a/ZB.MOM.WW.Theme/src/ZB.MOM.WW.Theme/Components/NavRailItem.razor b/ZB.MOM.WW.Theme/src/ZB.MOM.WW.Theme/Components/NavRailItem.razor new file mode 100644 index 0000000..28e87f6 --- /dev/null +++ b/ZB.MOM.WW.Theme/src/ZB.MOM.WW.Theme/Components/NavRailItem.razor @@ -0,0 +1,12 @@ +@* Components/NavRailItem.razor *@ + + @if (Icon is not null) { @Icon } + @Text + + +@code { + [Parameter, EditorRequired] public string Href { get; set; } = string.Empty; + [Parameter, EditorRequired] public string Text { get; set; } = string.Empty; + [Parameter] public RenderFragment? Icon { get; set; } + [Parameter] public NavLinkMatch Match { get; set; } = NavLinkMatch.Prefix; +} diff --git a/ZB.MOM.WW.Theme/src/ZB.MOM.WW.Theme/Components/NavRailSection.razor b/ZB.MOM.WW.Theme/src/ZB.MOM.WW.Theme/Components/NavRailSection.razor new file mode 100644 index 0000000..eb5bd5d --- /dev/null +++ b/ZB.MOM.WW.Theme/src/ZB.MOM.WW.Theme/Components/NavRailSection.razor @@ -0,0 +1,12 @@ +@* Components/NavRailSection.razor — CSS-only collapsible (no JS, works in static SSR). + Apps that want cookie-persisted expand state keep their own interactive NavSection. *@ +
+ @Title +
@ChildContent
+
+ +@code { + [Parameter, EditorRequired] public string Title { get; set; } = string.Empty; + [Parameter] public bool Expanded { get; set; } = true; + [Parameter] public RenderFragment? ChildContent { get; set; } +} diff --git a/ZB.MOM.WW.Theme/tests/ZB.MOM.WW.Theme.Tests/NavRailTests.cs b/ZB.MOM.WW.Theme/tests/ZB.MOM.WW.Theme.Tests/NavRailTests.cs new file mode 100644 index 0000000..3e6ec95 --- /dev/null +++ b/ZB.MOM.WW.Theme/tests/ZB.MOM.WW.Theme.Tests/NavRailTests.cs @@ -0,0 +1,27 @@ +namespace ZB.MOM.WW.Theme.Tests; + +public class NavRailTests : TestContext +{ + [Fact] + public void NavRailItem_renders_rail_link_with_href_and_text() + { + var cut = RenderComponent(p => p + .Add(x => x.Href, "/clusters") + .Add(x => x.Text, "Clusters")); + var a = cut.Find("a.rail-link"); + Assert.Equal("/clusters", a.GetAttribute("href")); + Assert.Contains("Clusters", a.TextContent); + } + + [Fact] + public void NavRailSection_renders_title_and_children_open_by_default() + { + var cut = RenderComponent(p => p + .Add(x => x.Title, "Navigation") + .AddChildContent("X")); + var details = cut.Find("details.rail-section"); + Assert.True(details.HasAttribute("open")); + Assert.Contains("Navigation", cut.Find("summary").TextContent); + Assert.NotNull(cut.Find(".rail-section-body .rail-link")); + } +}