diff --git a/ZB.MOM.WW.Theme/src/ZB.MOM.WW.Theme/Components/ThemeShell.razor b/ZB.MOM.WW.Theme/src/ZB.MOM.WW.Theme/Components/ThemeShell.razor new file mode 100644 index 0000000..0e4977b --- /dev/null +++ b/ZB.MOM.WW.Theme/src/ZB.MOM.WW.Theme/Components/ThemeShell.razor @@ -0,0 +1,32 @@ +@* Components/ThemeShell.razor — the one canonical side-rail chassis. + Not a LayoutComponentBase: the app's thin MainLayout delegates to this. *@ +@namespace ZB.MOM.WW.Theme +
+ +
+ +
+
@ChildContent
+
+ +@code { + [Parameter, EditorRequired] public string Product { get; set; } = string.Empty; + [Parameter] public string? Accent { get; set; } + [Parameter] public RenderFragment? Logo { get; set; } + [Parameter] public RenderFragment? Nav { get; set; } + [Parameter] public RenderFragment? RailFooter { get; set; } + [Parameter] public RenderFragment? ChildContent { get; set; } + + private string? AccentStyle => Accent is null ? null : $"--accent: {Accent}"; +} diff --git a/ZB.MOM.WW.Theme/tests/ZB.MOM.WW.Theme.Tests/ThemeShellTests.cs b/ZB.MOM.WW.Theme/tests/ZB.MOM.WW.Theme.Tests/ThemeShellTests.cs new file mode 100644 index 0000000..cb8c6c8 --- /dev/null +++ b/ZB.MOM.WW.Theme/tests/ZB.MOM.WW.Theme.Tests/ThemeShellTests.cs @@ -0,0 +1,43 @@ +namespace ZB.MOM.WW.Theme.Tests; + +public class ThemeShellTests : TestContext +{ + [Fact] + public void Renders_product_nav_and_body() + { + var cut = RenderComponent(p => p + .Add(x => x.Product, "OtOpcUa") + .Add(x => x.Nav, (RenderFragment)(b => b.AddMarkupContent(0, "N"))) + .AddChildContent("
BODY
")); + Assert.NotNull(cut.Find(".side-rail .brand")); + Assert.Contains("OtOpcUa", cut.Markup); + Assert.NotNull(cut.Find(".side-rail .rail-link")); + Assert.NotNull(cut.Find("main.page .pagebody")); + } + + [Fact] + public void Accent_sets_css_variable_on_shell_root() + { + var cut = RenderComponent(p => p + .Add(x => x.Product, "ScadaBridge") + .Add(x => x.Accent, "#2f855a")); + var shell = cut.Find(".app-shell"); + Assert.Contains("--accent: #2f855a", shell.GetAttribute("style")); + } + + [Fact] + public void No_accent_emits_no_style() + { + var cut = RenderComponent(p => p.Add(x => x.Product, "MXAccess Gateway")); + Assert.False(cut.Find(".app-shell").HasAttribute("style")); + } + + [Fact] + public void RailFooter_renders_when_supplied() + { + var cut = RenderComponent(p => p + .Add(x => x.Product, "OtOpcUa") + .Add(x => x.RailFooter, (RenderFragment)(b => b.AddMarkupContent(0, "S")))); + Assert.NotNull(cut.Find(".rail-foot .sess")); + } +}