diff --git a/frontend/src/components/KeyboardShortcutsModal.vue b/frontend/src/components/KeyboardShortcutsModal.vue index e82bf7542..09fa47add 100644 --- a/frontend/src/components/KeyboardShortcutsModal.vue +++ b/frontend/src/components/KeyboardShortcutsModal.vue @@ -3,40 +3,58 @@ v-model="showDialog" :options="{ title: 'Keyboard Shortcuts', - size: '4xl', + size: '6xl', }"> @@ -44,11 +62,12 @@ diff --git a/frontend/src/pages/PageBuilder.vue b/frontend/src/pages/PageBuilder.vue index 849c62130..1e3fa44fb 100644 --- a/frontend/src/pages/PageBuilder.vue +++ b/frontend/src/pages/PageBuilder.vue @@ -310,7 +310,7 @@ useShortcut([ key: "i", ctrl: true, description: "Edit block with AI", - group: "Block", + group: "Edit", condition: () => builderStore.isAIEnabled && !blockController.isRoot() && @@ -323,6 +323,21 @@ useShortcut([ } }, }, + { + key: "d", + ctrl: true, + shift: true, + description: "Delete Page", + group: "Page", + handler: () => { + if (pageStore.activePage && !pageStore.activePage.is_standard) { + pageStore.deletePage(pageStore.activePage).then(() => { + router.push({ name: "home" }); + }); + } + }, + condition: () => Boolean(pageStore.activePage && !pageStore.activePage.is_standard), + }, ]); // When space is released, revert back to last mode diff --git a/frontend/src/utils/useShortcut.ts b/frontend/src/utils/useShortcut.ts index d517239cc..2f38251b4 100644 --- a/frontend/src/utils/useShortcut.ts +++ b/frontend/src/utils/useShortcut.ts @@ -41,6 +41,16 @@ export interface RegisteredShortcut { condition?: () => boolean; } +export interface ActiveShortcut extends RegisteredShortcut { + keys: string[]; +} + +function getShortcutMergeIdentity( + shortcut: Pick, +) { + return [shortcut.group, shortcut.description, Boolean(shortcut.ctrl), Boolean(shortcut.shift)].join("|"); +} + const activeShortcuts = reactive([]); const shortcutHandlers = new Map(); @@ -274,7 +284,31 @@ export function useShortcut(shortcuts: ShortcutConfig | ShortcutConfig[]) { * Get all currently registered shortcuts whose conditions are met (read-only). */ export function getActiveShortcuts() { - return computed(() => activeShortcuts.filter((s) => !s.condition || s.condition())); + return computed(() => { + const visibleShortcuts = activeShortcuts.filter( + (shortcut) => !shortcut.condition || shortcut.condition(), + ); + const mergedShortcuts = new Map(); + + for (const shortcut of visibleShortcuts) { + const identity = getShortcutMergeIdentity(shortcut); + const existing = mergedShortcuts.get(identity); + + if (!existing) { + mergedShortcuts.set(identity, { + ...shortcut, + keys: [shortcut.key], + }); + continue; + } + + if (!existing.keys.some((key) => key.toLowerCase() === shortcut.key.toLowerCase())) { + existing.keys.push(shortcut.key); + } + } + + return [...mergedShortcuts.values()]; + }); } export { formatShortcutLabel };