You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 67df229
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: CHANGELOG.md
+17Lines changed: 17 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,6 +4,23 @@ All notable changes to ShellDocs land here. Format follows [Keep a Changelog](ht
4
4
5
5
## [Unreleased]
6
6
7
+
### Added
8
+
9
+
-**Preview layout.**`razor:preview stretch` (fence info string), or `Layout="stretch"` on `<DemoPreview>` / `<ComponentPreview>` / `PreviewFrame`, lets block-level components (charts, inputs, tables) fill the frame instead of shrinking to their content. `center` stays the default.
10
+
-**`not-prose` class.** Every `.shelldocs-prose` rule skips `.not-prose` subtrees. Preview frames carry it; add it to any element that should keep page typography out.
11
+
12
+
### Changed
13
+
14
+
-**`razor:preview` child content is parsed as Razor, not markdown.** Component bodies inside a fence (and `<ComponentPreview>` bodies) go through the same node parser as the fence itself: elements wrap nested components exactly as written and nothing is wrapped in `<p>`. Inline component tags in prose still take markdown bodies.
15
+
-**`ThemeToggle` works without a Blazor runtime.** Clicks are handled by `shelldocs.js` and both icons render, with CSS picking one from `<html class="dark">`.
16
+
17
+
### Fixed
18
+
19
+
-**Prose styles leaked into previews.** Paragraph margins, list padding, heading sizes and link underlines from `.shelldocs-prose` hit live components and beat Tailwind's layered utilities (gaps inside cards and menus, underlined nav links).
20
+
-**Nested markup inside a preview component was mangled.**`<Navbar><div><a/>…<ThemeToggle/></div></Navbar>` closed the `<div>` before the nested component and wrapped loose text in `<p>`.
21
+
-**Theme state only followed ShellDocs' own toggle.** A component library flipping `<html class="dark">` left the stored theme and `ThemeState` stale. `shelldocs.js` now watches the class, saves it under `shelldocs-theme` and pushes it into `ThemeState`.
22
+
-**`enhancedload` handlers never ran.** Blazor raises the event through `Blazor.addEventListener`, not as a DOM event, so re-applying the theme, re-attaching the TOC and closing the mobile nav after enhanced navigation (static SSR apps) silently did nothing.
23
+
7
24
## [0.1.9-alpha] — 2026-10-02
8
25
9
26
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.
-**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.
42
+
-**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`. So does the themetoggle. Search, desktop sidebar collapse and stateful demos need a running Blazor app.
43
43
44
44
## Versioned docs
45
45
@@ -69,6 +69,9 @@ It's all server-rendered links plus `shelldocs.js`, so it works on static hosts.
69
69
70
70
-**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`.
71
71
-**`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.
72
+
-**Child content is Razor.** Component bodies inside a fence are parsed like the fence itself, so `<Navbar><div>…<ThemeToggle /></div></Navbar>` keeps its structure and nothing is wrapped in `<p>`.
73
+
-**Page typography stays out.** Preview frames are `not-prose`, so prose margins, list padding and link underlines don't reach your components.
74
+
-**Centred or stretched.** Examples are centred; `razor:preview stretch` (or `Layout="stretch"` on `<DemoPreview>` / `<ComponentPreview>`) lets charts, inputs and tables fill the frame.
-**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.
74
77
-**Inline code stays code.**`` `<Button>` `` in prose renders as literal code, not a component.
Copy file name to clipboardExpand all lines: docs/ARCHITECTURE.md
+7-5Lines changed: 7 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -112,7 +112,7 @@ Placeholders plus a slot list keep everything at render time: no generated Razor
112
112
113
113
### `razor:preview` fences
114
114
115
-
`PreviewParser` turns the fence into ordered nodes: component nodes (registered capitalised tags; their children kept raw), element nodes (HTML, including unregistered capitalised tags) and text. `@code { }` / `@functions { }` blocks, `@* *@` comments and directive lines (`@using`, `@inject`, …) are skipped for rendering but stay in the Code tab. If no registered component is found the slot carries an `Error`, rendered as a red panel instead of a silent code block.
115
+
`PreviewParser` turns the fence into ordered nodes: component nodes (registered capitalised tags; their children kept raw and parsed the same way, as Razor, when the component renders), element nodes (HTML, including unregistered capitalised tags) and text. `@code { }` / `@functions { }` blocks, `@* *@` comments and directive lines (`@using`, `@inject`, …) are skipped for rendering but stay in the Code tab. If no registered component is found the slot carries an `Error`, rendered as a red panel instead of a silent code block. `razor:preview stretch` in the info string sets `PreviewSlot.Layout`.
116
116
117
117
---
118
118
@@ -124,11 +124,11 @@ Placeholders plus a slot list keep everything at render time: no generated Razor
124
124
-`ComponentSlot` → `<DynamicComponent>` with parameters from `SlotRenderer.BuildParameters`.
125
125
-`PreviewSlot` → `<PreviewFrame Id="preview-N">`, where `SlotRenderer.RenderNodes` emits elements and components as real render-tree nodes, so wrappers keep their children under interactive re-renders.
126
126
127
-
Component child markup is rendered recursively by `SlotRenderer.FromMarkup` (dedented first, since Markdig treats 4-space indentation as a code block). Child tags named after a `RenderFragment` parameter (`<Icon>` → `Alert.Icon`) are routed into that slot.
127
+
Component child markup is rendered recursively. Inline tags in prose take markdown bodies (`SlotRenderer.FromMarkup`, dedented first, since Markdig treats 4-space indentation as a code block). Inside a `razor:preview` and in `<ComponentPreview>` the body is Razor: `SlotRenderer.FromRazor` parses it with `PreviewParser` and emits real elements, so wrappers around nested components stay intact. Child tags named after a `RenderFragment` parameter (`<Icon>` → `Alert.Icon`) are routed into that slot.
128
128
129
129
**Parameter coercion.** Attribute values are strings. `BuildParameters` matches them to `[Parameter]` properties case-insensitively and coerces string, bool, char, numeric primitives and enums, accepting Razor forms: a leading `@`, `@( … )`, `Type.Member` enum values, `A | B` flags, numeric suffixes, `@null`. It never throws. Anything static markup can't set is skipped with a logged warning: directive attributes, delegate/`EventCallback` parameters, unsupported types, unparseable values, unknown attributes on components without a `CaptureUnmatchedValues` catch-all, and child content on components without a plain `RenderFragment ChildContent`.
130
130
131
-
**`PreviewFrame`** is the frame for every example: a toolbar with Preview | Code tabs, copy and a ⋯ menu (*Open in new tab* → the example's anchor; *Report a bug* / *Suggest something* → new-issue links built by `PreviewLinks` from `IssueTrackerUrl` or `GitHubRepo`). `ComponentPreview` and `DemoPreview` feed it a ready-made `Content` fragment and `Code` string instead of a `PreviewSlot`. `DemoPreview` reads its source from the first `{DemoSourceRoot}/**/X.razor` (shallowest path wins, cached, re-read when the file changes).
131
+
**`PreviewFrame`** is the frame for every example. It carries `not-prose` (every `.shelldocs-prose` rule skips `.not-prose` subtrees) and a `Layout` of `center` or `stretch`. It has a toolbar with Preview | Code tabs, copy and a ⋯ menu (*Open in new tab* → the example's anchor; *Report a bug* / *Suggest something* → new-issue links built by `PreviewLinks` from `IssueTrackerUrl` or `GitHubRepo`). `ComponentPreview` and `DemoPreview` feed it a ready-made `Content` fragment and `Code` string instead of a `PreviewSlot`. `DemoPreview` reads its source from the first `{DemoSourceRoot}/**/X.razor` (shallowest path wins, cached, re-read when the file changes).
132
132
133
133
**`DocsPageState`** (scoped) is fed by `MarkdownContent` and recomputes current node, prev/next and breadcrumbs on navigation, so the layout chrome needs no per-page wiring.
134
134
@@ -195,9 +195,11 @@ Chrome that must work without a Blazor runtime follows one contract:
195
195
| Tabs, CodeGroup |`[data-tabs]`, `[data-tab-target]`, `[data-tab-panel]`| switch on click / arrows; `[data-tabs-sync]` groups switch together and persist in `localStorage`|
196
196
| Mobile nav | page shell `[data-mobile-open]`| hamburger toggles; backdrop, Escape, link or navigation closes; page scroll locked on `<html>`|
197
197
| TOC |`[data-toc-list][data-toc-ids]`| IntersectionObserver scroll-spy, re-attached on `enhancedload`|
198
-
| Theme |`<html class="dark">`| inline head script applies the saved / system theme; re-applied after enhanced navigation |
198
+
| Theme |`<html class="dark">`, `[data-theme-toggle]`| inline head script applies the saved / system theme; the toggle flips the class and CSS picks its icon; a `MutationObserver` saves any change (including another library's toggle) and pushes it to `ThemeState`; re-applied after enhanced navigation |
199
199
200
-
Still Blazor-only: search, the `ThemeToggle` button, the desktop sidebar-collapse button.
200
+
Still Blazor-only: search, the desktop sidebar-collapse button.
201
+
202
+
`enhancedload` is a Blazor event (`Blazor.addEventListener`), not a DOM event; `shelldocsOnEnhancedLoad(fn)` attaches once `blazor.web.js` has run.
201
203
202
204
**Syntax highlighting.** Shiki (loaded by the app as `window.__shiki`) never replaces Blazor-owned nodes: the source `<pre>` gets `data-shiki="source"` (hidden by CSS) and the highlighted output goes into a JS-owned `[data-shiki-output]` sibling, re-rendered when the source text changes and removed when its source is gone.
Copy file name to clipboardExpand all lines: examples/ShellDocs.Preview/content/docs/components/component-preview.md
+2-1Lines changed: 2 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -23,7 +23,8 @@ Body content that becomes the Callout's ChildContent.
23
23
24
24
-`Component` — required. The registered tag name (`"Callout"`, `"Card"`, `"LinkCard"`, …). Resolved through the same registry as `razor:preview`, so anything `AddShellDocs` or your `RegisterComponent*` calls register works.
25
25
- Any other attribute — forwarded to the target. Values are strings in markdown and are coerced to each parameter's type (`bool`, numbers, enums including `Type.Member` and `A | B` flags). Attributes that can't be set this way are skipped with a logged warning.
26
-
- The tag body becomes the target's `ChildContent`.
26
+
-`Layout` — `"center"` (default) or `"stretch"`, which lets block-level components fill the frame's width.
27
+
- The tag body is parsed as Razor (HTML and registered components, no markdown) and becomes the target's `ChildContent`. Child tags named after one of the target's `RenderFragment` parameters fill that slot.
Copy file name to clipboardExpand all lines: examples/ShellDocs.Preview/content/docs/installation.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -55,4 +55,4 @@ shelldocs build
55
55
-`--spa-fallback` copies `index.html` to `404.html`.
56
56
-`--site-url https://docs.example.com` emits `sitemap.xml`, `robots.txt` and `og:` meta tags.
57
57
58
-
In the static output, navigation, sidebar sections, the mobile menu, the version and package selectors, tabs, preview tabs and menus, the table of contentsand code copy all work through `shelldocs.js`. Search, the theme toggle, the desktop sidebar-collapse button and stateful demo components still need a running Blazor app (Server or WebAssembly).
58
+
In the static output, navigation, sidebar sections, the mobile menu, the version and package selectors, tabs, preview tabs and menus, the table of contents, the theme toggle and code copy all work through `shelldocs.js`. Search, the desktop sidebar-collapse button and stateful demo components still need a running Blazor app (Server or WebAssembly).
Copy file name to clipboardExpand all lines: examples/ShellDocs.Preview/content/docs/markdown-syntax.md
+22Lines changed: 22 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -50,3 +50,25 @@ A code fence with the info string `razor:preview` renders live in a preview fram
50
50
```
51
51
52
52
Attribute values accept Razor forms such as `Variant="ButtonVariant.Destructive"`, `@true` and `[Flags]` values like `Bold | Italic`. Attributes a static preview can't evaluate (`OnClick="Handler"`, `@bind-*`, `@ref`) are skipped with a logged warning. For demos that need `@code`, see `<DemoPreview>` in the README.
53
+
54
+
### Child content is Razor
55
+
56
+
Inside a fence, component bodies are Razor markup, not markdown. Elements wrap nested components exactly as written, and nothing is wrapped in `<p>`:
Inline component tags in prose (outside a fence) still take markdown bodies.
65
+
66
+
### Layout
67
+
68
+
Examples are centred. Add `stretch` to the info string (`razor:preview stretch`) so block-level components such as charts, inputs and tables fill the frame's width. `<DemoPreview>` and `<ComponentPreview>` take `Layout="stretch"`.
69
+
70
+
```razor:preview stretch
71
+
<Callout Variant="info" Text="This callout fills the frame instead of shrinking to its text." />
72
+
```
73
+
74
+
Preview frames are marked `not-prose`, so the page's typography (paragraph margins, list padding, link underlines) never reaches the components inside. Add the class to any other element that should opt out.
Copy file name to clipboardExpand all lines: examples/ShellDocs.Preview/content/docs/theming.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -26,4 +26,4 @@ Override any of these in a stylesheet loaded after `tokens.css` and every compon
26
26
27
27
## Dark mode
28
28
29
-
Dark mode is the `dark` class on `<html>`. The `ThemeToggle` in the header / sidebar footer saves the choice in `localStorage` and falls back to `prefers-color-scheme` on the first visit; an inline script in `App.razor` applies it before first paint. The toggle button itself needs a running Blazor app; on a static build the saved or system preference still applies.
29
+
Dark mode is the `dark` class on `<html>`. The `ThemeToggle` in the header / sidebar footer saves the choice in `localStorage` and falls back to `prefers-color-scheme` on the first visit; an inline script in `App.razor` applies it before first paint. The toggle is handled by `shelldocs.js`, so it works on static builds too. Whatever flips the class, including a component library's own theme toggle, is saved the same way, so the choice sticks across pages.
0 commit comments