Follow the OS appearance when set to System without a new window (#540)

This commit is contained in:
Gregory Schier
2026-08-14 13:14:01 -07:00
committed by GitHub
parent 68671377fd
commit cb43f0b9b9
7 changed files with 88 additions and 82 deletions
+27
View File
@@ -4,6 +4,21 @@ export type Appearance = "light" | "dark";
const SYSTEM_APPEARANCE_CHANGE_EVENT = "system_appearance_change";
declare global {
interface Window {
__YAAK_INITIAL_APPEARANCE__?: Appearance;
}
}
// NOTE: On macOS and Linux the backend detects the appearance the OS prefers and injects
// it here, later emitting change events. This is required because applying a theme forces
// the window appearance, which poisons what the webview reports (CSS media queries and
// window theme events follow the override).
export function getSystemAppearance(): Appearance | null {
const appearance = window.__YAAK_INITIAL_APPEARANCE__;
return appearance === "dark" || appearance === "light" ? appearance : null;
}
export function getCSSAppearance(): Appearance {
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
}
@@ -41,12 +56,24 @@ export function resolveAppearance(
}
export function subscribeToPreferredAppearance(cb: (appearance: Appearance) => void) {
const systemAppearance = getSystemAppearance();
if (systemAppearance != null) {
cb(systemAppearance);
return subscribeToSystemAppearanceChange(cb);
}
cb(getCSSAppearance());
void getWindowAppearance().then(cb);
return subscribeToPreferredAppearanceChange(cb);
}
export function subscribeToPreferredAppearanceChange(cb: (appearance: Appearance) => void) {
if (getSystemAppearance() != null) {
// The CSS and window sources are poisoned by forced window appearances, so only
// listen to the backend's system appearance detection when it's available
return subscribeToSystemAppearanceChange(cb);
}
const unsubscribeCSS = subscribeToCSSAppearanceChange(cb);
const unsubscribeWindow = subscribeToWindowAppearanceChange(cb);
const unsubscribeSystem = subscribeToSystemAppearanceChange(cb);