refactor(app): reuse menu shortcuts in chrome

This commit is contained in:
Danila Poyarkov 2026-05-17 14:35:50 +03:00
parent 883601f548
commit 6c8fd8fc59
3 changed files with 61 additions and 7 deletions

View file

@ -6,6 +6,7 @@ import { editorCommandMetadata } from '@open-pencil/vue'
import type { EditorCommandId } from '@open-pencil/vue'
import { TOOL_SHORTCUTS } from '@/app/editor/session'
import { appMenuTinykeysShortcut } from '@/app/shell/menu/shortcut'
import { isEditing } from '@/app/shell/keyboard/focus'
import { bindSpaceHandTool } from '@/app/shell/keyboard/space-tool'
import type {
@ -83,14 +84,26 @@ export function registerKeyboardShortcuts(options: KeyboardShortcutOptions) {
),
{
id: 'export-selection-png',
keys: '$mod+Shift+KeyE',
keys: appMenuTinykeysShortcut('export-selection') ?? '$mod+Shift+KeyE',
run: ({ actions }) => actions.exportSelectionPng()
},
{ id: 'save-as', keys: '$mod+Shift+KeyS', run: ({ store }) => void store.saveFigFileAs() },
{
id: 'save-as',
keys: appMenuTinykeysShortcut('save-as') ?? '$mod+Shift+KeyS',
run: ({ store }) => void store.saveFigFileAs()
},
...commandShortcuts('selection.ungroup', 'edit.redo'),
{ id: 'toggle-ui', keys: '$mod+Backslash', run: ({ actions }) => actions.toggleUI() },
{
id: 'toggle-ui',
keys: appMenuTinykeysShortcut('toggle-ui') ?? '$mod+Backslash',
run: ({ actions }) => actions.toggleUI()
},
{ id: 'toggle-ai', keys: '$mod+KeyJ', run: ({ actions }) => actions.toggleAI() },
{ id: 'close-tab', keys: '$mod+KeyW', run: ({ closeActiveTab }) => closeActiveTab() },
{
id: 'close-tab',
keys: appMenuTinykeysShortcut('close') ?? '$mod+KeyW',
run: ({ closeActiveTab }) => closeActiveTab()
},
{ id: 'new-tab', keys: ['$mod+KeyN', '$mod+KeyT'], run: ({ createTab }) => createTab() },
...commandShortcuts(
'edit.undo',
@ -100,8 +113,16 @@ export function registerKeyboardShortcuts(options: KeyboardShortcutOptions) {
'selection.duplicate',
'selection.selectAll'
),
{ id: 'save', keys: '$mod+KeyS', run: ({ store }) => void store.saveFigFile() },
{ id: 'open-file', keys: '$mod+KeyO', run: ({ openFileDialog }) => openFileDialog() },
{
id: 'save',
keys: appMenuTinykeysShortcut('save') ?? '$mod+KeyS',
run: ({ store }) => void store.saveFigFile()
},
{
id: 'open-file',
keys: appMenuTinykeysShortcut('open') ?? '$mod+KeyO',
run: ({ openFileDialog }) => openFileDialog()
},
...commandShortcuts('selection.group'),
{
id: 'toggle-auto-layout',

View file

@ -0,0 +1,32 @@
import type { AppMenuActionItem, AppMenuEntry } from '@/app/shell/menu/schema'
import { APP_MENU_SCHEMA } from '@/app/shell/menu/schema'
function isActionItem(entry: AppMenuEntry): entry is AppMenuActionItem {
return !('type' in entry && entry.type === 'separator')
}
function findShortcutInEntries(entries: readonly AppMenuEntry[], id: string): string | undefined {
for (const entry of entries) {
if (!isActionItem(entry)) continue
if (entry.id === id) return entry.shortcut
const shortcut = entry.sub ? findShortcutInEntries(entry.sub, id) : undefined
if (shortcut) return shortcut
}
return undefined
}
export function appMenuShortcut(id: string): string | undefined {
for (const group of APP_MENU_SCHEMA) {
const shortcut = findShortcutInEntries(group.items, id)
if (shortcut) return shortcut
}
return undefined
}
export function appMenuTinykeysShortcut(id: string): string | string[] | undefined {
const shortcut = appMenuShortcut(id)
return shortcut
?.replaceAll('MOD', '$mod')
.replaceAll('⇧', 'Shift')
.replaceAll('⌥', 'Alt')
}

View file

@ -13,6 +13,7 @@ import { useCollab, COLLAB_KEY } from '@/app/collab/use'
import { connectAutomation } from '@/app/automation/bridge/server'
import { spawnMCPIfNeeded } from '@/app/automation/mcp/spawn'
import { isTauri } from '@/app/tauri/env'
import { appMenuShortcut } from '@/app/shell/menu/shortcut'
import { createDemoShapes } from '@/app/demo/document'
import { useEditorStore } from '@/app/editor/active-store'
import { createTab, activeTab, getActiveStore, tabCount } from '@/app/tabs'
@ -194,7 +195,7 @@ onUnmounted(() => {
<button
data-test-id="editor-show-ui"
class="ml-1 flex size-6 cursor-pointer items-center justify-center rounded text-muted transition-colors hover:bg-hover hover:text-surface"
:title="`Show UI (${formatShortcut('MOD+\\')})`"
:title="`Show UI (${formatShortcut(appMenuShortcut('toggle-ui'))})`"
@click="store.state.showUI = true"
>
<icon-lucide-sidebar class="size-3.5" />