fix editor tab theme toggle (#1467)
This commit is contained in:
2
App.tsx
2
App.tsx
@@ -990,7 +990,7 @@ function App({ settings }: { settings: SettingsState }) {
|
|||||||
logViews={logViews}
|
logViews={logViews}
|
||||||
t={t}
|
t={t}
|
||||||
/>
|
/>
|
||||||
<AppView ctx={{ accentMode, addShellHistoryEntry, addSessionToWorkspace, addToWorkspaceDialog, appendHostToWorkspace, appendLocalTerminalToWorkspace, clearAndRemoveSource, clearAndRemoveSources, clearUnsavedConnectionLogs, clearSessionFontSizeOverride, closeLogView, closeSession, closeTabsBatch, copySessionWithCurrentShell, copySessionToNewWindowWithCurrentShell, closeWorkspace, connectionLogs, convertKnownHostToHost, createWorkspaceFromSessions, createWorkspaceFromTargets, createWorkspaceWithHosts, customAccent, customGroups, currentTerminalTheme, deleteConnectionLog, draggingSessionId, effectiveKnownHosts, editorTabs, editorWordWrap, emptyVaultConflict, followAppTerminalTheme, groupConfigs, handleAddKnownHost, handleConnectSerial, handleConnectToHost, handleCreateLocalTerminal, handleDeleteHost, handleEndSessionDrag, handleHostConnectWithProtocolCheck, handleHotkeyAction, handleKeyboardInteractiveCancel, handleKeyboardInteractiveSubmit, handleOpenQuickSwitcher, handleOpenSettings, handleRootContextMenu, handlePassphraseCancel, handlePassphraseSkip, handlePassphraseSubmit, handleProtocolSelect, handleRequestCloseEditorTabRef, handleSessionStatusChange, handleSyncNowManual, handleTerminalDataCapture, handleToggleTheme, handleUpdateHostFromTerminal, hostById, hosts, hotkeyScheme, identities, importOrReuseKey, isBroadcastEnabled, isCreateWorkspaceOpen, isMacClient, isQuickSwitcherOpen, keyBindings, keyboardInteractiveQueue, keys, logViews, managedSources, navigateToSection, openLogView, orderedTabsWithEditors, orphanSessions, passphraseQueue, protocolSelectHost, proxyProfiles, quickResults, quickSearch, removeSessionFromWorkspace, reorderWorkTabs, reorderWorkspaceSessions, resetSessionRename, resetWorkspaceRename, resolveEmptyVaultConflict, resolvedTheme, runSnippet: handleRunSnippet, sessionLogsDir, sessionLogsEnabled, sessionLogsFormat, sessionLogsTimestampsEnabled, sessionRenameTarget, sessionRenameValue, sessions, setActiveTabId, setAddToWorkspaceDialog, setDraggingSessionId, setEditorWordWrap, setIsCreateWorkspaceOpen, setIsQuickSwitcherOpen, setNavigateToSection, setProtocolSelectHost, setQuickSearch, setSessionRenameValue, setTerminalFontFamilyId, setTerminalFontSize, setTerminalThemeId, setWorkspaceFocusedSession, setWorkspaceRenameValue, settings, sftpAutoOpenSidebar, sftpFollowTerminalCwd, setSftpFollowTerminalCwd, sftpAutoSync, sftpDefaultViewMode, sftpDoubleClickBehavior, sftpShowHiddenFiles, sftpUseCompressedUpload, shellHistory, snippetPackages, snippets, splitSessionWithCurrentShell, sshDebugLogsEnabled: settings.sshDebugLogsEnabled, startSessionRename, renameSessionInline, startWorkspaceRename, submitSessionRename, submitWorkspaceRename, t, terminalFontFamilyId, terminalFontSize, terminalSettings, terminalThemeId, toggleBroadcast, toggleConnectionLogSaved, toggleScriptsSidePanelRef, toggleSidePanelRef, toggleWorkspaceViewMode, unmanageSource, updateConnectionLog, updateCustomGroups, updateGroupConfigs, updateHostDistro, updateHosts, updateIdentities, updateKeys, updateKnownHosts, updateManagedSources, updateProxyProfiles, updateSnippetPackages, updateSnippets, updateSplitSizes, updateSessionFontSize, updateTerminalSetting, workspaceRenameTarget, workspaceRenameValue, workspaces, VaultViewContainer, SftpViewMount, TerminalLayerMount, LogViewWrapper }} />
|
<AppView ctx={{ accentMode, addShellHistoryEntry, addSessionToWorkspace, addToWorkspaceDialog, appendHostToWorkspace, appendLocalTerminalToWorkspace, clearAndRemoveSource, clearAndRemoveSources, clearUnsavedConnectionLogs, clearSessionFontSizeOverride, closeLogView, closeSession, closeTabsBatch, copySessionWithCurrentShell, copySessionToNewWindowWithCurrentShell, closeWorkspace, connectionLogs, convertKnownHostToHost, createWorkspaceFromSessions, createWorkspaceFromTargets, createWorkspaceWithHosts, customAccent, customGroups, currentTerminalTheme, deleteConnectionLog, draggingSessionId, effectiveKnownHosts, editorTabs, editorWordWrap, emptyVaultConflict, followAppTerminalTheme, groupConfigs, handleAddKnownHost, handleConnectSerial, handleConnectToHost, handleCreateLocalTerminal, handleDeleteHost, handleEndSessionDrag, handleHostConnectWithProtocolCheck, handleHotkeyAction, handleKeyboardInteractiveCancel, handleKeyboardInteractiveSubmit, handleOpenQuickSwitcher, handleOpenSettings, handleRootContextMenu, handlePassphraseCancel, handlePassphraseSkip, handlePassphraseSubmit, handleProtocolSelect, handleRequestCloseEditorTabRef, handleSessionStatusChange, handleSyncNowManual, handleTerminalDataCapture, handleToggleTheme, handleUpdateHostFromTerminal, hostById, hosts, hotkeyScheme, identities, importOrReuseKey, isBroadcastEnabled, isCreateWorkspaceOpen, isMacClient, isQuickSwitcherOpen, keyBindings, keyboardInteractiveQueue, keys, logViews, managedSources, navigateToSection, openLogView, orderedTabsWithEditors, orphanSessions, passphraseQueue, protocolSelectHost, proxyProfiles, quickResults, quickSearch, removeSessionFromWorkspace, reorderWorkTabs, reorderWorkspaceSessions, resetSessionRename, resetWorkspaceRename, resolveEmptyVaultConflict, resolvedTheme, runSnippet: handleRunSnippet, sessionLogsDir, sessionLogsEnabled, sessionLogsFormat, sessionLogsTimestampsEnabled, sessionRenameTarget, sessionRenameValue, sessions, setActiveTabId, setAddToWorkspaceDialog, setDraggingSessionId, setEditorWordWrap, setIsCreateWorkspaceOpen, setIsQuickSwitcherOpen, setNavigateToSection, setProtocolSelectHost, setQuickSearch, setSessionRenameValue, setTerminalFontFamilyId, setTerminalFontSize, setTerminalThemeId, setWorkspaceFocusedSession, setWorkspaceRenameValue, settings, sftpAutoOpenSidebar, sftpFollowTerminalCwd, setSftpFollowTerminalCwd, sftpAutoSync, sftpDefaultViewMode, sftpDoubleClickBehavior, sftpShowHiddenFiles, sftpUseCompressedUpload, shellHistory, snippetPackages, snippets, splitSessionWithCurrentShell, sshDebugLogsEnabled: settings.sshDebugLogsEnabled, startSessionRename, renameSessionInline, startWorkspaceRename, submitSessionRename, submitWorkspaceRename, t, terminalFontFamilyId, terminalFontSize, terminalSettings, terminalThemeId, themeById, toggleBroadcast, toggleConnectionLogSaved, toggleScriptsSidePanelRef, toggleSidePanelRef, toggleWorkspaceViewMode, unmanageSource, updateConnectionLog, updateCustomGroups, updateGroupConfigs, updateHostDistro, updateHosts, updateIdentities, updateKeys, updateKnownHosts, updateManagedSources, updateProxyProfiles, updateSnippetPackages, updateSnippets, updateSplitSizes, updateSessionFontSize, updateTerminalSetting, workspaceRenameTarget, workspaceRenameValue, workspaces, VaultViewContainer, SftpViewMount, TerminalLayerMount, LogViewWrapper }} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import type { GroupConfig, Host, TerminalSession, TerminalTheme, Workspace } fro
|
|||||||
import {
|
import {
|
||||||
isHostTreeWorkTabSurface,
|
isHostTreeWorkTabSurface,
|
||||||
resolveWorkTabActiveHostId,
|
resolveWorkTabActiveHostId,
|
||||||
|
resolveWorkTabHostTreeTheme,
|
||||||
} from './workTabSurface';
|
} from './workTabSurface';
|
||||||
|
|
||||||
interface AppHostTreeLayerProps {
|
interface AppHostTreeLayerProps {
|
||||||
@@ -20,7 +21,12 @@ interface AppHostTreeLayerProps {
|
|||||||
editorTabs: readonly EditorTab[];
|
editorTabs: readonly EditorTab[];
|
||||||
logViews: readonly LogView[];
|
logViews: readonly LogView[];
|
||||||
orderedTabs: readonly string[];
|
orderedTabs: readonly string[];
|
||||||
resolvedPreviewTheme: TerminalTheme;
|
accentMode: 'theme' | 'custom';
|
||||||
|
currentTerminalTheme: TerminalTheme;
|
||||||
|
customAccent: string;
|
||||||
|
followAppTerminalTheme: boolean;
|
||||||
|
hostById: ReadonlyMap<string, Host>;
|
||||||
|
themeById: ReadonlyMap<string, TerminalTheme>;
|
||||||
onConnect: (host: Host) => void;
|
onConnect: (host: Host) => void;
|
||||||
onCreateLocalTerminal?: () => void;
|
onCreateLocalTerminal?: () => void;
|
||||||
}
|
}
|
||||||
@@ -43,7 +49,12 @@ export const AppHostTreeLayer: React.FC<AppHostTreeLayerProps> = ({
|
|||||||
editorTabs,
|
editorTabs,
|
||||||
logViews,
|
logViews,
|
||||||
orderedTabs,
|
orderedTabs,
|
||||||
resolvedPreviewTheme,
|
accentMode,
|
||||||
|
currentTerminalTheme,
|
||||||
|
customAccent,
|
||||||
|
followAppTerminalTheme,
|
||||||
|
hostById,
|
||||||
|
themeById,
|
||||||
onConnect,
|
onConnect,
|
||||||
onCreateLocalTerminal,
|
onCreateLocalTerminal,
|
||||||
}) => {
|
}) => {
|
||||||
@@ -67,6 +78,24 @@ export const AppHostTreeLayer: React.FC<AppHostTreeLayerProps> = ({
|
|||||||
workspaces,
|
workspaces,
|
||||||
}), [activeTabId, editorTabs, sessions, workspaces]);
|
}), [activeTabId, editorTabs, sessions, workspaces]);
|
||||||
|
|
||||||
|
const hostTreeTheme = useMemo(() => resolveWorkTabHostTreeTheme({
|
||||||
|
activeHostId,
|
||||||
|
accentMode,
|
||||||
|
currentTerminalTheme,
|
||||||
|
customAccent,
|
||||||
|
followAppTerminalTheme,
|
||||||
|
hostById,
|
||||||
|
themeById,
|
||||||
|
}), [
|
||||||
|
activeHostId,
|
||||||
|
accentMode,
|
||||||
|
currentTerminalTheme,
|
||||||
|
customAccent,
|
||||||
|
followAppTerminalTheme,
|
||||||
|
hostById,
|
||||||
|
themeById,
|
||||||
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="absolute left-0 top-0 bottom-0 flex min-h-0"
|
className="absolute left-0 top-0 bottom-0 flex min-h-0"
|
||||||
@@ -79,7 +108,7 @@ export const AppHostTreeLayer: React.FC<AppHostTreeLayerProps> = ({
|
|||||||
hosts={hosts}
|
hosts={hosts}
|
||||||
customGroups={customGroups}
|
customGroups={customGroups}
|
||||||
groupConfigs={groupConfigs}
|
groupConfigs={groupConfigs}
|
||||||
resolvedPreviewTheme={resolvedPreviewTheme}
|
resolvedPreviewTheme={hostTreeTheme}
|
||||||
activeHostId={activeHostId}
|
activeHostId={activeHostId}
|
||||||
onConnect={onConnect}
|
onConnect={onConnect}
|
||||||
onCreateLocalTerminal={onCreateLocalTerminal}
|
onCreateLocalTerminal={onCreateLocalTerminal}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export function AppView({ ctx }: { ctx: AppViewContext }) {
|
|||||||
setNavigateToSection, setProtocolSelectHost, setQuickSearch, setSessionRenameValue, setTerminalFontFamilyId, setTerminalFontSize, setTerminalThemeId, updateSessionFontSize, clearSessionFontSizeOverride,
|
setNavigateToSection, setProtocolSelectHost, setQuickSearch, setSessionRenameValue, setTerminalFontFamilyId, setTerminalFontSize, setTerminalThemeId, updateSessionFontSize, clearSessionFontSizeOverride,
|
||||||
setWorkspaceFocusedSession, setWorkspaceRenameValue, settings, sftpAutoOpenSidebar, sftpFollowTerminalCwd, setSftpFollowTerminalCwd, sftpAutoSync, sftpDefaultViewMode, sftpDoubleClickBehavior,
|
setWorkspaceFocusedSession, setWorkspaceRenameValue, settings, sftpAutoOpenSidebar, sftpFollowTerminalCwd, setSftpFollowTerminalCwd, sftpAutoSync, sftpDefaultViewMode, sftpDoubleClickBehavior,
|
||||||
sftpShowHiddenFiles, sftpUseCompressedUpload, shellHistory, snippetPackages, snippets, splitSessionWithCurrentShell, startSessionRename,
|
sftpShowHiddenFiles, sftpUseCompressedUpload, shellHistory, snippetPackages, snippets, splitSessionWithCurrentShell, startSessionRename,
|
||||||
startWorkspaceRename, submitSessionRename, submitWorkspaceRename, t, terminalFontFamilyId, terminalFontSize, terminalSettings, terminalThemeId,
|
startWorkspaceRename, submitSessionRename, submitWorkspaceRename, t, terminalFontFamilyId, terminalFontSize, terminalSettings, terminalThemeId, themeById,
|
||||||
toggleBroadcast, toggleConnectionLogSaved, toggleScriptsSidePanelRef, toggleSidePanelRef, toggleWorkspaceViewMode, unmanageSource, updateConnectionLog,
|
toggleBroadcast, toggleConnectionLogSaved, toggleScriptsSidePanelRef, toggleSidePanelRef, toggleWorkspaceViewMode, unmanageSource, updateConnectionLog,
|
||||||
updateCustomGroups, updateGroupConfigs, updateHostDistro, updateHosts, updateIdentities, updateKeys, updateKnownHosts, updateManagedSources,
|
updateCustomGroups, updateGroupConfigs, updateHostDistro, updateHosts, updateIdentities, updateKeys, updateKnownHosts, updateManagedSources,
|
||||||
updateProxyProfiles, updateSnippetPackages, updateSnippets, updateSplitSizes, updateTerminalSetting, workspaceRenameTarget, workspaceRenameValue, workspaces,
|
updateProxyProfiles, updateSnippetPackages, updateSnippets, updateSplitSizes, updateTerminalSetting, workspaceRenameTarget, workspaceRenameValue, workspaces,
|
||||||
@@ -153,7 +153,12 @@ export function AppView({ ctx }: { ctx: AppViewContext }) {
|
|||||||
editorTabs={editorTabs}
|
editorTabs={editorTabs}
|
||||||
logViews={logViews}
|
logViews={logViews}
|
||||||
orderedTabs={orderedTabsWithEditors}
|
orderedTabs={orderedTabsWithEditors}
|
||||||
resolvedPreviewTheme={currentTerminalTheme}
|
accentMode={accentMode}
|
||||||
|
currentTerminalTheme={currentTerminalTheme}
|
||||||
|
customAccent={customAccent}
|
||||||
|
followAppTerminalTheme={followAppTerminalTheme}
|
||||||
|
hostById={hostById}
|
||||||
|
themeById={themeById}
|
||||||
onConnect={handleConnectToHost}
|
onConnect={handleConnectToHost}
|
||||||
onCreateLocalTerminal={handleCreateLocalTerminal}
|
onCreateLocalTerminal={handleCreateLocalTerminal}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ const baseInput = {
|
|||||||
workspaceById: new Map<string, Workspace>(),
|
workspaceById: new Map<string, Workspace>(),
|
||||||
};
|
};
|
||||||
|
|
||||||
test("editor tabs use the theme from their owning host", () => {
|
test("editor tabs use the owning host terminal theme when follow-app terminal theme is off", () => {
|
||||||
const editorTab = {
|
const editorTab = {
|
||||||
id: "editor-1",
|
id: "editor-1",
|
||||||
hostId: "host-1",
|
hostId: "host-1",
|
||||||
@@ -58,6 +58,26 @@ test("editor tabs use the theme from their owning host", () => {
|
|||||||
assert.equal(resolved?.id, hostTheme.id);
|
assert.equal(resolved?.id, hostTheme.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("editor tabs use the followed terminal theme when follow-app terminal theme is on", () => {
|
||||||
|
const editorTab = {
|
||||||
|
id: "editor-1",
|
||||||
|
hostId: "host-1",
|
||||||
|
sessionId: "sftp-1",
|
||||||
|
};
|
||||||
|
|
||||||
|
const resolved = resolveActiveChromeTheme({
|
||||||
|
...baseInput,
|
||||||
|
activeTabId: toEditorTabId(editorTab.id),
|
||||||
|
editorTabs: [editorTab as unknown as EditorTab],
|
||||||
|
followAppTerminalTheme: true,
|
||||||
|
hostById: new Map([
|
||||||
|
["host-1", { id: "host-1", theme: hostTheme.id } as unknown as Host],
|
||||||
|
]),
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(resolved?.id, currentTheme.id);
|
||||||
|
});
|
||||||
|
|
||||||
test("log tabs use the saved log theme when available", () => {
|
test("log tabs use the saved log theme when available", () => {
|
||||||
const resolved = resolveActiveChromeTheme({
|
const resolved = resolveActiveChromeTheme({
|
||||||
...baseInput,
|
...baseInput,
|
||||||
|
|||||||
@@ -54,22 +54,21 @@ export function resolveActiveChromeTheme({
|
|||||||
}: ResolveActiveChromeThemeInput): TerminalTheme | null {
|
}: ResolveActiveChromeThemeInput): TerminalTheme | null {
|
||||||
if (activeTabId === "vault" || activeTabId === "sftp") return null;
|
if (activeTabId === "vault" || activeTabId === "sftp") return null;
|
||||||
|
|
||||||
const resolveSessionTheme = (session: TerminalSession): TerminalTheme => {
|
const resolveHostTheme = (hostId: string): TerminalTheme => {
|
||||||
if (followAppTerminalTheme) return currentTerminalTheme;
|
if (followAppTerminalTheme) return currentTerminalTheme;
|
||||||
const host = hostById.get(session.hostId) ?? null;
|
const host = hostById.get(hostId) ?? null;
|
||||||
const themeId = resolveHostTerminalThemeId(host, currentTerminalTheme.id);
|
const themeId = resolveHostTerminalThemeId(host, currentTerminalTheme.id);
|
||||||
const baseTheme = themeById.get(themeId) ?? currentTerminalTheme;
|
const baseTheme = themeById.get(themeId) ?? currentTerminalTheme;
|
||||||
return applyCustomAccentToTerminalTheme(baseTheme, accentMode, customAccent);
|
return applyCustomAccentToTerminalTheme(baseTheme, accentMode, customAccent);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const resolveSessionTheme = (session: TerminalSession): TerminalTheme => resolveHostTheme(session.hostId);
|
||||||
|
|
||||||
if (isEditorTabId(activeTabId)) {
|
if (isEditorTabId(activeTabId)) {
|
||||||
const editorTabId = fromEditorTabId(activeTabId);
|
const editorTabId = fromEditorTabId(activeTabId);
|
||||||
const editorTab = editorTabs.find((tab) => tab.id === editorTabId);
|
const editorTab = editorTabs.find((tab) => tab.id === editorTabId);
|
||||||
if (!editorTab) return null;
|
if (!editorTab) return null;
|
||||||
const host = hostById.get(editorTab.hostId) ?? null;
|
return resolveHostTheme(editorTab.hostId);
|
||||||
const themeId = resolveHostTerminalThemeId(host, currentTerminalTheme.id);
|
|
||||||
const baseTheme = themeById.get(themeId) ?? currentTerminalTheme;
|
|
||||||
return applyCustomAccentToTerminalTheme(baseTheme, accentMode, customAccent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const logView = logViews.find((item) => item.id === activeTabId);
|
const logView = logViews.find((item) => item.id === activeTabId);
|
||||||
|
|||||||
@@ -8,9 +8,38 @@ import {
|
|||||||
isTerminalContentTabSurface,
|
isTerminalContentTabSurface,
|
||||||
reorderWorkTabIds,
|
reorderWorkTabIds,
|
||||||
resolveWorkTabActiveHostId,
|
resolveWorkTabActiveHostId,
|
||||||
|
resolveWorkTabHostTreeTheme,
|
||||||
} from './workTabSurface';
|
} from './workTabSurface';
|
||||||
import type { EditorTab } from '../state/editorTabStore';
|
import type { EditorTab } from '../state/editorTabStore';
|
||||||
import type { TerminalSession, Workspace } from '../../types';
|
import type { Host, TerminalSession, TerminalTheme, Workspace } from '../../types';
|
||||||
|
|
||||||
|
const makeTheme = (id: string, type: TerminalTheme['type'], background: string): TerminalTheme => ({
|
||||||
|
id,
|
||||||
|
name: id,
|
||||||
|
type,
|
||||||
|
colors: {
|
||||||
|
background,
|
||||||
|
foreground: type === 'dark' ? '#ffffff' : '#000000',
|
||||||
|
cursor: '#888888',
|
||||||
|
selection: '#555555',
|
||||||
|
black: '#000000',
|
||||||
|
red: '#ff0000',
|
||||||
|
green: '#00ff00',
|
||||||
|
yellow: '#ffff00',
|
||||||
|
blue: '#0000ff',
|
||||||
|
magenta: '#ff00ff',
|
||||||
|
cyan: '#00ffff',
|
||||||
|
white: '#ffffff',
|
||||||
|
brightBlack: '#444444',
|
||||||
|
brightRed: '#ff5555',
|
||||||
|
brightGreen: '#55ff55',
|
||||||
|
brightYellow: '#ffff55',
|
||||||
|
brightBlue: '#5555ff',
|
||||||
|
brightMagenta: '#ff55ff',
|
||||||
|
brightCyan: '#55ffff',
|
||||||
|
brightWhite: '#ffffff',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
test('work tab order keeps custom positions and appends new tabs', () => {
|
test('work tab order keeps custom positions and appends new tabs', () => {
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
@@ -104,3 +133,73 @@ test('shared host tree resolves active host ids across work tab types', () => {
|
|||||||
assert.equal(resolveWorkTabActiveHostId({ activeTabId: 'editor:file-1', sessions, workspaces, editorTabs }), 'host-3');
|
assert.equal(resolveWorkTabActiveHostId({ activeTabId: 'editor:file-1', sessions, workspaces, editorTabs }), 'host-3');
|
||||||
assert.equal(resolveWorkTabActiveHostId({ activeTabId: 'log-1', sessions, workspaces, editorTabs }), null);
|
assert.equal(resolveWorkTabActiveHostId({ activeTabId: 'log-1', sessions, workspaces, editorTabs }), null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('shared host tree uses the active host theme when follow-app terminal theme is off', () => {
|
||||||
|
const currentTheme = makeTheme('app-dark', 'dark', '#111111');
|
||||||
|
const hostTheme = makeTheme('host-light', 'light', '#fafafa');
|
||||||
|
const host = {
|
||||||
|
id: 'host-1',
|
||||||
|
label: 'Host',
|
||||||
|
hostname: 'host.local',
|
||||||
|
username: 'root',
|
||||||
|
tags: [],
|
||||||
|
os: 'linux',
|
||||||
|
theme: hostTheme.id,
|
||||||
|
themeOverride: true,
|
||||||
|
} as Host;
|
||||||
|
|
||||||
|
const resolved = resolveWorkTabHostTreeTheme({
|
||||||
|
activeHostId: host.id,
|
||||||
|
accentMode: 'theme',
|
||||||
|
currentTerminalTheme: currentTheme,
|
||||||
|
customAccent: '#8b5cf6',
|
||||||
|
followAppTerminalTheme: false,
|
||||||
|
hostById: new Map([[host.id, host]]),
|
||||||
|
themeById: new Map([[currentTheme.id, currentTheme], [hostTheme.id, hostTheme]]),
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(resolved.id, hostTheme.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('shared host tree uses the followed terminal theme when follow-app terminal theme is on', () => {
|
||||||
|
const currentTheme = makeTheme('app-light', 'light', '#ffffff');
|
||||||
|
const hostTheme = makeTheme('host-dark', 'dark', '#050505');
|
||||||
|
const host = {
|
||||||
|
id: 'host-1',
|
||||||
|
label: 'Host',
|
||||||
|
hostname: 'host.local',
|
||||||
|
username: 'root',
|
||||||
|
tags: [],
|
||||||
|
os: 'linux',
|
||||||
|
theme: hostTheme.id,
|
||||||
|
themeOverride: true,
|
||||||
|
} as Host;
|
||||||
|
|
||||||
|
const resolved = resolveWorkTabHostTreeTheme({
|
||||||
|
activeHostId: host.id,
|
||||||
|
accentMode: 'theme',
|
||||||
|
currentTerminalTheme: currentTheme,
|
||||||
|
customAccent: '#8b5cf6',
|
||||||
|
followAppTerminalTheme: true,
|
||||||
|
hostById: new Map([[host.id, host]]),
|
||||||
|
themeById: new Map([[currentTheme.id, currentTheme], [hostTheme.id, hostTheme]]),
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(resolved.id, currentTheme.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('shared host tree falls back to the current terminal theme without an active host', () => {
|
||||||
|
const currentTheme = makeTheme('app-dark', 'dark', '#111111');
|
||||||
|
|
||||||
|
const resolved = resolveWorkTabHostTreeTheme({
|
||||||
|
activeHostId: null,
|
||||||
|
accentMode: 'theme',
|
||||||
|
currentTerminalTheme: currentTheme,
|
||||||
|
customAccent: '#8b5cf6',
|
||||||
|
followAppTerminalTheme: false,
|
||||||
|
hostById: new Map(),
|
||||||
|
themeById: new Map([[currentTheme.id, currentTheme]]),
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(resolved.id, currentTheme.id);
|
||||||
|
});
|
||||||
|
|||||||
@@ -2,8 +2,9 @@ import {
|
|||||||
fromEditorTabId,
|
fromEditorTabId,
|
||||||
isEditorTabId,
|
isEditorTabId,
|
||||||
} from '../state/activeTabStore';
|
} from '../state/activeTabStore';
|
||||||
|
import { applyCustomAccentToTerminalTheme, resolveHostTerminalThemeId } from '../../domain/terminalAppearance';
|
||||||
import type { EditorTab } from '../state/editorTabStore';
|
import type { EditorTab } from '../state/editorTabStore';
|
||||||
import type { TerminalSession, Workspace } from '../../types';
|
import type { Host, TerminalSession, TerminalTheme, Workspace } from '../../types';
|
||||||
|
|
||||||
function uniqueTabIds(tabIds: readonly string[]): string[] {
|
function uniqueTabIds(tabIds: readonly string[]): string[] {
|
||||||
const seen = new Set<string>();
|
const seen = new Set<string>();
|
||||||
@@ -125,3 +126,28 @@ export function resolveWorkTabActiveHostId({
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function resolveWorkTabHostTreeTheme({
|
||||||
|
activeHostId,
|
||||||
|
accentMode,
|
||||||
|
currentTerminalTheme,
|
||||||
|
customAccent,
|
||||||
|
followAppTerminalTheme,
|
||||||
|
hostById,
|
||||||
|
themeById,
|
||||||
|
}: {
|
||||||
|
activeHostId: string | null;
|
||||||
|
accentMode: 'theme' | 'custom';
|
||||||
|
currentTerminalTheme: TerminalTheme;
|
||||||
|
customAccent: string;
|
||||||
|
followAppTerminalTheme: boolean;
|
||||||
|
hostById: ReadonlyMap<string, Host>;
|
||||||
|
themeById: ReadonlyMap<string, TerminalTheme>;
|
||||||
|
}): TerminalTheme {
|
||||||
|
if (!activeHostId || followAppTerminalTheme) return currentTerminalTheme;
|
||||||
|
|
||||||
|
const host = hostById.get(activeHostId) ?? null;
|
||||||
|
const themeId = resolveHostTerminalThemeId(host, currentTerminalTheme.id);
|
||||||
|
const baseTheme = themeById.get(themeId) ?? currentTerminalTheme;
|
||||||
|
return applyCustomAccentToTerminalTheme(baseTheme, accentMode, customAccent);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user