From 6b0c085caead6e7e419194614a7b9c0c8a64bbea Mon Sep 17 00:00:00 2001 From: Phil Scott Date: Sat, 4 Apr 2026 20:36:18 -0400 Subject: [PATCH 1/2] Bump MyLittleContentEngine dependencies to v0.0.2-alpha.0.6, add versioned resource URLs, enable flat file redirects, and standardize trailing slashes in page routes. --- Spectre.Docs/Components/App.razor | 22 +++++++++++++------ Spectre.Docs/Components/Pages/Blog.razor | 4 ++-- Spectre.Docs/Components/Pages/CliIndex.razor | 2 +- .../Components/Pages/ConsoleIndex.razor | 2 +- Spectre.Docs/Program.cs | 1 + Spectre.Docs/Spectre.Docs.csproj | 6 ++--- 6 files changed, 23 insertions(+), 14 deletions(-) diff --git a/Spectre.Docs/Components/App.razor b/Spectre.Docs/Components/App.razor index bb60f7d..db511cd 100644 --- a/Spectre.Docs/Components/App.razor +++ b/Spectre.Docs/Components/App.razor @@ -1,12 +1,15 @@ - +@using Microsoft.AspNetCore.WebUtilities +@inject IWebHostEnvironment WebHostEnvironment + + - - - - + + + + - + - + @code { + static readonly string Version = DateTime.Now.Ticks.ToString(); + + string GetVersioned(string url) => WebHostEnvironment.IsDevelopment() + ? QueryHelpers.AddQueryString(url, "v", DateTime.Now.Ticks.ToString()) // if we are in dev mode, always cache bust + : QueryHelpers.AddQueryString(url, "v", Version); // in prod we'll use the static tick that we stored for all pages } \ No newline at end of file diff --git a/Spectre.Docs/Components/Pages/Blog.razor b/Spectre.Docs/Components/Pages/Blog.razor index 00278c5..4054dce 100644 --- a/Spectre.Docs/Components/Pages/Blog.razor +++ b/Spectre.Docs/Components/Pages/Blog.razor @@ -1,4 +1,4 @@ -@page "/blog" +@page "/blog/" @using Spectre.Console @layout BlogLayout @inject IMarkdownContentService BlogService @@ -63,7 +63,7 @@ } - diff --git a/Spectre.Docs/Components/Pages/CliIndex.razor b/Spectre.Docs/Components/Pages/CliIndex.razor index c4d8f5f..df55656 100644 --- a/Spectre.Docs/Components/Pages/CliIndex.razor +++ b/Spectre.Docs/Components/Pages/CliIndex.razor @@ -1,4 +1,4 @@ -@page "/cli" +@page "/cli/" @using Spectre.Console @inject IMarkdownContentService CliContentServices @inject ContentEngineOptions ContentEngineOptions diff --git a/Spectre.Docs/Components/Pages/ConsoleIndex.razor b/Spectre.Docs/Components/Pages/ConsoleIndex.razor index 00c1ba0..0c2b0d1 100644 --- a/Spectre.Docs/Components/Pages/ConsoleIndex.razor +++ b/Spectre.Docs/Components/Pages/ConsoleIndex.razor @@ -1,4 +1,4 @@ -@page "/console" +@page "/console/" @using Spectre.Console @inject IMarkdownContentService ConsoleContentServices @inject ContentEngineOptions ContentEngineOptions diff --git a/Spectre.Docs/Program.cs b/Spectre.Docs/Program.cs index 72e10d0..167d386 100644 --- a/Spectre.Docs/Program.cs +++ b/Spectre.Docs/Program.cs @@ -54,6 +54,7 @@ { SolutionPath = "../Spectre.Docs.slnx", }) + .WithFlatFileRedirects() // this will allow links without a trailing slash to redirect to the new URL with a trailing slash // this allows us to use blazor components within Markdown. // see https://phil-scott-78.github.io/MyLittleContentEngine/guides/markdown-extensions#blazor-within-markdown .AddMdazor() diff --git a/Spectre.Docs/Spectre.Docs.csproj b/Spectre.Docs/Spectre.Docs.csproj index 443b9ab..311590d 100644 --- a/Spectre.Docs/Spectre.Docs.csproj +++ b/Spectre.Docs/Spectre.Docs.csproj @@ -16,9 +16,9 @@ library where if you don't reference it directly they don't include the BuildHost folders. Include for now. --> - - - + + + From be6d9938f78d5373882c689f8f95d0d55aa5408b Mon Sep 17 00:00:00 2001 From: Phil Scott Date: Sat, 4 Apr 2026 21:11:13 -0400 Subject: [PATCH 2/2] Integrate SPA navigation with `SpectreArticleIslandRenderer`, add dynamic SPA resource loading, and update layouts for enhanced content rendering. --- Spectre.Docs/Components/App.razor | 10 +++++ .../Components/Layouts/MainLayout.razor | 2 +- Spectre.Docs/Content/_redirects.yml | 1 - Spectre.Docs/Program.cs | 7 +++ .../Slots/Components/SpectreArticle.razor | 45 +++++++++++++++++++ .../Slots/SpectreArticleIslandRenderer.cs | 45 +++++++++++++++++++ 6 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 Spectre.Docs/Slots/Components/SpectreArticle.razor create mode 100644 Spectre.Docs/Slots/SpectreArticleIslandRenderer.cs diff --git a/Spectre.Docs/Components/App.razor b/Spectre.Docs/Components/App.razor index db511cd..067ed7c 100644 --- a/Spectre.Docs/Components/App.razor +++ b/Spectre.Docs/Components/App.razor @@ -9,6 +9,7 @@ + diff --git a/Spectre.Docs/Components/Layouts/MainLayout.razor b/Spectre.Docs/Components/Layouts/MainLayout.razor index 6f59c80..234689e 100644 --- a/Spectre.Docs/Components/Layouts/MainLayout.razor +++ b/Spectre.Docs/Components/Layouts/MainLayout.razor @@ -38,7 +38,7 @@ } -
+
@Body diff --git a/Spectre.Docs/Content/_redirects.yml b/Spectre.Docs/Content/_redirects.yml index 1ffae25..f8e3d67 100644 --- a/Spectre.Docs/Content/_redirects.yml +++ b/Spectre.Docs/Content/_redirects.yml @@ -45,7 +45,6 @@ redirects: /cli/unit-testing: /cli/how-to/testing-command-line-applications /cli/migration: /cli/ /cli/opencli: /cli/ - /cli: /cli/tutorials/quick-start-your-first-cli-app # Appendix Section /appendix/styles: /console/reference/text-style-reference diff --git a/Spectre.Docs/Program.cs b/Spectre.Docs/Program.cs index 167d386..df443de 100644 --- a/Spectre.Docs/Program.cs +++ b/Spectre.Docs/Program.cs @@ -6,12 +6,14 @@ using MyLittleContentEngine; using MyLittleContentEngine.MonorailCss; using MyLittleContentEngine.Services.Content.CodeAnalysis.Configuration; +using MyLittleContentEngine.Services.Spa; using MyLittleContentEngine.UI.Components; using Spectre.Docs.Components; using Spectre.Docs.Components.Layouts; using Spectre.Docs.Components.Reference; using Spectre.Docs.Components.Shared; using Spectre.Docs.Services; +using Spectre.Docs.Slots; var builder = WebApplication.CreateBuilder(args); @@ -55,6 +57,10 @@ SolutionPath = "../Spectre.Docs.slnx", }) .WithFlatFileRedirects() // this will allow links without a trailing slash to redirect to the new URL with a trailing slash + .WithSpaNavigation(spa => + { + spa.AddIsland(); + }) // this allows us to use blazor components within Markdown. // see https://phil-scott-78.github.io/MyLittleContentEngine/guides/markdown-extensions#blazor-within-markdown .AddMdazor() @@ -130,5 +136,6 @@ // this adds the route for styles.css which is generated dynamically based on the used // CSS classes. app.UseMonorailCss(); +app.UseSpaNavigation(); await app.RunOrBuildContent(args); \ No newline at end of file diff --git a/Spectre.Docs/Slots/Components/SpectreArticle.razor b/Spectre.Docs/Slots/Components/SpectreArticle.razor new file mode 100644 index 0000000..1f5c806 --- /dev/null +++ b/Spectre.Docs/Slots/Components/SpectreArticle.razor @@ -0,0 +1,45 @@ +@using MyLittleContentEngine.UI.Components + +
+
+
+
+

+ @Title +

+ + @if (!string.IsNullOrEmpty(Description)) + { +

+ @Description +

+ } +
+ +
+
+
+ @((MarkupString)HtmlContent) +
+
+ + +
+
+
+
+ +@code { + [Parameter] public string Title { get; set; } = ""; + [Parameter] public string Description { get; set; } = ""; + [Parameter] public string HtmlContent { get; set; } = ""; +} diff --git a/Spectre.Docs/Slots/SpectreArticleIslandRenderer.cs b/Spectre.Docs/Slots/SpectreArticleIslandRenderer.cs new file mode 100644 index 0000000..095f204 --- /dev/null +++ b/Spectre.Docs/Slots/SpectreArticleIslandRenderer.cs @@ -0,0 +1,45 @@ +using MyLittleContentEngine.Services.Content; +using MyLittleContentEngine.Services.Spa; +using Spectre.Console; + +namespace Spectre.Docs.Slots; + +internal class SpectreArticleIslandRenderer( + IMarkdownContentService consoleContentService, + IMarkdownContentService cliContentService, + ComponentRenderer renderer) : RazorIslandRenderer(renderer) +{ + public override string IslandName => "content"; + + protected override async Task?> BuildParametersAsync(string url) + { + // Try console content first, then CLI + var consoleResult = await consoleContentService.GetRenderedContentPageByUrlOrDefault(url); + if (consoleResult is not null) + { + return BuildParams( + consoleResult.Value.Page.FrontMatter.Title, + consoleResult.Value.Page.FrontMatter.Description, + consoleResult.Value.HtmlContent); + } + + var cliResult = await cliContentService.GetRenderedContentPageByUrlOrDefault(url); + if (cliResult is not null) + { + return BuildParams( + cliResult.Value.Page.FrontMatter.Title, + cliResult.Value.Page.FrontMatter.Description, + cliResult.Value.HtmlContent); + } + + return null; + } + + private static Dictionary BuildParams(string title, string description, string htmlContent) => + new() + { + [nameof(Components.SpectreArticle.Title)] = title, + [nameof(Components.SpectreArticle.Description)] = description, + [nameof(Components.SpectreArticle.HtmlContent)] = htmlContent, + }; +}