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();