Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions src/command/render/pandoc-html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,15 +101,13 @@ export async function resolveSassBundles(
const userBrand = bundle.user?.findIndex((layer) => layer === "brand");
let cloned = false;
if (userBrand && userBrand !== -1) {
// console.log('light brand order specified', userBrand, cloned);
bundle = cloneDeep(bundle);
cloned = true;
bundle.user!.splice(userBrand, 1, ...(maybeBrandBundle?.user || []));
foundBrand.light = true;
}
const darkBrand = bundle.dark?.user?.findIndex((layer) => layer === "brand");
if (darkBrand && darkBrand !== -1) {
// console.log('dark brand order specified', darkBrand, cloned);
if (!cloned) {
bundle = cloneDeep(bundle);
}
Expand Down
36 changes: 18 additions & 18 deletions src/project/project-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -521,12 +521,12 @@ export async function projectResolveBrand(
) as BrandJson;
return new Brand(brand, dirname(brandPath), project.dir);
}
async function loadLocalBrand(brandPath: string) : Promise<Brand> {
async function loadRelativeBrand(brandPath: string, dir: string = dirname(fileName!)) : Promise<Brand> {
let resolved: string = "";
if (brandPath.startsWith("/")) {
resolved = join(project.dir, brandPath);
} else {
resolved = join(dirname(fileName!), brandPath);
resolved = join(dir, brandPath);
}
return await loadBrand(resolved);
}
Expand All @@ -538,28 +538,28 @@ export async function projectResolveBrand(
let fileNames = ["_brand.yml", "_brand.yaml"].map((file) =>
join(project.dir, file)
);
if (project?.config?.brand === false) {
let brand = project?.config?.brand as Boolean | string | {light?: string, dark?: string};
if (brand === false) {
project.brandCache.brand = undefined;
return project.brandCache.brand;
}
if (typeof project?.config?.brand === "string") {
fileNames = [join(project.dir, project.config.brand)];
if (typeof brand === "object" && brand &&
("light" in brand || "dark" in brand)) {
project.brandCache.brand = {
light: brand.light ? await loadRelativeBrand(brand.light, project.dir) : undefined,
dark: brand.dark ? await loadRelativeBrand(brand.dark, project.dir) : undefined,
};
return project.brandCache.brand;
}
if (typeof brand === "string") {
fileNames = [join(project.dir, brand)];
}

for (const brandPath of fileNames) {
if (!existsSync(brandPath)) {
continue;
}
const brand = await readAndValidateYamlFromFile(
brandPath,
refSchema("brand", "Format-independent brand configuration."),
"Brand validation failed for " + brandPath + ".",
) as BrandJson;
project.brandCache.brand = {light: new Brand(
brand,
dirname(brandPath),
project.dir,
)};
project.brandCache.brand = {light: await loadBrand(brandPath)};
}
return project.brandCache.brand;
} else {
Expand All @@ -576,14 +576,14 @@ export async function projectResolveBrand(
return fileInformation.brand;
}
if (typeof brand === "string") {
fileInformation.brand = {light: await loadLocalBrand(brand)};
fileInformation.brand = {light: await loadRelativeBrand(brand)};
return fileInformation.brand;
} else {
assert(typeof brand === "object");
if ("light" in brand || "dark" in brand) {
let light, dark;
if (typeof brand.light === "string") {
light = await loadLocalBrand(brand.light)
light = await loadRelativeBrand(brand.light)
} else {
light = new Brand(
brand.light!,
Expand All @@ -592,7 +592,7 @@ export async function projectResolveBrand(
);
}
if (typeof brand.dark === "string") {
dark = await loadLocalBrand(brand.dark)
dark = await loadRelativeBrand(brand.dark)
} else {
dark = new Brand(
brand.dark!,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
project:
type: default
brand:
dark: red-background.yml
light: blue-background.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
color:
background: "#ccddff"
foreground: "#336644"
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
title: "dark brand - ggplot"
brand: false
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
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
title: "dark brand - ggplot"
theme:
light: simplex
dark: cyborg # same effect as [brand, cyborg]
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
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
color:
background: "#42070b"
foreground: "#cceedd"
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
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
```
11 changes: 11 additions & 0 deletions tests/integration/playwright/tests/html-dark-mode-nojs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,14 @@ test('Light brand default, no JS', async ({ page }) => {
await expect(locatr).toHaveClass('fullcontent quarto-light');
await expect(locatr).toHaveCSS('background-color', 'rgb(252, 252, 252)');
});


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');
const locatr = await page.locator('body').first();
await expect(locatr).toHaveClass('fullcontent quarto-dark');
await expect(locatr).toHaveCSS('background-color', 'rgb(66, 7, 11)');
});

49 changes: 39 additions & 10 deletions tests/integration/playwright/tests/html-dark-mode.spec.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,55 @@
import { test, expect } from '@playwright/test';

test('Dark and light brand after user themes', 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/brand-after-theme.html');
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)');
});
}


test('Dark and light brand before user themes', 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/brand-before-theme.html');
async function check_theme_overrides(page) {
const locatr = await page.locator('body').first();
await expect(locatr).toHaveClass('fullcontent quarto-light');
await expect(locatr).toHaveCSS('background-color', 'rgb(252, 252, 252)');
await page.locator("a.quarto-color-scheme-toggle").click();
const locatr2 = await page.locator('body').first();
await expect(locatr2).toHaveCSS('background-color', 'rgb(6, 6, 6)');
}
// 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');
await check_theme_overrides(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 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');
const locatr = await page.locator('body').first();
await expect(locatr).toHaveClass('fullcontent quarto-light');
await expect(locatr).toHaveCSS('background-color', 'rgb(255, 255, 255)');
// no toggle
expect(await page.locator('a.quarto-color-scheme-toggle').count()).toEqual(0);
});
Loading