@if (_parts is null)
@@ -40,6 +41,7 @@
{
var doc = Document ?? (Markdown is not null ? Renderer.Render(Markdown) : null);
_parts = doc is null ? null : SlotSplitter.Split(doc);
+ PageState.SetDocument(doc);
}
protected override async Task OnAfterRenderAsync(bool firstRender)
diff --git a/src/ShellDocs.Components/DocsPageState.cs b/src/ShellDocs.Components/DocsPageState.cs
new file mode 100644
index 0000000..4cc0d48
--- /dev/null
+++ b/src/ShellDocs.Components/DocsPageState.cs
@@ -0,0 +1,56 @@
+using Microsoft.AspNetCore.Components;
+using ShellDocs.Core;
+using ShellDocs.Markdown;
+
+namespace ShellDocs.Components;
+
+// Populated by MarkdownContent on each page render, read by DocsLayout's chrome
+// (TOC, PrevNext, Breadcrumb) so those components don't need per-page wiring.
+public sealed class DocsPageState : IDisposable
+{
+ private readonly NavigationGraph _graph;
+ private readonly NavigationManager _nav;
+
+ public DocsPageState(NavigationGraph graph, NavigationManager nav)
+ {
+ _graph = graph;
+ _nav = nav;
+ _nav.LocationChanged += OnLocationChanged;
+ }
+
+ public RenderedDocument? Document { get; private set; }
+ public NavigationNode? CurrentNode { get; private set; }
+ public NavigationNode? Prev { get; private set; }
+ public NavigationNode? Next { get; private set; }
+ public IReadOnlyList
Breadcrumbs { get; private set; } = Array.Empty();
+
+ public event Action? OnChange;
+
+ public void SetDocument(RenderedDocument? document)
+ {
+ Document = document;
+ Recompute();
+ }
+
+ private void OnLocationChanged(object? sender, Microsoft.AspNetCore.Components.Routing.LocationChangedEventArgs e)
+ => Recompute();
+
+ private void Recompute()
+ {
+ var path = new Uri(_nav.Uri).AbsolutePath;
+ CurrentNode = _graph.ResolveByUrl(path);
+ if (CurrentNode is null)
+ {
+ Prev = Next = null;
+ Breadcrumbs = Array.Empty();
+ }
+ else
+ {
+ (Prev, Next) = _graph.GetPrevNext(CurrentNode);
+ Breadcrumbs = _graph.GetBreadcrumb(CurrentNode);
+ }
+ OnChange?.Invoke();
+ }
+
+ public void Dispose() => _nav.LocationChanged -= OnLocationChanged;
+}
diff --git a/src/ShellDocs.Components/Layouts/DocsLayout.razor b/src/ShellDocs.Components/Layouts/DocsLayout.razor
index 0ffb0b6..f2f18e3 100644
--- a/src/ShellDocs.Components/Layouts/DocsLayout.razor
+++ b/src/ShellDocs.Components/Layouts/DocsLayout.razor
@@ -44,11 +44,13 @@
}
diff --git a/src/ShellDocs.Components/ServiceCollectionExtensions.cs b/src/ShellDocs.Components/ServiceCollectionExtensions.cs
index 9e9629f..ff419b1 100644
--- a/src/ShellDocs.Components/ServiceCollectionExtensions.cs
+++ b/src/ShellDocs.Components/ServiceCollectionExtensions.cs
@@ -19,6 +19,7 @@ public static IServiceCollection AddShellDocs(this IServiceCollection services,
services.AddScoped