From 0dec0c853281dfe2f5fb5f66245f177beb9cf899 Mon Sep 17 00:00:00 2001 From: Shephard Tseisi Date: Sat, 22 Aug 2026 20:01:23 +0200 Subject: [PATCH 1/5] feat: enhance ShellDocsOptions with namespace-based component registration; improve error handling in PreviewFrame and add error styling --- .../Chrome/DocsSidebar.razor.css | 6 +-- .../Content/PreviewFrame.razor | 23 ++++++++-- .../Content/PreviewFrame.razor.css | 44 +++++++++++++++++++ .../Layouts/DocsLayout.razor.css | 15 +++---- src/ShellDocs.Components/ShellDocsOptions.cs | 18 ++++++++ 5 files changed, 90 insertions(+), 16 deletions(-) diff --git a/src/ShellDocs.Components/Chrome/DocsSidebar.razor.css b/src/ShellDocs.Components/Chrome/DocsSidebar.razor.css index 36c3d2d..ef8627f 100644 --- a/src/ShellDocs.Components/Chrome/DocsSidebar.razor.css +++ b/src/ShellDocs.Components/Chrome/DocsSidebar.razor.css @@ -1,11 +1,7 @@ .docs-sidebar { display: flex; flex-direction: column; - /* No `height: 100%` — the parent .docs-sidebar-slot in the sidebar-variant - layout already sizes us via `flex: 1; min-height: 0`. Adding height: 100% - fights that: it makes this nav match the WHOLE slot height (header - included), which pushes the footer (theme + gh links) past the visible - area whenever the tree gets tall enough to scroll. */ + flex: 1; min-height: 0; font-size: 0.8125rem; padding: 0.85rem 0.75rem 0 1rem; diff --git a/src/ShellDocs.Components/Content/PreviewFrame.razor b/src/ShellDocs.Components/Content/PreviewFrame.razor index 5f8d2ae..201fd5d 100644 --- a/src/ShellDocs.Components/Content/PreviewFrame.razor +++ b/src/ShellDocs.Components/Content/PreviewFrame.razor @@ -4,8 +4,22 @@
- + @if (Preview!.ComponentType is not null) + { + + } + else + { + + + }
@Preview!.Code
@@ -72,6 +86,9 @@ [Inject] private IJSRuntime JS { get; set; } = default!; + /* Only called from the render-region branch guarded by + `Preview!.ComponentType is not null`, so the ! here is a safe assertion + — never dereferenced when the tag was unknown. */ private IDictionary BuildParameters(IReadOnlyDictionary attrs, string? childContentRaw) => - SlotRenderer.BuildParameters(Renderer, Preview!.ComponentType, attrs, childContentRaw); + SlotRenderer.BuildParameters(Renderer, Preview!.ComponentType!, attrs, childContentRaw); } diff --git a/src/ShellDocs.Components/Content/PreviewFrame.razor.css b/src/ShellDocs.Components/Content/PreviewFrame.razor.css index 54e9a49..dc28a68 100644 --- a/src/ShellDocs.Components/Content/PreviewFrame.razor.css +++ b/src/ShellDocs.Components/Content/PreviewFrame.razor.css @@ -21,6 +21,50 @@ transparent 1px, transparent 8px); } +.preview-error { + display: flex; + align-items: flex-start; + gap: 0.85rem; + max-width: 44rem; + padding: 1rem 1.15rem; + background: color-mix(in oklch, var(--error, oklch(0.637 0.237 25.331)) 12%, var(--card)); + border: 1px solid color-mix(in oklch, var(--error, oklch(0.637 0.237 25.331)) 35%, var(--border)); + border-radius: calc(var(--radius) - 2px); + color: var(--foreground); + text-align: left; +} +.preview-error-icon { + width: 1.15rem; + height: 1.15rem; + flex-shrink: 0; + color: var(--error, oklch(0.637 0.237 25.331)); + margin-top: 0.1rem; +} +.preview-error-body { + display: flex; + flex-direction: column; + gap: 0.25rem; + min-width: 0; +} +.preview-error-title { + font-size: 0.8125rem; + font-weight: 600; + letter-spacing: -0.005em; +} +.preview-error-message { + font-size: 0.8125rem; + color: var(--muted-foreground); + line-height: 1.5; + word-break: break-word; +} +.preview-error-message code { + font-family: var(--font-mono); + font-size: 0.78rem; + background: color-mix(in oklch, var(--foreground) 8%, transparent); + padding: 0.05rem 0.3rem; + border-radius: 3px; +} + .preview-code-wrap { position: relative; border-top: 1px solid var(--border); diff --git a/src/ShellDocs.Components/Layouts/DocsLayout.razor.css b/src/ShellDocs.Components/Layouts/DocsLayout.razor.css index 4d48a68..3f4fe1a 100644 --- a/src/ShellDocs.Components/Layouts/DocsLayout.razor.css +++ b/src/ShellDocs.Components/Layouts/DocsLayout.razor.css @@ -43,6 +43,8 @@ transform: translateX(-100%); transition: transform 260ms cubic-bezier(0.16, 1, 0.3, 1); z-index: 45; + display: flex; + flex-direction: column; } .docs-sidebar-slot.open { transform: translateX(0); @@ -133,10 +135,10 @@ max-width: 1500px; grid-template-columns: var(--sidebar-width) 1fr; } - /* Sidebar = the floating card */ + /* Sidebar = the floating card. `display: flex; flex-direction: column` + already comes from the base .docs-sidebar-slot rule — we only override + the card chrome + positioning here. */ .docs-shell-sidebar .docs-sidebar-slot { - display: flex; - flex-direction: column; position: sticky; top: 0.85rem; height: calc(100vh - 1.85rem); @@ -147,11 +149,8 @@ margin-right: 0; overflow: hidden; } - /* DocsSidebar's own