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
1 change: 1 addition & 0 deletions news/changelog-1.12.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ All changes included in 1.12:
## Accessibility

- ([#15269](https://github.com/quarto-dev/quarto-cli/pull/15269)): Announce every link that opens a new tab to screen readers, not only links opened by `link-external-newwindow`. (author: @mcanouil)
- ([#15306](https://github.com/quarto-dev/quarto-cli/issues/15306)): Fix the notebook preview title taking the theme's heading color on the primary-colored header bar, which left it low-contrast or unreadable with themes such as `lux` or a custom `$headings-color`. The title now uses the same color as the header buttons. (author: @SabyaXSachi)

## Formats

Expand Down
5 changes: 4 additions & 1 deletion src/resources/formats/html/embed/template.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,15 @@
border-bottom: solid 1px;
}

/* The title sits on the theme's primary background, so it inherits the
header's contrasting text color instead of the theme heading color */
#quarto-embed-header h6 {
font-size: 1.1em;
padding-top: 0.6em;
margin-left: 1em;
margin-right: 1em;
font-weight: 400;
color: inherit;
}

#quarto-embed-header a.quarto-back-link,
Expand Down Expand Up @@ -123,7 +126,7 @@
</head>

<body>
<nav id="quarto-embed-header" class="headroom fixed-top bg-primary" aria-labelledby="quarto-embed-title">
<nav id="quarto-embed-header" class="headroom fixed-top text-bg-primary" aria-labelledby="quarto-embed-title">

<a href="$if(nbMeta.backHref)$$nbMeta.backHref$$endif$" onclick="window.quartoBackToArticle(); return false;" class="btn btn-primary quarto-back-link"><i class="bi bi-caret-left"></i> $nbMeta.backLabel$</a>
<h6 id="quarto-embed-title"><i class="bi bi-journal-code"></i> $nbMeta.title$</h6>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/notebook.out.ipynb
**/*.quarto_ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
title: "Home"
theme: cerulean
---

{{< embed notebook.ipynb#answer >}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "answer",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"2"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#| label: answer\n",
"1 + 1"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/notebook.out.ipynb
**/*.quarto_ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
title: "Home"
theme: lux
---

{{< embed notebook.ipynb#answer >}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "answer",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"2"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#| label: answer\n",
"1 + 1"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/notebook.out.ipynb
**/*.quarto_ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
title: "Home"
theme: [default, theme-light-heading.scss]
---

{{< embed notebook.ipynb#answer >}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "answer",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"2"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#| label: answer\n",
"1 + 1"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/*-- scss:defaults --*/

// A user theme setting a custom light heading color. The heading color
// previously leaked onto the notebook preview title, which sits on the
// theme's primary background.
$headings-color: #dee2e6 !default;
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { expect, test, type Locator, type Page } from "@playwright/test";
import { checkColorIdentical } from "../src/utils";

// The notebook preview header is painted with the theme's primary background,
// so its title must use the same contrasting text color as the header's
// buttons. A theme with a custom $headings-color used to leak that color onto
// the title, making it hard or impossible to read against the primary
// background while the buttons next to it stayed white.
const testCases = [
{
name: "default theme (no custom heading color)",
dir: "./html/notebook-preview-standalone",
},
{
name: "theme with custom dark heading color (lux)",
dir: "./html/notebook-preview-theme-dark-heading",
},
{
name: "theme with custom light heading color",
dir: "./html/notebook-preview-theme-light-heading",
},
{
// cerulean defines a light heading color of its own, but also paints
// headings white inside .bg-primary containers, so the title must stay
// white rather than regressing to the theme heading color
name: "theme that already compensates heading colors on .bg-primary (cerulean)",
dir: "./html/notebook-preview-theme-cerulean",
},
];

async function bgPrimaryColor(page: Page): Promise<string> {
// Compute the color the `bg-primary` utility produces for this theme
return await page.evaluate(() => {
const probe = window.document.createElement("div");
probe.className = "bg-primary";
window.document.body.appendChild(probe);
const color = window.getComputedStyle(probe).backgroundColor;
probe.remove();
return color;
});
}

test.describe("Notebook preview title color", () => {
for (const { name, dir } of testCases) {
test.describe(name, () => {
let title: Locator;
let header: Locator;

test.beforeEach(async ({ page }) => {
await page.goto(`${dir}/notebook-preview.html`);
header = page.locator("#quarto-embed-header");
title = page.locator("#quarto-embed-title");
await expect(title).toBeVisible();
});

test("title matches the header buttons' contrasting color", async ({ page }) => {
const backLink = page.locator(".quarto-back-link");
await expect(backLink).toBeVisible();
await checkColorIdentical(title, backLink, "color");
});

test("header keeps the primary background", async ({ page }) => {
await expect(header).toHaveCSS(
"background-color",
await bgPrimaryColor(page),
);
});
});
}
});
Loading