diff --git a/news/changelog-1.7.md b/news/changelog-1.7.md
index 1b6ce2062e..c4ef5a4b57 100644
--- a/news/changelog-1.7.md
+++ b/news/changelog-1.7.md
@@ -61,6 +61,7 @@ All changes included in 1.7:
- ([#12277](https://github.com/quarto-dev/quarto-cli/pull/12277)): Provide light and dark plot and table renderings with `renderings: [light,dark]`
- ([#11860](https://github.com/quarto-dev/quarto-cli/issues/11860)): ES6 modules that import other local JS modules in documents with `embed-resources: true` are now correctly embedded.
- ([#1325](https://github.com/quarto-dev/quarto-cli/issues/1325)): Dark Mode pages should not flash light on reload. (Nor should Light Mode pages flash dark.)
+- ([#1470](https://github.com/quarto-dev/quarto-cli/issues/1470)): `respect-user-color-scheme` enables checking the media query `prefers-color-scheme` for user preference. This is only on page load, not dynamically. Author preference still influences stylesheet order and therefore NoJS experience. Defaults to `false`, leaving to author preference.
- ([#12307](https://github.com/quarto-dev/quarto-cli/issues/12307)): Tabsets using `tabby.js` in non-boostrap html (`theme: pandoc`, `theme: none` or `minimal: true`) now correctly render reactive content when `server: shiny` is used.
- ([#12356](https://github.com/quarto-dev/quarto-cli/issues/12356)): Remove duplicate id in HTML document when using `#lst-` prefix label for using Quarto crossref.
diff --git a/src/config/constants.ts b/src/config/constants.ts
index 988e34f1ce..56e75b1d82 100644
--- a/src/config/constants.ts
+++ b/src/config/constants.ts
@@ -142,6 +142,7 @@ export const kHtmlTableProcessing = "html-table-processing";
export const kHtmlPreTagProcessing = "html-pre-tag-processing";
export const kCssPropertyProcessing = "css-property-processing";
export const kBrandMode = "brand-mode";
+export const kRespectUserColorScheme = "respect-user-color-scheme";
export const kUseRsvgConvert = "use-rsvg-convert";
export const kValidateYaml = "validate-yaml";
diff --git a/src/format/html/format-html.ts b/src/format/html/format-html.ts
index d5f465f039..9f35fd599a 100644
--- a/src/format/html/format-html.ts
+++ b/src/format/html/format-html.ts
@@ -24,14 +24,15 @@ import {
kFigResponsive,
kFilterParams,
kHeaderIncludes,
- kIncludeBeforeBody,
kIncludeAfterBody,
+ kIncludeBeforeBody,
kIncludeInHeader,
kLinkExternalFilter,
kLinkExternalIcon,
kLinkExternalNewwindow,
kNotebookLinks,
kNotebookViewStyle,
+ kRespectUserColorScheme,
kTheme,
} from "../../config/constants.ts";
@@ -343,6 +344,8 @@ export async function htmlFormatExtras(
options.codeTools = formatHasCodeTools(format);
options.darkMode = formatDarkMode(format);
options.darkModeDefault = darkModeDefault(format.metadata);
+ options.respectUserColorScheme = format.metadata[kRespectUserColorScheme] ||
+ false;
options.linkExternalIcon = format.render[kLinkExternalIcon];
options.linkExternalNewwindow = format.render[kLinkExternalNewwindow];
options.linkExternalFilter = format.render[kLinkExternalFilter];
@@ -502,7 +505,7 @@ export async function htmlFormatExtras(
renderEjs(
formatResourcePath("html", join("hypothesis", "hypothesis.ejs")),
{ hypothesis: options.hypothesis },
- )
+ ),
);
includeInHeader.push(hypothesisHeader);
}
@@ -516,10 +519,12 @@ export async function htmlFormatExtras(
!!options[option]
);
if (quartoHtmlRequired) {
- for(const {dest, ejsfile} of [
- {dest: includeBeforeBody, ejsfile: "quarto-html-before-body.ejs"},
- {dest: includeAfterBody, ejsfile: "quarto-html-after-body.ejs"}
- ]) {
+ for (
+ const { dest, ejsfile } of [
+ { dest: includeBeforeBody, ejsfile: "quarto-html-before-body.ejs" },
+ { dest: includeAfterBody, ejsfile: "quarto-html-after-body.ejs" },
+ ]
+ ) {
const quartoHtmlScript = temp.createFile();
const renderedHtml = renderEjs(
formatResourcePath("html", join("templates", ejsfile)),
diff --git a/src/resources/editor/tools/vs-code.mjs b/src/resources/editor/tools/vs-code.mjs
index af71dc0997..79af6837fe 100644
--- a/src/resources/editor/tools/vs-code.mjs
+++ b/src/resources/editor/tools/vs-code.mjs
@@ -16869,6 +16869,20 @@ var require_yaml_intelligence_resources = __commonJS({
},
description: "Enables smooth scrolling within the page."
},
+ {
+ name: "respect-user-color-scheme",
+ schema: "boolean",
+ default: false,
+ tags: {
+ formats: [
+ "$html-doc"
+ ]
+ },
+ description: {
+ short: "Whether the `prefers-color-scheme` media query controls dark mode.",
+ long: "Whether to use the `prefers-color-scheme` media query to determine whether to show\nthe user a dark or light page. Otherwise the author preference (order of `light`\nand `dark` in `theme` or `brand`) determines what is shown to the user at first visit.\n"
+ }
+ },
{
name: "html-math-method",
tags: {
@@ -22751,6 +22765,7 @@ var require_yaml_intelligence_resources = __commonJS({
},
"Control the \\pagestyle{} for the document.",
"The paper size for the document.",
+ "The brand mode to use for rendering the Typst document,\nlight or dark.",
{
short: "The options for margins and text layout for this document.",
long: 'The options for margins and text layout for this document.\nSee ConTeXt\nLayout for additional information.'
@@ -24043,7 +24058,10 @@ var require_yaml_intelligence_resources = __commonJS({
"Manuscript configuration",
"internal-schema-hack",
"List execution engines you want to give priority when determining\nwhich engine should render a notebook. If two engines have support for a\nnotebook, the one listed earlier will be chosen. Quarto\u2019s default order\nis \u2018knitr\u2019, \u2018jupyter\u2019, \u2018markdown\u2019, \u2018julia\u2019.",
- "The brand mode to use for rendering the Typst document,\nlight or dark."
+ {
+ short: "Whether the prefers-color-scheme media query controls\ndark mode.",
+ long: "Whether to use the prefers-color-scheme media query to\ndetermine whether to show the user a dark or light page. Otherwise the\nauthor preference (order of light and dark in\ntheme or brand) determines what is shown to\nthe user at first visit."
+ }
],
"schema/external-schemas.yml": [
{
@@ -24272,12 +24290,12 @@ var require_yaml_intelligence_resources = __commonJS({
mermaid: "%%"
},
"handlers/mermaid/schema.yml": {
- _internalId: 194259,
+ _internalId: 194479,
type: "object",
description: "be an object",
properties: {
"mermaid-format": {
- _internalId: 194251,
+ _internalId: 194471,
type: "enum",
enum: [
"png",
@@ -24293,7 +24311,7 @@ var require_yaml_intelligence_resources = __commonJS({
exhaustiveCompletions: true
},
theme: {
- _internalId: 194258,
+ _internalId: 194478,
type: "anyOf",
anyOf: [
{
diff --git a/src/resources/editor/tools/yaml/web-worker.js b/src/resources/editor/tools/yaml/web-worker.js
index 7bc0b7f304..cf935b89c4 100644
--- a/src/resources/editor/tools/yaml/web-worker.js
+++ b/src/resources/editor/tools/yaml/web-worker.js
@@ -16870,6 +16870,20 @@ try {
},
description: "Enables smooth scrolling within the page."
},
+ {
+ name: "respect-user-color-scheme",
+ schema: "boolean",
+ default: false,
+ tags: {
+ formats: [
+ "$html-doc"
+ ]
+ },
+ description: {
+ short: "Whether the `prefers-color-scheme` media query controls dark mode.",
+ long: "Whether to use the `prefers-color-scheme` media query to determine whether to show\nthe user a dark or light page. Otherwise the author preference (order of `light`\nand `dark` in `theme` or `brand`) determines what is shown to the user at first visit.\n"
+ }
+ },
{
name: "html-math-method",
tags: {
@@ -22752,6 +22766,7 @@ try {
},
"Control the \\pagestyle{} for the document.",
"The paper size for the document.",
+ "The brand mode to use for rendering the Typst document,\nlight or dark.",
{
short: "The options for margins and text layout for this document.",
long: 'The options for margins and text layout for this document.\nSee ConTeXt\nLayout for additional information.'
@@ -24044,7 +24059,10 @@ try {
"Manuscript configuration",
"internal-schema-hack",
"List execution engines you want to give priority when determining\nwhich engine should render a notebook. If two engines have support for a\nnotebook, the one listed earlier will be chosen. Quarto\u2019s default order\nis \u2018knitr\u2019, \u2018jupyter\u2019, \u2018markdown\u2019, \u2018julia\u2019.",
- "The brand mode to use for rendering the Typst document,\nlight or dark."
+ {
+ short: "Whether the prefers-color-scheme media query controls\ndark mode.",
+ long: "Whether to use the prefers-color-scheme media query to\ndetermine whether to show the user a dark or light page. Otherwise the\nauthor preference (order of light and dark in\ntheme or brand) determines what is shown to\nthe user at first visit."
+ }
],
"schema/external-schemas.yml": [
{
@@ -24273,12 +24291,12 @@ try {
mermaid: "%%"
},
"handlers/mermaid/schema.yml": {
- _internalId: 194259,
+ _internalId: 194479,
type: "object",
description: "be an object",
properties: {
"mermaid-format": {
- _internalId: 194251,
+ _internalId: 194471,
type: "enum",
enum: [
"png",
@@ -24294,7 +24312,7 @@ try {
exhaustiveCompletions: true
},
theme: {
- _internalId: 194258,
+ _internalId: 194478,
type: "anyOf",
anyOf: [
{
diff --git a/src/resources/editor/tools/yaml/yaml-intelligence-resources.json b/src/resources/editor/tools/yaml/yaml-intelligence-resources.json
index 5c1e641f1f..b205f1dd52 100644
--- a/src/resources/editor/tools/yaml/yaml-intelligence-resources.json
+++ b/src/resources/editor/tools/yaml/yaml-intelligence-resources.json
@@ -9841,6 +9841,20 @@
},
"description": "Enables smooth scrolling within the page."
},
+ {
+ "name": "respect-user-color-scheme",
+ "schema": "boolean",
+ "default": false,
+ "tags": {
+ "formats": [
+ "$html-doc"
+ ]
+ },
+ "description": {
+ "short": "Whether the `prefers-color-scheme` media query controls dark mode.",
+ "long": "Whether to use the `prefers-color-scheme` media query to determine whether to show\nthe user a dark or light page. Otherwise the author preference (order of `light`\nand `dark` in `theme` or `brand`) determines what is shown to the user at first visit.\n"
+ }
+ },
{
"name": "html-math-method",
"tags": {
@@ -15723,6 +15737,7 @@
},
"Control the \\pagestyle{} for the document.",
"The paper size for the document.",
+ "The brand mode to use for rendering the Typst document,\nlight or dark.",
{
"short": "The options for margins and text layout for this document.",
"long": "The options for margins and text layout for this document.\nSee ConTeXt\nLayout for additional information."
@@ -17015,7 +17030,10 @@
"Manuscript configuration",
"internal-schema-hack",
"List execution engines you want to give priority when determining\nwhich engine should render a notebook. If two engines have support for a\nnotebook, the one listed earlier will be chosen. Quarto’s default order\nis ‘knitr’, ‘jupyter’, ‘markdown’, ‘julia’.",
- "The brand mode to use for rendering the Typst document,\nlight or dark."
+ {
+ "short": "Whether the prefers-color-scheme media query controls\ndark mode.",
+ "long": "Whether to use the prefers-color-scheme media query to\ndetermine whether to show the user a dark or light page. Otherwise the\nauthor preference (order of light and dark in\ntheme or brand) determines what is shown to\nthe user at first visit."
+ }
],
"schema/external-schemas.yml": [
{
@@ -17244,12 +17262,12 @@
"mermaid": "%%"
},
"handlers/mermaid/schema.yml": {
- "_internalId": 194259,
+ "_internalId": 194479,
"type": "object",
"description": "be an object",
"properties": {
"mermaid-format": {
- "_internalId": 194251,
+ "_internalId": 194471,
"type": "enum",
"enum": [
"png",
@@ -17265,7 +17283,7 @@
"exhaustiveCompletions": true
},
"theme": {
- "_internalId": 194258,
+ "_internalId": 194478,
"type": "anyOf",
"anyOf": [
{
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 9f2f5c04f0..95b8929f50 100644
--- a/src/resources/formats/html/templates/quarto-html-before-body.ejs
+++ b/src/resources/formats/html/templates/quarto-html-before-body.ejs
@@ -128,7 +128,12 @@
return localAlternateSentinel;
}
}
- const darkModeDefault = <%= darkModeDefault %>;
+ <% if (respectUserColorScheme) { %>
+ const darkModeDefault = window.matchMedia('(prefers-color-scheme: dark)').matches;
+ <% } else { %>
+ const darkModeDefault = <%= darkModeDefault %>;
+ <% } %>
+
let localAlternateSentinel = darkModeDefault ? 'alternate' : 'default';
// Dark / light mode switch
diff --git a/src/resources/schema/document-options.yml b/src/resources/schema/document-options.yml
index 0b7be354fb..b309c9f293 100644
--- a/src/resources/schema/document-options.yml
+++ b/src/resources/schema/document-options.yml
@@ -84,6 +84,18 @@
formats: [$html-doc]
description: Enables smooth scrolling within the page.
+- name: respect-user-color-scheme
+ schema: boolean
+ default: false
+ tags:
+ formats: [$html-doc]
+ description:
+ short: "Whether the `prefers-color-scheme` media query controls dark mode."
+ long: |
+ Whether to use the `prefers-color-scheme` media query to determine whether to show
+ the user a dark or light page. Otherwise the author preference (order of `light`
+ and `dark` in `theme` or `brand`) determines what is shown to the user at first visit.
+
- name: html-math-method
tags:
formats: [$html-doc, $epub-all, gfm]
diff --git a/tests/docs/playwright/html/dark-brand/project-light-dark/_quarto.yml b/tests/docs/playwright/html/dark-brand/project-dark/_quarto.yml
similarity index 100%
rename from tests/docs/playwright/html/dark-brand/project-light-dark/_quarto.yml
rename to tests/docs/playwright/html/dark-brand/project-dark/_quarto.yml
diff --git a/tests/docs/playwright/html/dark-brand/project-light-dark/blue-background.yml b/tests/docs/playwright/html/dark-brand/project-dark/blue-background.yml
similarity index 100%
rename from tests/docs/playwright/html/dark-brand/project-light-dark/blue-background.yml
rename to tests/docs/playwright/html/dark-brand/project-dark/blue-background.yml
diff --git a/tests/docs/playwright/html/dark-brand/project-light-dark/brand-false.qmd b/tests/docs/playwright/html/dark-brand/project-dark/brand-false.qmd
similarity index 100%
rename from tests/docs/playwright/html/dark-brand/project-light-dark/brand-false.qmd
rename to tests/docs/playwright/html/dark-brand/project-dark/brand-false.qmd
diff --git a/tests/docs/playwright/html/dark-brand/project-light-dark/brand-under-theme.qmd b/tests/docs/playwright/html/dark-brand/project-dark/brand-under-theme.qmd
similarity index 100%
rename from tests/docs/playwright/html/dark-brand/project-light-dark/brand-under-theme.qmd
rename to tests/docs/playwright/html/dark-brand/project-dark/brand-under-theme.qmd
diff --git a/tests/docs/playwright/html/dark-brand/project-light-dark/red-background.yml b/tests/docs/playwright/html/dark-brand/project-dark/red-background.yml
similarity index 100%
rename from tests/docs/playwright/html/dark-brand/project-light-dark/red-background.yml
rename to tests/docs/playwright/html/dark-brand/project-dark/red-background.yml
diff --git a/tests/docs/playwright/html/dark-brand/project-dark/simple-respect-color-scheme.qmd b/tests/docs/playwright/html/dark-brand/project-dark/simple-respect-color-scheme.qmd
new file mode 100644
index 0000000000..4e61498251
--- /dev/null
+++ b/tests/docs/playwright/html/dark-brand/project-dark/simple-respect-color-scheme.qmd
@@ -0,0 +1,55 @@
+---
+title: "dark brand - ggplot"
+format:
+ html:
+ respect-user-color-scheme: true
+execute:
+ echo: false
+ warning: false
+---
+
+```{r}
+#| echo: false
+#| warning: false
+library(ggplot2)
+
+ggplot_theme <- function(bgcolor, fgcolor) {
+ theme_minimal(base_size = 11) %+%
+ theme(
+ panel.border = element_blank(),
+ panel.grid.major.y = element_blank(),
+ panel.grid.minor.y = element_blank(),
+ panel.grid.major.x = element_blank(),
+ panel.grid.minor.x = element_blank(),
+ text = element_text(colour = fgcolor),
+ axis.text = element_text(colour = fgcolor),
+ rect = element_rect(colour = bgcolor, fill = bgcolor),
+ plot.background = element_rect(fill = bgcolor, colour = NA),
+ axis.line = element_line(colour = fgcolor),
+ axis.ticks = element_line(colour = fgcolor)
+ )
+}
+
+brand_ggplot <- function(brand_yml) {
+ brand <- yaml::yaml.load_file(brand_yml)
+ ggplot_theme(brand$color$background, brand$color$foreground)
+}
+
+blue_theme <- brand_ggplot("blue-background.yml")
+red_theme <- brand_ggplot("red-background.yml")
+
+colour_scale <- scale_colour_manual(values = c("darkorange", "purple", "cyan4"))
+```
+
+
+```{r}
+#| renderings: [light, dark]
+ggplot(mtcars, aes(mpg, wt)) +
+ geom_point(aes(colour = factor(cyl))) +
+ blue_theme +
+ colour_scale
+ggplot(mtcars, aes(mpg, wt)) +
+ geom_point(aes(colour = factor(cyl))) +
+ red_theme +
+ colour_scale
+```
diff --git a/tests/docs/playwright/html/dark-brand/project-light-dark/simple.qmd b/tests/docs/playwright/html/dark-brand/project-dark/simple.qmd
similarity index 100%
rename from tests/docs/playwright/html/dark-brand/project-light-dark/simple.qmd
rename to tests/docs/playwright/html/dark-brand/project-dark/simple.qmd
diff --git a/tests/docs/playwright/html/dark-brand/project-light/_quarto.yml b/tests/docs/playwright/html/dark-brand/project-light/_quarto.yml
new file mode 100644
index 0000000000..636e01deb3
--- /dev/null
+++ b/tests/docs/playwright/html/dark-brand/project-light/_quarto.yml
@@ -0,0 +1,5 @@
+project:
+ type: default
+brand:
+ light: blue-background.yml
+ dark: red-background.yml
diff --git a/tests/docs/playwright/html/dark-brand/project-light/blue-background.yml b/tests/docs/playwright/html/dark-brand/project-light/blue-background.yml
new file mode 100644
index 0000000000..e905fff2be
--- /dev/null
+++ b/tests/docs/playwright/html/dark-brand/project-light/blue-background.yml
@@ -0,0 +1,3 @@
+color:
+ background: "#ccddff"
+ foreground: "#336644"
diff --git a/tests/docs/playwright/html/dark-brand/project-light/red-background.yml b/tests/docs/playwright/html/dark-brand/project-light/red-background.yml
new file mode 100644
index 0000000000..6d95abf09f
--- /dev/null
+++ b/tests/docs/playwright/html/dark-brand/project-light/red-background.yml
@@ -0,0 +1,3 @@
+color:
+ background: "#42070b"
+ foreground: "#cceedd"
diff --git a/tests/docs/playwright/html/dark-brand/project-light/simple-respect-color-scheme.qmd b/tests/docs/playwright/html/dark-brand/project-light/simple-respect-color-scheme.qmd
new file mode 100644
index 0000000000..4e61498251
--- /dev/null
+++ b/tests/docs/playwright/html/dark-brand/project-light/simple-respect-color-scheme.qmd
@@ -0,0 +1,55 @@
+---
+title: "dark brand - ggplot"
+format:
+ html:
+ respect-user-color-scheme: true
+execute:
+ echo: false
+ warning: false
+---
+
+```{r}
+#| echo: false
+#| warning: false
+library(ggplot2)
+
+ggplot_theme <- function(bgcolor, fgcolor) {
+ theme_minimal(base_size = 11) %+%
+ theme(
+ panel.border = element_blank(),
+ panel.grid.major.y = element_blank(),
+ panel.grid.minor.y = element_blank(),
+ panel.grid.major.x = element_blank(),
+ panel.grid.minor.x = element_blank(),
+ text = element_text(colour = fgcolor),
+ axis.text = element_text(colour = fgcolor),
+ rect = element_rect(colour = bgcolor, fill = bgcolor),
+ plot.background = element_rect(fill = bgcolor, colour = NA),
+ axis.line = element_line(colour = fgcolor),
+ axis.ticks = element_line(colour = fgcolor)
+ )
+}
+
+brand_ggplot <- function(brand_yml) {
+ brand <- yaml::yaml.load_file(brand_yml)
+ ggplot_theme(brand$color$background, brand$color$foreground)
+}
+
+blue_theme <- brand_ggplot("blue-background.yml")
+red_theme <- brand_ggplot("red-background.yml")
+
+colour_scale <- scale_colour_manual(values = c("darkorange", "purple", "cyan4"))
+```
+
+
+```{r}
+#| renderings: [light, dark]
+ggplot(mtcars, aes(mpg, wt)) +
+ geom_point(aes(colour = factor(cyl))) +
+ blue_theme +
+ colour_scale
+ggplot(mtcars, aes(mpg, wt)) +
+ geom_point(aes(colour = factor(cyl))) +
+ red_theme +
+ colour_scale
+```
diff --git a/tests/docs/playwright/html/dark-brand/project-light/simple.qmd b/tests/docs/playwright/html/dark-brand/project-light/simple.qmd
new file mode 100644
index 0000000000..ff402f3ee3
--- /dev/null
+++ b/tests/docs/playwright/html/dark-brand/project-light/simple.qmd
@@ -0,0 +1,52 @@
+---
+title: "dark brand - ggplot"
+execute:
+ echo: false
+ warning: false
+---
+
+```{r}
+#| echo: false
+#| warning: false
+library(ggplot2)
+
+ggplot_theme <- function(bgcolor, fgcolor) {
+ theme_minimal(base_size = 11) %+%
+ theme(
+ panel.border = element_blank(),
+ panel.grid.major.y = element_blank(),
+ panel.grid.minor.y = element_blank(),
+ panel.grid.major.x = element_blank(),
+ panel.grid.minor.x = element_blank(),
+ text = element_text(colour = fgcolor),
+ axis.text = element_text(colour = fgcolor),
+ rect = element_rect(colour = bgcolor, fill = bgcolor),
+ plot.background = element_rect(fill = bgcolor, colour = NA),
+ axis.line = element_line(colour = fgcolor),
+ axis.ticks = element_line(colour = fgcolor)
+ )
+}
+
+brand_ggplot <- function(brand_yml) {
+ brand <- yaml::yaml.load_file(brand_yml)
+ ggplot_theme(brand$color$background, brand$color$foreground)
+}
+
+blue_theme <- brand_ggplot("blue-background.yml")
+red_theme <- brand_ggplot("red-background.yml")
+
+colour_scale <- scale_colour_manual(values = c("darkorange", "purple", "cyan4"))
+```
+
+
+```{r}
+#| renderings: [light, dark]
+ggplot(mtcars, aes(mpg, wt)) +
+ geom_point(aes(colour = factor(cyl))) +
+ blue_theme +
+ colour_scale
+ggplot(mtcars, aes(mpg, wt)) +
+ geom_point(aes(colour = factor(cyl))) +
+ red_theme +
+ colour_scale
+```
diff --git a/tests/integration/playwright/tests/html-dark-mode-defaultdark.spec.ts b/tests/integration/playwright/tests/html-dark-mode-defaultdark.spec.ts
new file mode 100644
index 0000000000..1f41fa66f4
--- /dev/null
+++ b/tests/integration/playwright/tests/html-dark-mode-defaultdark.spec.ts
@@ -0,0 +1,51 @@
+import { test, expect } from '@playwright/test';
+
+async function check_backgrounds(page, class_, primary, secondary) {
+ const locatr = await page.locator('body').first();
+ await expect(locatr).toHaveClass(`fullcontent ${class_}`);
+ await expect(locatr).toHaveCSS('background-color', primary);
+ await page.locator("a.quarto-color-scheme-toggle").click();
+ const locatr2 = await page.locator('body').first();
+ await expect(locatr2).toHaveCSS('background-color', secondary);
+}
+
+test.use({
+ colorScheme: 'dark'
+});
+
+const blue = 'rgb(204, 221, 255)';
+const red = 'rgb(66, 7, 11)';
+
+
+// brands used in these documents have background colors
+
+test('Dark and light brand after user themes', async ({ page }) => {
+ // brand overrides theme background color
+ await page.goto('./html/dark-brand/brand-after-theme.html');
+ await check_backgrounds(page, 'quarto-dark', red, blue);
+});
+
+// project tests
+
+test('Project specifies light and dark brands', async ({ page }) => {
+ await page.goto('./html/dark-brand/project-light/simple.html');
+ await check_backgrounds(page, 'quarto-light', blue, red);
+});
+
+
+test('Project specifies dark and light brands', async ({ page }) => {
+ await page.goto('./html/dark-brand/project-dark/simple.html');
+ await check_backgrounds(page, 'quarto-dark', red, blue);
+});
+
+
+test('Project specifies light and dark brands and respect-user-color-scheme', async ({ page }) => {
+ await page.goto('./html/dark-brand/project-light/simple-respect-color-scheme.html');
+ await check_backgrounds(page, 'quarto-dark', red, blue);
+});
+
+
+test('Project specifies dark and light brands and respect-user-color-scheme', async ({ page }) => {
+ await page.goto('./html/dark-brand/project-dark/simple-respect-color-scheme.html');
+ await check_backgrounds(page, 'quarto-dark', red, blue);
+});
diff --git a/tests/integration/playwright/tests/html-dark-mode-defaultlight.spec.ts b/tests/integration/playwright/tests/html-dark-mode-defaultlight.spec.ts
new file mode 100644
index 0000000000..9a4abc2f96
--- /dev/null
+++ b/tests/integration/playwright/tests/html-dark-mode-defaultlight.spec.ts
@@ -0,0 +1,49 @@
+import { test, expect } from '@playwright/test';
+
+async function check_backgrounds(page, class_, primary, secondary) {
+ const locatr = await page.locator('body').first();
+ await expect(locatr).toHaveClass(`fullcontent ${class_}`);
+ await expect(locatr).toHaveCSS('background-color', primary);
+ await page.locator("a.quarto-color-scheme-toggle").click();
+ const locatr2 = await page.locator('body').first();
+ await expect(locatr2).toHaveCSS('background-color', secondary);
+}
+
+test.use({
+ colorScheme: 'light'
+});
+
+const blue = 'rgb(204, 221, 255)';
+const red = 'rgb(66, 7, 11)';
+
+// brands used in these documents have background colors
+
+test('Dark and light brand after user themes', async ({ page }) => {
+ // brand overrides theme background color
+ await page.goto('./html/dark-brand/brand-after-theme.html');
+ await check_backgrounds(page, 'quarto-dark', red, blue);
+});
+
+// project tests
+
+test('Project specifies light and dark brands', async ({ page }) => {
+ await page.goto('./html/dark-brand/project-light/simple.html');
+ await check_backgrounds(page, 'quarto-light', blue, red);
+});
+
+
+test('Project specifies dark and light brands', async ({ page }) => {
+ await page.goto('./html/dark-brand/project-dark/simple.html');
+ await check_backgrounds(page, 'quarto-dark', red, blue);
+});
+
+
+test('Project specifies light and dark brands and respect-user-color-scheme', async ({ page }) => {
+ await page.goto('./html/dark-brand/project-light/simple-respect-color-scheme.html');
+ await check_backgrounds(page, 'quarto-light', blue, red);
+});
+
+test('Project specifies dark and light brands and respect-user-color-scheme', async ({ page }) => {
+ await page.goto('./html/dark-brand/project-dark/simple-respect-color-scheme.html');
+ await check_backgrounds(page, 'quarto-light', blue, red);
+});
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 636dc5d7ec..b08a0bbaf4 100644
--- a/tests/integration/playwright/tests/html-dark-mode-nojs.spec.ts
+++ b/tests/integration/playwright/tests/html-dark-mode-nojs.spec.ts
@@ -25,7 +25,7 @@ test('Light brand default, no JS', async ({ page }) => {
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
- await page.goto('./html/dark-brand/project-light-dark/simple.html');
+ await page.goto('./html/dark-brand/project-dark/simple.html');
const locatr = await page.locator('body').first();
await expect(locatr).toHaveClass('fullcontent quarto-dark');
await expect(locatr).toHaveCSS('background-color', 'rgb(66, 7, 11)');
diff --git a/tests/integration/playwright/tests/html-dark-mode.spec.ts b/tests/integration/playwright/tests/html-dark-mode.spec.ts
index 7dedfa7839..23c0b2fa67 100644
--- a/tests/integration/playwright/tests/html-dark-mode.spec.ts
+++ b/tests/integration/playwright/tests/html-dark-mode.spec.ts
@@ -1,14 +1,5 @@
import { test, expect } from '@playwright/test';
-async function check_red_blue(page) {
- const locatr = await page.locator('body').first();
- await expect(locatr).toHaveClass('fullcontent quarto-dark');
- await expect(locatr).toHaveCSS('background-color', 'rgb(66, 7, 11)');
- await page.locator("a.quarto-color-scheme-toggle").click();
- const locatr2 = await page.locator('body').first();
- await expect(locatr2).toHaveCSS('background-color', 'rgb(204, 221, 255)');
-}
-
async function check_theme_overrides(page) {
const locatr = await page.locator('body').first();
await expect(locatr).toHaveClass('fullcontent quarto-light');
@@ -19,12 +10,6 @@ async function check_theme_overrides(page) {
}
// themes used in these documents have background colors
-test('Dark and light brand after user themes', async ({ page }) => {
- // brand overrides theme background color
- await page.goto('./html/dark-brand/brand-after-theme.html');
- await check_red_blue(page);
-});
-
test('Dark and light brand before user themes', async ({ page }) => {
// theme will override brand
await page.goto('./html/dark-brand/brand-before-theme.html');
@@ -33,20 +18,15 @@ test('Dark and light brand before user themes', async ({ page }) => {
// project tests
-test('Project specifies dark and light brands', async ({ page }) => {
- await page.goto('./html/dark-brand/project-light-dark/simple.html');
- await check_red_blue(page);
-});
-
test('Project brand before user themes', async ({ page }) => {
// theme will override brand
- await page.goto('./html/dark-brand/project-light-dark/brand-under-theme.html');
+ await page.goto('./html/dark-brand/project-dark/brand-under-theme.html');
await check_theme_overrides(page);
});
test('Brand false remove project brand', async ({ page }) => {
// theme will override brand
- await page.goto('./html/dark-brand/project-light-dark/brand-false.html');
+ await page.goto('./html/dark-brand/project-dark/brand-false.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)');