From 1d4539b80bf5d599164568f80c5d30e053e0d0ee Mon Sep 17 00:00:00 2001 From: Shephard Tseisi Date: Tue, 7 Jul 2026 19:33:50 +0200 Subject: [PATCH 1/5] feat: implement initial structure for ShellDocs CLI and components, including command scaffolding, project files, and templates. Add CLI entry point with commands for initialization, creation, development, building, and previewing documentation. Introduce core services and markdown processing capabilities. --- src/ShellDocs.CLI/Program.cs | 105 ++++++++++++++++++ src/ShellDocs.CLI/ShellDocs.CLI.csproj | 21 ++++ .../ServiceCollectionExtensions.cs | 39 +++++++ .../ShellDocs.Components.csproj | 22 ++++ src/ShellDocs.Components/_Imports.razor | 9 ++ src/ShellDocs.Components/wwwroot/shelldocs.js | 9 ++ src/ShellDocs.Core/NavigationNode.cs | 17 +++ src/ShellDocs.Core/ShellDocs.Core.csproj | 15 +++ .../MarkdownPipelineFactory.cs | 15 +++ .../ShellDocs.Markdown.csproj | 15 +++ .../ShellDocs.Templates.csproj | 9 ++ .../StarterPageTemplate.cs | 17 +++ 12 files changed, 293 insertions(+) create mode 100644 src/ShellDocs.CLI/Program.cs create mode 100644 src/ShellDocs.CLI/ShellDocs.CLI.csproj create mode 100644 src/ShellDocs.Components/ServiceCollectionExtensions.cs create mode 100644 src/ShellDocs.Components/ShellDocs.Components.csproj create mode 100644 src/ShellDocs.Components/_Imports.razor create mode 100644 src/ShellDocs.Components/wwwroot/shelldocs.js create mode 100644 src/ShellDocs.Core/NavigationNode.cs create mode 100644 src/ShellDocs.Core/ShellDocs.Core.csproj create mode 100644 src/ShellDocs.Markdown/MarkdownPipelineFactory.cs create mode 100644 src/ShellDocs.Markdown/ShellDocs.Markdown.csproj create mode 100644 src/ShellDocs.Templates/ShellDocs.Templates.csproj create mode 100644 src/ShellDocs.Templates/StarterPageTemplate.cs diff --git a/src/ShellDocs.CLI/Program.cs b/src/ShellDocs.CLI/Program.cs new file mode 100644 index 0000000..9883404 --- /dev/null +++ b/src/ShellDocs.CLI/Program.cs @@ -0,0 +1,105 @@ +using System.CommandLine; +using Spectre.Console; + +namespace ShellDocs.CLI; + +/* CLI entry point. Real command handlers land in feat/cli-init and feat/cli-dev-build. + This scaffolding wires up the command tree so `shelldocs --help` produces the right shape. */ +internal class Program +{ + // ANSI Shadow figlet — same font ShellUI uses so the family reads as one thing. + private const string Logo = @" + ███████╗██╗ ██╗███████╗██╗ ██╗ ██████╗ ██████╗ ██████╗███████╗ + ██╔════╝██║ ██║██╔════╝██║ ██║ ██╔══██╗██╔═══██╗██╔════╝██╔════╝ + ███████╗███████║█████╗ ██║ ██║ ██║ ██║██║ ██║██║ ███████╗ + ╚════██║██╔══██║██╔══╝ ██║ ██║ ██║ ██║██║ ██║██║ ╚════██║ + ███████║██║ ██║███████╗███████╗███████╗██████╔╝╚██████╔╝╚██████╗███████║ + ╚══════╝╚═╝ ╚═╝╚══════╝╚══════╝╚══════╝╚═════╝ ╚═════╝ ╚═════╝╚══════╝ +"; + + private static int Main(string[] args) + { + var root = new RootCommand("ShellDocs — the docs framework for .NET."); + root.Subcommands.Add(CreateInitCommand()); + root.Subcommands.Add(CreateNewCommand()); + root.Subcommands.Add(CreateDevCommand()); + root.Subcommands.Add(CreateBuildCommand()); + root.Subcommands.Add(CreatePreviewCommand()); + return root.Parse(args).Invoke(); + } + + private static Command CreateInitCommand() + { + var yes = new Option("--yes") { Description = "Non-interactive mode with default options." }; + var theme = new Option("--theme") + { + Description = "Theme preset: shadcn, fuma, nextra.", + DefaultValueFactory = _ => "shadcn" + }; + var cmd = new Command("init", "Initialize ShellDocs in a Blazor WASM project — adds packages, generates content/ and Layout/, patches Program.cs.") + { + yes, theme + }; + cmd.SetAction(_ => + { + AnsiConsole.Markup($"[blue]{Logo}[/]"); + AnsiConsole.MarkupLine("[dim] the docs framework for .NET[/]"); + AnsiConsole.WriteLine(); + AnsiConsole.MarkupLine("[yellow]shelldocs init[/] — not yet implemented (feat/cli-init)."); + }); + return cmd; + } + + private static Command CreateNewCommand() + { + var kind = new Argument("kind") { Description = "Template kind: page, component-page." }; + var name = new Argument("name") { Description = "File name for the new page." }; + var cmd = new Command("new", "Scaffold a new doc page from a template.") { kind, name }; + cmd.SetAction(pr => + { + AnsiConsole.MarkupLine($"[yellow]shelldocs new {pr.GetValue(kind)} {pr.GetValue(name)}[/] — not yet implemented (feat/cli-init)."); + }); + return cmd; + } + + private static Command CreateDevCommand() + { + var port = new Option("--port") + { + Description = "Port to bind on.", + DefaultValueFactory = _ => 5000 + }; + var cmd = new Command("dev", "Start dev server with hot-reload for .razor / .cs / .md changes.") { port }; + cmd.SetAction(_ => + { + AnsiConsole.MarkupLine("[yellow]shelldocs dev[/] — not yet implemented (feat/cli-dev-build)."); + }); + return cmd; + } + + private static Command CreateBuildCommand() + { + var output = new Option("--output") + { + Description = "Output directory.", + DefaultValueFactory = _ => "publish" + }; + var cmd = new Command("build", "Produce a static site ready for GH Pages / Vercel / Netlify.") { output }; + cmd.SetAction(_ => + { + AnsiConsole.MarkupLine("[yellow]shelldocs build[/] — not yet implemented (feat/cli-dev-build)."); + }); + return cmd; + } + + private static Command CreatePreviewCommand() + { + var name = new Argument("name") { Description = "Component name to preview." }; + var cmd = new Command("preview", "Render a single component in isolation for design review.") { name }; + cmd.SetAction(pr => + { + AnsiConsole.MarkupLine($"[yellow]shelldocs preview {pr.GetValue(name)}[/] — not yet implemented."); + }); + return cmd; + } +} diff --git a/src/ShellDocs.CLI/ShellDocs.CLI.csproj b/src/ShellDocs.CLI/ShellDocs.CLI.csproj new file mode 100644 index 0000000..425e586 --- /dev/null +++ b/src/ShellDocs.CLI/ShellDocs.CLI.csproj @@ -0,0 +1,21 @@ + + + + Exe + true + true + shelldocs + ShellDocs.CLI + Global tool for ShellDocs — the docs framework for .NET. Commands: init, new, dev, build, preview. + ShellDocs.CLI + shelldocs + + + + + + + + + + diff --git a/src/ShellDocs.Components/ServiceCollectionExtensions.cs b/src/ShellDocs.Components/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..3ce46f2 --- /dev/null +++ b/src/ShellDocs.Components/ServiceCollectionExtensions.cs @@ -0,0 +1,39 @@ +using Microsoft.Extensions.DependencyInjection; +using ShellDocs.Core; + +namespace ShellDocs.Components; + +/// Registers ShellDocs services with the consumer's DI container. +/// Consumer's Program.cs calls this once — everything else is discovered by convention. +public static class ServiceCollectionExtensions +{ + public static IServiceCollection AddShellDocs( + this IServiceCollection services, + Action? configure = null) + { + var options = new ShellDocsOptions(); + configure?.Invoke(options); + services.AddSingleton(options); + + // Real service wiring lands in feat/core-navigation-graph + feat/markdown-pipeline. + // Scaffolding: keep the surface consumers will call, no implementation yet. + return services; + } +} + +/// Fluent options bag consumers configure in Program.cs. +public class ShellDocsOptions +{ + public string ContentRoot { get; set; } = "content"; + public string SiteName { get; set; } = ""; + public string? GitHubRepo { get; set; } + public bool EnableSearch { get; set; } = true; + public string SearchIndexPath { get; set; } = "search-index.json"; + public List RegisteredComponents { get; } = new(); + + public ShellDocsOptions RegisterComponent() where T : Microsoft.AspNetCore.Components.ComponentBase + { + RegisteredComponents.Add(typeof(T)); + return this; + } +} diff --git a/src/ShellDocs.Components/ShellDocs.Components.csproj b/src/ShellDocs.Components/ShellDocs.Components.csproj new file mode 100644 index 0000000..51e3192 --- /dev/null +++ b/src/ShellDocs.Components/ShellDocs.Components.csproj @@ -0,0 +1,22 @@ + + + + true + ShellDocs.Components + Blazor RCL — DocsLayout, DocsSidebar, DocsHeader, CodeBlock, SearchDialog, TableOfContents, and every other primitive that makes a ShellDocs site look sleek. + + + + + + + + + + + + + + + + diff --git a/src/ShellDocs.Components/_Imports.razor b/src/ShellDocs.Components/_Imports.razor new file mode 100644 index 0000000..612f80f --- /dev/null +++ b/src/ShellDocs.Components/_Imports.razor @@ -0,0 +1,9 @@ +@using System.Net.Http +@using System.Net.Http.Json +@using Microsoft.AspNetCore.Components +@using Microsoft.AspNetCore.Components.Forms +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using Microsoft.JSInterop +@using ShellDocs.Components +@using ShellDocs.Core diff --git a/src/ShellDocs.Components/wwwroot/shelldocs.js b/src/ShellDocs.Components/wwwroot/shelldocs.js new file mode 100644 index 0000000..3514324 --- /dev/null +++ b/src/ShellDocs.Components/wwwroot/shelldocs.js @@ -0,0 +1,9 @@ +// ShellDocs JS interop — mirrors the ShellUI pattern: +// window.ShellDocs monolith for classic consumption + ES module exports for dynamic import. +// Real implementation lands with the primitives that need JS (SearchDialog hotkey, scroll-spy, etc.) + +window.ShellDocs = window.ShellDocs || {}; + +Object.assign(window.ShellDocs, { + // Populated in Phase 1 branches. Kept here as the extension point. +}); diff --git a/src/ShellDocs.Core/NavigationNode.cs b/src/ShellDocs.Core/NavigationNode.cs new file mode 100644 index 0000000..d3cad6b --- /dev/null +++ b/src/ShellDocs.Core/NavigationNode.cs @@ -0,0 +1,17 @@ +namespace ShellDocs.Core; + +/// One page in the ShellDocs navigation graph. Built from a .md file's frontmatter + path. +public class NavigationNode +{ + public required string Url { get; init; } + public required string Title { get; init; } + public string? Description { get; init; } + public string? Category { get; init; } + public int Order { get; init; } + public string? Path { get; init; } + public IReadOnlyList Headings { get; init; } = Array.Empty(); + public NavigationNode? Parent { get; internal set; } + public IReadOnlyList Children { get; internal set; } = Array.Empty(); +} + +public record Heading(int Level, string Text, string Id); diff --git a/src/ShellDocs.Core/ShellDocs.Core.csproj b/src/ShellDocs.Core/ShellDocs.Core.csproj new file mode 100644 index 0000000..768f355 --- /dev/null +++ b/src/ShellDocs.Core/ShellDocs.Core.csproj @@ -0,0 +1,15 @@ + + + + true + ShellDocs.Core + Navigation graph, search index model, and routing helpers for ShellDocs — the docs framework for .NET. + + + + + + + + + diff --git a/src/ShellDocs.Markdown/MarkdownPipelineFactory.cs b/src/ShellDocs.Markdown/MarkdownPipelineFactory.cs new file mode 100644 index 0000000..997ee0b --- /dev/null +++ b/src/ShellDocs.Markdown/MarkdownPipelineFactory.cs @@ -0,0 +1,15 @@ +using Markdig; + +namespace ShellDocs.Markdown; + +/// Configures a Markdig pipeline with ShellDocs' custom extensions: +/// YAML frontmatter, razor:preview fenced blocks, inline Razor component tags. +public static class MarkdownPipelineFactory +{ + // Real implementation lands in feat/markdown-pipeline. This stub gets us compiling. + public static MarkdownPipeline Create() => + new MarkdownPipelineBuilder() + .UseAdvancedExtensions() + .UseYamlFrontMatter() + .Build(); +} diff --git a/src/ShellDocs.Markdown/ShellDocs.Markdown.csproj b/src/ShellDocs.Markdown/ShellDocs.Markdown.csproj new file mode 100644 index 0000000..8e517c7 --- /dev/null +++ b/src/ShellDocs.Markdown/ShellDocs.Markdown.csproj @@ -0,0 +1,15 @@ + + + + true + ShellDocs.Markdown + Markdig pipeline for ShellDocs — frontmatter parsing, razor:preview fenced blocks, inline Razor component tags. + + + + + + + + + diff --git a/src/ShellDocs.Templates/ShellDocs.Templates.csproj b/src/ShellDocs.Templates/ShellDocs.Templates.csproj new file mode 100644 index 0000000..1b97b38 --- /dev/null +++ b/src/ShellDocs.Templates/ShellDocs.Templates.csproj @@ -0,0 +1,9 @@ + + + + true + ShellDocs.Templates + Templates used by the ShellDocs CLI to scaffold new doc projects and pages. Not intended for direct consumption. + + + diff --git a/src/ShellDocs.Templates/StarterPageTemplate.cs b/src/ShellDocs.Templates/StarterPageTemplate.cs new file mode 100644 index 0000000..71f6018 --- /dev/null +++ b/src/ShellDocs.Templates/StarterPageTemplate.cs @@ -0,0 +1,17 @@ +namespace ShellDocs.Templates; + +/// Starter markdown emitted by `shelldocs new page`. +/// Real templates land alongside the CLI init/new commands. +public static class StarterPageTemplate +{ + public static string Content(string title, string description) => $$""" + --- + title: {{title}} + description: {{description}} + --- + + # {{title}} + + Start writing. + """; +} From b14a7364146c64ef6913ded3833042972e94b67f Mon Sep 17 00:00:00 2001 From: Shephard Tseisi Date: Tue, 7 Jul 2026 19:33:59 +0200 Subject: [PATCH 2/5] feat: add initial test suite for ShellDocs, including scaffolding tests for NavigationNode, MarkdownPipelineFactory, and StarterPageTemplate. Introduce project file for test project configuration and dependencies. --- tests/ShellDocs.Tests/ScaffoldingTests.cs | 35 ++++++++++++++++++++ tests/ShellDocs.Tests/ShellDocs.Tests.csproj | 21 ++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 tests/ShellDocs.Tests/ScaffoldingTests.cs create mode 100644 tests/ShellDocs.Tests/ShellDocs.Tests.csproj diff --git a/tests/ShellDocs.Tests/ScaffoldingTests.cs b/tests/ShellDocs.Tests/ScaffoldingTests.cs new file mode 100644 index 0000000..a27e6a8 --- /dev/null +++ b/tests/ShellDocs.Tests/ScaffoldingTests.cs @@ -0,0 +1,35 @@ +using ShellDocs.Core; +using ShellDocs.Markdown; +using ShellDocs.Templates; +using Xunit; + +namespace ShellDocs.Tests; + +// Smoke tests — verify each package's public surface loads and its trivial APIs behave. +// Real tests land branch-by-branch. +public class ScaffoldingTests +{ + [Fact] + public void NavigationNode_HoldsRequiredFields() + { + var node = new NavigationNode { Url = "/docs/hello", Title = "Hello" }; + Assert.Equal("/docs/hello", node.Url); + Assert.Equal("Hello", node.Title); + } + + [Fact] + public void MarkdownPipelineFactory_ProducesUsablePipeline() + { + var pipeline = MarkdownPipelineFactory.Create(); + Assert.NotNull(pipeline); + } + + [Fact] + public void StarterPageTemplate_EmitsFrontmatterAndBody() + { + var content = StarterPageTemplate.Content("Introduction", "Getting started with ShellDocs"); + Assert.Contains("title: Introduction", content); + Assert.Contains("description: Getting started with ShellDocs", content); + Assert.Contains("# Introduction", content); + } +} diff --git a/tests/ShellDocs.Tests/ShellDocs.Tests.csproj b/tests/ShellDocs.Tests/ShellDocs.Tests.csproj new file mode 100644 index 0000000..ee33a79 --- /dev/null +++ b/tests/ShellDocs.Tests/ShellDocs.Tests.csproj @@ -0,0 +1,21 @@ + + + + false + true + + + + + + + + + + + + + + + + From 82bbe7acd54294255bae90a4a5afb7ddc7850d18 Mon Sep 17 00:00:00 2001 From: Shephard Tseisi Date: Tue, 7 Jul 2026 19:34:32 +0200 Subject: [PATCH 3/5] docs: enhance README and add foundational documentation for ShellDocs, including architecture, design, and roadmap details. Introduce comprehensive descriptions of features, usage, and package structure to support developers in utilizing the framework. --- README.md | 94 ++++++++- docs/ARCHITECTURE.md | 451 +++++++++++++++++++++++++++++++++++++++++++ docs/DESIGN.md | 438 +++++++++++++++++++++++++++++++++++++++++ docs/ROADMAP.md | 327 +++++++++++++++++++++++++++++++ 4 files changed, 1308 insertions(+), 2 deletions(-) create mode 100644 docs/ARCHITECTURE.md create mode 100644 docs/DESIGN.md create mode 100644 docs/ROADMAP.md diff --git a/README.md b/README.md index 364802f..6f55a6b 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,92 @@ -# shelldocs -shelldocs framework for writing docs using shellui +# ShellDocs + +**The docs framework for .NET.** Beautiful, animated, Cmd+K-searchable documentation sites, powered by Blazor and Tailwind. Compose with ShellUI (or any Blazor component library) — like fumadocs composes with shadcn/ui. + +> Status: **`0.1.0-alpha` in progress.** Not yet published to NuGet. See [ROADMAP](docs/ROADMAP.md). + +## Why ShellDocs + +Every .NET UI library ends up hand-rolling their own docs site. MudBlazor, Radzen, AvaloniaUI — each spent months rebuilding a sidebar, a search box, a code block, a theme toggle, from scratch. None of it is reusable. + +ShellDocs is the "just use this" answer. It's the docs framework for the whole .NET ecosystem. + +- **Markdown authoring** with YAML frontmatter, inline Razor tags, and live component previews (`` ```razor:preview ``) +- **File-based routing** — drop a `.md` in `content/` and it's a page +- **Cmd+K search** with a build-time client-side index — no backend needed +- **Blazor-native** — components render as real Razor, not iframes, not screenshots +- **Composable with any Blazor component library** — ShellUI, MudBlazor, Radzen, your own +- **Tailwind CSS v4** — same aesthetic as ShellUI + shadcn, same theme tokens for interop +- **Animated** — page transitions, sidebar collapses, scroll-spy, `prefers-reduced-motion` aware +- **Static site output** — deploy to GitHub Pages, Vercel, Netlify, Cloudflare, anywhere + +## Quick start + +```bash +# Create a new Blazor WASM app +dotnet new blazorwasm -n MyDocs +cd MyDocs + +# Install the ShellDocs CLI +dotnet tool install -g ShellDocs.CLI + +# Initialize the docs site +shelldocs init + +# Author content in Markdown +shelldocs new page introduction + +# Develop with hot-reload +shelldocs dev + +# Ship it +shelldocs build +``` + +## Coexists with ShellUI (and any Blazor UI library) + +ShellDocs uses the same Tailwind v4 setup and CSS variable contract as ShellUI. Both libraries share the same theme tokens (`--background`, `--foreground`, `--primary`, `--border`, `--radius`, etc.), so you can drop them into the same page and they compose seamlessly — the fumadocs + shadcn pattern, ported to .NET. + +```razor +@* Your docs page — ShellUI components inline in Markdown *@ + +A ShellDocs callout +``` + +Under the hood ShellDocs takes a hard dependency on `ShellUI.Components` for base primitives (`Button`, `Dialog`, `Command`, `Sidebar`, etc.). Zero style clash. + +## Package family + +| Package | Purpose | +|---|---| +| [`ShellDocs.CLI`](src/ShellDocs.CLI) | Global tool — `shelldocs init`, `shelldocs new`, `shelldocs dev`, `shelldocs build` | +| [`ShellDocs.Components`](src/ShellDocs.Components) | RCL — `DocsLayout`, `DocsSidebar`, `CodeBlock`, `SearchDialog`, `TableOfContents`, etc. | +| [`ShellDocs.Markdown`](src/ShellDocs.Markdown) | Markdig pipeline — frontmatter, `razor:preview` fences, inline Razor tags | +| [`ShellDocs.Core`](src/ShellDocs.Core) | Navigation graph, search index model, routing helpers. Blazor-agnostic. | +| [`ShellDocs.Templates`](src/ShellDocs.Templates) | Content used by `ShellDocs.CLI` scaffolding | + +Optional / v2: + +- **`ShellDocs.Xml`** — extract `` from XML doc comments +- **`ShellDocs.Themes.Fuma`**, **`ShellDocs.Themes.Nextra`** — theme presets +- **`ShellDocs.OpenApi`** — OpenAPI spec → API reference pages + +## Documentation + +- [Design](docs/DESIGN.md) — what ShellDocs is, positioning, primitives, ecosystem story +- [Roadmap](docs/ROADMAP.md) — branch-by-branch implementation plan +- [Architecture](docs/ARCHITECTURE.md) — technical architecture: package boundaries, service registration, markdown pipeline, navigation graph, search index + +Once we ship `0.2.0-alpha`, official docs will live at **[shelldocs.dev](https://shelldocs.dev)** (dogfooded on ShellDocs itself). + +## Related projects + +- [ShellUI](https://github.com/shellui-dev/shellui) — the Blazor component library ShellDocs is built with +- [shellui.dev](https://github.com/shellui-dev/shellui.dev) *(coming soon)* — ShellUI's own docs site, built with ShellDocs + +## Contributing + +`0.1.0-alpha` is scaffolding-first — architecture and API surface are still moving. Once we hit `0.2.0-alpha`, we'll open up contributions with a proper `CONTRIBUTING.md`. + +## License + +[MIT](LICENSE) — do whatever you want, no warranty. diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 0000000..3538774 --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -0,0 +1,451 @@ +# ShellDocs Architecture + +Technical architecture. Consumers won't read this; contributors and future-you will. + +For high-level design see [DESIGN.md](DESIGN.md); for what ships when see [ROADMAP.md](ROADMAP.md). + +--- + +## High-level dataflow + +``` +┌────────────────────────────────────────────────────────────────────────┐ +│ Build time │ +│ │ +│ content/**/*.md ──────► ShellDocs.Markdown ──────► Rendered pages │ +│ │ (Markdig) │ │ +│ │ │ │ +│ ▼ ▼ │ +│ Frontmatter ────► NavigationGraph ────► SearchIndexBuilder │ +│ (ShellDocs.Core) (ShellDocs.Core) │ +│ │ │ +│ ▼ │ +│ search-index.json │ +│ (wwwroot/) │ +└────────────────────────────────────────────────────────────────────────┘ + +┌────────────────────────────────────────────────────────────────────────┐ +│ Runtime (browser, Blazor WASM) │ +│ │ +│ URL /docs/button │ +│ │ │ +│ ▼ │ +│ Router ──► DocsPage ──► NavigationGraph.ResolveByUrl │ +│ │ │ │ +│ │ └──► NavigationNode │ +│ │ │ +│ ▼ │ +│ MarkdownRenderer ──► MarkupString + component-slot list │ +│ │ │ +│ │ slots contain: │ +│ │ │ +│ ▼ │ +│ DynamicComponent renders each slot via TypeRegistry │ +└────────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## Package boundaries + +### `ShellDocs.Core` + +**Purpose:** framework-agnostic building blocks. Zero dependency on Blazor. + +**Public API:** +- `NavigationNode` — POCO with `Url`, `Title`, `Description`, `Category`, `Order`, `Headings`, `Path`, `Children` +- `NavigationGraph` — tree wrapper with `ResolveByUrl(string)`, `GetPrevNext(NavigationNode)`, `GetBreadcrumb(NavigationNode)`, `Flatten()` +- `NavigationGraphBuilder` — takes `contentRoot` path + `FrontmatterParser`, returns `NavigationGraph` +- `FrontmatterParser` — YamlDotNet-backed, returns `Dictionary` +- `SearchIndexEntry` — POCO for one page's search entry +- `SearchIndexBuilder` — walks `NavigationGraph` + rendered content, emits `IEnumerable` + +**Depends on:** Markdig (for AST types only — no rendering), YamlDotNet, `System.Text.Json` + +**Why separate:** static site generators, external tooling, or non-Blazor consumers could reuse the graph + index logic without pulling in Blazor. + +### `ShellDocs.Markdown` + +**Purpose:** turn `.md` files into Razor-renderable output with typed component slots. + +**Public API:** +- `MarkdownPipelineFactory` — configures a Markdig pipeline with all custom extensions +- `MarkdownRenderer` — takes markdown text or file path, returns `RenderedDocument` +- `RenderedDocument { MarkupString Html, List Slots, DocumentFrontmatter Frontmatter, List Headings }` +- `ComponentSlot { Guid Id, Type ComponentType, Dictionary Parameters, RenderFragment? ChildContent }` +- `TypeRegistry` — maps `string tagName` → `Type componentType`; consumers register their types + +**Depends on:** `ShellDocs.Core`, Markdig, YamlDotNet + +**Key design decisions:** +- **Two-pass rendering.** First pass: Markdig turns markdown into HTML + placeholder `` markers for component tags. Second pass: `MarkdownContent` component walks its own DOM (or better: uses a `RenderTreeBuilder` on the AST directly) and swaps placeholders for `` calls. +- **`razor:preview` blocks are two things.** Markdown fence with language `razor:preview` → a `` slot with two children: a live-rendered `` for the "Preview" tab and a `` for the "Code" tab. +- **Inline tags are strict.** ` +\`\`\` + +## API Reference + + + + + + +``` + +Two extensions to standard markdown: + +1. **`razor:preview` fenced blocks** — render as ``. Preview and code stay in sync automatically. + +2. **Inline component tags** — ``, ``, `` and any registered component render as real Razor via ``. Consumer registers additional component types in options: + + ```csharp + options.RegisterComponent(); + options.RegisterComponent(); + options.RegisterComponent