feat: add keyboard shortcuts for workstream actions (#323)

Ctrl+Shift+R  Refresh title (regenerate via LLM)
Ctrl+Shift+E  Edit title
Ctrl+Shift+F  Fork workstream
Ctrl+Shift+X  Delete workstream (X not D — avoids Chrome DevTools conflict)

Shortcuts are blocked when any modal is open (edit-title, delete-ws,
batch-delete, new-ws). Help dialog (?) updated with the new bindings.
This commit is contained in:
Patrick Buckley
2026-04-06 03:11:06 -07:00
committed by GitHub
parent 24f59a6c53
commit 7f63cd2d33
2 changed files with 44 additions and 4 deletions
+39 -3
View File
@@ -4494,9 +4494,17 @@ document
});
document.addEventListener("keydown", function (e) {
// Defer to modal's own keydown handler when new-ws modal is open
var nwsOverlay = document.getElementById("new-ws-overlay");
if (nwsOverlay && nwsOverlay.style.display !== "none") return;
// Defer to modal's own keydown handler when any modal is open
var modalIds = [
"new-ws-overlay",
"edit-title-overlay",
"delete-ws-overlay",
"ws-delete-overlay",
];
for (var mi = 0; mi < modalIds.length; mi++) {
var modal = document.getElementById(modalIds[mi]);
if (modal && modal.style.display !== "none") return;
}
if (e.key === "Escape" && dashboardVisible) {
e.preventDefault();
@@ -4542,6 +4550,34 @@ document.addEventListener("keydown", function (e) {
}
return;
}
// Workstream action shortcuts — only preventDefault when a workstream
// is active, so native browser shortcuts (e.g. Ctrl+Shift+R hard reload)
// still work when no workstream is focused.
if (e.ctrlKey && e.shiftKey) {
var wsActionKey = e.key.toLowerCase();
var activeWsId = !dashboardVisible && getCurrentWsId();
if (wsActionKey === "r" && activeWsId) {
e.preventDefault();
refreshWorkstreamTitle();
return;
}
if (wsActionKey === "e" && activeWsId) {
e.preventDefault();
editWorkstreamTitle();
return;
}
if (wsActionKey === "f" && activeWsId) {
e.preventDefault();
forkWorkstream();
return;
}
// X not D — D conflicts with Chrome DevTools
if (wsActionKey === "x" && activeWsId) {
e.preventDefault();
confirmDeleteWorkstream();
return;
}
}
// Ctrl+W: close current workstream tab
if (e.ctrlKey && !e.shiftKey && e.key === "w") {
if (Object.keys(workstreams).length > 1) {
+5 -1
View File
@@ -153,7 +153,11 @@ window.TURNSTONE_KB_SHORTCUTS = [
{ desc: "Toggle dashboard", badge: '<span class="kb-key">Ctrl+D</span>' },
{ desc: "New workstream", badge: '<span class="kb-key">Ctrl+T</span>' },
{ desc: "Close workstream", badge: '<span class="kb-key">Ctrl+W</span>' },
{ desc: "Switch to tab 1\u20139", badge: '<span class="kb-key">Ctrl+1</span>\u2026<span class="kb-key">9</span>' }
{ desc: "Switch to tab 1\u20139", badge: '<span class="kb-key">Ctrl+1</span>\u2026<span class="kb-key">9</span>' },
{ desc: "Refresh title", badge: '<span class="kb-key">Ctrl+Shift+R</span>' },
{ desc: "Edit title", badge: '<span class="kb-key">Ctrl+Shift+E</span>' },
{ desc: "Fork workstream", badge: '<span class="kb-key">Ctrl+Shift+F</span>' },
{ desc: "Delete workstream", badge: '<span class="kb-key">Ctrl+Shift+X</span>' }
]},
{ title: "Split panes", keys: [
{ desc: "Split right", badge: '<span class="kb-key">Ctrl+\\</span>' },