fix(editor): keep an editor color scheme chosen together with the theme (#1138)

Since #1100 a theme that turns light or dark switches a chosen scheme of the other kind back to the theme's own. It did so also when the scheme was chosen in the same Apply as the theme, so One Light + Solarized Dark left the default light editor. A scheme set by the settings change that also changes the theme now goes with it; a later theme change on its own still switches it back.

Closes #1136

Co-authored-by: fhrmrk <81476595+fhrmrk@users.noreply.github.com>
This commit is contained in:
Park Jong Hyun
2026-11-04 10:07:04 +08:00
committed by GitHub
parent 2ec2b76d7a
commit 280c2da48f
2 changed files with 28 additions and 2 deletions
+15 -2
View File
@@ -2,7 +2,8 @@
* Applies Settings › Editor › Color Scheme (scheme + attribute overrides) as one
* stylesheet, and Editor › Font › Typography Settings as the root's
* `--fw-code` / `--fw-code-bold`. When the IDE theme turns light or dark, a chosen
* scheme of the other kind is switched back to the theme's own.
* scheme of the other kind is switched back to the theme's own, unless it was chosen
* in the same change as the theme (one Apply of both).
*/
import { useProject } from "@/platform/project";
import { editorPrefs, fontWeightVars } from "@/platform/editorSettings";
@@ -24,6 +25,10 @@ export function installColorScheme(): () => void {
if (root.style.getPropertyValue(name) !== value) root.style.setProperty(name, value);
};
let kind = root.dataset.theme;
// The scheme set by the latest settings change, until the next task: the theme's
// `data-theme` change from the same change is observed before then.
let picked: string | undefined;
let clearPicked: ReturnType<typeof setTimeout> | undefined;
const followTheme = () => {
const next = root.dataset.theme;
if (next === kind) return;
@@ -31,6 +36,7 @@ export function installColorScheme(): () => void {
kind = next;
const settings = useProject.getState().settings;
if (!previous || !settings || (next !== "light" && next !== "dark")) return;
if (picked !== undefined && picked === settings.editor?.colorScheme) return;
const scheme = schemeAfterThemeChange(settings.editor?.colorScheme, next, editorPrefs(settings).customSchemes);
if (scheme === null) return;
if (!isTauri()) {
@@ -44,7 +50,13 @@ export function installColorScheme(): () => void {
};
apply();
const unsubscribe = useProject.subscribe((s, prev) => {
if (s.settings !== prev.settings) apply();
if (s.settings === prev.settings) return;
apply();
const scheme = s.settings?.editor?.colorScheme;
if (scheme === prev.settings?.editor?.colorScheme) return;
picked = scheme;
clearTimeout(clearPicked);
clearPicked = setTimeout(() => (picked = undefined));
});
const observer =
typeof MutationObserver !== "undefined"
@@ -59,6 +71,7 @@ export function installColorScheme(): () => void {
});
return () => {
unsubscribe();
clearTimeout(clearPicked);
observer?.disconnect();
el.remove();
root.style.removeProperty("--fw-code");
+13
View File
@@ -92,6 +92,19 @@ describe("color schemes", () => {
root.dataset.theme = "dark";
await Promise.resolve();
expect(scheme()).toBe("dark");
// A scheme chosen in the same change as the theme (one Apply) goes with it.
await new Promise((r) => setTimeout(r));
useProject.setState({ settings: { editor: { colorScheme: "solarized-dark" } } as unknown as Settings });
root.dataset.theme = "light";
await Promise.resolve();
expect(scheme()).toBe("solarized-dark");
// A later theme change on its own still switches it back.
await new Promise((r) => setTimeout(r));
root.dataset.theme = "dark";
await Promise.resolve();
root.dataset.theme = "light";
await Promise.resolve();
expect(scheme()).toBe("theme-default");
} finally {
dispose();
delete root.dataset.colorTheme;