diff --git a/layouts/DocsPage/Navigation.stories.tsx b/layouts/DocsPage/Navigation.stories.tsx index cd3e40fc91..441e3d3194 100644 --- a/layouts/DocsPage/Navigation.stories.tsx +++ b/layouts/DocsPage/Navigation.stories.tsx @@ -22,6 +22,10 @@ export const NavigationFourLevels = () => { title: "Deploy Machine ID on AWS", slug: "/enroll-resources/machine-id/deployment/aws/", }, + { + title: "General Deployment Tips", + slug: "/enroll-resources/machine-id/deployment/deployment/", + }, ], }, ], diff --git a/layouts/DocsPage/Navigation.tsx b/layouts/DocsPage/Navigation.tsx index 4de84d9678..b753628e54 100644 --- a/layouts/DocsPage/Navigation.tsx +++ b/layouts/DocsPage/Navigation.tsx @@ -12,6 +12,7 @@ import { } from "./types"; import styles from "./Navigation.module.css"; import { useVersionAgnosticPages } from "utils/useVersionAgnosticPages"; +import { dirname } from "path"; const SCOPELESS_HREF_REGEX = /\?|\#/; @@ -45,10 +46,13 @@ const DocsNavigationItems = ({ <> {!!entries.length && entries.map((entry) => { + // Determine whether to highlight the entry in the navigation sidebar. + // We highlight an entry if: + // - It is the currently selected entry. + // - One of its entries is either the currently selected entry or the + // parent of the currently selected entry. const selected = entry.slug === docPath; - const active = - selected || - entry.entries?.some((entry) => docPath.startsWith(entry.slug)); + const active = hasChildEntry(entry, docPath); return (
  • @@ -84,6 +88,24 @@ const DocsNavigationItems = ({ ); }; +// hasChildEntry recursively descends through entry to determine if it or one of +// its children has the provided slug. +function hasChildEntry( + entry: NavigationCategory | NavigationItem, + slug: string +) { + const item = entry as NavigationItem; + if (item.slug && item.slug === slug) { + return true; + } + if (!entry.entries) { + return false; + } + return entry.entries.some((e) => { + return hasChildEntry(e, slug); + }); +} + interface DocNavigationCategoryProps extends NavigationCategory { id: number; opened: boolean; diff --git a/server/pages-helpers.ts b/server/pages-helpers.ts index 88f68f6f6e..d982716981 100644 --- a/server/pages-helpers.ts +++ b/server/pages-helpers.ts @@ -98,11 +98,18 @@ const categoryPagePathForDir = (fs, dirPath) => { const outerCategoryPage = join(dirname(dirPath), name + ".mdx"); const innerCategoryPage = join(dirPath, name + ".mdx"); + const outerExists = fs.existsSync(outerCategoryPage); + const innerExists = fs.existsSync(innerCategoryPage); - if (fs.existsSync(outerCategoryPage)) { + if (outerExists && innerExists) { + throw new Error( + `cannot generate the docs navigation sidebar due to an ambiguous category page: must have a page named ${outerCategoryPage} or ${innerCategoryPage}, not not both` + ); + } + if (outerExists) { return outerCategoryPage; } - if (fs.existsSync(innerCategoryPage)) { + if (innerExists) { return innerCategoryPage; } throw new Error( diff --git a/uvu-tests/config-docs.test.ts b/uvu-tests/config-docs.test.ts index b7272875d6..54524d8b5b 100644 --- a/uvu-tests/config-docs.test.ts +++ b/uvu-tests/config-docs.test.ts @@ -434,4 +434,29 @@ title: Database Access Deployment Guides assert.equal(actual, expected); }); +Suite("page named after directory at two possible dir levels", () => { + const files = { + "/docs/pages/database-access/deployment/deployment.mdx": `--- +title: Database Access Deployment Guides +---`, + "/docs/pages/database-access/deployment.mdx": `--- +title: Deploying the Database Service +---`, + "/docs/pages/database-access/deployment/kubernetex.mdx": `--- +title: Deploying the Database Service on Kubernetes +---`, + }; + + const vol = Volume.fromJSON(files); + const fs = createFsFromVolume(vol); + assert.throws( + () => { + const actual = generateNavPaths(fs, "/docs/pages/database-access"); + console.log(actual); + }, + "database-access/deployment/deployment.mdx", + "database-access/deployment.mdx" + ); +}); + Suite.run();