Skip to content

Commit 668f554

Browse files
authored
Allow switching into dark mode theme (#181)
* Enable switching editor into dark mode * Allow light and dark themes on docs and test websites * Add release note * Add conditioning on whether `quarto-light` or `quarto-dark` is specified on the body HTML element. * Add themeing doc note * Add theme test document note
1 parent e5c09cc commit 668f554

9 files changed

+141
-13
lines changed

_extensions/webr/qwebr-monaco-editor-element.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// Global dictionary to store Monaco Editor instances
2-
globalThis.qwebrEditorInstances = {};
1+
// Global array to store Monaco Editor instances
2+
globalThis.qwebrEditorInstances = [];
33

44
// Function that builds and registers a Monaco Editor instance
55
globalThis.qwebrCreateMonacoEditorInstance = function (cellData) {

_extensions/webr/qwebr-styling.css

+42-9
Original file line numberDiff line numberDiff line change
@@ -35,45 +35,74 @@
3535
color: #0d9c29
3636
}
3737

38-
.qwebr-output-code-stdout {
38+
body.quarto-light .qwebr-output-code-stdout {
3939
color: #111;
4040
}
4141

42+
body.quarto-dark .qwebr-output-code-stdout {
43+
color: #EEE;
44+
}
45+
4246
.qwebr-output-code-stderr {
4347
color: #db4133;
4448
}
4549

46-
.qwebr-editor {
50+
body.quarto-light .qwebr-editor {
4751
border: 1px solid #EEEEEE;
4852
}
4953

50-
.qwebr-editor-toolbar {
54+
body.quarto-light .qwebr-editor-toolbar {
5155
background-color: #EEEEEE;
5256
padding: 0.2rem 0.5rem;
5357
}
5458

59+
body.quarto-dark .qwebr-editor {
60+
border: 1px solid #111;
61+
}
62+
63+
body.quarto-dark .qwebr-editor-toolbar {
64+
background-color: #111;
65+
padding: 0.2rem 0.5rem;
66+
}
67+
5568
.qwebr-button {
56-
background-color: #EEEEEE;
5769
display: inline-block;
5870
font-weight: 400;
5971
line-height: 1;
6072
text-decoration: none;
6173
text-align: center;
62-
color: #000;
63-
border-color: #dee2e6;
64-
border: 1px solid rgba(0,0,0,0);
6574
padding: 0.375rem 0.75rem;
6675
font-size: .9rem;
6776
border-radius: 0.25rem;
6877
transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
6978
}
7079

71-
.qwebr-button:hover {
80+
body.quarto-light .qwebr-button {
81+
background-color: #EEEEEE;
82+
color: #000;
83+
border-color: #dee2e6;
84+
border: 1px solid rgba(0,0,0,0);
85+
}
86+
87+
body.quarto-dark .qwebr-button {
88+
background-color: #111;
89+
color: #EEE;
90+
border-color: #dee2e6;
91+
border: 1px solid rgba(0,0,0,0);
92+
}
93+
94+
body.quarto-light .qwebr-button:hover {
7295
color: #000;
7396
background-color: #d9dce0;
7497
border-color: #c8ccd0;
7598
}
7699

100+
body.quarto-dark .qwebr-button:hover {
101+
color: #d9dce0;
102+
background-color: #323232;
103+
border-color: #d9dce0;
104+
}
105+
77106
.qwebr-button:disabled,.qwebr-button.disabled,fieldset:disabled .qwebr-button {
78107
pointer-events: none;
79108
opacity: .65
@@ -111,10 +140,14 @@
111140
display: contents;
112141
}
113142

114-
.reveal pre div code.qwebr-output-code-stdout {
143+
body.reveal.quarto-light pre div code.qwebr-output-code-stdout {
115144
color: #111;
116145
}
117146

147+
body.reveal.quarto-dark pre div code.qwebr-output-code-stdout {
148+
color: #EEEEEE;
149+
}
150+
118151
.reveal pre div code.qwebr-output-code-stderr {
119152
color: #db4133;
120153
}
+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Function to update Monaco Editors when body class changes
2+
function updateMonacoEditorsOnBodyClassChange() {
3+
// Select the body element
4+
const body = document.querySelector('body');
5+
6+
// Options for the observer (which mutations to observe)
7+
const observerOptions = {
8+
attributes: true, // Observe changes to attributes
9+
attributeFilter: ['class'] // Only observe changes to the 'class' attribute
10+
};
11+
12+
// Callback function to execute when mutations are observed
13+
const bodyClassChangeCallback = function(mutationsList, observer) {
14+
for(let mutation of mutationsList) {
15+
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
16+
// Class attribute has changed
17+
// Update all Monaco Editors on the page
18+
updateMonacoEditorTheme();
19+
}
20+
}
21+
};
22+
23+
// Create an observer instance linked to the callback function
24+
const observer = new MutationObserver(bodyClassChangeCallback);
25+
26+
// Start observing the target node for configured mutations
27+
observer.observe(body, observerOptions);
28+
}
29+
30+
// Function to update all instances of Monaco Editors on the page
31+
function updateMonacoEditorTheme() {
32+
// Determine what VS Theme to use
33+
const vsThemeToUse = document.body.classList.contains("quarto-dark") ? 'vs-dark' : 'vs' ;
34+
35+
// Iterate through all initialized Monaco Editors
36+
qwebrEditorInstances.forEach( function(editorInstance) {
37+
editorInstance.updateOptions({ theme: vsThemeToUse });
38+
});
39+
}
40+
41+
// Call the function to start observing changes to body class
42+
updateMonacoEditorsOnBodyClassChange();

_extensions/webr/webr.lua

+2
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,8 @@ local function ensureWebRSetup()
438438
-- Insert the monaco editor initialization
439439
quarto.doc.include_file("before-body", "qwebr-monaco-editor-init.html")
440440

441+
includeFileInHTMLTag("before-body", "qwebr-theme-switch.js", "js")
442+
441443
-- Insert the extension styling for defined elements
442444
includeFileInHTMLTag("before-body", "qwebr-monaco-editor-element.js", "js")
443445

docs/_quarto.yml

+5-1
Original file line numberDiff line numberDiff line change
@@ -74,5 +74,9 @@ website:
7474

7575
format:
7676
html:
77-
theme: cosmo
7877
toc: true
78+
79+
# Allow quarto to switch between light and dark themes.
80+
theme:
81+
light: flatly
82+
dark: darkly

docs/qwebr-release-notes.qmd

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Features listed under the `-dev` version have not yet been solidified and may ch
2020

2121
- Added `editor-max-height` cell option to limit growth of the editor window. ([#177](https://github.com/coatless/quarto-webr/pulls/173), thanks [ute](https://github.com/ute)!)
2222

23+
- Added the ability to have the monaco editor switch between Quarto's light and dark theme modes. ([#176](https://github.com/coatless/quarto-webr/issues/176))
2324

2425
## Bug fixes
2526

docs/qwebr-theming.qmd

+17-1
Original file line numberDiff line numberDiff line change
@@ -133,4 +133,20 @@ format:
133133
- cosmo
134134
- custom.scss
135135
---
136-
```
136+
```
137+
138+
## Light and Dark Mode
139+
140+
The Monaco editor used by `{quarto-webr}` to power interactive code cells respects [Quarto's light and dark theme modes](https://quarto.org/docs/output-formats/html-themes.html#dark-mode). To apply light and dark themes on a Quarto website, specify the following settings in the `_quarto.yml` configuration file:
141+
142+
```yaml
143+
theme:
144+
light: flatly
145+
dark: darkly
146+
```
147+
148+
Once set, a clickable toggle will appear on the page that can switch between these modes. This toggle modifies CSS classes on the `body` HTML element, adding `.quarto-light` for light mode and `.quarto-dark` for dark mode.
149+
150+
:::{.callout-note}
151+
The Monaco editor's theme automatically adjusts based on the document's theme. It uses a light theme (`vs`) in light mode and a dark theme (`vs-dark`) in dark mode.
152+
:::

tests/_quarto.yml

+5
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ website:
2323
- icon: github
2424
href: https://github.com/coatless/quarto-webr
2525

26+
# Allow quarto to switch between light and dark themes.
27+
theme:
28+
light: flatly
29+
dark: darkly
30+
2631
# Set the language that should be used for Quarto websites
2732
# https://github.com/quarto-dev/quarto-cli/tree/main/src/resources/language
2833
# lang: en

tests/qwebr-test-theme-switch.qmd

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
title: "Test: Light and Dark Mode"
3+
format: html
4+
engine: knitr
5+
filters:
6+
- webr
7+
---
8+
9+
Test classes for Quarto's light and dark mode.
10+
11+
Toggle the switch to see: editor change from `vs` to `vs-dark` and standard output.
12+
13+
## Interactive
14+
15+
```{webr-r}
16+
#| autorun: true
17+
cat("Display letters: ")
18+
print(letters[1:5])
19+
20+
plot(1:5)
21+
22+
warning("This is a warning message!")
23+
24+
stop("This is a hard error message!")
25+
```

0 commit comments

Comments
 (0)