Repository navigation
Conversation
danieldjohnson
left a comment
There was a problem hiding this comment.
Interesting idea, I like the text-color-based autodetection! A few comments on the implementation and defaults.
| module=__name__, | ||
| qualname="theme", | ||
| initial_value="light", | ||
| initial_value="auto", |
There was a problem hiding this comment.
I think for now it would be best to keep the default as "light" to avoid unexpected behavior changes for users. We can still leave in "auto" as a setting so that users can customize this.
There was a problem hiding this comment.
Sure thing, happy to amend this.
| const [r, g, b] = colorChannels.map(Number); | ||
| // Perceptual luminance, as in arrayviz's contrasting-color logic. | ||
| const pageIsDark = 0.2126 * r + 0.7152 * g + 0.0722 * b > 128; | ||
| root.dataset.treescopeTheme = pageIsDark ? "dark" : "light"; |
There was a problem hiding this comment.
The name treescopeTheme is a bit confusing since it only seems to be used when the theme is auto? Maybe we can instead name this as root.dataset.treescopeDetectedTheme.
There was a problem hiding this comment.
Agree, will rename, along with the matching data-treescope-detected-theme CSS selectors.
| // inherited across the shadow root boundary, so this has to run before the | ||
| // rendering sets a color of its own. If we can't tell, we leave the attribute | ||
| // unset, and the rendering falls back to its own light background. | ||
| const inheritedColor = window.getComputedStyle(root).color; |
There was a problem hiding this comment.
I think that window.getComputedStyle(root).color can resolve to a non-RGB color space in some cases (e.g. if the page specifies it as oklch(...)). It would be good if we could make this robust to that somehow.
One simple thing would just be to check that it's an RGB color and log an error otherwise. A possibly more advanced solution would be to use something like color-mix to force the browser to reinterpret the color as RGB?
There was a problem hiding this comment.
Good catch, the regex would misread oklch/color() silently. Instead of parsing, we could potentially draw the colour onto a 1x1 canvas and read back the pixel, so the browser does the conversion for any colour format? If this fails, we could log a warning and fall back to light theme?
There was a problem hiding this comment.
Good idea, sounds reasonable!
| :host([data-treescope-theme="light"]) .treescope_root.theme_auto { | ||
| /* Keep the page's own background, since themes disagree about which | ||
| off-white or dark gray to use. */ | ||
| --treescope-bg: transparent; | ||
| } |
There was a problem hiding this comment.
Can you say more about the reasoning for this?
There was a problem hiding this comment.
This will become much more readable with the rename from your second comment. Will update this to:
:host([data-treescope-detected-theme]) .treescope_root.theme_auto {
--treescope-bg: transparent;
}
The idea behind these lines of code is if we have "auto" mode selected, and we're able to detect the notebook theme successfully, then we set the Treescope rendering canvas to be transparent, so the Treescope output gets drawn directly onto the cell output area, which feels more clean/seamless. Could alternatively try to derive the output cell area colour and use this for the render canvas, but this would be hard to do reliably.
In #7, (PR 3: Add an auto theme) I added a screenshot comparing "dark" to "auto" for reference :)
Renderings have always used dark text on a white background, which looks
out of place in a notebook with a dark theme. This adds a dark palette,
following VSCode's Dark Modern in the same way the existing light palette
follows Light+.
treescope.theme.set_globally('dark') # 'light' is the default
with treescope.theme.set_scoped('dark'):
...
Block colors are unchanged, since they are chosen by the objects being
rendered rather than by Treescope.
`treescope.theme` now defaults to auto, which matches the page it is rendered into. Detection happens in the browser: the container reads the text color it inherits from the page and checks whether it is light enough to have been meant for a dark background. A rendering that has matched the page keeps that page's background rather than drawing its own, since themes disagree about which off-white or dark gray to use. Where JavaScript doesn't run there is nothing to match, so renderings fall back to light on a background of their own.
- Keep light as the default, make auto opt-in. - Rename detection attribute to data-treescope-detected-theme. - Read the inherited text color via a canvas so any color format works. Failing logs a warning and falls back to light theme. - Collaspse the transparent background selectors into one.
|
Have rebased this on #75 and applied the changes mentioned in the comments. Kept in one commit so it's easier to compare. Hope it's all right! |
danieldjohnson
left a comment
There was a problem hiding this comment.
Looks good, happy to merge once conflicts are resolved! (Seems like conflicts are just due to merging the prior PR)
| // inherited across the shadow root boundary, so this has to run before the | ||
| // rendering sets a color of its own. If we can't tell, we leave the attribute | ||
| // unset, and the rendering falls back to its own light background. | ||
| const inheritedColor = window.getComputedStyle(root).color; |
There was a problem hiding this comment.
Good idea, sounds reasonable!
Related Issue: Feature request: Dark mode #7
Stacked on #75, that PR's commits are included in this diff; the new work is6fd0c7a.Part of #7, see that issue for screenshots.
Adds
'auto'totreescope.themekeeping'light'mode as the default. Detection happens in the browser: the container reads the text colour it inherits from the page and checks whether it's light enough to have been meant for a dark background.This is indirect, but works everywhere.
prefers-color-schemefollows the browser rather than the notebook's own theme setting, and is reported incorrectly inside VSCode's output cells (microsoft/vscode#117804).A rendering that has matched the page keeps that page's background rather than drawing its own, since themes disagree about which off-white or dark grey to use. Where JavaScript doesn't run there is nothing to match, so renderings fall back to light on a background of their own.
This changes the default for existing users, which makes it the most intrusive of the three changes. It's entirely reasonable to take the first two PRs and leave this one, or to keepAdjusted this.'auto'opt-in with'light'remaining the default. Say the word and I'll adjust.Tests added for the detection hook and the attribute/dataset contract it depends on.
pyink,pylint,pytypeand the test suite are green.