Skip to content

Commit 388c887

Browse files
committed
add title canonicalization html postprocessor
1 parent 9f91d81 commit 388c887

File tree

11 files changed

+145
-1
lines changed

11 files changed

+145
-1
lines changed

news/changelog-1.6.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ All changes included in 1.6:
8686
- ([#2671](https://github.com/quarto-dev/quarto-cli/issues/2671)): Ensure that `--output-dir` works across filesystem boundaries.
8787
- ([#8517](https://github.com/quarto-dev/quarto-cli/issues/8571)), ([#10829](https://github.com/quarto-dev/quarto-cli/issues/10829)): Allow listing categories with non-alphanumeric characters such as apostrophes, etc.
8888
- ([#8932](https://github.com/quarto-dev/quarto-cli/issues/8932)): Escape render ids in markdown pipeline to allow special characters in sidebars/navbars, etc.
89+
- ([#10567](https://github.com/quarto-dev/quarto-cli/issues/10567)): Generate breadcrumbs correctly for documents using a level-1 heading as the title.
8990
- ([#10616](https://github.com/quarto-dev/quarto-cli/issues/10268)): Add a `z-index` setting to the 'back to top' button to ensure it is always visible.
9091

9192
### Quarto Blog

src/command/render/pandoc.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ import {
201201
MarkdownPipelineHandler,
202202
} from "../../core/markdown-pipeline.ts";
203203
import { getEnv } from "../../../package/src/util/utils.ts";
204+
import { canonicalizeTitlePostprocessor } from "../../format/html/format-html-title.ts";
204205

205206
// in case we are running multiple pandoc processes
206207
// we need to make sure we capture all of the trace files
@@ -431,6 +432,11 @@ export async function runPandoc(
431432
// record postprocessors
432433
postprocessors.push(...(extras.postprocessors || []));
433434

435+
// Fix H1 title inconsistency
436+
if (isHtmlFileOutput(options.format.pandoc)) {
437+
htmlPostprocessors.push(canonicalizeTitlePostprocessor);
438+
}
439+
434440
// add a keep-source post processor if we need one
435441
if (
436442
options.format?.render[kKeepSource] || formatHasCodeTools(options.format)

src/format/html/format-html-title.ts

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,17 @@ import { existsSync } from "../../deno_ral/fs.ts";
88
import { dirname, isAbsolute, join } from "../../deno_ral/path.ts";
99
import { kDateFormat, kTocLocation } from "../../config/constants.ts";
1010
import { Format, Metadata, PandocFlags } from "../../config/types.ts";
11-
import { Document } from "../../core/deno-dom.ts";
11+
import { Document, Element } from "../../core/deno-dom.ts";
1212
import { formatResourcePath } from "../../core/resources.ts";
1313
import { sassLayer } from "../../core/sass.ts";
1414
import { TempContext } from "../../core/temp-types.ts";
1515
import { MarkdownPipeline } from "../../core/markdown-pipeline.ts";
16+
import {
17+
HtmlPostProcessResult,
18+
PandocInputTraits,
19+
RenderedFormat,
20+
} from "../../command/render/types.ts";
21+
import { InternalError } from "../../core/lib/error.ts";
1622

1723
export const kTitleBlockStyle = "title-block-style";
1824
const kTitleBlockBanner = "title-block-banner";
@@ -177,6 +183,69 @@ export function documentTitlePartial(
177183
}
178184
}
179185

186+
export async function canonicalizeTitlePostprocessor(
187+
doc: Document,
188+
_options: {
189+
inputMetadata: Metadata;
190+
inputTraits: PandocInputTraits;
191+
renderedFormats: RenderedFormat[];
192+
quiet?: boolean;
193+
},
194+
): Promise<HtmlPostProcessResult> {
195+
// https://github.com/quarto-dev/quarto-cli/issues/10567
196+
// this fix cannot happen in `processDocumentTitle` because
197+
// that's too late in the postprocessing order
198+
const titleBlock = doc.querySelector("header.quarto-title-block");
199+
200+
const main = doc.querySelector("main");
201+
// if no main element exists, this is likely a revealjs presentation
202+
// which will generally have a title slide instead of a title block
203+
// so we don't need to do anything
204+
205+
if (!titleBlock && main) {
206+
const header = doc.createElement("header");
207+
header.id = "title-block-header";
208+
header.classList.add("quarto-title-block");
209+
main.insertBefore(header, main.firstChild);
210+
const h1s = Array.from(doc.querySelectorAll("h1"));
211+
for (const h1n of h1s) {
212+
const h1 = h1n as Element;
213+
if (h1.classList.contains("quarto-secondary-nav-title")) {
214+
continue;
215+
}
216+
217+
// Now we need to check whether this is a plausible title element.
218+
if (h1.parentElement?.tagName === "SECTION") {
219+
// If the parent element is a section, then we need to check if there's
220+
// any content before the section. If there is, then this is not a title
221+
if (
222+
h1.parentElement?.parentElement?.firstElementChild !==
223+
h1.parentElement
224+
) {
225+
continue;
226+
}
227+
} else {
228+
// If the parent element is not a section, then we need to check if there's
229+
// any content before the h1. If there is, then this is not a title
230+
if (h1.parentElement?.firstElementChild !== h1) {
231+
continue;
232+
}
233+
}
234+
235+
const div = doc.createElement("div");
236+
div.classList.add("quarto-title-banner");
237+
h1.classList.add("title");
238+
header.appendChild(h1);
239+
break;
240+
}
241+
}
242+
243+
return {
244+
resources: [],
245+
supporting: [],
246+
};
247+
}
248+
180249
export function processDocumentTitle(
181250
input: string,
182251
format: Format,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/.quarto/
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
project:
2+
type: website
3+
4+
website:
5+
title: "issue-10567"
6+
sidebar:
7+
- contents:
8+
- section: "Tutorials"
9+
contents:
10+
- text: Tutorials bad
11+
href: tutorials-bad.qmd
12+
- text: Tutorials good
13+
href: tutorials-good.qmd
14+
navbar:
15+
left:
16+
- href: index.qmd
17+
text: Home
18+
- about.qmd
19+
20+
format:
21+
html:
22+
theme: cosmo
23+
css: styles.css
24+
toc: true
25+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
title: "About"
3+
---
4+
5+
About this site
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
title: "issue-10567"
3+
---
4+
5+
This is a Quarto website.
6+
7+
To learn more about Quarto websites visit <https://quarto.org/docs/websites>.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
title: hello
3+
format: revealjs
4+
---
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/* css styles */
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
# uncomment below to see breadcrumbs say "Tutorial sidebar title"
3+
# title: Tutorial topmatter title
4+
_quarto:
5+
tests:
6+
html:
7+
ensureHtmlElements:
8+
- ["header.quarto-title-block ol.breadcrumb"]
9+
- []
10+
---
11+
12+
# Tutorial qmd first header (not working)
13+
14+
abc

0 commit comments

Comments
 (0)