From 07c9073f75d1072fb2ee2157cc0c6cb4430c46f7 Mon Sep 17 00:00:00 2001 From: Gordon Woodhull Date: Mon, 14 Apr 2025 14:19:26 -0400 Subject: [PATCH 1/3] tests for a11y and arrow highlighting these test some elements we saw bad behavior in nojs mode also, a rather more severe bug where light highlighting is being applied --- .../a11y-syntax-highlighting.qmd | 47 +++++++++++++++++ .../arrow-syntax-highlighting.qmd | 52 +++++++++++++++++++ .../tests/html-dark-mode-nojs.spec.ts | 23 ++++++++ .../playwright/tests/html-dark-mode.spec.ts | 30 ++++++++++- 4 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 tests/docs/playwright/html/dark-brand/syntax-highlighting/a11y-syntax-highlighting.qmd create mode 100644 tests/docs/playwright/html/dark-brand/syntax-highlighting/arrow-syntax-highlighting.qmd diff --git a/tests/docs/playwright/html/dark-brand/syntax-highlighting/a11y-syntax-highlighting.qmd b/tests/docs/playwright/html/dark-brand/syntax-highlighting/a11y-syntax-highlighting.qmd new file mode 100644 index 00000000000..47729714248 --- /dev/null +++ b/tests/docs/playwright/html/dark-brand/syntax-highlighting/a11y-syntax-highlighting.qmd @@ -0,0 +1,47 @@ +--- +title: a11y syntax highlighting +execute: + echo: false + warning: false +theme: + light: [cosmo, theme.scss] + dark: [cosmo, theme-dark.scss] +highlight-style: a11y +--- + + +```markdown +![asdf](asd.png) +``` + + +```python +#| label: fig-polar +#| fig-cap: "A line plot on a polar axis" + +import numpy as np +import matplotlib.pyplot as plt + +r = np.arange(0, 2, 0.01) +theta = 2 * np.pi * r +fig, ax = plt.subplots( + subplot_kw = {'projection': 'polar'} +) +ax.plot(theta, r) +ax.set_rticks([0.5, 1, 1.5, 2]) +ax.grid(True) +plt.show() +``` + +```r +nycflights13::flights %>% + mutate( + cancelled = is.na(dep_time), + sched_hour = sched_dep_time %/% 100, + sched_min = sched_dep_time %% 100, + sched_dep_time = sched_hour + sched_min / 60 + ) %>% + ggplot(mapping = aes(sched_dep_time)) + + geom_freqpoly(mapping = aes(colour = cancelled), binwidth = 1/4) + + labs (x = "Scheduled Departure Time") +``` diff --git a/tests/docs/playwright/html/dark-brand/syntax-highlighting/arrow-syntax-highlighting.qmd b/tests/docs/playwright/html/dark-brand/syntax-highlighting/arrow-syntax-highlighting.qmd new file mode 100644 index 00000000000..344fd955c72 --- /dev/null +++ b/tests/docs/playwright/html/dark-brand/syntax-highlighting/arrow-syntax-highlighting.qmd @@ -0,0 +1,52 @@ +--- +format: html +title: arrow syntax highlighting +theme: + light: united + dark: slate +_quarto: + tests: + html: + ensureHtmlElements: + - [] + - ["link[href*=\"-dark-\"]"] +--- + +## Hello + +```markdown +![asdf](asd.png) +``` + + +```python +#| label: fig-polar +#| fig-cap: "A line plot on a polar axis" + +import numpy as np +import matplotlib.pyplot as plt + +r = np.arange(0, 2, 0.01) +theta = 2 * np.pi * r +fig, ax = plt.subplots( + subplot_kw = {'projection': 'polar'} +) +ax.plot(theta, r) +ax.set_rticks([0.5, 1, 1.5, 2]) +ax.grid(True) +plt.show() +``` + +```r +nycflights13::flights %>% + mutate( + cancelled = is.na(dep_time), + sched_hour = sched_dep_time %/% 100, + sched_min = sched_dep_time %% 100, + sched_dep_time = sched_hour + sched_min / 60 + ) %>% + ggplot(mapping = aes(sched_dep_time)) + + geom_freqpoly(mapping = aes(colour = cancelled), binwidth = 1/4) + + labs (x = "Scheduled Departure Time") +``` + diff --git a/tests/integration/playwright/tests/html-dark-mode-nojs.spec.ts b/tests/integration/playwright/tests/html-dark-mode-nojs.spec.ts index b08a0bbaf4d..b4cf840c21d 100644 --- a/tests/integration/playwright/tests/html-dark-mode-nojs.spec.ts +++ b/tests/integration/playwright/tests/html-dark-mode-nojs.spec.ts @@ -22,6 +22,29 @@ test('Light brand default, no JS', async ({ page }) => { }); +test('Syntax highlighting, a11y, no JS', async ({ page }) => { + // This document use a custom theme file that change the background color of the title banner + // Same user defined color should be used in both dark and light theme + await page.goto('./html/dark-brand/syntax-highlighting/a11y-syntax-highlighting.html'); + const locatr = await page.locator('body').first(); + await expect(locatr).toHaveClass('fullcontent quarto-light'); + await expect(locatr).toHaveCSS('background-color', 'rgb(255, 255, 255)'); + const importKeyword = await page.locator('span.im').first(); + await expect(importKeyword).toHaveCSS('color', 'rgb(84, 84, 84)'); +}); + + +test('Syntax highlighting, arrow, no JS', async ({ page }) => { + // This document use a custom theme file that change the background color of the title banner + // Same user defined color should be used in both dark and light theme + await page.goto('./html/dark-brand/syntax-highlighting/arrow-syntax-highlighting.html'); + const locatr = await page.locator('body').first(); + await expect(locatr).toHaveClass('fullcontent quarto-light'); + await expect(locatr).toHaveCSS('background-color', 'rgb(255, 255, 255)'); + const link = await page.locator('span.al').first(); + await expect(link).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)'); +}); + test('Project dark brand default, no JS', async ({ page }) => { // This document use a custom theme file that change the background color of the title banner // Same user defined color should be used in both dark and light theme diff --git a/tests/integration/playwright/tests/html-dark-mode.spec.ts b/tests/integration/playwright/tests/html-dark-mode.spec.ts index 23c0b2fa671..ddc2fb7c8e8 100644 --- a/tests/integration/playwright/tests/html-dark-mode.spec.ts +++ b/tests/integration/playwright/tests/html-dark-mode.spec.ts @@ -32,4 +32,32 @@ test('Brand false remove project brand', async ({ page }) => { await expect(locatr).toHaveCSS('background-color', 'rgb(255, 255, 255)'); // no toggle expect(await page.locator('a.quarto-color-scheme-toggle').count()).toEqual(0); -}); \ No newline at end of file +}); + + +test('Syntax highlighting, a11y, with JS', async ({ page }) => { + // This document use a custom theme file that change the background color of the title banner + // Same user defined color should be used in both dark and light theme + await page.goto('./html/dark-brand/syntax-highlighting/a11y-syntax-highlighting.html'); + const locatr = await page.locator('body').first(); + await expect(locatr).toHaveClass('fullcontent quarto-light'); + await expect(locatr).toHaveCSS('background-color', 'rgb(255, 255, 255)'); + const importKeyword = await page.locator('span.im').first(); + // light highlight stylesheet + await expect(importKeyword).toHaveCSS('color', 'rgb(84, 84, 84)'); + await page.locator("a.quarto-color-scheme-toggle").click(); + // dark highlight stylesheet + await expect(importKeyword).toHaveCSS('color', 'rgb(248, 248, 242)'); +}); + + +test('Syntax highlighting, arrow, with JS', async ({ page }) => { + // This document use a custom theme file that change the background color of the title banner + // Same user defined color should be used in both dark and light theme + await page.goto('./html/dark-brand/syntax-highlighting/arrow-syntax-highlighting.html'); + const locatr = await page.locator('body').first(); + await expect(locatr).toHaveClass('fullcontent quarto-light'); + await expect(locatr).toHaveCSS('background-color', 'rgb(255, 255, 255)'); + const link = await page.locator('span.al').first(); + await expect(link).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)'); +}); From f99ae99f6dc8c49281d5fd9222f0bdc222506d5a Mon Sep 17 00:00:00 2001 From: Gordon Woodhull Date: Mon, 14 Apr 2025 14:14:53 -0400 Subject: [PATCH 2/3] highlight fixes for a11y and arrow in nojs these more specific and bad highlight styles bleed through from dark to light mode fixes #12399 fixes #12522 --- src/resources/pandoc/highlight-styles/a11y-dark.theme | 1 - src/resources/pandoc/highlight-styles/arrow-dark.theme | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/resources/pandoc/highlight-styles/a11y-dark.theme b/src/resources/pandoc/highlight-styles/a11y-dark.theme index bac593cbfae..e396529e32a 100644 --- a/src/resources/pandoc/highlight-styles/a11y-dark.theme +++ b/src/resources/pandoc/highlight-styles/a11y-dark.theme @@ -155,7 +155,6 @@ "underline": false }, "Import": { - "text-color": "#f8f8f2", "background-color": null, "bold": false, "italic": false, diff --git a/src/resources/pandoc/highlight-styles/arrow-dark.theme b/src/resources/pandoc/highlight-styles/arrow-dark.theme index 648615b342b..eea32c30123 100644 --- a/src/resources/pandoc/highlight-styles/arrow-dark.theme +++ b/src/resources/pandoc/highlight-styles/arrow-dark.theme @@ -1,8 +1,6 @@ { "text-styles": { "Alert": { - "background-color": "#2a0f15", - "bold": true, "selected-text-color": "#f07178", "text-color": "#f07178" }, From 113e809d96f6fd26e2ddf518a1117a2912541a5e Mon Sep 17 00:00:00 2001 From: Gordon Woodhull Date: Mon, 14 Apr 2025 14:56:21 -0400 Subject: [PATCH 3/3] order highlight stylesheets light, dark or light, dark, light this fixes the light syntax highlighting being applied in dark mdoe since we are no longer disabling the light stylesheet use the same light, dark, light pattern as the main stylesheet --- src/command/render/pandoc-html.ts | 40 ++++++++++++------- .../templates/quarto-html-before-body.ejs | 3 +- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/command/render/pandoc-html.ts b/src/command/render/pandoc-html.ts index 1ba9fde76d1..bdf23f5a3df 100644 --- a/src/command/render/pandoc-html.ts +++ b/src/command/render/pandoc-html.ts @@ -295,19 +295,9 @@ export async function resolveSassBundles( } } - // Resolve generated quarto css variables - if (hasDarkStyles && defaultStyle !== "dark") { - // Put dark stylesheet first if light is default (for NoJS) - extras = await resolveQuartoSyntaxHighlighting( - inputDir, - extras, - format, - project, - "dark", - defaultStyle, - ); - } - + // light only: light + // author prefers dark: light, dark + // author prefers light: light, dark, light extras = await resolveQuartoSyntaxHighlighting( inputDir, extras, @@ -317,8 +307,15 @@ export async function resolveSassBundles( defaultStyle, ); - if (hasDarkStyles && defaultStyle === "dark") { - // Put dark stylesheet second if dark is default (for NoJS) + if (hasDarkStyles) { + // find the last entry, for the light highlight stylesheet + // so we can duplicate it below. + // (note we must do this before adding the dark highlight stylesheet) + const lightDep = extras.html?.[kDependencies]?.find((extraDep) => + extraDep.name === kQuartoHtmlDependency + ); + const lightEntry = lightDep?.stylesheets && + lightDep.stylesheets[lightDep.stylesheets.length - 1]; extras = await resolveQuartoSyntaxHighlighting( inputDir, extras, @@ -327,6 +324,19 @@ export async function resolveSassBundles( "dark", defaultStyle, ); + if (defaultStyle === "light") { + const dep2 = extras.html?.[kDependencies]?.find((extraDep) => + extraDep.name === kQuartoHtmlDependency + ); + assert(dep2?.stylesheets && lightEntry); + dep2.stylesheets.push({ + ...lightEntry, + attribs: { + ...lightEntry.attribs, + class: "quarto-color-scheme-extra", + }, + }); + } } if (isHtmlOutput(format.pandoc, true)) { diff --git a/src/resources/formats/html/templates/quarto-html-before-body.ejs b/src/resources/formats/html/templates/quarto-html-before-body.ejs index 0cbb9891031..441c1f2a96a 100644 --- a/src/resources/formats/html/templates/quarto-html-before-body.ejs +++ b/src/resources/formats/html/templates/quarto-html-before-body.ejs @@ -172,7 +172,8 @@ <% } %> <% if (!darkModeDefault) { %> - document.querySelector('link.quarto-color-scheme-extra').rel = 'disabled-stylesheet'; + document.querySelector('link#quarto-text-highlighting-styles.quarto-color-scheme-extra').rel = 'disabled-stylesheet'; + document.querySelector('link#quarto-bootstrap.quarto-color-scheme-extra').rel = 'disabled-stylesheet'; <% } %> let localAlternateSentinel = darkModeDefault ? 'alternate' : 'default';