mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-28 06:05:24 +00:00
fix: move macOS split pane navigation to Cmd+Option+Arrow
This commit is contained in:
1 parent
6bacb17390
commit
9949d0711e
5 files changed
+88
-15
No files matched your search
@@ -11,6 +11,7 @@
|
||||
|
||||
- The Docker Compose files no longer start a guacd container. npm run dev -- --guacd also points remote desktop at the guacd it starts
|
||||
- The side menu now opens over the page when it expands on hover, so open sessions like remote desktop are not resized each time. Turn on Push content when it expands in Settings to get the old behavior back
|
||||
- On macOS, moving between split panes is now Cmd+Option+Arrow, so Option+Arrow can move the cursor by word in a terminal
|
||||
|
||||
### Fixed
|
||||
|
||||
|
||||
+6
-14
@@ -125,6 +125,7 @@ import type {
|
||||
} from "@/types/ui-types";
|
||||
import { applyAccentColor, applyFontSize } from "@/lib/theme";
|
||||
import { globalShortcutHandler } from "@/lib/global-shortcut-handler";
|
||||
import { getPaneNavDirection } from "@/lib/pane-nav-hotkey";
|
||||
import { getTabJumpDigit } from "@/lib/tab-jump-hotkey";
|
||||
import { useTheme } from "@/components/theme-provider";
|
||||
import {
|
||||
@@ -829,20 +830,11 @@ export function AppShell({
|
||||
}
|
||||
}
|
||||
|
||||
// Alt+Arrow moves between panes of the active split
|
||||
if (e.altKey && !e.ctrlKey && !e.shiftKey && !e.metaKey) {
|
||||
const direction = (
|
||||
{
|
||||
ArrowLeft: "left",
|
||||
ArrowRight: "right",
|
||||
ArrowUp: "up",
|
||||
ArrowDown: "down",
|
||||
} as Record<string, NavDirection>
|
||||
)[e.code];
|
||||
if (direction && splitActionsRef.current?.navigate(direction)) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
// Alt+Arrow (Cmd+Option+Arrow on macOS) moves between panes of the active split
|
||||
const paneDirection = getPaneNavDirection(e);
|
||||
if (paneDirection && splitActionsRef.current?.navigate(paneDirection)) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
// Cmd+1..9 on macOS, Alt+1..9 elsewhere: jump directly to the tab at that position
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { isMacPlatform } from "./tab-jump-hotkey";
|
||||
|
||||
export type PaneNavDirection = "left" | "right" | "up" | "down";
|
||||
|
||||
const ARROWS: Record<string, PaneNavDirection> = {
|
||||
ArrowLeft: "left",
|
||||
ArrowRight: "right",
|
||||
ArrowUp: "up",
|
||||
ArrowDown: "down",
|
||||
};
|
||||
|
||||
/**
|
||||
* The split pane to move to for this key, if any. Cmd+Option+Arrow on macOS,
|
||||
* where Option+Arrow moves the shell cursor by word, Alt+Arrow elsewhere.
|
||||
*/
|
||||
export function getPaneNavDirection(e: KeyboardEvent): PaneNavDirection | null {
|
||||
const direction = ARROWS[e.code];
|
||||
if (!direction || e.ctrlKey || e.shiftKey || !e.altKey) return null;
|
||||
if (e.metaKey !== isMacPlatform()) return null;
|
||||
return direction;
|
||||
}
|
||||
|
||||
export function paneNavHotkeyLabel(): string {
|
||||
return isMacPlatform() ? "Cmd+Option+Arrows" : "Alt+Arrows";
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
type SplitPresetId,
|
||||
} from "./split-presets";
|
||||
import { MAX_PANES, type PaneEdge } from "./split-tree";
|
||||
import { paneNavHotkeyLabel } from "@/lib/pane-nav-hotkey";
|
||||
|
||||
function NodeThumb({ node }: { node: LayoutNode }) {
|
||||
if (node.kind === "pane") {
|
||||
@@ -129,7 +130,7 @@ export function SplitLayoutMenu({
|
||||
<div className="flex flex-col gap-1 px-2 pb-1.5 text-xs text-muted-foreground">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<span>{t("splitScreen.shortcutNavigate")}</span>
|
||||
<kbd className="font-mono text-[10px]">Alt+Arrows</kbd>
|
||||
<kbd className="font-mono text-[10px]">{paneNavHotkeyLabel()}</kbd>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<span>{t("splitScreen.zoom")}</span>
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
getPaneNavDirection,
|
||||
paneNavHotkeyLabel,
|
||||
} from "../../lib/pane-nav-hotkey";
|
||||
|
||||
function keyEvent(init: Partial<KeyboardEvent>): KeyboardEvent {
|
||||
return {
|
||||
code: "ArrowLeft",
|
||||
altKey: false,
|
||||
ctrlKey: false,
|
||||
metaKey: false,
|
||||
shiftKey: false,
|
||||
...init,
|
||||
} as KeyboardEvent;
|
||||
}
|
||||
|
||||
afterEach(() => vi.unstubAllGlobals());
|
||||
|
||||
describe("pane-nav-hotkey", () => {
|
||||
it("uses Alt+Arrow outside macOS", () => {
|
||||
vi.stubGlobal("navigator", { platform: "Win32" });
|
||||
expect(getPaneNavDirection(keyEvent({ altKey: true }))).toBe("left");
|
||||
expect(
|
||||
getPaneNavDirection(keyEvent({ code: "ArrowDown", altKey: true })),
|
||||
).toBe("down");
|
||||
expect(
|
||||
getPaneNavDirection(keyEvent({ altKey: true, metaKey: true })),
|
||||
).toBeNull();
|
||||
expect(paneNavHotkeyLabel()).toBe("Alt+Arrows");
|
||||
});
|
||||
|
||||
it("leaves Option+Arrow to the shell on macOS", () => {
|
||||
vi.stubGlobal("navigator", { platform: "MacIntel" });
|
||||
expect(getPaneNavDirection(keyEvent({ altKey: true }))).toBeNull();
|
||||
expect(
|
||||
getPaneNavDirection(
|
||||
keyEvent({ code: "ArrowRight", altKey: true, metaKey: true }),
|
||||
),
|
||||
).toBe("right");
|
||||
expect(paneNavHotkeyLabel()).toBe("Cmd+Option+Arrows");
|
||||
});
|
||||
|
||||
it("ignores other keys and modifiers", () => {
|
||||
vi.stubGlobal("navigator", { platform: "Win32" });
|
||||
expect(
|
||||
getPaneNavDirection(keyEvent({ code: "KeyA", altKey: true })),
|
||||
).toBeNull();
|
||||
expect(
|
||||
getPaneNavDirection(keyEvent({ altKey: true, shiftKey: true })),
|
||||
).toBeNull();
|
||||
expect(getPaneNavDirection(keyEvent({}))).toBeNull();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user