feat: add global keyboard shortcuts for navigation and panels

This commit is contained in:
plenarius
2026-04-20 22:10:11 -04:00
parent 83d1a0a169
commit 1a46baa7fe
+35 -2
View File
@@ -1,5 +1,5 @@
import { useState, useEffect } from "react"; import { useState, useEffect, useCallback } from "react";
import { Outlet, Link, useLocation } from "react-router-dom"; import { Outlet, Link, useLocation, useNavigate } from "react-router-dom";
import { Terminal } from "../components/terminal/Terminal"; import { Terminal } from "../components/terminal/Terminal";
import { useWebSocket } from "../hooks/useWebSocket"; import { useWebSocket } from "../hooks/useWebSocket";
import { useTheme } from "../hooks/useTheme"; import { useTheme } from "../hooks/useTheme";
@@ -18,6 +18,7 @@ export function IDELayout({ sidebar }: { sidebar?: React.ReactNode }) {
const [upstreamBehind, setUpstreamBehind] = useState(0); const [upstreamBehind, setUpstreamBehind] = useState(0);
const [pendingToolset, setPendingToolset] = useState(0); const [pendingToolset, setPendingToolset] = useState(0);
const location = useLocation(); const location = useLocation();
const navigate = useNavigate();
const { subscribe } = useWebSocket(); const { subscribe } = useWebSocket();
const { theme, toggleTheme } = useTheme(); const { theme, toggleTheme } = useTheme();
@@ -45,6 +46,38 @@ export function IDELayout({ sidebar }: { sidebar?: React.ReactNode }) {
if (location.pathname === "/toolset") setPendingToolset(0); if (location.pathname === "/toolset") setPendingToolset(0);
}, [location.pathname]); }, [location.pathname]);
const handleKeyDown = useCallback(
(e: KeyboardEvent) => {
const tag = (e.target as HTMLElement)?.tagName;
if (tag === "INPUT" || tag === "TEXTAREA" || (e.target as HTMLElement)?.closest?.(".monaco-editor")) {
return;
}
if (e.ctrlKey && e.shiftKey && e.key === "B") {
e.preventDefault();
navigate("/build");
} else if (e.ctrlKey && e.key === "`") {
e.preventDefault();
setTerminalOpen((v) => !v);
} else if (e.ctrlKey && e.shiftKey && e.key === "F") {
e.preventDefault();
navigate("/editor");
} else if (e.ctrlKey && e.shiftKey && e.key === "G") {
e.preventDefault();
navigate("/repos");
} else if (e.ctrlKey && e.key === ",") {
e.preventDefault();
navigate("/settings");
}
},
[navigate],
);
useEffect(() => {
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, [handleKeyDown]);
const getBadge = (path: string): number => { const getBadge = (path: string): number => {
if (path === "/repos") return upstreamBehind; if (path === "/repos") return upstreamBehind;
if (path === "/toolset") return pendingToolset; if (path === "/toolset") return pendingToolset;