diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..6cb76f4 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,37 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + workflow_dispatch: + +jobs: + build-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: global.json + + - name: Restore + run: dotnet restore shelldocs.slnx + + - name: Build + run: dotnet build shelldocs.slnx --configuration Release --no-restore + + - name: Test + run: dotnet test shelldocs.slnx --configuration Release --no-build --verbosity normal + + # Smoke test: verify the CLI packs cleanly as a global tool + - name: Pack CLI + run: dotnet pack src/ShellDocs.CLI --configuration Release --output nupkgs + + - name: Verify CLI installs + runs + run: | + dotnet tool install --global --add-source ./nupkgs ShellDocs.CLI --prerelease + shelldocs --help diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..266d540 --- /dev/null +++ b/.gitignore @@ -0,0 +1,63 @@ +# .NET build output +[Bb]in/ +[Oo]bj/ +[Rr]elease/ +[Dd]ebug/ +*.user +*.suo +*.userosscache +*.sln.docstates +*.dll +*.pdb +*.exe +*.cache + +# NuGet +*.nupkg +*.snupkg +project.lock.json +project.assets.json +packages/ +!.nuget/packages/ +.nuget/ + +# Test results +[Tt]est[Rr]esult*/ +[Cc]overage*/ + +# IDE +.vs/ +.vscode/ +.idea/ +*.swp +*.swo + +# JetBrains Rider +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# OS +.DS_Store +Thumbs.db + +# Node (for Tailwind CLI + Shiki) +node_modules/ +package-lock.json +yarn.lock +pnpm-lock.yaml + +# ShellDocs — local build artifacts +publish/ +dist/ +.shelldocs/ +*.shellui-classes-generated + +# Environment +.env +.env.* +!.env.example + +# Logs +*.log +logs/ diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..6e9259b --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,46 @@ + + + + net10.0 + latest + enable + enable + false + Nullable + true + $(NoWarn);CS1591 + + + + + true + + + + + ShellUI + ShellUI + Copyright © 2026 ShellUI + MIT + https://github.com/shellui-dev/shelldocs + https://github.com/shellui-dev/shelldocs + git + blazor;docs;documentation;framework;shellui;shadcn;fumadocs;tailwind + README.md + true + snupkg + true + true + + + + + false + + + + + + + + diff --git a/Directory.Packages.props b/Directory.Packages.props new file mode 100644 index 0000000..b1efe97 --- /dev/null +++ b/Directory.Packages.props @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a70742b --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 ShellUI + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. 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