From c08661b55407697c7809ad3374dc2a1aa8e2b11e Mon Sep 17 00:00:00 2001 From: Kalinoff <18365725+kalinof@users.noreply.github.com> Date: Thu, 6 Aug 2026 00:42:44 +0000 Subject: [PATCH 1/2] [verified] fix: use canonical slug for folder graphs --- src/components/scripts/currentSlug.ts | 22 +++++++++ src/components/scripts/graph.inline.ts | 16 ++++--- test/currentSlug.test.ts | 64 ++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 6 deletions(-) create mode 100644 src/components/scripts/currentSlug.ts create mode 100644 test/currentSlug.test.ts diff --git a/src/components/scripts/currentSlug.ts b/src/components/scripts/currentSlug.ts new file mode 100644 index 0000000..b48a7a2 --- /dev/null +++ b/src/components/scripts/currentSlug.ts @@ -0,0 +1,22 @@ +import { simplifySlug } from "@quartz-community/utils"; + +export interface GraphSlugInput { + canonicalSlug?: string; + urlSlug: string; + basePath: string; +} + +export function resolveGraphSlug({ canonicalSlug, urlSlug, basePath }: GraphSlugInput): string { + let slug = canonicalSlug || urlSlug; + + if (!canonicalSlug) { + const base = basePath.replace(/^\//, "").replace(/\/$/, ""); + if (base && (slug === base || slug.startsWith(`${base}/`))) { + slug = slug.slice(base.length); + if (slug.startsWith("/")) slug = slug.slice(1); + } + } + + const simplified = simplifySlug(slug); + return simplified === "" ? "index" : simplified; +} diff --git a/src/components/scripts/graph.inline.ts b/src/components/scripts/graph.inline.ts index 3b2773e..02158b3 100644 --- a/src/components/scripts/graph.inline.ts +++ b/src/components/scripts/graph.inline.ts @@ -6,16 +6,20 @@ import { simplifySlug, resolveBasePath, } from "@quartz-community/utils"; +import { resolveGraphSlug } from "./currentSlug"; (function () { function getSlugFromUrl() { - var slug = getFullSlugFromUrl(); - var base = getBasePath(); - if (base && slug.startsWith(base.replace(/^\//, ""))) { - slug = slug.slice(base.replace(/^\//, "").length); - if (slug.startsWith("/")) slug = slug.slice(1); + var canonicalSlug = document.body?.dataset?.slug; + if (canonicalSlug) { + return resolveGraphSlug({ canonicalSlug, urlSlug: "", basePath: "" }); } - return slug; + + return resolveGraphSlug({ + canonicalSlug: undefined, + urlSlug: getFullSlugFromUrl(), + basePath: getBasePath(), + }); } function loadScript(src) { diff --git a/test/currentSlug.test.ts b/test/currentSlug.test.ts new file mode 100644 index 0000000..2c744cc --- /dev/null +++ b/test/currentSlug.test.ts @@ -0,0 +1,64 @@ +import { describe, expect, it } from "vitest"; +import { resolveGraphSlug } from "../src/components/scripts/currentSlug"; + +describe("resolveGraphSlug", () => { + it("canonicalizes a Quartz folder-page body slug to the graph index key", () => { + expect( + resolveGraphSlug({ + canonicalSlug: "projects/example/index", + urlSlug: "projects/example", + basePath: "", + }), + ).toBe("projects/example/"); + }); + + it("preserves a trailing-slash folder URL when body metadata is unavailable", () => { + expect( + resolveGraphSlug({ + canonicalSlug: undefined, + urlSlug: "projects/example/", + basePath: "", + }), + ).toBe("projects/example/"); + }); + + it("preserves an ordinary page slug from body metadata", () => { + expect( + resolveGraphSlug({ + canonicalSlug: "hermes/overview", + urlSlug: "hermes/overview", + basePath: "", + }), + ).toBe("hermes/overview"); + }); + + it("preserves an ordinary page slug through the URL fallback", () => { + expect( + resolveGraphSlug({ + canonicalSlug: undefined, + urlSlug: "hermes/overview", + basePath: "", + }), + ).toBe("hermes/overview"); + }); + + it("strips the configured base path from the URL fallback", () => { + expect( + resolveGraphSlug({ + canonicalSlug: undefined, + urlSlug: "archive/projects/example/", + basePath: "/archive", + }), + ).toBe("projects/example/"); + }); + + it("does not strip a similar URL path segment", () => { + expect( + resolveGraphSlug({ + canonicalSlug: undefined, + urlSlug: "archives/projects/example/", + basePath: "/archive", + }), + ).toBe("archives/projects/example/"); + }); +}); From cdd59ab9620bebcab15ca9eb0e9977a97803448b Mon Sep 17 00:00:00 2001 From: Kalinoff <18365725+kalinof@users.noreply.github.com> Date: Thu, 6 Aug 2026 00:54:58 +0000 Subject: [PATCH 2/2] [verified] test: cover browser slug fallback --- src/components/scripts/currentSlug.ts | 11 ++++++++++- src/components/scripts/graph.inline.ts | 21 +++------------------ test/currentSlug.test.ts | 25 ++++++++++++++++++++++++- 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/src/components/scripts/currentSlug.ts b/src/components/scripts/currentSlug.ts index b48a7a2..7e0d8ba 100644 --- a/src/components/scripts/currentSlug.ts +++ b/src/components/scripts/currentSlug.ts @@ -1,4 +1,4 @@ -import { simplifySlug } from "@quartz-community/utils"; +import { getBasePath, getFullSlugFromUrl, simplifySlug } from "@quartz-community/utils"; export interface GraphSlugInput { canonicalSlug?: string; @@ -6,6 +6,15 @@ export interface GraphSlugInput { basePath: string; } +export function getCurrentGraphSlug(): string { + const canonicalSlug = document.body?.dataset?.slug; + return resolveGraphSlug({ + canonicalSlug, + urlSlug: canonicalSlug ? "" : getFullSlugFromUrl(), + basePath: canonicalSlug ? "" : getBasePath(), + }); +} + export function resolveGraphSlug({ canonicalSlug, urlSlug, basePath }: GraphSlugInput): string { let slug = canonicalSlug || urlSlug; diff --git a/src/components/scripts/graph.inline.ts b/src/components/scripts/graph.inline.ts index 02158b3..f221bc0 100644 --- a/src/components/scripts/graph.inline.ts +++ b/src/components/scripts/graph.inline.ts @@ -1,25 +1,10 @@ // @ts-nocheck -import { - removeAllChildren, - getBasePath, - getFullSlugFromUrl, - simplifySlug, - resolveBasePath, -} from "@quartz-community/utils"; -import { resolveGraphSlug } from "./currentSlug"; +import { removeAllChildren, simplifySlug, resolveBasePath } from "@quartz-community/utils"; +import { getCurrentGraphSlug } from "./currentSlug"; (function () { function getSlugFromUrl() { - var canonicalSlug = document.body?.dataset?.slug; - if (canonicalSlug) { - return resolveGraphSlug({ canonicalSlug, urlSlug: "", basePath: "" }); - } - - return resolveGraphSlug({ - canonicalSlug: undefined, - urlSlug: getFullSlugFromUrl(), - basePath: getBasePath(), - }); + return getCurrentGraphSlug(); } function loadScript(src) { diff --git a/test/currentSlug.test.ts b/test/currentSlug.test.ts index 2c744cc..feb8347 100644 --- a/test/currentSlug.test.ts +++ b/test/currentSlug.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { resolveGraphSlug } from "../src/components/scripts/currentSlug"; +import { getCurrentGraphSlug, resolveGraphSlug } from "../src/components/scripts/currentSlug"; describe("resolveGraphSlug", () => { it("canonicalizes a Quartz folder-page body slug to the graph index key", () => { @@ -61,4 +61,27 @@ describe("resolveGraphSlug", () => { }), ).toBe("archives/projects/example/"); }); + + it("uses Quartz's browser URL and base-path utilities for the fallback", () => { + const previousWindow = Object.getOwnPropertyDescriptor(globalThis, "window"); + const previousDocument = Object.getOwnPropertyDescriptor(globalThis, "document"); + + Object.defineProperty(globalThis, "window", { + configurable: true, + value: { location: { pathname: "/archive/hermes/overview/" } }, + }); + Object.defineProperty(globalThis, "document", { + configurable: true, + value: { body: { dataset: { basepath: "/archive" } } }, + }); + + try { + expect(getCurrentGraphSlug()).toBe("hermes/overview"); + } finally { + if (previousWindow) Object.defineProperty(globalThis, "window", previousWindow); + else Reflect.deleteProperty(globalThis, "window"); + if (previousDocument) Object.defineProperty(globalThis, "document", previousDocument); + else Reflect.deleteProperty(globalThis, "document"); + } + }); });