From 88653af3d898ece76d39fc78c71cd42f9dd048cd Mon Sep 17 00:00:00 2001 From: "Charles Graham, SWT" Date: Mon, 11 May 2026 12:40:41 -0700 Subject: [PATCH] Fix duplicated docs hash links --- src/App.jsx | 5 ++--- src/app-url.js | 29 +++++++++++++++++++++++++++++ src/app-url.test.js | 31 +++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 src/app-url.js create mode 100644 src/app-url.test.js diff --git a/src/App.jsx b/src/App.jsx index 762d28e..4b847e7 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -3,6 +3,7 @@ import { getNavHelper } from "internal-nav-helper"; import { useConnect } from "redux-bundler-hook"; import links from "./nav-links"; import { FaGithub } from "react-icons/fa"; +import { normalizeUrlForHash } from "./app-url"; const version = import.meta.env.PKG_VERSION; const BASE_URL = import.meta.env.BASE_URL; @@ -38,9 +39,7 @@ function App() { return (
{ - // Remove BASE_URL# before it is added again by the navhelper so it can be included in the hrefs for copy url purposes - url = url.replace(`${BASE_URL}#`, ""); - doUpdateHash(url); + doUpdateHash(normalizeUrlForHash(url, BASE_URL)); })} > = 0) { + // Internal hash links are already pointing at the target route, so keep + // only the path after "#". + return url.slice(hashIndex + 1) || "/"; + } + + let basePath = "/"; + try { + basePath = new URL(baseUrl, "http://localhost").pathname; + } catch { + basePath = "/"; + } + + const normalizedBasePath = `/${basePath.replace(/^\/+|\/+$/g, "")}/`; + if (normalizedBasePath !== "//" && url.startsWith(normalizedBasePath)) { + // Same-origin links without a hash still need the deploy subpath removed + // before they are handed to doUpdateHash. + return url.slice(normalizedBasePath.length - 1) || "/"; + } + + return url; +} diff --git a/src/app-url.test.js b/src/app-url.test.js new file mode 100644 index 0000000..61ef49a --- /dev/null +++ b/src/app-url.test.js @@ -0,0 +1,31 @@ +import { describe, expect, it } from "vitest"; +import { normalizeUrlForHash } from "./app-url"; + +describe("normalizeUrlForHash", () => { + it("extracts the route from a same-origin hash URL under a base path", () => { + expect( + normalizeUrlForHash( + "/groundwork/#/docs/navigation/sidebar", + "https://usace.github.io/groundwork/", + ), + ).toBe("/docs/navigation/sidebar"); + }); + + it("extracts the route from a root hash URL", () => { + expect( + normalizeUrlForHash( + "/#/docs/navigation/sidebar", + "http://localhost:5173/", + ), + ).toBe("/docs/navigation/sidebar"); + }); + + it("strips the base path from non-hash same-origin URLs", () => { + expect( + normalizeUrlForHash( + "/groundwork/docs", + "https://usace.github.io/groundwork/", + ), + ).toBe("/docs"); + }); +});