Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions application/AppHandlers.globalHotkeys.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -674,3 +674,53 @@ test('connection log host snapshot includes custom host icon fields', () => {
},
);
});

test('toggleOpacity hotkey invokes toggleWindowOpacity', () => {
let called = false;
const noop = () => {};

executeHotkeyActionImpl(
() => ({
IS_DEV: false,
MOVE_FOCUS_DEBOUNCE_MS: 0,
activeTabStore: { getActiveTabId: () => 'vault' },
addConnectionLogRef: { current: noop },
closeSession: noop,
closeTabInFlightRef: { current: false },
closeWorkspace: noop,
collectSessionIds: () => [],
confirmIfBusyLocalTerminal: async () => true,
createLocalTerminalWithCurrentShell: noop,
editorTabs: [],
fromEditorTabId: () => null,
handleOpenSettingsRef: { current: noop },
handleRequestCloseEditorTabRef: { current: noop },
isEditorTabId: () => false,
isQuickSwitcherOpen: false,
lastMoveFocusTimeRef: { current: 0 },
moveFocusInWorkspace: noop,
orderedTabs: [],
resolveCloseIntent: () => ({ kind: 'noop' }),
resolveSnippetsShortcutIntent: () => ({ kind: 'noop' }),
sessions: [],
setActiveTabId: noop,
setAddToWorkspaceDialog: noop,
setIsQuickSwitcherOpen: noop,
setNavigateToSection: noop,
settings: { showSftpTab: true, shellOnlyTabNumberShortcuts: false },
splitSessionWithCurrentShell: noop,
systemInfoRef: { current: { username: 'user', hostname: 'host' } },
toEditorTabId: (id: string) => `editor:${id}`,
toggleBroadcast: noop,
toggleScriptsSidePanelRef: { current: noop },
toggleSidePanelRef: { current: noop },
toggleWindowOpacity: () => { called = true; },
toggleWorkspaceViewMode: noop,
workspaces: [],
}),
'toggleOpacity',
{ key: 'u', code: 'KeyU', ctrlKey: true, shiftKey: true } as KeyboardEvent,
);

assert.equal(called, true);
});
5 changes: 4 additions & 1 deletion application/app/AppHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -702,7 +702,7 @@ export async function closeTabsBatchImpl(getCtx: AppContextGetter, targetIds: st
}

export function executeHotkeyActionImpl(getCtx: AppContextGetter, action: string, e: KeyboardEvent) {
const { IS_DEV, MOVE_FOCUS_DEBOUNCE_MS, activeTabStore, addConnectionLogRef, closePluginViewTab, closeSession, closeTabInFlightRef, closeWorkspace, collectSessionIds, confirmIfBusyLocalTerminal, createLocalTerminalWithCurrentShell, editorTabs, fromEditorTabId, handleOpenSettingsRef, handleRequestCloseEditorTabRef, isEditorTabId, isPluginViewTabId, isQuickSwitcherOpen, lastMoveFocusTimeRef, moveFocusInWorkspace, orderedTabs, resolveCloseIntent, resolveSnippetsShortcutIntent, sessions, setActiveTabId, setAddToWorkspaceDialog, setIsQuickSwitcherOpen, setNavigateToSection, settings, sftpPaneMagnificationRef, splitSessionWithCurrentShell, systemInfoRef, terminalPaneMagnificationRef, toEditorTabId, toggleBroadcast, toggleScriptsSidePanelRef, toggleSidePanelRef, workspaces } = getCtx();
const { IS_DEV, MOVE_FOCUS_DEBOUNCE_MS, activeTabStore, addConnectionLogRef, closePluginViewTab, closeSession, closeTabInFlightRef, closeWorkspace, collectSessionIds, confirmIfBusyLocalTerminal, createLocalTerminalWithCurrentShell, editorTabs, fromEditorTabId, handleOpenSettingsRef, handleRequestCloseEditorTabRef, isEditorTabId, isPluginViewTabId, isQuickSwitcherOpen, lastMoveFocusTimeRef, moveFocusInWorkspace, orderedTabs, resolveCloseIntent, resolveSnippetsShortcutIntent, sessions, setActiveTabId, setAddToWorkspaceDialog, setIsQuickSwitcherOpen, setNavigateToSection, settings, sftpPaneMagnificationRef, splitSessionWithCurrentShell, systemInfoRef, terminalPaneMagnificationRef, toEditorTabId, toggleBroadcast, toggleScriptsSidePanelRef, toggleSidePanelRef, toggleWindowOpacity, workspaces } = getCtx();
{
const shortcutTabs = buildNumberShortcutTabTargets({
showSftpTab: settings.showSftpTab ?? true,
Expand Down Expand Up @@ -892,6 +892,9 @@ export function executeHotkeyActionImpl(getCtx: AppContextGetter, action: string
setNavigateToSection('snippets');
}
break;
case 'toggleOpacity':
toggleWindowOpacity();
break;
case 'toggleSidePanel':
toggleSidePanelRef.current?.();
break;
Expand Down
3 changes: 3 additions & 0 deletions application/app/AppSideEffects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ export function AppSideEffects() {
showSftpTab,
shellOnlyTabNumberShortcuts,
workspaceFocusStyle,
toggleWindowOpacity,
} = settings;

useTerminalKeyboardFocus(hotkeyScheme !== 'disabled' && !disableTerminalFontZoom);
Expand Down Expand Up @@ -1076,6 +1077,7 @@ export function AppSideEffects() {
toggleBroadcast,
toggleScriptsSidePanelRef,
toggleSidePanelRef,
toggleWindowOpacity,
toggleWorkspaceViewMode,
workspaces: workspacesRefForHotkeys.current,
}), action, e);
Expand All @@ -1088,6 +1090,7 @@ export function AppSideEffects() {
splitSessionWithCurrentShell,
moveFocusInWorkspace,
toggleBroadcast,
toggleWindowOpacity,
toggleWorkspaceViewMode,
confirmIfBusyLocalTerminal,
]);
Expand Down
1 change: 1 addition & 0 deletions application/i18n/locales/ru/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,7 @@ export const ruCoreMessages: Messages = {
'settings.shortcuts.binding.new-workspace': 'Новая рабочая область',
'settings.shortcuts.binding.snippets': 'Открыть сниппеты',
'settings.shortcuts.binding.broadcast': 'Переключить режим трансляции',
'settings.shortcuts.binding.toggle-opacity': 'Переключить прозрачность окна',
'settings.shortcuts.binding.toggle-side-panel': 'Переключить боковую панель',
'settings.shortcuts.binding.sftp-copy': 'Копировать файл',
'settings.shortcuts.binding.sftp-cut': 'Вырезать файл',
Expand Down
1 change: 1 addition & 0 deletions application/i18n/locales/zh-CN/terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,7 @@ export const zhCNTerminalMessages: Messages = {
'settings.shortcuts.binding.new-workspace': '新建工作区',
'settings.shortcuts.binding.snippets': '打开代码片段',
'settings.shortcuts.binding.broadcast': '切换广播模式',
'settings.shortcuts.binding.toggle-opacity': '切换窗口透明度',
'settings.shortcuts.binding.toggle-side-panel': '切换侧边栏',
'settings.shortcuts.binding.sftp-copy': '复制文件',
'settings.shortcuts.binding.sftp-cut': '剪切文件',
Expand Down
1 change: 1 addition & 0 deletions application/i18n/locales/zh-TW/terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,7 @@ export const zhTWTerminalMessages: Messages = {
'settings.shortcuts.binding.new-workspace': '新增工作區',
'settings.shortcuts.binding.snippets': '開啟程式碼片段',
'settings.shortcuts.binding.broadcast': '切換廣播模式',
'settings.shortcuts.binding.toggle-opacity': '切換視窗透明度',
'settings.shortcuts.binding.toggle-side-panel': '切換側邊欄',
'settings.shortcuts.binding.sftp-copy': '複製檔案',
'settings.shortcuts.binding.sftp-cut': '剪下檔案',
Expand Down
1 change: 1 addition & 0 deletions application/state/useGlobalHotkeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export const getAppLevelActions = (): Set<string> => {
'togglePaneZoom',
'openLocal',
'openSettings',
'toggleOpacity',
]);
};

Expand Down
13 changes: 13 additions & 0 deletions application/state/useSettingsState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,18 @@ export const useSettingsState = (options: { enableSettingsSync?: boolean; enable
return incoming;
});
}, []);
// Tracks the user's preferred transparency level (last value below 100%) so
// Cmd+U can restore it after toggling transparency off. Session-only (useRef),
// never persisted — matches iTerm2's session-level toggle behavior.
const lastNonFullOpacityRef = useRef<number | null>(windowOpacity < 1.0 ? windowOpacity : null);
useEffect(() => {
if (windowOpacity < 1.0) {
lastNonFullOpacityRef.current = windowOpacity;
}
}, [windowOpacity]);
const toggleWindowOpacity = useCallback(() => {
setWindowOpacity(windowOpacity < 1.0 ? 1.0 : (lastNonFullOpacityRef.current ?? 0.85));
}, [windowOpacity, setWindowOpacity]);
const [appIconVariant, setAppIconVariantState] = useState<AppIconVariant>(() => {
const stored = readStoredString(STORAGE_KEY_APP_ICON_VARIANT);
return resolveAppIconVariant(stored ?? DEFAULT_APP_ICON_VARIANT);
Expand Down Expand Up @@ -2110,6 +2122,7 @@ export const useSettingsState = (options: { enableSettingsSync?: boolean; enable
setGlobalHotkeyEnabled,
windowOpacity,
setWindowOpacity,
toggleWindowOpacity,
appIconVariant,
setAppIconVariant,
rehydrateAllFromStorage,
Expand Down
2 changes: 1 addition & 1 deletion components/TopTabsQuickControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export const TopTabsQuickControls: React.FC<TopTabsQuickControlsProps> = ({
onClick={() => setIsOpacityExpanded((current) => !current)}
>
<div className="flex min-w-0 items-center gap-2 text-sm">
<Droplets size={14} className="shrink-0 text-muted-foreground" />
<Droplets size={14} className={cn("shrink-0", windowOpacity < 1.0 ? "text-primary" : "text-muted-foreground")} />
<span className="truncate">{t('topTabs.windowOpacity')}</span>
</div>
<div className="flex shrink-0 items-center gap-1.5">
Expand Down
1 change: 1 addition & 0 deletions domain/models/keyBindings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ export const DEFAULT_KEY_BINDINGS: KeyBinding[] = [
{ id: 'broadcast', action: 'broadcast', label: 'Switch the Broadcast Mode', mac: '⌘ + B', pc: 'Ctrl + B', category: 'app' },
{ id: 'toggle-side-panel', action: 'toggleSidePanel', label: 'Toggle Side Panel', mac: '⌘ + \\', pc: 'Ctrl + \\', category: 'app' },
{ id: 'open-settings', action: 'openSettings', label: 'Open Settings', mac: '⌘ + ,', pc: 'Ctrl + ,', category: 'app' },
{ id: 'toggle-opacity', action: 'toggleOpacity', label: 'Toggle Window Transparency', mac: '⌘ + U', pc: 'Ctrl + Shift + U', category: 'app' },

// SFTP Operations
{ id: 'sftp-copy', action: 'sftpCopy', label: 'Copy Files', mac: '⌘ + C', pc: 'Ctrl + C', category: 'sftp' },
Expand Down