diff --git a/Spectre.Docs/Components/App.razor b/Spectre.Docs/Components/App.razor index bb60f7d..067ed7c 100644 --- a/Spectre.Docs/Components/App.razor +++ b/Spectre.Docs/Components/App.razor @@ -1,12 +1,16 @@ - +@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/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/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/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 72e10d0..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); @@ -54,6 +56,11 @@ { 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() @@ -129,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, + }; +} 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. --> - - - + + +