From bd917a2b2c60d7855e260dd2bcee26342484bcfa Mon Sep 17 00:00:00 2001 From: Paul Gottschling Date: Tue, 6 Aug 2024 11:54:56 -0400 Subject: [PATCH 1/2] Fix sidebar generation and display logic This change fixes two issues that prevented auto-generated sidebar entries from appearing as highlighted in the sidebar when a user visits them: 1. The sidebar generator assumes that the table of contents page for a subsection can *either* be at the same level as its corresponding subdirectory *or* within that subdirectory. Currently, placing a page at both locations causes an unexpected reuslt. This change throws an error if a page exists at both locations. 2. The navigation component currently assumes that a docs page's slug begins with the slug of its parent menu page. However, this is not true if the menu page is within its corresponding directory. E.g., the sidebar generator treats `docs/pages/directory/directory/` as a valid slug for the menu page of `docs/pages/directory/`, but the navigation component would not show `docs/pages/directory/page1` as highlighted in that case. This change resolves this issue by recursively descending through an entry to determine whether one of its entries is highlighted, rather than using the URL path alone. --- layouts/DocsPage/Navigation.stories.tsx | 4 ++++ layouts/DocsPage/Navigation.tsx | 24 +++++++++++++++++++++--- server/pages-helpers.ts | 11 +++++++++-- uvu-tests/config-docs.test.ts | 25 +++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 5 deletions(-) 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..76de31196d 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,20 @@ const DocsNavigationItems = ({ ); }; +// hasChildEntry recursively descends through entry to determine if it or one of +// its children has the provided slug. +function hasChildEntry(entry: NavigationCategory, slug: string) { + if (entry.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(); From a53439e2497fac27ae98c0435fe4f3ede9d331c9 Mon Sep 17 00:00:00 2001 From: Paul Gottschling Date: Wed, 28 Aug 2024 17:02:45 -0400 Subject: [PATCH 2/2] Fix types --- layouts/DocsPage/Navigation.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/layouts/DocsPage/Navigation.tsx b/layouts/DocsPage/Navigation.tsx index 76de31196d..b753628e54 100644 --- a/layouts/DocsPage/Navigation.tsx +++ b/layouts/DocsPage/Navigation.tsx @@ -90,8 +90,12 @@ const DocsNavigationItems = ({ // hasChildEntry recursively descends through entry to determine if it or one of // its children has the provided slug. -function hasChildEntry(entry: NavigationCategory, slug: string) { - if (entry.slug === slug) { +function hasChildEntry( + entry: NavigationCategory | NavigationItem, + slug: string +) { + const item = entry as NavigationItem; + if (item.slug && item.slug === slug) { return true; } if (!entry.entries) {