From 72d612537a64d32cfcbed058b869baef0ec1aebc Mon Sep 17 00:00:00 2001 From: aeei <18022843+aeei@users.noreply.github.com> Date: Tue, 21 Jul 2026 15:30:13 +0900 Subject: [PATCH 1/5] fix(theme): restore Mermaid prose spacing --- README.md | 2 +- packages/docusaurus-theme/package.json | 4 ++-- packages/docusaurus-theme/src/package-contract.test.ts | 4 ++-- packages/docusaurus-theme/src/theme/base.scss | 1 + .../docusaurus-theme/src/theme/mermaid-contract.test.ts | 6 ++++++ 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 2e3317dc6..f32c7ec23 100644 --- a/README.md +++ b/README.md @@ -172,7 +172,7 @@ Requirements: Consumers then install a pinned release: ```bash -npm install @aeei/docusaurus-theme@0.1.5 +npm install @aeei/docusaurus-theme@0.1.6 ``` This repository does not publish automatically from an unapproved working tree. diff --git a/packages/docusaurus-theme/package.json b/packages/docusaurus-theme/package.json index c23eb9e88..48b1ff237 100644 --- a/packages/docusaurus-theme/package.json +++ b/packages/docusaurus-theme/package.json @@ -1,6 +1,6 @@ { "name": "@aeei/docusaurus-theme", - "version": "0.1.5", + "version": "0.1.6", "description": "A shadcn Base Nova theme for Docusaurus docs.", "license": "MIT", "keywords": [ @@ -16,7 +16,7 @@ }, "repository": { "type": "git", - "url": "https://github.com/aeei/docusaurus-theme.git", + "url": "git+https://github.com/aeei/docusaurus-theme.git", "directory": "packages/docusaurus-theme" }, "bugs": { diff --git a/packages/docusaurus-theme/src/package-contract.test.ts b/packages/docusaurus-theme/src/package-contract.test.ts index 6746ccdd9..d42420220 100644 --- a/packages/docusaurus-theme/src/package-contract.test.ts +++ b/packages/docusaurus-theme/src/package-contract.test.ts @@ -19,13 +19,13 @@ it("uses the public docs-only package identity and metadata", () => { const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf8")); expect(packageJson.name).toBe("@aeei/docusaurus-theme"); - expect(packageJson.version).toBe("0.1.5"); + expect(packageJson.version).toBe("0.1.6"); expect(packageJson.description).toBe( "A shadcn Base Nova theme for Docusaurus docs." ); expect(packageJson.repository).toEqual({ type: "git", - url: "https://github.com/aeei/docusaurus-theme.git", + url: "git+https://github.com/aeei/docusaurus-theme.git", directory: "packages/docusaurus-theme", }); expect(packageJson.bugs).toEqual({ diff --git a/packages/docusaurus-theme/src/theme/base.scss b/packages/docusaurus-theme/src/theme/base.scss index 9dd975561..f08fa69df 100644 --- a/packages/docusaurus-theme/src/theme/base.scss +++ b/packages/docusaurus-theme/src/theme/base.scss @@ -1717,6 +1717,7 @@ a[class*="skipToContent"]:focus { } .theme-doc-markdown .docusaurus-mermaid-container { + margin-block-start: var(--typeset-flow); display: flex; justify-content: safe center; overflow-x: auto; diff --git a/packages/docusaurus-theme/src/theme/mermaid-contract.test.ts b/packages/docusaurus-theme/src/theme/mermaid-contract.test.ts index 9398376da..ac8f91d8f 100644 --- a/packages/docusaurus-theme/src/theme/mermaid-contract.test.ts +++ b/packages/docusaurus-theme/src/theme/mermaid-contract.test.ts @@ -23,6 +23,12 @@ describe("Mermaid ownership contract", () => { ); }); + it("keeps Mermaid diagrams in the article flow rhythm", () => { + expect(stylesheet).toMatch( + /\.theme-doc-markdown \.docusaurus-mermaid-container\s*\{[^}]*margin-block-start: var\(--typeset-flow\);[^}]*\}/ + ); + }); + it("keeps wide actual-route diagrams readable in a horizontal scroll surface", () => { expect(stylesheet).toMatch( /\.docusaurus-mermaid-container\s*\{[\s\S]*justify-content: safe center;[\s\S]*overflow-x: auto;/ From c8feb071160936f46d1f9060ca711481e278ad9f Mon Sep 17 00:00:00 2001 From: aeei <18022843+aeei@users.noreply.github.com> Date: Wed, 22 Jul 2026 00:16:08 +0900 Subject: [PATCH 2/5] fix(theme): align TOC inline code styling --- .../docs-starter/docs/guides/markdown-gfm.md | 4 +++ .../src/theme/TOCItems/Tree.tsx | 6 +++- packages/docusaurus-theme/src/theme/base.scss | 19 +++++------ .../docusaurus-theme/src/theme/base.test.ts | 4 ++- .../src/theme/prose-contract.test.ts | 21 ++++++++++++ tests/theme-parity.spec.ts | 34 +++++++++++++++++++ 6 files changed, 76 insertions(+), 12 deletions(-) diff --git a/examples/docs-starter/docs/guides/markdown-gfm.md b/examples/docs-starter/docs/guides/markdown-gfm.md index 14e976028..dec3aa272 100644 --- a/examples/docs-starter/docs/guides/markdown-gfm.md +++ b/examples/docs-starter/docs/guides/markdown-gfm.md @@ -10,6 +10,10 @@ This page exercises standard Markdown, GFM, and Docusaurus docs conventions. ## Table of contents depth +### Inline code heading `provider-id` + +This heading verifies that table-of-contents code uses the canonical inline code surface. + ### Link targets Jump to [paragraph flow](#paragraph-flow-and-emphasis), [lists](#lists-and-tasks), [tables](#tables), or [details](#details-and-admonitions). diff --git a/packages/docusaurus-theme/src/theme/TOCItems/Tree.tsx b/packages/docusaurus-theme/src/theme/TOCItems/Tree.tsx index 36e56dbd8..96d1417dc 100644 --- a/packages/docusaurus-theme/src/theme/TOCItems/Tree.tsx +++ b/packages/docusaurus-theme/src/theme/TOCItems/Tree.tsx @@ -13,7 +13,11 @@ function HeadingLabel({ html }: { html: string }): React.JSX.Element { const code = part.match(codeContentPattern); if (code) { return ( - + ); } diff --git a/packages/docusaurus-theme/src/theme/base.scss b/packages/docusaurus-theme/src/theme/base.scss index f08fa69df..bf4125ffe 100644 --- a/packages/docusaurus-theme/src/theme/base.scss +++ b/packages/docusaurus-theme/src/theme/base.scss @@ -69,6 +69,8 @@ --theme-leading-sm: 1.25rem; --theme-text-xs: 0.75rem; --theme-leading-xs: 1rem; + --theme-prose-body-size: 0.9375rem; + --theme-prose-leading: 1.75; --theme-backdrop-blur: 12px; } @@ -508,9 +510,9 @@ a[class*="skipToContent"]:focus { --typeset-font-body: inherit; --typeset-font-heading: var(--ifm-heading-font-family); --typeset-font-mono: var(--ifm-font-family-monospace); - --typeset-size: 0.9375rem; + --typeset-size: var(--theme-prose-body-size); --typeset-body-size: var(--typeset-size); - --typeset-leading: 1.75; + --typeset-leading: var(--theme-prose-leading); --typeset-flow: 1.25em; --typeset-muted: var(--muted-foreground); --typeset-rule: var(--border); @@ -1147,9 +1149,11 @@ a[class*="skipToContent"]:focus { border-radius: min(calc(var(--radius) * 0.6), 0.35em); background-color: var(--muted); color: inherit; - font-family: var(--typeset-font-mono); - font-size: calc(var(--typeset-body-size) * 0.85); - line-height: var(--typeset-leading); + font-family: var(--typeset-font-mono, var(--ifm-font-family-monospace)); + font-size: calc( + var(--typeset-body-size, var(--theme-prose-body-size)) * 0.85 + ); + line-height: var(--typeset-leading, var(--theme-prose-leading)); padding: 0.125em 0.3em; } @@ -1778,11 +1782,6 @@ a[class*="skipToContent"]:focus { transition: color 150ms ease; } -.table-of-contents__link code { - font-size: inherit; - line-height: inherit; -} - .table-of-contents__link[data-depth="3"] { padding-left: calc(var(--spacing) * 4); } diff --git a/packages/docusaurus-theme/src/theme/base.test.ts b/packages/docusaurus-theme/src/theme/base.test.ts index ba1aedd86..f0059d085 100644 --- a/packages/docusaurus-theme/src/theme/base.test.ts +++ b/packages/docusaurus-theme/src/theme/base.test.ts @@ -22,7 +22,9 @@ it("leaves component focus visuals to official primitives", () => { }); it("keeps article prose size stable across responsive widths", () => { - expect(stylesheet).toContain("--typeset-size: 0.9375rem;"); + expect(stylesheet).toContain("--theme-prose-body-size: 0.9375rem;"); + expect(stylesheet).toContain("--theme-prose-leading: 1.75;"); + expect(stylesheet).toContain("--typeset-size: var(--theme-prose-body-size);"); expect(stylesheet).toContain("--typeset-flow: 1.25em;"); expect(stylesheet).toContain("--typeset-body-size: var(--typeset-size);"); expect(stylesheet).toContain("font-size: var(--typeset-body-size);"); diff --git a/packages/docusaurus-theme/src/theme/prose-contract.test.ts b/packages/docusaurus-theme/src/theme/prose-contract.test.ts index df4495f9d..665bdae1a 100644 --- a/packages/docusaurus-theme/src/theme/prose-contract.test.ts +++ b/packages/docusaurus-theme/src/theme/prose-contract.test.ts @@ -49,6 +49,27 @@ describe("prose ownership contract", () => { expect(stylesheet).not.toContain(":where(:not(pre) > code)"); }); + it("reuses canonical inline code styling in table-of-contents labels", () => { + const tocTree = fs.readFileSync( + path.join(__dirname, "TOCItems/Tree.tsx"), + "utf8" + ); + + expect(tocTree).toContain('className="theme-code-inline"'); + expect(stylesheet).not.toContain(".table-of-contents__link code {"); + expect(stylesheet).toContain("--theme-prose-body-size: 0.9375rem;"); + expect(stylesheet).toContain("--theme-prose-leading: 1.75;"); + expect(stylesheet).toContain( + "var(--typeset-font-mono, var(--ifm-font-family-monospace))" + ); + expect(stylesheet).toContain( + "var(--typeset-body-size, var(--theme-prose-body-size))" + ); + expect(stylesheet).toContain( + "var(--typeset-leading, var(--theme-prose-leading))" + ); + }); + it("keeps heading hash links on the official inherit contract", () => { expect(canonicalStylesheet).toContain( canonicalize(`${localBoundary}:where(:is(h1, h2, h3, h4, h5, h6) :is(a))`) diff --git a/tests/theme-parity.spec.ts b/tests/theme-parity.spec.ts index 6dfd82cd6..c28f38d26 100644 --- a/tests/theme-parity.spec.ts +++ b/tests/theme-parity.spec.ts @@ -804,6 +804,40 @@ test("inline code keeps one component-owned surface inside Details", async ({ } }); +test("table-of-contents code reuses the canonical inline code surface", async ({ + page, +}) => { + await page.setViewportSize({ width: 1440, height: 900 }); + await page.goto(markdownRoute); + + const metrics = await page.evaluate(() => { + const content = Array.from( + document.querySelectorAll(".theme-doc-markdown h3 code") + ).find((element) => element.textContent === "provider-id"); + const toc = Array.from( + document.querySelectorAll(".table-of-contents__link code") + ).find((element) => element.textContent === "provider-id"); + const read = (element?: Element) => { + if (!element) return null; + const style = getComputedStyle(element); + return { + className: element.className, + fontFamily: style.fontFamily, + fontSize: style.fontSize, + lineHeight: style.lineHeight, + padding: style.padding, + borderRadius: style.borderRadius, + backgroundColor: style.backgroundColor, + }; + }; + return { content: read(content), toc: read(toc) }; + }); + + expect(metrics.content).not.toBeNull(); + expect(metrics.toc).toEqual(metrics.content); + expect(metrics.toc?.className).toContain("theme-code-inline"); +}); + test("CodeBlock matches the official shadcn docs surface", async ({ page }) => { await page.setViewportSize({ width: 390, height: 900 }); await page.goto(markdownRoute); From 153283b70f4f65f2a435a5b480b0877756a0805b Mon Sep 17 00:00:00 2001 From: aeei <18022843+aeei@users.noreply.github.com> Date: Wed, 22 Jul 2026 00:16:08 +0900 Subject: [PATCH 3/5] fix(theme): filter doc metadata from navbar links --- .../src/theme/Navbar/Content/index.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/docusaurus-theme/src/theme/Navbar/Content/index.tsx b/packages/docusaurus-theme/src/theme/Navbar/Content/index.tsx index 3903a992f..df7178074 100644 --- a/packages/docusaurus-theme/src/theme/Navbar/Content/index.tsx +++ b/packages/docusaurus-theme/src/theme/Navbar/Content/index.tsx @@ -74,8 +74,12 @@ function NavbarNavigationMenuDocItem({ }: { item: NavigationItemConfig; }): ReactNode { - const { activeDoc } = useActiveDocContext(item.docsPluginId); - const doc = useLayoutDoc(item.docId!, item.docsPluginId); + const { docId, docsPluginId, label, ...navLinkProps } = item; + delete navLinkProps.type; + delete navLinkProps.items; + + const { activeDoc } = useActiveDocContext(docsPluginId); + const doc = useLayoutDoc(docId!, docsPluginId); const pageActive = activeDoc?.path === doc?.path; if (doc === null || (doc.unlisted && !pageActive)) return null; @@ -86,10 +90,10 @@ function NavbarNavigationMenuDocItem({ className={navigationMenuTriggerStyle()} render={ pageActive || (!!activeDoc?.sidebar && activeDoc.sidebar === doc.sidebar) From 68b8c14cfc11eae594d7c0571a1307d829b09aba Mon Sep 17 00:00:00 2001 From: aeei <18022843+aeei@users.noreply.github.com> Date: Wed, 22 Jul 2026 00:16:09 +0900 Subject: [PATCH 4/5] chore(theme): release 0.1.7 --- README.md | 2 +- packages/docusaurus-theme/package.json | 2 +- packages/docusaurus-theme/src/package-contract.test.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f32c7ec23..fb5b3edbf 100644 --- a/README.md +++ b/README.md @@ -172,7 +172,7 @@ Requirements: Consumers then install a pinned release: ```bash -npm install @aeei/docusaurus-theme@0.1.6 +npm install @aeei/docusaurus-theme@0.1.7 ``` This repository does not publish automatically from an unapproved working tree. diff --git a/packages/docusaurus-theme/package.json b/packages/docusaurus-theme/package.json index 48b1ff237..dea1d58cc 100644 --- a/packages/docusaurus-theme/package.json +++ b/packages/docusaurus-theme/package.json @@ -1,6 +1,6 @@ { "name": "@aeei/docusaurus-theme", - "version": "0.1.6", + "version": "0.1.7", "description": "A shadcn Base Nova theme for Docusaurus docs.", "license": "MIT", "keywords": [ diff --git a/packages/docusaurus-theme/src/package-contract.test.ts b/packages/docusaurus-theme/src/package-contract.test.ts index d42420220..3326f2899 100644 --- a/packages/docusaurus-theme/src/package-contract.test.ts +++ b/packages/docusaurus-theme/src/package-contract.test.ts @@ -19,7 +19,7 @@ it("uses the public docs-only package identity and metadata", () => { const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf8")); expect(packageJson.name).toBe("@aeei/docusaurus-theme"); - expect(packageJson.version).toBe("0.1.6"); + expect(packageJson.version).toBe("0.1.7"); expect(packageJson.description).toBe( "A shadcn Base Nova theme for Docusaurus docs." ); From a6d0afbee13a50069a3cf1267e34a3b966cb789c Mon Sep 17 00:00:00 2001 From: aeei <18022843+aeei@users.noreply.github.com> Date: Wed, 22 Jul 2026 01:05:50 +0900 Subject: [PATCH 5/5] test(theme): align audits with sticky sidebar --- scripts/audit-critical-ui-relations.cjs | 10 ++++------ scripts/audit-docs-starter.cjs | 25 +++++++++++++------------ 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/scripts/audit-critical-ui-relations.cjs b/scripts/audit-critical-ui-relations.cjs index 70ddec5da..25ba001bf 100644 --- a/scripts/audit-critical-ui-relations.cjs +++ b/scripts/audit-critical-ui-relations.cjs @@ -193,9 +193,7 @@ async function openPage(browser, width, route = "showcase/mdx-playground") { backgroundColor: navbarBlur.backgroundColor, }, toc: { - headerOutsideScroll: Boolean( - tocHeader && tocScroll && !tocScroll.contains(tocHeader) - ), + headerAbsent: !tocHeader, scrollFade: fadeActive(tocScroll), }, }; @@ -203,7 +201,7 @@ async function openPage(browser, width, route = "showcase/mdx-playground") { await page.evaluate(() => scrollTo(0, document.documentElement.scrollHeight)); await page.waitForTimeout(50); const sidebarFooterBoundary = await page.evaluate(() => { - const sidebar = document.querySelector(".theme-doc-sidebar-container"); + const sidebar = document.querySelector(".theme-doc-sidebar-desktop"); const sidebarFooter = sidebar?.querySelector( '[data-slot="sidebar-footer"]' ); @@ -335,10 +333,10 @@ async function openPage(browser, width, route = "showcase/mdx-playground") { ); expect( desktopSurface.sidebarScrollFade === true && - desktopSurface.toc.headerOutsideScroll === true && + desktopSurface.toc.headerAbsent === true && desktopSurface.toc.scrollFade === true && mobileSurface.sidebarScrollFade === true, - "LNB and TOC scroll viewports must use scroll-fade while the TOC header remains fixed", + "LNB and TOC scroll viewports must use scroll-fade without restoring the removed TOC header", { desktopSurface, mobileSurface } ); expect( diff --git a/scripts/audit-docs-starter.cjs b/scripts/audit-docs-starter.cjs index 2b90aa4f7..ed2416302 100644 --- a/scripts/audit-docs-starter.cjs +++ b/scripts/audit-docs-starter.cjs @@ -155,7 +155,7 @@ async function auditRoute(page, viewport, theme, route) { }); const desktopSidebar = document.querySelector( - '[data-slot="sidebar-container"]' + ".theme-doc-sidebar-desktop" ); const mobileTrigger = document.querySelector( "[data-mobile-navigation-trigger]" @@ -163,7 +163,7 @@ async function auditRoute(page, viewport, theme, route) { const responsiveFailure = viewportName === "desktop" ? !desktopSidebar || - getComputedStyle(desktopSidebar).position !== "fixed" || + getComputedStyle(desktopSidebar).position !== "sticky" || mobileTrigger?.getBoundingClientRect().width : !!desktopSidebar?.getBoundingClientRect().width || !mobileTrigger?.getBoundingClientRect().width; @@ -252,20 +252,21 @@ async function auditDesktopInteractions(page, theme) { window.scrollTo(0, document.documentElement.scrollHeight) ); await page.waitForTimeout(100); - const sidebarContainer = await visible( - page, - '[data-slot="sidebar-container"]' - ); - const sidebarRect = await sidebarContainer.boundingBox(); + const desktopSidebar = await visible(page, ".theme-doc-sidebar-desktop"); + const sidebarRect = await desktopSidebar.boundingBox(); const sidebarFooter = await visible(page, '[data-slot="sidebar-footer"]'); - const footerRect = await sidebarFooter.boundingBox(); + const sidebarFooterRect = await sidebarFooter.boundingBox(); + const pageFooter = await visible(page, ".theme-layout-footer"); + const pageFooterRect = await pageFooter.boundingBox(); if ( !sidebarRect || - !footerRect || - sidebarRect.y < 40 || - footerRect.y + footerRect.height > 901 + !sidebarFooterRect || + !pageFooterRect || + sidebarRect.y < -1 || + sidebarRect.y + sidebarRect.height > pageFooterRect.y + 1 || + sidebarFooterRect.y + sidebarFooterRect.height > pageFooterRect.y + 1 ) { - throw new Error("fixed Sidebar/footer scroll state failed"); + throw new Error("sticky Sidebar/footer boundary failed"); } const themeTrigger = page.getByRole("button", { name: /^Color theme:/ });