diff --git a/.changeset/base-aware-starter-navigation.md b/.changeset/base-aware-starter-navigation.md new file mode 100644 index 00000000..6916d98b --- /dev/null +++ b/.changeset/base-aware-starter-navigation.md @@ -0,0 +1,6 @@ +--- +"@cloudflare/nimbus-docs": patch +"@cloudflare/create-nimbus-docs": patch +--- + +Keep framework assets and starter navigation working when an Astro site is deployed under a sub-path. diff --git a/packages/nimbus-docs/src/components/NimbusHead.astro b/packages/nimbus-docs/src/components/NimbusHead.astro index c2564c29..c4ddf28c 100644 --- a/packages/nimbus-docs/src/components/NimbusHead.astro +++ b/packages/nimbus-docs/src/components/NimbusHead.astro @@ -165,7 +165,7 @@ const ogType = isHomePage ? "website" : "article"; // Favicon precedence: svg > ico > png. The first file that exists wins; // when none exists we still emit the svg link so users who drop one in // later don't need to touch the layout. -const faviconHref = `${import.meta.env.BASE_URL}${headDefaults.favicon.file}`; +const faviconHref = withBase(headDefaults.favicon.file, baseUrl); const faviconType = headDefaults.favicon.type; // Social image precedence: page prop > config > `public/opengraph.png` > @@ -205,7 +205,7 @@ const structuredData = canonical // Per-HTML last-element-wins semantics: page extras come after config // extras so per-page overrides win for any duplicated single-value tag. const mergedHead = [...(config.head ?? []), ...pageHead]; -const shikiCssHref = `${import.meta.env.BASE_URL}_nimbus/shiki.css${import.meta.env.DEV ? `?v=${Date.now()}` : ""}`; +const shikiCssHref = `${withBase("/_nimbus/shiki.css", baseUrl)}${import.meta.env.DEV ? `?v=${Date.now()}` : ""}`; --- {fullTitle} diff --git a/packages/nimbus-docs/test/subpath-template-contract.test.ts b/packages/nimbus-docs/test/subpath-template-contract.test.ts new file mode 100644 index 00000000..2860aa86 --- /dev/null +++ b/packages/nimbus-docs/test/subpath-template-contract.test.ts @@ -0,0 +1,69 @@ +import assert from "node:assert/strict"; +import { readFileSync } from "node:fs"; +import { test } from "node:test"; +import { fileURLToPath } from "node:url"; +import path from "node:path"; + +const repoRoot = path.resolve( + fileURLToPath(new URL("../../..", import.meta.url)), +); + +function source(relativePath: string): string { + return readFileSync(path.join(repoRoot, relativePath), "utf8"); +} + +test("framework and starter-owned navigation apply Astro's base path", () => { + const head = source("packages/nimbus-docs/src/components/NimbusHead.astro"); + assert.match( + head, + /const faviconHref = withBase\(headDefaults\.favicon\.file, baseUrl\);/, + ); + assert.match(head, /withBase\("\/_nimbus\/shiki\.css", baseUrl\)/); + + const starterRoot = "packages/nimbus-starter-source/src"; + const header = source(`${starterRoot}/components/Header.astro`); + assert.match( + header, + /const homeHref = withBase\("\/", import\.meta\.env\.BASE_URL\);/, + ); + assert.match(header, /href=\{homeHref\}/); + assert.match( + header, + /href=\{withBase\(section\.href, import\.meta\.env\.BASE_URL\)\}/, + ); + + const sidebarLink = source( + `${starterRoot}/components/ui/sidebar/SidebarLink.astro`, + ); + assert.match( + sidebarLink, + /const hrefWithBase = withBase\(href, import\.meta\.env\.BASE_URL\);/, + ); + assert.match(sidebarLink, /href=\{hrefWithBase\}/); + + const breadcrumbs = source( + `${starterRoot}/components/ui/breadcrumbs/Breadcrumbs.astro`, + ); + assert.match(breadcrumbs, /href=\{hrefWithBase\(crumb\.href\)\}/); + + const pagination = source( + `${starterRoot}/components/ui/pagination/Pagination.astro`, + ); + assert.match( + pagination, + /const prevHref = prev && withBase\(prev\.href, import\.meta\.env\.BASE_URL\);/, + ); + assert.match( + pagination, + /const nextHref = next && withBase\(next\.href, import\.meta\.env\.BASE_URL\);/, + ); + + assert.match( + source(`${starterRoot}/layouts/DocsLayout.astro`), + /const homeHref = withBase\("\/", import\.meta\.env\.BASE_URL\);/, + ); + assert.match( + source(`${starterRoot}/pages/404.astro`), + /const homeHref = withBase\("\/", import\.meta\.env\.BASE_URL\);/, + ); +}); diff --git a/packages/nimbus-starter-source/src/components/Header.astro b/packages/nimbus-starter-source/src/components/Header.astro index 33d2bf15..4b622c3d 100644 --- a/packages/nimbus-starter-source/src/components/Header.astro +++ b/packages/nimbus-starter-source/src/components/Header.astro @@ -6,7 +6,7 @@ import { LinkButton } from "./ui/link-button"; import { ThemeToggle } from "./ui/theme-toggle"; import SearchTrigger from "./ui/search/SearchTrigger.astro"; import { config } from "virtual:nimbus/config"; -import { getSidebarSections } from "@cloudflare/nimbus-docs/runtime"; +import { getSidebarSections, withBase } from "@cloudflare/nimbus-docs/runtime"; interface Props { /** Astro collection id for the current page, forwarded from DocsLayout. */ @@ -32,13 +32,14 @@ const currentSlug = Astro.url.pathname.replace(/\/$/, "") || "/"; const sections = sectionsProp ?? (await getSidebarSections(currentSlug, { collection })); const showSections = sections.length >= 2; +const homeHref = withBase("/", import.meta.env.BASE_URL); ---
- + {config.title} @@ -49,7 +50,7 @@ const showSections = sections.length >= 2;