diff --git a/CHANGELOG.md b/CHANGELOG.md index d90b8d5..a2ffc2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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, ``, ``) 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 (``, ``, …), 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. +- **`` / `` 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 `` / `` 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 ``, 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. +- **`` tabs didn't work on static hosts.** They switched through `@onclick` state. `CodeGroup` now uses the same `shelldocs.js` contract as ``, 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 `
` elements, so Blazor kept updating the detached originals. After client-side navigation the Code tab showed the previous page's source, and a `
` already gone made the swap throw. The source `
` 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.** `` `
         
             
@@ -92,16 +87,33 @@
             }
         
     
+    @if (MobileMenu && Options.PrimaryNav.Count > 0)
+    {
+        
+    }
 
 
-@implements IDisposable
-
 @code {
     // HomeLayout hides search and the version selector on marketing pages.
     [Parameter] public bool ShowSearch { get; set; } = true;
     [Parameter] public bool ShowVersionSelector { get; set; } = true;
-
-    protected override void OnInitialized() => MobileNav.OnChange += StateHasChanged;
-    public void Dispose() => MobileNav.OnChange -= StateHasChanged;
+    // Layouts without a sidebar drawer render the primary nav as a mobile menu.
+    [Parameter] public bool MobileMenu { get; set; }
     private Task OpenSearch() => JS.InvokeVoidAsync("shelldocsSearch.open").AsTask();
 }
diff --git a/src/ShellDocs.Components/Chrome/DocsHeader.razor.css b/src/ShellDocs.Components/Chrome/DocsHeader.razor.css
index 255bf0e..78f87c7 100644
--- a/src/ShellDocs.Components/Chrome/DocsHeader.razor.css
+++ b/src/ShellDocs.Components/Chrome/DocsHeader.razor.css
@@ -40,6 +40,46 @@
 @media (min-width: 1024px) {
     .docs-header-hamburger { display: none; }
 }
+.docs-header-hamburger ::deep .mobile-nav-icon-close { display: none; }
+[data-mobile-open="true"] .docs-header-hamburger ::deep .mobile-nav-icon-open { display: none; }
+[data-mobile-open="true"] .docs-header-hamburger ::deep .mobile-nav-icon-close { display: block; }
+
+/* Mobile primary-nav menu (layouts without a sidebar drawer). */
+.docs-header-mobile-menu {
+    display: none;
+    position: absolute;
+    top: 100%;
+    left: 0;
+    right: 0;
+    flex-direction: column;
+    gap: 0.1rem;
+    padding: 0.5rem 1rem 1rem;
+    background: var(--background);
+    border-bottom: 1px solid var(--border);
+    box-shadow: 0 16px 32px -16px rgb(0 0 0 / 0.25);
+}
+[data-mobile-open="true"] .docs-header-mobile-menu { display: flex; }
+@media (min-width: 1024px) {
+    [data-mobile-open="true"] .docs-header-mobile-menu { display: none; }
+}
+.docs-header-mobile-group {
+    padding: 0.75rem 0.5rem 0.25rem;
+    font-size: 0.75rem;
+    font-weight: 600;
+    color: var(--muted-foreground);
+    text-transform: uppercase;
+    letter-spacing: 0.04em;
+}
+.docs-header-mobile-link {
+    padding: 0.55rem 0.5rem;
+    border-radius: calc(var(--radius) - 3px);
+    color: var(--foreground);
+    font-size: 0.9375rem;
+    font-weight: 500;
+    text-decoration: none;
+}
+.docs-header-mobile-link.nested { padding-left: 1rem; font-weight: 400; }
+.docs-header-mobile-link:hover { background: var(--muted); }
 
 .docs-header-brand {
     display: inline-flex;
diff --git a/src/ShellDocs.Components/Chrome/DocsMobileBar.razor b/src/ShellDocs.Components/Chrome/DocsMobileBar.razor
index 0007399..4745806 100644
--- a/src/ShellDocs.Components/Chrome/DocsMobileBar.razor
+++ b/src/ShellDocs.Components/Chrome/DocsMobileBar.razor
@@ -1,17 +1,10 @@
 @using ShellIcons.Icons
-@inject MobileNavState MobileNav
 @inject IJSRuntime JS
 
 
     
- @foreach (var tab in _tabs) + @for (var i = 0; i < _tabs.Count; i++) { - var isActive = tab.Label == _active; -