Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
8a3795b
feat(preview): Preview | Code toolbar with copy and ⋯ menu
Shewart Oct 2, 2026
8bce90c
fix(chrome): attach handlers immediately and restore preview tabs aft…
Shewart Oct 2, 2026
0328d00
fix(markdown): keep inline code spans literal and unmask component ch…
Shewart Oct 2, 2026
fa62b56
fix(registry): consumer components win name collisions; built-ins kee…
Shewart Oct 2, 2026
2454a62
fix(cli): scaffold ShellDocs packages at the CLI's own version
Shewart Oct 2, 2026
a846dd8
fix(chrome): JS-driven mobile nav, with a primary-nav menu on pages w…
Shewart Oct 2, 2026
a6fe6a8
fix(example): give the home feature icons a visible colour
Shewart Oct 2, 2026
657a111
fix(highlight): render Shiki output beside Blazor-owned code instead …
Shewart Oct 2, 2026
ea22f30
fix(chrome): keep the mobile header pinned above the open drawer
Shewart Oct 2, 2026
71dc7e5
fix(versions): leave version folders out of the sidebar outside a ver…
Shewart Oct 2, 2026
f5c9e5f
docs: preview toolbar, name collisions and code spans in README
Shewart Oct 2, 2026
7e77e4f
chore: bump to 0.1.9-alpha, changelog
Shewart Oct 2, 2026
dd7ed3c
fix(content): CodeGroup tabs work on static hosts
Shewart Oct 2, 2026
d8dfe2e
feat(content): Tabs/Tab primitive
Shewart Oct 2, 2026
217fa68
docs: bring README, architecture and example pages in line with the code
Shewart Oct 2, 2026
732484b
chore: bump to 0.1.9-alpha, changelog
Shewart Oct 2, 2026
595475c
Merge branch 'feat/preview-toolbar' of https://github.com/shellui-dev…
Shewart Oct 2, 2026
e11bd3e
docs: correct release steps, static export flags and component pages
Shewart Oct 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,45 @@ All notable changes to ShellDocs land here. Format follows [Keep a Changelog](ht

## [Unreleased]

## [0.1.9-alpha] — 2026-10-02

A Preview | Code toolbar for every example, fixes for chrome that reset or ignored early clicks, consumer components no longer losing to built-ins with the same name, and code spans that stay code.

### Added

- **Preview toolbar.** `PreviewFrame` (razor:preview fences, `<DemoPreview>`, `<ComponentPreview>`) has a header with **Preview | Code** tabs, a copy button, and a **⋯ menu**: *Open in new tab* (links to the example's anchor), *Report a bug* and *Suggest something* (new-issue links pre-filled with the example name and page URL). Tabs follow the WAI-ARIA pattern, including arrow keys, Home and End. It replaces the "View Code" fade overlay.
- `ShellDocsOptions.IssueTrackerUrl`: where the issue links point. Defaults to `https://github.com/{GitHubRepo}/issues/new`; the items are hidden when neither is set.
- Stable example anchors: `preview-1`, `preview-2`, … in page order, `demo-{component}`, and `example-{component}-{hash}`. `DemoPreview` takes an optional `Id`.
- `Docs{Name}` aliases for every built-in primitive (`<DocsCard>`, `<DocsCallout>`, …), always resolving to ShellDocs' own component.
- `TypeRegistry.Collisions` (`TypeCollision(TagName, Replaced, Winner)`); collisions are logged at startup.
- `DocsHeader.MobileMenu`: the primary nav as a mobile menu. `HomeLayout` turns it on.
- **`<Tabs>` / `<Tab>` content primitive.** The tab strip and every panel are server-rendered and switched by `shelldocs.js`, so they work on static hosts. Supports `DefaultValue` (by `Label` or `Value`), `SyncKey` groups that switch together and persist in `localStorage` across pages, and the WAI-ARIA keyboard pattern. Available as `<DocsTabs>` / `<DocsTab>` when a consumer library shadows the names.

### Changed

- **Your components win name collisions with built-ins.** Built-ins are now registered before consumer components. Previously ShellDocs' `Card`, `Callout`, `Steps`, … silently replaced a consumer library's component of the same name (e.g. ShellUI's `Card`). The built-in stays reachable as `<DocsCard>`, and an informational log says so. Two consumer components claiming the same tag log a warning.
- **Version folders stay out of the sidebar outside a version.** On unversioned pages the sidebar used to list every version folder (`V0.3`, `V0.2.1`, …) as collapsible sections. The version selector already covers that navigation, so they are hidden there, along with sections that hold nothing but version folders. `DocsVersionResolver.IsHiddenInSidebar(node)`.
- `ComponentPreview` renders through `PreviewFrame`, so it gets the same toolbar. Its own `.component-preview-*` markup and CSS are gone.
- The hamburger is driven by `shelldocs.js` (`[data-mobile-open]` on the page shell) instead of `MobileNavState` + `@onclick`, so the mobile drawer also works on static hosts. The backdrop, Escape, or picking a link closes it. `MobileNavState` is still registered but no longer used by the built-in chrome.
- Documentation corrected to match the code:
- README rewritten;
- ARCHITECTURE rewritten to describe what's built;
- ROADMAP marks what shipped;
- DESIGN gets a status note;
- the example site's Tabs, CodeBlock, TypeTable, ComponentPreview, Installation and Theming pages are fixed, and each primitive page has live previews.
- `shelldocs init` scaffolds packages at the CLI's own version (read from its assembly), instead of a hard-coded constant that had been stuck at `0.1.2-alpha`.

### Fixed

- **"View Code" sometimes didn't respond.** `shelldocs.js` attached its click handlers on `DOMContentLoaded`, which waits for module scripts such as the Shiki import, so early clicks on prerendered chrome were dropped. Handlers now attach as soon as the script runs.
- **Chrome state reset when the Blazor circuit started.** Interactive render replaces the prerendered DOM, so a tab picked (or a mobile menu opened) before then snapped back. The selected tab and the mobile-nav state are restored on the replacement nodes.
- **`<CodeGroup>` tabs didn't work on static hosts.** They switched through `@onclick` state. `CodeGroup` now uses the same `shelldocs.js` contract as `<Tabs>`, and `SyncKey` choices persist in `localStorage` across pages instead of per circuit. `CodeGroupSyncState` is still registered but no longer used.
- **Highlighted code went stale or threw `replaceChild` errors.** Shiki highlighting replaced Blazor-owned `<pre>` elements, so Blazor kept updating the detached originals. After client-side navigation the Code tab showed the previous page's source, and a `<pre>` already gone made the swap throw. The source `<pre>` now stays in place (hidden once highlighted) and Shiki renders into a JS-owned sibling. That output is re-rendered when the source text changes and dropped when its source goes away.
- **Inline code spans are no longer treated as components.** `` `<Button>` `` in prose stays literal code. Fences and code spans inside a component's child content are restored before that content renders, instead of leaking `SHELLDOCS_MASK_…` tokens.
- **Page content showed above the open mobile drawer.** The scroll lock set `overflow: hidden` on the page shell, which made the shell the sticky mobile bar's scroll container, so after scrolling the bar slid away from above the drawer. The lock now sits on `<html>`, and the mobile bar is exactly `--header-height` tall so the drawer and backdrop meet it with no gap.
- **Hamburger did nothing on pages without a sidebar** (e.g. the home page). It now opens the primary-nav menu.
- Example home: feature icons used the `--accent` surface token as their colour and were nearly invisible.

## [0.1.8-alpha] — 2026-10-02

Versioned docs, plus `razor:preview` fixes that let real component-library docs (ShellUI) preview what they actually write. Every new chrome interaction follows the 0.1.7 static-host pattern: server-rendered initial state, data attributes, and delegated handlers in `shelldocs.js`, with no `@onclick` state.
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

<!-- Package metadata (applies to any project with IsPackable=true) -->
<PropertyGroup>
<Version>0.1.8-alpha</Version>
<Version>0.1.9-alpha</Version>
<Authors>ShellUI</Authors>
<Company>ShellUI</Company>
<Copyright>Copyright © 2026 ShellUI</Copyright>
Expand Down
72 changes: 43 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,45 @@
# ShellDocs

**The docs framework for .NET.** Beautiful, animated, `Cmd+K`-searchable documentation sites. Powered by Blazor, styled with Tailwind-shaped design tokens, composable with any Blazor component library. The fumadocs / shadcn pattern, ported to .NET.
**The docs framework for .NET.** Markdown-driven documentation sites with live Blazor component previews, versioned docs, `Cmd+K` search, and a static export. Styled with shadcn-shaped design tokens and composable with any Blazor component library. The fumadocs / shadcn pattern, ported to .NET.

> `0.1.2-alpha` on nuget.org. See [CHANGELOG](CHANGELOG.md) and [ROADMAP](docs/ROADMAP.md). Docs at [shelldocs.dev](https://shelldocs.dev).
[![NuGet](https://img.shields.io/nuget/vpre/ShellDocs.CLI?label=ShellDocs.CLI)](https://www.nuget.org/packages/ShellDocs.CLI) — alpha: APIs may change between minor versions. See the [CHANGELOG](CHANGELOG.md) and [ROADMAP](docs/ROADMAP.md).

## Quick start

```bash
# Install the CLI (once)
dotnet tool install -g ShellDocs.CLI --prerelease

# Scaffold a site (creates docs/MyDocs.Docs/)
shelldocs init MyDocs
# From your repo root: scaffold a Blazor Web App in docs/<RepoFolder>.Docs
shelldocs init
cd docs/<RepoFolder>.Docs

# Add pages
# Add pages (or drop .md files into content/docs/)
shelldocs add component Button
shelldocs add guide getting-started

# Run with hot reload
cd docs/MyDocs.Docs
# Run with hot reload on http://localhost:5000
shelldocs dev

# Ship
shelldocs build --output publish
# Prerender a static site into publish/
shelldocs build
```

That's a working docs site. See [shelldocs.dev/docs/getting-started/quick-start](https://shelldocs.dev/docs/getting-started/quick-start) for the walkthrough.
Already have a Blazor project? Run `shelldocs init --attach` inside it: it adds the packages and content, and writes `SHELLDOCS_SETUP.md` with the `Program.cs` / `App.razor` snippets instead of editing your code.

## What you get

- **Markdown-first authoring.** YAML frontmatter, fenced code blocks with Shiki, live-rendered `razor:preview` examples, inline Razor component tags mid-prose.
- **Auto-wired navigation.** File-based routing. Drop a `.md` in `content/docs/` and it becomes a page. Sidebar, breadcrumb, prev/next, TOC — all derived from the tree.
- **`Cmd+K` search.** Client-side substring scoring against title, description, section, and body text. Snippet extraction for body-only hits. Zero backend, zero external service.
- **Blazor-native.** Components render as real Razor. Full JS interop, hot reload, all the tooling you already have.
- **Composable.** Bring your own component library (ShellUI, MudBlazor, Radzen, hand-rolled). One-line assembly-scan registration:
- **Markdown-first authoring.** YAML frontmatter, Shiki-highlighted code fences, live `razor:preview` examples, inline component tags mid-prose.
- **File-based navigation.** Drop a `.md` in `content/docs/` and it's a page. Sidebar, breadcrumb, prev/next and TOC come from the folder tree; `meta.json` controls order, dividers, subsections and hidden pages.
- **`Cmd+K` search** across titles, headings and page text, with body snippets. The index is built in memory at startup, so there's no external service; search needs a running Blazor app (it isn't available in the static export).
- **Blazor-native.** Your components render as real Razor components, not iframes.
- **Composable.** Bring your own component library (ShellUI, MudBlazor, Radzen, hand-rolled) and register it in one line:
```csharp
o.RegisterComponentsFromAssembly<MyLib.Button>();
```
- **Static site output.** `shelldocs build` produces static HTML ready for GitHub Pages, Vercel, Netlify, Cloudflare, anywhere. Base-href rewrite + SPA 404 fallback included.
Your components win name collisions with ShellDocs' built-ins, which stay available as `<DocsCard>`, `<DocsCallout>`, `<DocsTabs>`, and so on.
- **Content primitives.** `Callout`, `Card` / `CardGrid` / `LinkCard`, `Steps`, `FileTree`, `Tabs`, `CodeGroup`, `TypeTable` / `AutoTypeTable`, `ComponentPreview`, `DemoPreview`.
- **Static export.** `shelldocs build` prerenders every page to static HTML for GitHub Pages, Cloudflare Pages, Netlify or S3. Optional flags rewrite `<base href>` (`--base-href`), add a SPA `404.html` (`--spa-fallback`), and write sitemap / robots / `og:` meta (`--site-url`). Navigation, sidebar sections, the mobile menu, selectors, tabs, preview toolbars, the TOC and code copy work there through `shelldocs.js`. Search, the theme-toggle button, desktop sidebar collapse and stateful demos need a running Blazor app.

## Versioned docs

Expand All @@ -51,16 +53,26 @@ o.AddVersion("v0.2.1", "v0.2.1", "/docs/v0.2.1", "Previous release");
o.AddPackage("shellui.cli", "ShellUI.CLI", "Command line", "/docs/{version}/cli", icon);
```

The current version is the one whose `RootUrl` prefixes the path (segment-aware), otherwise the `latest` one. With 2+ versions a `<VersionSelector />` renders under the package selector (and in the mobile drawer; in the `TopNav` layout it sits in the header). Switching versions keeps the same page when it exists, else the current package's root, else the version's first page. Switching packages keeps the version. Inside a version the sidebar shows only that version's tree, prev/next never crosses into another version, search shows the current version plus pages outside every version, and the version folder is left out of the breadcrumb. Everything is server-rendered `<a href>`s plus `shelldocs.js` delegation, so it works on static hosts.
The current version is the one whose `RootUrl` prefixes the path (segment-aware), otherwise the `latest` one. With 2+ versions a `<VersionSelector />` renders under the package selector (and in the mobile drawer; in the `TopNav` layout it sits in the header).

- **Switching versions** keeps the same page when it exists, else the current package's root, else the version's first page.
- **Switching packages** keeps the version.
- **Inside a version**, the sidebar shows only that version's tree, prev/next never crosses into another version, and search shows the current version plus pages outside every version.
- **Outside a version**, the sidebar leaves the version folders to the selector.
- **Breadcrumbs** leave out the version folder.

It's all server-rendered links plus `shelldocs.js`, so it works on static hosts.

> Routes declared as `/docs/{*Path:nonfile}` don't match a URL whose **last** segment has a dot (`/docs/v0.2.1`). Pages below it (`/docs/v0.2.1/introduction`) are fine, and the selectors never link to a bare version root unless it has an `index.md`. If you add one, drop `:nonfile` from the route.

## Component previews

- **`razor:preview` fences render everything** — several sibling components, HTML wrappers (`<div class="flex gap-2">…</div>`) and text, in order, inside one frame. The source tab shows the whole fence.
- **Preview | Code toolbar on every example**, with copy and a ⋯ menu: *Open in new tab*, *Report a bug*, *Suggest something*. The issue links go to `https://github.com/{GitHubRepo}/issues/new`, pre-filled with the example and page URL; point them elsewhere with `o.IssueTrackerUrl`.
- **`razor:preview` fences render everything.** Several sibling components, HTML wrappers (`<div class="flex gap-2">…</div>`) and text render in order inside one frame, and the Code tab shows the whole fence.
- **Razor-shaped attribute values work:** `Variant="ButtonVariant.Destructive"`, `@ButtonVariant.Destructive`, `@true`, `@42`, `[Flags]` values as `Bold | Italic`.
- **Attributes a static preview can't evaluate are skipped, not fatal:** `OnClick="HandleClick"`, `@onclick`, `@bind-*`, `@ref`, non-primitive parameter types, unparseable values. Each logs a warning and the component still renders.
- **Stateful demos from real files.** For demos that need `@code` (dialogs, bound selects, toasts, charts with data), write a `.razor` component, register it, and drop `<DemoPreview Component="ButtonClickDemo" Title="Optional" />` into markdown. The source tab shows `{DemoSourceRoot}/**/ButtonClickDemo.razor`:
- **Inline code stays code.** `` `<Button>` `` in prose renders as literal code, not a component.
- **Stateful demos from real files.** For demos that need `@code` (dialogs, bound selects, toasts, charts with data), write a `.razor` component, register it, and drop `<DemoPreview Component="ButtonClickDemo" Title="Optional" />` into markdown. The Code tab shows `{DemoSourceRoot}/**/ButtonClickDemo.razor`:

```csharp
o.RegisterComponentsFromAssembly<App>("MyDocs.Demos");
Expand All @@ -77,20 +89,22 @@ The current version is the one whose `RootUrl` prefixes the path (segment-aware)

| Package | Purpose |
|---|---|
| [`ShellDocs.CLI`](src/ShellDocs.CLI) | Global tool. `shelldocs init`, `add`, `dev`, `build` |
| [`ShellDocs.Components`](src/ShellDocs.Components) | RCL. Chrome (layout, sidebar, header, search, version/package selectors) + content primitives (Callout, Card, Steps, CodeGroup, FileTree, TypeTable, ComponentPreview, DemoPreview). Icons via [ShellIcons.Blazor](https://www.nuget.org/packages/ShellIcons.Blazor) |
| [`ShellDocs.Markdown`](src/ShellDocs.Markdown) | Markdig pipeline. Frontmatter parser, `razor:preview` fence extractor, inline Razor tag extractor, per-property type coercion |
| [`ShellDocs.Core`](src/ShellDocs.Core) | Navigation graph, search index, plain-text extraction. No UI |
| [`ShellDocs.Tokens`](src/ShellDocs.Tokens) | Design-system CSS variables. shadcn-compatible names for interop with ShellUI and Tailwind-shaped design systems |
| [`ShellDocs.Templates`](src/ShellDocs.Templates) | Starter markdown + Program.cs snippets emitted by `shelldocs init` |
| [`ShellDocs.CLI`](src/ShellDocs.CLI) | Global tool: `shelldocs init`, `add`, `dev`, `build` |
| [`ShellDocs.Components`](src/ShellDocs.Components) | Razor class library: layouts and chrome (sidebar, header, search, TOC, version / package selectors) and the content primitives. Icons via [ShellIcons.Blazor](https://www.nuget.org/packages/ShellIcons.Blazor) |
| [`ShellDocs.Markdown`](src/ShellDocs.Markdown) | Markdig pipeline: frontmatter, `razor:preview` fences, inline component tags, the type registry |
| [`ShellDocs.Core`](src/ShellDocs.Core) | Navigation graph, `meta.json`, search index, URL helpers. No UI |
| [`ShellDocs.Tokens`](src/ShellDocs.Tokens) | Design-token CSS variables, shadcn-compatible names for interop with ShellUI and Tailwind-shaped design systems |
| [`ShellDocs.Templates`](src/ShellDocs.Templates) | Files and snippets emitted by `shelldocs init` and `shelldocs add` |

## Docs

- [shelldocs.dev](https://shelldocs.dev) : full documentation site (built with ShellDocs itself)
- [docs/DESIGN.md](docs/DESIGN.md) : product positioning, primitive inventory, ecosystem story
- [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) : package boundaries, service registration, markdown pipeline, navigation graph, search
- [docs/ROADMAP.md](docs/ROADMAP.md) : branch-by-branch delivery plan
- [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) : how it works: packages, pipeline, rendering, navigation, search, client-side chrome, CLI
- [docs/TOKENS.md](docs/TOKENS.md) : the design-token contract and how to override it
- [docs/DESIGN.md](docs/DESIGN.md) : original product design and positioning
- [docs/ROADMAP.md](docs/ROADMAP.md) : branch-by-branch plan and what has shipped
- [docs/RELEASING.md](docs/RELEASING.md) : how a maintainer cuts a NuGet release (Trusted Publishing)
- [examples/ShellDocs.Preview](examples/ShellDocs.Preview) : the example site used for development, with versions, previews and demos

## Related

Expand All @@ -99,7 +113,7 @@ The current version is the one whose `RootUrl` prefixes the path (segment-aware)

## Contributing

The alpha is API-fluid : we're taking freedom to break minor versions until `1.0`. Bug reports and dogfood-driven fixes welcome via issues. A proper `CONTRIBUTING.md` lands with the `0.2.0-alpha` cut.
The alpha is API-fluid: we're taking freedom to break minor versions until `1.0`. Bug reports and dogfood-driven fixes are welcome via issues. A proper `CONTRIBUTING.md` lands with the `0.2.0-alpha` cut.

## License

Expand Down
Loading
Loading