From c5fe05870907377662a44c50e17ea18f95e0cec8 Mon Sep 17 00:00:00 2001 From: Shephard Tseisi Date: Fri, 24 Jul 2026 18:45:19 +0200 Subject: [PATCH 1/4] feat: add package registrations for ShellDocs components and documentation links to enhance navigation and usability --- examples/ShellDocs.Preview/Program.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/examples/ShellDocs.Preview/Program.cs b/examples/ShellDocs.Preview/Program.cs index 317e4dc..c75944f 100644 --- a/examples/ShellDocs.Preview/Program.cs +++ b/examples/ShellDocs.Preview/Program.cs @@ -33,6 +33,17 @@ o.AddNavLink("Showcase", "/showcase"); o.AddNavLink("Blog", "/blog"); + o.AddPackage("shelldocs", "ShellDocs", "The docs framework itself.", "/docs/introduction", + "M12 2 4 6v6c0 5 3.5 9.5 8 10 4.5-.5 8-5 8-10V6z"); + o.AddPackage("shelldocs.markdown", "ShellDocs.Markdown", "Markdig extensions, slots, MDX.", "/docs/markdown", + "M4 4h16v16H4z M4 9h16 M9 4v16"); + o.AddPackage("shelldocs.core", "ShellDocs.Core", "Navigation graph + content model.", "/docs/core", + "M12 2 2 7l10 5 10-5-10-5z M2 17l10 5 10-5 M2 12l10 5 10-5"); + o.AddPackage("shelldocs.cli", "ShellDocs.CLI", "Scaffold, build, publish.", "/docs/cli", + "m8 6-6 6 6 6 M16 6l6 6-6 6"); + o.AddPackage("shelldocs.components","ShellDocs.Components","Layouts, header, sidebar, TOC.", "/docs/components", + "M3 3h7v7H3z M14 3h7v7h-7z M3 14h7v7H3z M14 14h7v7h-7z"); + // Callout, Card, Steps, FileTree, CodeGroup, LinkCard etc. are // auto-registered by AddShellDocs — no extra work needed here. }); From 458e5fd7013f4e5df7186d1c106bebafcf5c3e17 Mon Sep 17 00:00:00 2001 From: Shephard Tseisi Date: Fri, 24 Jul 2026 18:46:15 +0200 Subject: [PATCH 2/4] feat: update PackageSelector component to utilize ShellDocsOptions for dynamic package management and improve icon handling --- .../Chrome/PackageSelector.razor | 101 ++++++++++-------- 1 file changed, 54 insertions(+), 47 deletions(-) diff --git a/src/ShellDocs.Components/Chrome/PackageSelector.razor b/src/ShellDocs.Components/Chrome/PackageSelector.razor index 1f2d29f..3937134 100644 --- a/src/ShellDocs.Components/Chrome/PackageSelector.razor +++ b/src/ShellDocs.Components/Chrome/PackageSelector.razor @@ -1,63 +1,70 @@ @inject NavigationManager Nav +@inject ShellDocsOptions Options -
- + - @if (_open) - { -
- @foreach (var pkg in Packages) - { - var isSel = pkg.Id == Selected.Id; - - } -
- } -
+ @if (_open) + { +
+ @foreach (var pkg in Options.Packages) + { + var isSel = pkg.Id == Selected.Id; + + } +
+ } + +} @code { private bool _open; - private record Package(string Id, string Title, string Description, string IconPath, string RootUrl); + private const string DefaultIcon = "M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z M3.27 6.96 12 12.01l8.73-5.05 M12 22.08V12"; - private static readonly List Packages = new() + // Longest RootUrl prefix wins — "/docs/components" beats "/docs" for "/docs/components/callout". + private DocsPackage Selected { - new("shelldocs", "ShellDocs", "The docs framework itself.", "M12 2 4 6v6c0 5 3.5 9.5 8 10 4.5-.5 8-5 8-10V6z", "/docs/introduction"), - new("shelldocs.markdown", "ShellDocs.Markdown", "Markdig extensions, slots, MDX.", "M4 4h16v16H4z M4 9h16 M9 4v16", "/docs/markdown"), - new("shelldocs.core", "ShellDocs.Core", "Navigation graph + content model.","M12 2 2 7l10 5 10-5-10-5z M2 17l10 5 10-5 M2 12l10 5 10-5", "/docs/core"), - new("shelldocs.cli", "ShellDocs.CLI", "Scaffold, build, publish.", "m8 6-6 6 6 6 M16 6l6 6-6 6", "/docs/cli"), - new("shelldocs.components","ShellDocs.Components","Layouts, header, sidebar, TOC.","M3 3h7v7H3z M14 3h7v7h-7z M3 14h7v7H3z M14 14h7v7h-7z", "/docs/components") - }; - - private Package Selected => Packages.FirstOrDefault(p => Nav.Uri.Contains(p.RootUrl.Split('/', StringSplitOptions.RemoveEmptyEntries).LastOrDefault() ?? "")) ?? Packages[0]; + get + { + var path = new Uri(Nav.Uri).AbsolutePath; + return Options.Packages + .Where(p => path.StartsWith(p.RootUrl, StringComparison.OrdinalIgnoreCase)) + .OrderByDescending(p => p.RootUrl.Length) + .FirstOrDefault() + ?? Options.Packages[0]; + } + } private void Toggle() => _open = !_open; - private void Choose(Package pkg) + private void Choose(DocsPackage pkg) { _open = false; Nav.NavigateTo(pkg.RootUrl); From eefe5d2b4b6959f43a8a13d860ddb142d9640298 Mon Sep 17 00:00:00 2001 From: Shephard Tseisi Date: Fri, 24 Jul 2026 18:46:54 +0200 Subject: [PATCH 3/4] feat: introduce Packages property and AddPackage method in ShellDocsOptions for enhanced package management --- src/ShellDocs.Components/ShellDocsOptions.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/ShellDocs.Components/ShellDocsOptions.cs b/src/ShellDocs.Components/ShellDocsOptions.cs index 4e6db87..d048b3f 100644 --- a/src/ShellDocs.Components/ShellDocsOptions.cs +++ b/src/ShellDocs.Components/ShellDocsOptions.cs @@ -14,6 +14,8 @@ public class ShellDocsOptions public DocsLayoutVariant LayoutVariant { get; set; } = DocsLayoutVariant.TopNav; public List PrimaryNav { get; } = new(); + // 0 or 1 entries hides the sidebar package selector entirely. + public List Packages { get; } = new(); public List RegisteredComponents { get; } = new(); /* Per-type tag alias — when a type appears here, BuildTypeRegistry uses this string as the markdown-facing tag name instead of the type's short name. @@ -109,6 +111,12 @@ public ShellDocsOptions AddNavMenu(string label, params NavMenuItem[] items) return this; } + public ShellDocsOptions AddPackage(string id, string title, string description, string rootUrl, string? iconPath = null) + { + Packages.Add(new DocsPackage(id, title, description, rootUrl, iconPath)); + return this; + } + internal TypeRegistry BuildTypeRegistry() { var registry = new TypeRegistry(); @@ -126,6 +134,9 @@ internal TypeRegistry BuildTypeRegistry() public record NavLink(string Label, string Href, List? Children = null); public record NavMenuItem(string Label, string Href, string? Description = null, string? IconSvg = null); +// IconPath is a raw SVG `d` attribute value on a 24×24 viewBox — not a URL. +public record DocsPackage(string Id, string Title, string Description, string RootUrl, string? IconPath = null); + public enum ShellDocsTheme { Shadcn, From 065514d543a216a565115e578bbd6baf5bf3fa9f Mon Sep 17 00:00:00 2001 From: Shephard Tseisi Date: Fri, 24 Jul 2026 18:48:50 +0200 Subject: [PATCH 4/4] test: add unit tests for PackageRegistration to verify package addition and default state in ShellDocsOptions --- .../PackageRegistrationTests.cs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tests/ShellDocs.Tests/PackageRegistrationTests.cs diff --git a/tests/ShellDocs.Tests/PackageRegistrationTests.cs b/tests/ShellDocs.Tests/PackageRegistrationTests.cs new file mode 100644 index 0000000..5325ce9 --- /dev/null +++ b/tests/ShellDocs.Tests/PackageRegistrationTests.cs @@ -0,0 +1,30 @@ +using ShellDocs.Components; +using Xunit; + +namespace ShellDocs.Tests; + +public class PackageRegistrationTests +{ + [Fact] + public void AddPackage_FluentChain_AppendsInOrder() + { + var options = new ShellDocsOptions() + .AddPackage("core", "Core", "Foundation.", "/docs/core") + .AddPackage("components", "Components", "Widgets.", "/docs/components", iconPath: "M0 0h10v10H0z"); + + Assert.Equal(2, options.Packages.Count); + Assert.Equal("core", options.Packages[0].Id); + Assert.Equal("Core", options.Packages[0].Title); + Assert.Equal("/docs/core", options.Packages[0].RootUrl); + Assert.Null(options.Packages[0].IconPath); + Assert.Equal("components", options.Packages[1].Id); + Assert.Equal("M0 0h10v10H0z", options.Packages[1].IconPath); + } + + [Fact] + public void Packages_DefaultToEmpty_SoSelectorHides() + { + var options = new ShellDocsOptions(); + Assert.Empty(options.Packages); + } +}