fix(frontend,macos): reduce dark mode white flash on window open

Detect dark/light mode before React hydrates to eliminate the visible
white-to-dark flash when opening windows in dark mode.

Frontend:
- Inline script now reads next-themes localStorage key and applies
  .dark class, colorScheme, and backgroundColor on <html> before first
  paint
- Add CSS-only fallback via prefers-color-scheme media query in an
  inline <style> tag that fires before any JS executes

macOS backend:
- Detect system dark mode via `defaults read -g AppleInterfaceStyle`
  (cached with OnceLock) and set native window background color to
  match dark theme in apply_platform_window_style
- Persist user appearance mode preference (dark/light/system) to DB
  alongside zoom level so new windows use the correct background
- Add update_appearance_mode Tauri command; frontend syncs on mount,
  on settings change, and on cross-window storage events

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
xintaofei
2026-04-13 11:15:13 +08:00
parent e05ae76453
commit 41b28001af
7 changed files with 145 additions and 9 deletions

View File

@@ -32,6 +32,21 @@ const SCRIPT = `
var storedZoom = parseInt(localStorage.getItem("${STORAGE_KEY_ZOOM_LEVEL}") || "", 10);
var zoom = VALID_ZOOMS.indexOf(storedZoom) >= 0 ? storedZoom : 100;
document.documentElement.style.fontSize = (16 * zoom / 100) + "px";
// 在 next-themes 水合之前同步检测暗色模式,防止白色闪屏。
// next-themes 使用 localStorage key "theme"attribute="class"。
var storedMode = localStorage.getItem("theme");
var isDark = storedMode === "dark" ||
(storedMode !== "light" && window.matchMedia("(prefers-color-scheme: dark)").matches);
if (isDark) {
document.documentElement.classList.add("dark");
document.documentElement.style.colorScheme = "dark";
// 直接设置背景色,比等待 CSS 类匹配更快,覆盖"系统浅色 + 应用深色"场景
document.documentElement.style.backgroundColor = "#09090b";
} else {
document.documentElement.style.colorScheme = "light";
document.documentElement.style.backgroundColor = "";
}
} catch (e) {
// localStorage 不可用时静默走默认
}

View File

@@ -454,6 +454,10 @@ export async function updateTrafficLightPosition(zoom: number): Promise<void> {
return invoke("update_traffic_light_position", { zoom: zoom as number })
}
export async function updateAppearanceMode(mode: string): Promise<void> {
return invoke("update_appearance_mode", { mode })
}
// Folder history commands
export async function loadFolderHistory(): Promise<FolderHistoryEntry[]> {