diff --git a/src/project/types/website/website-navigation-md.ts b/src/project/types/website/website-navigation-md.ts index 5bc23ebeab4..999d615e692 100644 --- a/src/project/types/website/website-navigation-md.ts +++ b/src/project/types/website/website-navigation-md.ts @@ -301,7 +301,16 @@ const sidebarContentsHandler = (context: NavigationPipelineContext) => { ); for (let i = 0; i < sidebarSectionEls.length; i++) { const sectionEl = sidebarSectionEls[i] as Element; - const target = sectionEl.getAttribute("data-bs-target"); + // When a section has an href, the .sidebar-item-text element is a + // plain link without data-bs-target. Fall back to the sibling + // .sidebar-item-toggle, which always carries data-bs-target. + let target = sectionEl.getAttribute("data-bs-target"); + if (!target) { + const toggleEl = sectionEl.parentElement?.querySelector( + ".sidebar-item-toggle", + ); + target = toggleEl?.getAttribute("data-bs-target") ?? null; + } if (target) { const id = target.slice(1); diff --git a/tests/docs/websites/website-sidebar-section-href/.gitignore b/tests/docs/websites/website-sidebar-section-href/.gitignore new file mode 100644 index 00000000000..075b2542afb --- /dev/null +++ b/tests/docs/websites/website-sidebar-section-href/.gitignore @@ -0,0 +1 @@ +/.quarto/ diff --git a/tests/docs/websites/website-sidebar-section-href/_quarto.yml b/tests/docs/websites/website-sidebar-section-href/_quarto.yml new file mode 100644 index 00000000000..13e67f0ceb9 --- /dev/null +++ b/tests/docs/websites/website-sidebar-section-href/_quarto.yml @@ -0,0 +1,16 @@ +project: + type: website + +website: + title: "Sidebar section href test" + sidebar: + contents: + - index.qmd + - section: "**More info**" + href: more-info.qmd + contents: + - child.qmd + +format: + html: + theme: default diff --git a/tests/docs/websites/website-sidebar-section-href/child.qmd b/tests/docs/websites/website-sidebar-section-href/child.qmd new file mode 100644 index 00000000000..c2ef4f26091 --- /dev/null +++ b/tests/docs/websites/website-sidebar-section-href/child.qmd @@ -0,0 +1,5 @@ +--- +title: "Child page" +--- + +Child page. diff --git a/tests/docs/websites/website-sidebar-section-href/index.qmd b/tests/docs/websites/website-sidebar-section-href/index.qmd new file mode 100644 index 00000000000..17325bcf838 --- /dev/null +++ b/tests/docs/websites/website-sidebar-section-href/index.qmd @@ -0,0 +1,5 @@ +--- +title: "Home" +--- + +Home page. diff --git a/tests/docs/websites/website-sidebar-section-href/more-info.qmd b/tests/docs/websites/website-sidebar-section-href/more-info.qmd new file mode 100644 index 00000000000..b398bcba2b4 --- /dev/null +++ b/tests/docs/websites/website-sidebar-section-href/more-info.qmd @@ -0,0 +1,5 @@ +--- +title: "More info" +--- + +More info page. diff --git a/tests/smoke/website/website-sidebar-section-href.test.ts b/tests/smoke/website/website-sidebar-section-href.test.ts new file mode 100644 index 00000000000..c5ca6dc3d55 --- /dev/null +++ b/tests/smoke/website/website-sidebar-section-href.test.ts @@ -0,0 +1,50 @@ +/* + * website-sidebar-section-href.test.ts + * + * Tests that markdown in sidebar section titles is rendered correctly when + * the section has an href. Without the fix, the .sidebar-item-text element + * is a plain link without data-bs-target, so the markdown substitution in + * sidebarContentsHandler() fails to recover the sectionId and leaves raw + * markdown (e.g. **More info**) in the DOM instead of rendering it. + * + * Copyright (C) 2020-2025 Posit Software, PBC + */ + +import { docs } from "../../utils.ts"; +import { join } from "../../../src/deno_ral/path.ts"; +import { existsSync } from "../../../src/deno_ral/fs.ts"; +import { testQuartoCmd } from "../../test.ts"; +import { + ensureFileRegexMatches, + ensureHtmlElements, + noErrorsOrWarnings, +} from "../../verify.ts"; + +const renderDir = docs("websites/website-sidebar-section-href"); +const outDir = join(Deno.cwd(), renderDir, "_site"); + +testQuartoCmd( + "render", + [renderDir], + [ + noErrorsOrWarnings, + // Markdown in section title must be rendered: **More info** → + ensureHtmlElements( + join(outDir, "index.html"), + [".sidebar-item-text strong"], + ), + // Raw markdown asterisks must not appear in the sidebar HTML + ensureFileRegexMatches( + join(outDir, "index.html"), + [], + [/sidebar-item-text[^<]*\*\*/], + ), + ], + { + teardown: async () => { + if (existsSync(outDir)) { + await Deno.remove(outDir, { recursive: true }); + } + }, + }, +);