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'; 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" }, 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)'); +});