mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-01 08:13:37 +00:00
Add keyboard shortcuts store and update components to use customizable shortcuts
Co-authored-by: GTheMachine <156854865+GTheMachine@users.noreply.github.com>
This commit is contained in:
committed by
Kacper
parent
13f68cba4c
commit
e5095c7911
@@ -64,9 +64,7 @@ import {
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
useKeyboardShortcuts,
|
useKeyboardShortcuts,
|
||||||
NAV_SHORTCUTS,
|
useKeyboardShortcutsConfig,
|
||||||
UI_SHORTCUTS,
|
|
||||||
ACTION_SHORTCUTS,
|
|
||||||
KeyboardShortcut,
|
KeyboardShortcut,
|
||||||
} from "@/hooks/use-keyboard-shortcuts";
|
} from "@/hooks/use-keyboard-shortcuts";
|
||||||
import { getElectronAPI, Project, TrashedProject } from "@/lib/electron";
|
import { getElectronAPI, Project, TrashedProject } from "@/lib/electron";
|
||||||
@@ -221,6 +219,9 @@ export function Sidebar() {
|
|||||||
theme: globalTheme,
|
theme: globalTheme,
|
||||||
} = useAppStore();
|
} = useAppStore();
|
||||||
|
|
||||||
|
// Get customizable keyboard shortcuts
|
||||||
|
const shortcuts = useKeyboardShortcutsConfig();
|
||||||
|
|
||||||
// State for project picker dropdown
|
// State for project picker dropdown
|
||||||
const [isProjectPickerOpen, setIsProjectPickerOpen] = useState(false);
|
const [isProjectPickerOpen, setIsProjectPickerOpen] = useState(false);
|
||||||
const [showTrashDialog, setShowTrashDialog] = useState(false);
|
const [showTrashDialog, setShowTrashDialog] = useState(false);
|
||||||
@@ -496,13 +497,13 @@ export function Sidebar() {
|
|||||||
id: "board",
|
id: "board",
|
||||||
label: "Kanban Board",
|
label: "Kanban Board",
|
||||||
icon: LayoutGrid,
|
icon: LayoutGrid,
|
||||||
shortcut: NAV_SHORTCUTS.board,
|
shortcut: shortcuts.board,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "agent",
|
id: "agent",
|
||||||
label: "Agent Runner",
|
label: "Agent Runner",
|
||||||
icon: Bot,
|
icon: Bot,
|
||||||
shortcut: NAV_SHORTCUTS.agent,
|
shortcut: shortcuts.agent,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -513,25 +514,25 @@ export function Sidebar() {
|
|||||||
id: "spec",
|
id: "spec",
|
||||||
label: "Spec Editor",
|
label: "Spec Editor",
|
||||||
icon: FileText,
|
icon: FileText,
|
||||||
shortcut: NAV_SHORTCUTS.spec,
|
shortcut: shortcuts.spec,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "context",
|
id: "context",
|
||||||
label: "Context",
|
label: "Context",
|
||||||
icon: BookOpen,
|
icon: BookOpen,
|
||||||
shortcut: NAV_SHORTCUTS.context,
|
shortcut: shortcuts.context,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "tools",
|
id: "tools",
|
||||||
label: "Agent Tools",
|
label: "Agent Tools",
|
||||||
icon: Wrench,
|
icon: Wrench,
|
||||||
shortcut: NAV_SHORTCUTS.tools,
|
shortcut: shortcuts.tools,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "profiles",
|
id: "profiles",
|
||||||
label: "AI Profiles",
|
label: "AI Profiles",
|
||||||
icon: UserCircle,
|
icon: UserCircle,
|
||||||
shortcut: NAV_SHORTCUTS.profiles,
|
shortcut: shortcuts.profiles,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -573,26 +574,26 @@ export function Sidebar() {
|
|||||||
|
|
||||||
// Build keyboard shortcuts for navigation
|
// Build keyboard shortcuts for navigation
|
||||||
const navigationShortcuts: KeyboardShortcut[] = useMemo(() => {
|
const navigationShortcuts: KeyboardShortcut[] = useMemo(() => {
|
||||||
const shortcuts: KeyboardShortcut[] = [];
|
const shortcutsList: KeyboardShortcut[] = [];
|
||||||
|
|
||||||
// Sidebar toggle shortcut - always available
|
// Sidebar toggle shortcut - always available
|
||||||
shortcuts.push({
|
shortcutsList.push({
|
||||||
key: UI_SHORTCUTS.toggleSidebar,
|
key: shortcuts.toggleSidebar,
|
||||||
action: () => toggleSidebar(),
|
action: () => toggleSidebar(),
|
||||||
description: "Toggle sidebar",
|
description: "Toggle sidebar",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Open project shortcut - opens the folder selection dialog directly
|
// Open project shortcut - opens the folder selection dialog directly
|
||||||
shortcuts.push({
|
shortcutsList.push({
|
||||||
key: ACTION_SHORTCUTS.openProject,
|
key: shortcuts.openProject,
|
||||||
action: () => handleOpenFolder(),
|
action: () => handleOpenFolder(),
|
||||||
description: "Open folder selection dialog",
|
description: "Open folder selection dialog",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Project picker shortcut - only when we have projects
|
// Project picker shortcut - only when we have projects
|
||||||
if (projects.length > 0) {
|
if (projects.length > 0) {
|
||||||
shortcuts.push({
|
shortcutsList.push({
|
||||||
key: ACTION_SHORTCUTS.projectPicker,
|
key: shortcuts.projectPicker,
|
||||||
action: () => setIsProjectPickerOpen((prev) => !prev),
|
action: () => setIsProjectPickerOpen((prev) => !prev),
|
||||||
description: "Toggle project picker",
|
description: "Toggle project picker",
|
||||||
});
|
});
|
||||||
@@ -600,13 +601,13 @@ export function Sidebar() {
|
|||||||
|
|
||||||
// Project cycling shortcuts - only when we have project history
|
// Project cycling shortcuts - only when we have project history
|
||||||
if (projectHistory.length > 1) {
|
if (projectHistory.length > 1) {
|
||||||
shortcuts.push({
|
shortcutsList.push({
|
||||||
key: ACTION_SHORTCUTS.cyclePrevProject,
|
key: shortcuts.cyclePrevProject,
|
||||||
action: () => cyclePrevProject(),
|
action: () => cyclePrevProject(),
|
||||||
description: "Cycle to previous project (MRU)",
|
description: "Cycle to previous project (MRU)",
|
||||||
});
|
});
|
||||||
shortcuts.push({
|
shortcutsList.push({
|
||||||
key: ACTION_SHORTCUTS.cycleNextProject,
|
key: shortcuts.cycleNextProject,
|
||||||
action: () => cycleNextProject(),
|
action: () => cycleNextProject(),
|
||||||
description: "Cycle to next project (LRU)",
|
description: "Cycle to next project (LRU)",
|
||||||
});
|
});
|
||||||
@@ -617,7 +618,7 @@ export function Sidebar() {
|
|||||||
navSections.forEach((section) => {
|
navSections.forEach((section) => {
|
||||||
section.items.forEach((item) => {
|
section.items.forEach((item) => {
|
||||||
if (item.shortcut) {
|
if (item.shortcut) {
|
||||||
shortcuts.push({
|
shortcutsList.push({
|
||||||
key: item.shortcut,
|
key: item.shortcut,
|
||||||
action: () => setCurrentView(item.id as any),
|
action: () => setCurrentView(item.id as any),
|
||||||
description: `Navigate to ${item.label}`,
|
description: `Navigate to ${item.label}`,
|
||||||
@@ -627,15 +628,16 @@ export function Sidebar() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Add settings shortcut
|
// Add settings shortcut
|
||||||
shortcuts.push({
|
shortcutsList.push({
|
||||||
key: NAV_SHORTCUTS.settings,
|
key: shortcuts.settings,
|
||||||
action: () => setCurrentView("settings"),
|
action: () => setCurrentView("settings"),
|
||||||
description: "Navigate to Settings",
|
description: "Navigate to Settings",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return shortcuts;
|
return shortcutsList;
|
||||||
}, [
|
}, [
|
||||||
|
shortcuts,
|
||||||
currentProject,
|
currentProject,
|
||||||
setCurrentView,
|
setCurrentView,
|
||||||
toggleSidebar,
|
toggleSidebar,
|
||||||
@@ -644,6 +646,7 @@ export function Sidebar() {
|
|||||||
projectHistory.length,
|
projectHistory.length,
|
||||||
cyclePrevProject,
|
cyclePrevProject,
|
||||||
cycleNextProject,
|
cycleNextProject,
|
||||||
|
navSections,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Register keyboard shortcuts
|
// Register keyboard shortcuts
|
||||||
@@ -682,7 +685,7 @@ export function Sidebar() {
|
|||||||
className="ml-1 px-1 py-0.5 bg-brand-500/10 border border-brand-500/30 rounded text-[10px] font-mono text-brand-400/70"
|
className="ml-1 px-1 py-0.5 bg-brand-500/10 border border-brand-500/30 rounded text-[10px] font-mono text-brand-400/70"
|
||||||
data-testid="sidebar-toggle-shortcut"
|
data-testid="sidebar-toggle-shortcut"
|
||||||
>
|
>
|
||||||
{UI_SHORTCUTS.toggleSidebar}
|
{shortcuts.toggleSidebar}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
@@ -735,12 +738,12 @@ export function Sidebar() {
|
|||||||
<button
|
<button
|
||||||
onClick={handleOpenFolder}
|
onClick={handleOpenFolder}
|
||||||
className="group flex items-center justify-center flex-1 px-3 py-2.5 rounded-lg relative overflow-hidden transition-all text-muted-foreground hover:text-foreground hover:bg-sidebar-accent/50 border border-sidebar-border"
|
className="group flex items-center justify-center flex-1 px-3 py-2.5 rounded-lg relative overflow-hidden transition-all text-muted-foreground hover:text-foreground hover:bg-sidebar-accent/50 border border-sidebar-border"
|
||||||
title={`Open Folder (${ACTION_SHORTCUTS.openProject})`}
|
title={`Open Folder (${shortcuts.openProject})`}
|
||||||
data-testid="open-project-button"
|
data-testid="open-project-button"
|
||||||
>
|
>
|
||||||
<FolderOpen className="w-4 h-4 shrink-0" />
|
<FolderOpen className="w-4 h-4 shrink-0" />
|
||||||
<span className="hidden lg:flex items-center justify-center w-5 h-5 text-[10px] font-mono rounded bg-brand-500/10 border border-brand-500/30 text-brand-400/70 ml-2">
|
<span className="hidden lg:flex items-center justify-center w-5 h-5 text-[10px] font-mono rounded bg-brand-500/10 border border-brand-500/30 text-brand-400/70 ml-2">
|
||||||
{ACTION_SHORTCUTS.openProject}
|
{shortcuts.openProject}
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@@ -782,7 +785,7 @@ export function Sidebar() {
|
|||||||
className="hidden lg:flex items-center justify-center w-5 h-5 text-[10px] font-mono rounded bg-brand-500/10 border border-brand-500/30 text-brand-400/70"
|
className="hidden lg:flex items-center justify-center w-5 h-5 text-[10px] font-mono rounded bg-brand-500/10 border border-brand-500/30 text-brand-400/70"
|
||||||
data-testid="project-picker-shortcut"
|
data-testid="project-picker-shortcut"
|
||||||
>
|
>
|
||||||
{ACTION_SHORTCUTS.projectPicker}
|
{shortcuts.projectPicker}
|
||||||
</span>
|
</span>
|
||||||
<ChevronDown className="h-4 w-4 text-muted-foreground shrink-0" />
|
<ChevronDown className="h-4 w-4 text-muted-foreground shrink-0" />
|
||||||
</div>
|
</div>
|
||||||
@@ -889,14 +892,14 @@ export function Sidebar() {
|
|||||||
<Undo2 className="w-4 h-4 mr-2" />
|
<Undo2 className="w-4 h-4 mr-2" />
|
||||||
<span className="flex-1">Previous</span>
|
<span className="flex-1">Previous</span>
|
||||||
<span className="text-[10px] font-mono text-muted-foreground ml-2">
|
<span className="text-[10px] font-mono text-muted-foreground ml-2">
|
||||||
{ACTION_SHORTCUTS.cyclePrevProject}
|
{shortcuts.cyclePrevProject}
|
||||||
</span>
|
</span>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem onClick={cycleNextProject} data-testid="cycle-next-project">
|
<DropdownMenuItem onClick={cycleNextProject} data-testid="cycle-next-project">
|
||||||
<Redo2 className="w-4 h-4 mr-2" />
|
<Redo2 className="w-4 h-4 mr-2" />
|
||||||
<span className="flex-1">Next</span>
|
<span className="flex-1">Next</span>
|
||||||
<span className="text-[10px] font-mono text-muted-foreground ml-2">
|
<span className="text-[10px] font-mono text-muted-foreground ml-2">
|
||||||
{ACTION_SHORTCUTS.cycleNextProject}
|
{shortcuts.cycleNextProject}
|
||||||
</span>
|
</span>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem onClick={clearProjectHistory} data-testid="clear-project-history">
|
<DropdownMenuItem onClick={clearProjectHistory} data-testid="clear-project-history">
|
||||||
@@ -1052,7 +1055,7 @@ export function Sidebar() {
|
|||||||
)}
|
)}
|
||||||
data-testid="shortcut-settings"
|
data-testid="shortcut-settings"
|
||||||
>
|
>
|
||||||
{NAV_SHORTCUTS.settings}
|
{shortcuts.settings}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{!sidebarOpen && (
|
{!sidebarOpen && (
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ import {
|
|||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import type { SessionListItem } from "@/types/electron";
|
import type { SessionListItem } from "@/types/electron";
|
||||||
import { ACTION_SHORTCUTS } from "@/hooks/use-keyboard-shortcuts";
|
import { useKeyboardShortcutsConfig } from "@/hooks/use-keyboard-shortcuts";
|
||||||
|
import { useAppStore } from "@/store/app-store";
|
||||||
|
|
||||||
// Random session name generator
|
// Random session name generator
|
||||||
const adjectives = [
|
const adjectives = [
|
||||||
@@ -61,6 +62,7 @@ export function SessionManager({
|
|||||||
isCurrentSessionThinking = false,
|
isCurrentSessionThinking = false,
|
||||||
onQuickCreateRef,
|
onQuickCreateRef,
|
||||||
}: SessionManagerProps) {
|
}: SessionManagerProps) {
|
||||||
|
const shortcuts = useKeyboardShortcutsConfig();
|
||||||
const [sessions, setSessions] = useState<SessionListItem[]>([]);
|
const [sessions, setSessions] = useState<SessionListItem[]>([]);
|
||||||
const [activeTab, setActiveTab] = useState<"active" | "archived">("active");
|
const [activeTab, setActiveTab] = useState<"active" | "archived">("active");
|
||||||
const [editingSessionId, setEditingSessionId] = useState<string | null>(null);
|
const [editingSessionId, setEditingSessionId] = useState<string | null>(null);
|
||||||
@@ -246,12 +248,12 @@ export function SessionManager({
|
|||||||
size="sm"
|
size="sm"
|
||||||
onClick={handleQuickCreateSession}
|
onClick={handleQuickCreateSession}
|
||||||
data-testid="new-session-button"
|
data-testid="new-session-button"
|
||||||
title={`New Session (${ACTION_SHORTCUTS.newSession})`}
|
title={`New Session (${shortcuts.newSession})`}
|
||||||
>
|
>
|
||||||
<Plus className="w-4 h-4 mr-1" />
|
<Plus className="w-4 h-4 mr-1" />
|
||||||
New
|
New
|
||||||
<span className="ml-1.5 px-1.5 py-0.5 text-[10px] font-mono rounded bg-primary-foreground/20 border border-primary-foreground/30 text-primary-foreground">
|
<span className="ml-1.5 px-1.5 py-0.5 text-[10px] font-mono rounded bg-primary-foreground/20 border border-primary-foreground/30 text-primary-foreground">
|
||||||
{ACTION_SHORTCUTS.newSession}
|
{shortcuts.newSession}
|
||||||
</span>
|
</span>
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ import { Checkbox } from "@/components/ui/checkbox";
|
|||||||
import { useAutoMode } from "@/hooks/use-auto-mode";
|
import { useAutoMode } from "@/hooks/use-auto-mode";
|
||||||
import {
|
import {
|
||||||
useKeyboardShortcuts,
|
useKeyboardShortcuts,
|
||||||
ACTION_SHORTCUTS,
|
useKeyboardShortcutsConfig,
|
||||||
KeyboardShortcut,
|
KeyboardShortcut,
|
||||||
} from "@/hooks/use-keyboard-shortcuts";
|
} from "@/hooks/use-keyboard-shortcuts";
|
||||||
import { useWindowState } from "@/hooks/use-window-state";
|
import { useWindowState } from "@/hooks/use-window-state";
|
||||||
@@ -189,6 +189,7 @@ export function BoardView() {
|
|||||||
showProfilesOnly,
|
showProfilesOnly,
|
||||||
aiProfiles,
|
aiProfiles,
|
||||||
} = useAppStore();
|
} = useAppStore();
|
||||||
|
const shortcuts = useKeyboardShortcutsConfig();
|
||||||
const [activeFeature, setActiveFeature] = useState<Feature | null>(null);
|
const [activeFeature, setActiveFeature] = useState<Feature | null>(null);
|
||||||
const [editingFeature, setEditingFeature] = useState<Feature | null>(null);
|
const [editingFeature, setEditingFeature] = useState<Feature | null>(null);
|
||||||
const [showAddDialog, setShowAddDialog] = useState(false);
|
const [showAddDialog, setShowAddDialog] = useState(false);
|
||||||
@@ -292,14 +293,14 @@ export function BoardView() {
|
|||||||
|
|
||||||
// Keyboard shortcuts for this view
|
// Keyboard shortcuts for this view
|
||||||
const boardShortcuts: KeyboardShortcut[] = useMemo(() => {
|
const boardShortcuts: KeyboardShortcut[] = useMemo(() => {
|
||||||
const shortcuts: KeyboardShortcut[] = [
|
const shortcutsList: KeyboardShortcut[] = [
|
||||||
{
|
{
|
||||||
key: ACTION_SHORTCUTS.addFeature,
|
key: shortcuts.addFeature,
|
||||||
action: () => setShowAddDialog(true),
|
action: () => setShowAddDialog(true),
|
||||||
description: "Add new feature",
|
description: "Add new feature",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: ACTION_SHORTCUTS.startNext,
|
key: shortcuts.startNext,
|
||||||
action: () => startNextFeaturesRef.current(),
|
action: () => startNextFeaturesRef.current(),
|
||||||
description: "Start next features from backlog",
|
description: "Start next features from backlog",
|
||||||
},
|
},
|
||||||
@@ -309,7 +310,7 @@ export function BoardView() {
|
|||||||
inProgressFeaturesForShortcuts.slice(0, 10).forEach((feature, index) => {
|
inProgressFeaturesForShortcuts.slice(0, 10).forEach((feature, index) => {
|
||||||
// Keys 1-9 for first 9 cards, 0 for 10th card
|
// Keys 1-9 for first 9 cards, 0 for 10th card
|
||||||
const key = index === 9 ? "0" : String(index + 1);
|
const key = index === 9 ? "0" : String(index + 1);
|
||||||
shortcuts.push({
|
shortcutsList.push({
|
||||||
key,
|
key,
|
||||||
action: () => {
|
action: () => {
|
||||||
setOutputFeature(feature);
|
setOutputFeature(feature);
|
||||||
@@ -319,8 +320,8 @@ export function BoardView() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return shortcuts;
|
return shortcutsList;
|
||||||
}, [inProgressFeaturesForShortcuts]);
|
}, [inProgressFeaturesForShortcuts, shortcuts]);
|
||||||
useKeyboardShortcuts(boardShortcuts);
|
useKeyboardShortcuts(boardShortcuts);
|
||||||
|
|
||||||
// Prevent hydration issues
|
// Prevent hydration issues
|
||||||
@@ -1567,7 +1568,7 @@ export function BoardView() {
|
|||||||
className="ml-3 px-2 py-0.5 text-[10px] font-mono rounded bg-primary-foreground/20 border border-primary-foreground/30 text-primary-foreground inline-flex items-center justify-center"
|
className="ml-3 px-2 py-0.5 text-[10px] font-mono rounded bg-primary-foreground/20 border border-primary-foreground/30 text-primary-foreground inline-flex items-center justify-center"
|
||||||
data-testid="shortcut-add-feature"
|
data-testid="shortcut-add-feature"
|
||||||
>
|
>
|
||||||
{ACTION_SHORTCUTS.addFeature}
|
{shortcuts.addFeature}
|
||||||
</span>
|
</span>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -1636,7 +1637,7 @@ export function BoardView() {
|
|||||||
<FastForward className="w-3 h-3 mr-1" />
|
<FastForward className="w-3 h-3 mr-1" />
|
||||||
Start Next
|
Start Next
|
||||||
<span className="ml-1 px-1 py-0.5 text-[9px] font-mono rounded bg-accent border border-border-glass">
|
<span className="ml-1 px-1 py-0.5 text-[9px] font-mono rounded bg-accent border border-border-glass">
|
||||||
{ACTION_SHORTCUTS.startNext}
|
{shortcuts.startNext}
|
||||||
</span>
|
</span>
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect, useCallback } from "react";
|
import { useEffect, useCallback } from "react";
|
||||||
|
import { useAppStore } from "@/store/app-store";
|
||||||
|
|
||||||
export interface KeyboardShortcut {
|
export interface KeyboardShortcut {
|
||||||
key: string;
|
key: string;
|
||||||
@@ -97,36 +98,10 @@ export function useKeyboardShortcuts(shortcuts: KeyboardShortcut[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shortcut definitions for navigation
|
* Hook to get current keyboard shortcuts from store
|
||||||
|
* This replaces the static constants and allows customization
|
||||||
*/
|
*/
|
||||||
export const NAV_SHORTCUTS: Record<string, string> = {
|
export function useKeyboardShortcutsConfig() {
|
||||||
board: "K", // K for Kanban
|
const keyboardShortcuts = useAppStore((state) => state.keyboardShortcuts);
|
||||||
agent: "A", // A for Agent
|
return keyboardShortcuts;
|
||||||
spec: "D", // D for Document (Spec)
|
}
|
||||||
context: "C", // C for Context
|
|
||||||
tools: "T", // T for Tools
|
|
||||||
settings: "S", // S for Settings
|
|
||||||
profiles: "M", // M for Models/profiles
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shortcut definitions for UI controls
|
|
||||||
*/
|
|
||||||
export const UI_SHORTCUTS: Record<string, string> = {
|
|
||||||
toggleSidebar: "`", // Backtick to toggle sidebar
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shortcut definitions for add buttons
|
|
||||||
*/
|
|
||||||
export const ACTION_SHORTCUTS: Record<string, string> = {
|
|
||||||
addFeature: "N", // N for New feature
|
|
||||||
addContextFile: "F", // F for File (add context file)
|
|
||||||
startNext: "G", // G for Grab (start next features from backlog)
|
|
||||||
newSession: "N", // N for New session (in agent view)
|
|
||||||
openProject: "O", // O for Open project (navigate to welcome view)
|
|
||||||
projectPicker: "P", // P for Project picker
|
|
||||||
cyclePrevProject: "Q", // Q for previous project (cycle back through MRU)
|
|
||||||
cycleNextProject: "E", // E for next project (cycle forward through MRU)
|
|
||||||
addProfile: "N", // N for New profile (when in profiles view)
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -37,6 +37,58 @@ export interface ApiKeys {
|
|||||||
openai: string;
|
openai: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keyboard Shortcuts
|
||||||
|
export interface KeyboardShortcuts {
|
||||||
|
// Navigation shortcuts
|
||||||
|
board: string;
|
||||||
|
agent: string;
|
||||||
|
spec: string;
|
||||||
|
context: string;
|
||||||
|
tools: string;
|
||||||
|
settings: string;
|
||||||
|
profiles: string;
|
||||||
|
|
||||||
|
// UI shortcuts
|
||||||
|
toggleSidebar: string;
|
||||||
|
|
||||||
|
// Action shortcuts
|
||||||
|
addFeature: string;
|
||||||
|
addContextFile: string;
|
||||||
|
startNext: string;
|
||||||
|
newSession: string;
|
||||||
|
openProject: string;
|
||||||
|
projectPicker: string;
|
||||||
|
cyclePrevProject: string;
|
||||||
|
cycleNextProject: string;
|
||||||
|
addProfile: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default keyboard shortcuts
|
||||||
|
export const DEFAULT_KEYBOARD_SHORTCUTS: KeyboardShortcuts = {
|
||||||
|
// Navigation
|
||||||
|
board: "K",
|
||||||
|
agent: "A",
|
||||||
|
spec: "D",
|
||||||
|
context: "C",
|
||||||
|
tools: "T",
|
||||||
|
settings: "S",
|
||||||
|
profiles: "M",
|
||||||
|
|
||||||
|
// UI
|
||||||
|
toggleSidebar: "`",
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
addFeature: "N",
|
||||||
|
addContextFile: "F",
|
||||||
|
startNext: "G",
|
||||||
|
newSession: "N",
|
||||||
|
openProject: "O",
|
||||||
|
projectPicker: "P",
|
||||||
|
cyclePrevProject: "Q",
|
||||||
|
cycleNextProject: "E",
|
||||||
|
addProfile: "N",
|
||||||
|
};
|
||||||
|
|
||||||
export interface ImageAttachment {
|
export interface ImageAttachment {
|
||||||
id: string;
|
id: string;
|
||||||
data: string; // base64 encoded image data
|
data: string; // base64 encoded image data
|
||||||
@@ -203,6 +255,9 @@ export interface AppState {
|
|||||||
// Profile Display Settings
|
// Profile Display Settings
|
||||||
showProfilesOnly: boolean; // When true, hide model tweaking options and show only profile selection
|
showProfilesOnly: boolean; // When true, hide model tweaking options and show only profile selection
|
||||||
|
|
||||||
|
// Keyboard Shortcuts
|
||||||
|
keyboardShortcuts: KeyboardShortcuts; // User-defined keyboard shortcuts
|
||||||
|
|
||||||
// Project Analysis
|
// Project Analysis
|
||||||
projectAnalysis: ProjectAnalysis | null;
|
projectAnalysis: ProjectAnalysis | null;
|
||||||
isAnalyzing: boolean;
|
isAnalyzing: boolean;
|
||||||
@@ -303,6 +358,11 @@ export interface AppActions {
|
|||||||
// Profile Display Settings actions
|
// Profile Display Settings actions
|
||||||
setShowProfilesOnly: (enabled: boolean) => void;
|
setShowProfilesOnly: (enabled: boolean) => void;
|
||||||
|
|
||||||
|
// Keyboard Shortcuts actions
|
||||||
|
setKeyboardShortcut: (key: keyof KeyboardShortcuts, value: string) => void;
|
||||||
|
setKeyboardShortcuts: (shortcuts: Partial<KeyboardShortcuts>) => void;
|
||||||
|
resetKeyboardShortcuts: () => void;
|
||||||
|
|
||||||
// AI Profile actions
|
// AI Profile actions
|
||||||
addAIProfile: (profile: Omit<AIProfile, "id">) => void;
|
addAIProfile: (profile: Omit<AIProfile, "id">) => void;
|
||||||
updateAIProfile: (id: string, updates: Partial<AIProfile>) => void;
|
updateAIProfile: (id: string, updates: Partial<AIProfile>) => void;
|
||||||
@@ -404,6 +464,7 @@ const initialState: AppState = {
|
|||||||
defaultSkipTests: false, // Default to TDD mode (tests enabled)
|
defaultSkipTests: false, // Default to TDD mode (tests enabled)
|
||||||
useWorktrees: false, // Default to disabled (worktree feature is experimental)
|
useWorktrees: false, // Default to disabled (worktree feature is experimental)
|
||||||
showProfilesOnly: false, // Default to showing all options (not profiles only)
|
showProfilesOnly: false, // Default to showing all options (not profiles only)
|
||||||
|
keyboardShortcuts: DEFAULT_KEYBOARD_SHORTCUTS, // Default keyboard shortcuts
|
||||||
aiProfiles: DEFAULT_AI_PROFILES,
|
aiProfiles: DEFAULT_AI_PROFILES,
|
||||||
projectAnalysis: null,
|
projectAnalysis: null,
|
||||||
isAnalyzing: false,
|
isAnalyzing: false,
|
||||||
@@ -907,6 +968,29 @@ export const useAppStore = create<AppState & AppActions>()(
|
|||||||
// Profile Display Settings actions
|
// Profile Display Settings actions
|
||||||
setShowProfilesOnly: (enabled) => set({ showProfilesOnly: enabled }),
|
setShowProfilesOnly: (enabled) => set({ showProfilesOnly: enabled }),
|
||||||
|
|
||||||
|
// Keyboard Shortcuts actions
|
||||||
|
setKeyboardShortcut: (key, value) => {
|
||||||
|
set({
|
||||||
|
keyboardShortcuts: {
|
||||||
|
...get().keyboardShortcuts,
|
||||||
|
[key]: value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setKeyboardShortcuts: (shortcuts) => {
|
||||||
|
set({
|
||||||
|
keyboardShortcuts: {
|
||||||
|
...get().keyboardShortcuts,
|
||||||
|
...shortcuts,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
resetKeyboardShortcuts: () => {
|
||||||
|
set({ keyboardShortcuts: DEFAULT_KEYBOARD_SHORTCUTS });
|
||||||
|
},
|
||||||
|
|
||||||
// AI Profile actions
|
// AI Profile actions
|
||||||
addAIProfile: (profile) => {
|
addAIProfile: (profile) => {
|
||||||
const id = `profile-${Date.now()}-${Math.random()
|
const id = `profile-${Date.now()}-${Math.random()
|
||||||
@@ -985,6 +1069,7 @@ export const useAppStore = create<AppState & AppActions>()(
|
|||||||
defaultSkipTests: state.defaultSkipTests,
|
defaultSkipTests: state.defaultSkipTests,
|
||||||
useWorktrees: state.useWorktrees,
|
useWorktrees: state.useWorktrees,
|
||||||
showProfilesOnly: state.showProfilesOnly,
|
showProfilesOnly: state.showProfilesOnly,
|
||||||
|
keyboardShortcuts: state.keyboardShortcuts,
|
||||||
aiProfiles: state.aiProfiles,
|
aiProfiles: state.aiProfiles,
|
||||||
lastSelectedSessionByProject: state.lastSelectedSessionByProject,
|
lastSelectedSessionByProject: state.lastSelectedSessionByProject,
|
||||||
}),
|
}),
|
||||||
|
|||||||
Reference in New Issue
Block a user