Files
NetMesh/application/state/activeChromeThemeSync.ts
zhaolei 3c72efcb7f
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
[Init] Initial commit - NetMesh terminal manager
2026-09-13 18:24:01 +08:00

81 lines
3.3 KiB
TypeScript

import { isActiveChromeThemeResolvable, resolveActiveChromeTheme } from '../app/activeChromeTheme';
import { clearTopTabsChromeThemeVars } from '../app/topTabsChromeTheme';
import type { TerminalAppearanceHostScope, ResolvedAppearance } from '../../domain/terminalAppearanceRuntime';
import type { Host, TerminalSession, TerminalTheme, Workspace } from '../../types';
import { activeTabStore } from './activeTabStore';
import type { EditorTabChrome } from './editorTabStore';
import type { LogView } from './logViewState';
import { syncActiveChromeTheme, themeFingerprint } from './useActiveChromeTheme';
export type ActiveChromeThemeDeps = {
accentMode: 'theme' | 'custom';
applyAppTheme: () => void;
currentTerminalTheme: TerminalTheme;
customAccent: string;
editorTabs: readonly EditorTabChrome[];
followAppTerminalTheme: boolean;
hostById: Map<string, Host>;
logViews: readonly LogView[];
resolveSessionAppearance?: (hostScope: TerminalAppearanceHostScope) => ResolvedAppearance;
sessionById: Map<string, TerminalSession>;
themeById: Map<string, TerminalTheme>;
workspaceById: Map<string, Workspace>;
};
let depsRef: ActiveChromeThemeDeps | null = null;
let pendingRafId: number | null = null;
let pendingActiveTabId: string | null = null;
export function updateActiveChromeThemeDeps(deps: ActiveChromeThemeDeps): void {
depsRef = deps;
}
/**
* Apply chrome theme for a tab. Short-circuits when the resolved theme
* fingerprint matches the already-applied chrome fingerprint so rapid tab
* clicks do not force style work. Tab switches always use instant mode via
* syncActiveChromeTheme (no view transitions).
*/
export function applyChromeThemeForTab(activeTabId: string): void {
if (!depsRef || typeof document === 'undefined') return;
if (activeTabId === 'vault' || activeTabId === 'sftp') {
clearTopTabsChromeThemeVars();
}
// Non-terminal tabs: React chrome effect clears overlay theme. Do not force
// a full style reset here on every vault/sftp click.
if (!isActiveChromeThemeResolvable({ ...depsRef, activeTabId })) return;
const activeTheme = resolveActiveChromeTheme({ ...depsRef, activeTabId });
// Fingerprint short-circuit is also inside syncActiveChromeTheme; check here
// so we avoid even building transition work when the theme is unchanged.
if (activeTheme) {
const nextFp = themeFingerprint(activeTheme);
const applied = document.documentElement.dataset.activeChromeTheme ?? null;
if (nextFp === applied) return;
}
syncActiveChromeTheme(activeTheme, depsRef.applyAppTheme);
}
/**
* Schedule chrome theme apply on the next animation frame so click handlers
* and React commit are not blocked by :root CSS rewrites.
*/
export function notifyActiveChromeThemeForTab(activeTabId: string): void {
pendingActiveTabId = activeTabId;
if (typeof document === 'undefined') {
applyChromeThemeForTab(activeTabId);
return;
}
if (pendingRafId !== null) return;
const schedule = typeof requestAnimationFrame === 'function'
? requestAnimationFrame
: (cb: FrameRequestCallback) => window.setTimeout(() => cb(0), 0) as unknown as number;
pendingRafId = schedule(() => {
pendingRafId = null;
const tabId = pendingActiveTabId;
pendingActiveTabId = null;
if (tabId != null) applyChromeThemeForTab(tabId);
});
}
activeTabStore.subscribeSync(notifyActiveChromeThemeForTab);