Themeable selection color via --selection-bg, shared by page and CodeMirror

Nitro's orange accent selection fill clashed with accent-colored text.
Introduce --selection-bg (base: accent 30% mix, as before) used by both
::selection and the editors' selection layer; nitro overrides it with a
neutral grey. CodeMirror's selection needed a baseTheme with its exact
&light/&dark selectors to win, and is now hidden when unfocused like a
normal input.
This commit is contained in:
2026-08-29 03:39:24 +00:00
parent e3fbce8ece
commit daa1670653
3 changed files with 24 additions and 8 deletions
+4 -1
View File
@@ -18,6 +18,9 @@
/* Links stay quiet — mostly text color with a hint of the accent —
and light up to the full accent on hover. */
--link: color-mix(in oklab, var(--text) 50%, var(--accent));
/* Selection fill for page text and the CodeMirror editors; themes
override when the accent tint clashes with accent-colored text. */
--selection-bg: color-mix(var(--accent) 30%, transparent);
/* Code highlighting palette, consumed by pygments.css: complete light and
dark sets (background included), resolved by light-dark() from the
used color-scheme. A theme picks a set simply by declaring
@@ -71,7 +74,7 @@
}
::selection {
background: color-mix(var(--accent) 30%, transparent);
background: var(--selection-bg);
color: inherit;
}
+17 -3
View File
@@ -8,7 +8,7 @@ import { tags } from '@lezer/highlight'
// The base theme sets monospace on .cm-scroller, so the font must be set
// there, not on "&".
export const cmTheme = EditorView.theme({
const cmEditorTheme = EditorView.theme({
"&": {
backgroundColor: "var(--bg)",
color: "var(--text)",
@@ -33,11 +33,25 @@ export const cmTheme = EditorView.theme({
".cm-cursor": { borderLeftColor: "var(--text)" },
// basicSetup's active-line highlight assumes a dark theme.
".cm-activeLine": { backgroundColor: "transparent" },
"&.cm-focused .cm-selectionBackground, .cm-selectionBackground":
{ backgroundColor: "var(--line)" },
"&.cm-focused": { outline: "none" },
})
// Selection color needs a baseTheme: only base themes support the
// &light/&dark selectors, and @codemirror/view's own selection rules use
// them — we must match its selectors exactly (equal specificity) and rely
// on mounting later to win. Focused: the page's --selection-bg (the base
// accents tint; themes may override it). Unfocused: hidden, like a normal
// input (CodeMirror greys it by default).
const cmSelection = EditorView.baseTheme({
"&light .cm-selectionBackground, &dark .cm-selectionBackground":
{ backgroundColor: "transparent" },
"&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, &dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground":
{ backgroundColor: "var(--selection-bg)" },
})
// Exported as one extension so the editors just list `cmTheme`.
export const cmTheme = [cmEditorTheme, cmSelection]
export const cmHighlight = syntaxHighlighting(HighlightStyle.define([
{ tag: tags.heading, fontWeight: "600", color: "var(--accent)" },
{ tag: tags.strong, fontWeight: "700" },
+3 -4
View File
@@ -42,6 +42,9 @@
--font-body: var(--font-montserrat);
--font-heading: var(--font-literata);
--code-x-height: 0.517; /* Montserrat's x-height ratio */
/* Neutral grey selection instead of the accent tint: accent-colored
text (h2, links, markers) stays readable on it in both schemes. */
--selection-bg: #6664;
}
/* Dark scheme: same identity, but the page goes deep violet (never muddy
@@ -62,10 +65,6 @@
}
}
::selection {
background: var(--accent);
}
/* Any banner used is separated from page by a thick orange line */
#banner {
border-bottom: 4px solid var(--accent);