Skip to content

Commit 7f3a96d

Browse files
FIX: myst-nb 1.4+ compatibility, inline_literal_box option, and --qe-literal-color (#373)
* FIX: Set data-theme attribute on <html> for mystnb 1.4+ compatibility myst-nb 1.4.0 (PR executablebooks/MyST-NB#693) changed its dark mode CSS from html[data-theme="dark"] selectors to a CSS space-toggle technique that falls back to @media (prefers-color-scheme) when no data-theme attribute is present. Since quantecon-book-theme uses body.dark-theme class (not data-theme) for dark mode, mystnb never detects the theme mode and falls through to the OS color scheme preference, causing dark code cell backgrounds on light-themed sites for users with OS dark mode enabled. Fix: Set data-theme="light" on <html> by default and toggle it to data-theme="dark" when the contrast button is activated. This is the standard mechanism used by pydata-sphinx-theme, Furo, and sphinx-book-theme. Closes #372 * UPDATE: Regenerate all visual snapshots (8 files) * fix: override pydata-sphinx-theme .nf color rule activated by data-theme attribute pydata-sphinx-theme has a rule scoped to html[data-theme=light] that sets .highlight .nf color to #0078a1 with !important. This was dormant before we set data-theme on <html>. It overrode our custom function name color (#06287e) from _code.scss since :where() has zero specificity. Add a counter-rule with higher specificity to preserve our custom highlighting when qetheme_code_style is enabled. * fix: increase specificity of custom highlighting to beat pydata's Pygments rules pydata-sphinx-theme's overwrite_pygments_css scopes ALL Pygments rules to html[data-theme="light"] and html[data-theme="dark"] at specificity (0,3,1). Our :where() wrapper gave zero specificity, so setting data-theme activated pydata's Pygments rules which overrode ALL our custom token colors. Replace :where(body:not(.use-pygments-style)) with html body:not(.use-pygments-style) which gives specificity (0,3,2), beating pydata's (0,3,1). Applied to both _code.scss and _syntax.scss. Remove the previous .nf-specific override since higher base specificity now handles all tokens. * UPDATE: Regenerate all visual snapshots (3 files) * Add inline_literal_box option to control inline code box styling Add configurable theme option (default: False) that controls whether inline code elements (code.literal) show pydata-sphinx-theme's background box and border styling. When False, the boxes are stripped to match the theme's original look. Set inline_literal_box: True in html_theme_options to re-enable the box styling. * Document inline_literal_box option in code highlighting docs * UPDATE: Regenerate all visual snapshots (4 files) * Add --qe-literal-color to text color scheme system Integrate inline code literal (code.literal) color into the color scheme system alongside emphasis, strong, and definition colors: - Seoul256: #af5f5f (muted rust) / #d78787 (soft rose dark) - Gruvbox: #9d0006 (dark red) / #fb4934 (bright red dark) - None: inherits text color Overridable via --qe-literal-color CSS variable. * Apply Copilot review: add contrast ratios and fix leading space in body class --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent 3ffc996 commit 7f3a96d

20 files changed

Lines changed: 130 additions & 14 deletions

File tree

docs/user/code-highlighting.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,57 @@ full color table.
4444

4545
If you use a custom Pygments style (`qetheme_code_style: False`), the dark mode
4646
syntax colors are not applied and your Pygments configuration takes precedence.
47+
48+
## Inline Code Box Styling
49+
50+
By default, the theme removes the background box and border that
51+
`pydata-sphinx-theme` applies to inline code literals (e.g., `` `x` `` or
52+
`` `x = 42` ``). This keeps inline code visually consistent with the original
53+
QuantEcon look.
54+
55+
To re-enable the box styling (background color, border, and padding) on inline
56+
code elements:
57+
58+
```python
59+
html_theme_options = {
60+
...
61+
"inline_literal_box": True,
62+
...
63+
}
64+
```
65+
66+
For Jupyter Book projects:
67+
68+
```yaml
69+
sphinx:
70+
config:
71+
html_theme_options:
72+
inline_literal_box: true
73+
```
74+
75+
When `inline_literal_box` is `False` (the default), inline code appears without
76+
any visual container. When set to `True`, inline code elements display with a
77+
subtle background and border provided by the parent theme.
78+
79+
## Inline Code Color
80+
81+
Inline code literals (e.g., `` `x` ``) are styled with a distinct text color
82+
that integrates with the theme's color scheme system:
83+
84+
| Scheme | Light Mode | Dark Mode |
85+
|---|---|---|
86+
| **seoul256** (default) | `#af5f5f` (muted rust) | `#d78787` (soft rose) |
87+
| **gruvbox** | `#9d0006` (dark red) | `#fb4934` (bright red) |
88+
| **none** | inherits text color | inherits text color |
89+
90+
To override the inline code color, set `--qe-literal-color` in a custom CSS
91+
file placed in your `_static/` directory:
92+
93+
```css
94+
:root {
95+
--qe-literal-color: #912583; /* custom color for light mode */
96+
}
97+
body.dark-theme {
98+
--qe-literal-color: #f3c7ee; /* custom color for dark mode */
99+
}
100+
```

docs/user/text-color-schemes.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ terms using a built-in color scheme system.
1212

1313
| Scheme | Description |
1414
|---|---|
15-
| `seoul256` (default) | Dark teal for emphasis, dark amber for strong — with matching light variants for dark mode |
16-
| `gruvbox` | Earthy aqua for emphasis, warm orange for strong — with light variants for dark mode |
15+
| `seoul256` (default) | Dark teal for emphasis, dark amber for strong, muted rust for inline code — with matching light variants for dark mode |
16+
| `gruvbox` | Earthy aqua for emphasis, warm orange for strong, dark red for inline code — with light variants for dark mode |
1717
| `none` | Restores standard typography — italic for `em`, bold for `strong`, no color |
1818

1919
## Selecting a Scheme
@@ -44,17 +44,20 @@ sphinx:
4444
| **Emphasis** (`em`) | `#005f5f` dark teal | `#5fafaf` medium-light teal |
4545
| **Bold/Strong** (`strong`, `b`) | `#875f00` dark amber | `#d7af5f` light amber-gold |
4646
| **Definitions** (`dl dt`) | Inherits from bold/strong | Inherits from bold/strong |
47+
| **Inline Code** (`code.literal`) | `#af5f5f` muted rust | `#d78787` soft rose |
4748

4849
```css
4950
/* Seoul256 — Light Mode */
5051
em { color: #005f5f; } /* dark teal */
5152
strong { color: #875f00; } /* dark amber */
5253
dl dt { color: #875f00; } /* inherits from strong */
54+
code.literal { color: #af5f5f; } /* muted rust */
5355
5456
/* Seoul256 — Dark Mode */
5557
em { color: #5fafaf; } /* medium-light teal */
5658
strong { color: #d7af5f; } /* light amber-gold */
5759
dl dt { color: #d7af5f; } /* inherits from strong */
60+
code.literal { color: #d78787; } /* soft rose */
5861
```
5962

6063
## Gruvbox Colors
@@ -64,17 +67,20 @@ dl dt { color: #d7af5f; } /* inherits from strong */
6467
| **Emphasis** (`em`) | `#427b58` earthy aqua | `#8ec07c` light aqua |
6568
| **Bold/Strong** (`strong`, `b`) | `#af3a03` warm orange | `#fe8019` bright orange |
6669
| **Definitions** (`dl dt`) | Inherits from bold/strong | Inherits from bold/strong |
70+
| **Inline Code** (`code.literal`) | `#9d0006` dark red | `#fb4934` bright red |
6771

6872
```css
6973
/* Gruvbox — Light Mode */
7074
em { color: #427b58; } /* earthy aqua */
7175
strong { color: #af3a03; } /* warm orange */
7276
dl dt { color: #af3a03; } /* inherits from strong */
77+
code.literal { color: #9d0006; } /* dark red */
7378
7479
/* Gruvbox — Dark Mode */
7580
em { color: #8ec07c; } /* light aqua */
7681
strong { color: #fe8019; } /* bright orange */
7782
dl dt { color: #fe8019; } /* inherits from strong */
83+
code.literal { color: #fb4934; } /* bright red */
7884
```
7985

8086
## Custom Color Scheme
@@ -88,11 +94,13 @@ The theme will automatically detect and include it:
8894
--qe-emphasis-color: #005f5f;
8995
--qe-strong-color: #875f00;
9096
--qe-definition-color: #875f00;
97+
--qe-literal-color: #af5f5f;
9198
}
9299
body.dark-theme {
93100
--qe-emphasis-color: #5fafaf;
94101
--qe-strong-color: #d7af5f;
95102
--qe-definition-color: #d7af5f;
103+
--qe-literal-color: #d78787;
96104
}
97105
```
98106

src/quantecon_book_theme/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,11 @@ def add_pygments_style_class(app, pagename, templatename, context, doctree):
548548
# Set a context variable that can be used in templates
549549
context["use_pygments_style"] = not qetheme_code_style
550550

551+
inline_literal_box = config_theme.get("inline_literal_box", False)
552+
if isinstance(inline_literal_box, str):
553+
inline_literal_box = inline_literal_box.lower() == "true"
554+
context["inline_literal_box"] = inline_literal_box
555+
551556

552557
def setup_pygments_css(app):
553558
"""Ensure Pygments CSS is included when using Pygments styles.

src/quantecon_book_theme/assets/scripts/theme-settings.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ export function initThemeSettings() {
1414
if (setContrast == 1) {
1515
$body.addClass("dark-theme");
1616
$(".btn__contrast").addClass("btn-active");
17+
document.documentElement.setAttribute('data-theme', 'dark');
18+
} else {
19+
document.documentElement.setAttribute('data-theme', 'light');
1720
}
1821
}
1922

@@ -28,10 +31,12 @@ export function initThemeSettings() {
2831
$(this).removeClass("btn-active");
2932
localStorage.setContrast = 0;
3033
$body.removeClass("dark-theme");
34+
document.documentElement.setAttribute('data-theme', 'light');
3135
} else {
3236
$(this).addClass("btn-active");
3337
localStorage.setContrast = 1;
3438
$body.addClass("dark-theme");
39+
document.documentElement.setAttribute('data-theme', 'dark');
3540
if (!$darkLogo.length) {
3641
$lightLogo.css("display", "block");
3742
}

src/quantecon_book_theme/assets/styles/_base.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,11 @@ dl.field-list dt {
168168
color: var(--qe-definition-color, var(--qe-strong-color, colors.$definition));
169169
}
170170

171+
// Inline code literal styling - colored text for code.literal elements
172+
code.literal {
173+
color: var(--qe-literal-color, colors.$literal);
174+
}
175+
171176
li {
172177
margin: 0.5rem 0;
173178
}

src/quantecon_book_theme/assets/styles/_code.scss

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,25 @@
33
* To use Pygments built-in styles instead, set qetheme_code_style = False in html_theme_options
44
* and configure pygments_style in conf.py
55
*
6-
* Using :where() pseudo-class to keep specificity low so Pygments styles can override when enabled
6+
* The `html` ancestor ensures specificity (0,3,2) beats pydata-sphinx-theme's
7+
* Pygments rules scoped to html[data-theme] at (0,3,1).
8+
* When body has .use-pygments-style, these rules don't match so the configured
9+
* Pygments style takes effect instead.
710
*/
811

9-
:where(body:not(.use-pygments-style)) {
12+
/* Override pydata-sphinx-theme's code.literal box styling.
13+
* When inline_literal_box is False (default), we strip the background,
14+
* border, and padding from inline code elements to match our original look.
15+
* Set inline_literal_box: True in html_theme_options to re-enable boxes.
16+
*/
17+
body:not(.inline-literal-box) code.literal {
18+
background-color: transparent;
19+
border: none;
20+
border-radius: 0;
21+
padding: 0;
22+
}
23+
24+
html body:not(.use-pygments-style) {
1025
.highlight .hll {
1126
background-color: #ffc;
1227
}
@@ -213,7 +228,7 @@
213228
* A carefully chosen palette for readability on dark backgrounds (#1e1e32).
214229
* Inspired by VS Code Dark+ / One Dark themes.
215230
*/
216-
:where(body.dark-theme:not(.use-pygments-style)) {
231+
html body.dark-theme:not(.use-pygments-style) {
217232
.highlight .hll {
218233
background-color: #3a3a5c;
219234
}

src/quantecon_book_theme/assets/styles/_color-schemes.scss

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
/*
22
-----------------------------------
33
TEXT COLOR SCHEMES
4-
Built-in color scheme definitions for emphasis, strong, and definition markup.
4+
Built-in color scheme definitions for emphasis, strong, literal, and definition markup.
55
66
Available schemes:
77
- seoul256 (default): Seoul256-inspired teal & amber palette
88
- gruvbox: Warm earthy aqua & orange palette
99
- none: Restores standard typography (italic for em, bold for strong, no color)
1010
1111
Custom override: Place a custom_color_scheme.css in your project's _static/
12-
directory defining --qe-emphasis-color, --qe-strong-color, --qe-definition-color
13-
on :root and body.dark-theme.
12+
directory defining --qe-emphasis-color, --qe-strong-color, --qe-definition-color,
13+
--qe-literal-color on :root and body.dark-theme.
1414
-----------------------------------
1515
*/
1616

@@ -35,6 +35,10 @@ body.color-scheme-gruvbox {
3535
color: var(--qe-definition-color, var(--qe-strong-color, colors.$gruvbox-definition));
3636
}
3737

38+
code.literal {
39+
color: var(--qe-literal-color, colors.$gruvbox-literal);
40+
}
41+
3842
&.dark-theme {
3943
em {
4044
color: var(--qe-emphasis-color, colors.$gruvbox-emphasis-dark);
@@ -50,6 +54,10 @@ body.color-scheme-gruvbox {
5054
dl.field-list dt {
5155
color: var(--qe-definition-color, var(--qe-strong-color, colors.$gruvbox-definition-dark));
5256
}
57+
58+
code.literal {
59+
color: var(--qe-literal-color, colors.$gruvbox-literal-dark);
60+
}
5361
}
5462
}
5563

@@ -72,4 +80,8 @@ body.color-scheme-none {
7280
dl.field-list dt {
7381
color: inherit;
7482
}
83+
84+
code.literal {
85+
color: inherit;
86+
}
7587
}

src/quantecon_book_theme/assets/styles/_colors.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,13 @@ $emphasis: #005f5f; // Seoul256 #23 - dark teal for emphasis (em tags)
99
$emphasis-dark: #5fafaf; // Seoul256 #73 - medium-light teal for dark mode
1010
$definition: #875f00; // Seoul256 #94 - dark amber for strong/definitions
1111
$definition-dark: #d7af5f; // Seoul256 #179 - light amber-gold for dark mode
12+
$literal: #af5f5f; // Seoul256 #131 - muted rust for inline code literals
13+
$literal-dark: #d78787; // Seoul256 #174 - soft rose for dark mode
1214

1315
// Text color scheme: Gruvbox
1416
$gruvbox-emphasis: #427b58; // Gruvbox aqua (dark) - 5.2:1 contrast vs white
1517
$gruvbox-emphasis-dark: #8ec07c; // Gruvbox aqua (light) - 8.3:1 contrast vs #222
1618
$gruvbox-definition: #af3a03; // Gruvbox orange (dark) - 5.0:1 contrast vs white
1719
$gruvbox-definition-dark: #fe8019; // Gruvbox orange (light) - 7.5:1 contrast vs #222
20+
$gruvbox-literal: #9d0006; // Gruvbox red (dark) - 8.3:1 contrast vs white, for inline code literals
21+
$gruvbox-literal-dark: #fb4934; // Gruvbox red (light) - 4.1:1 contrast vs #222, for dark mode

src/quantecon_book_theme/assets/styles/_dark-theme.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,10 @@ body.dark-theme {
175175
color: var(--qe-dark-inline-code);
176176
}
177177

178+
code.literal {
179+
color: var(--qe-literal-color, colors.$literal-dark);
180+
}
181+
178182
// =========================================
179183
// TOOLBAR
180184
// =========================================

src/quantecon_book_theme/assets/styles/_syntax.scss

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,8 @@
1010
border-radius: 2px;
1111
}
1212

13-
/* Background and border for custom QuantEcon style only
14-
* Using :where() to keep specificity low so Pygments styles can override
15-
*/
16-
:where(body:not(.use-pygments-style)) .highlight {
13+
/* Background and border for custom QuantEcon style only */
14+
html body:not(.use-pygments-style) .highlight {
1715
border: 1px solid #e1e1e1;
1816
background: #f7f7f7;
1917
}

0 commit comments

Comments
 (0)