openpencil/src/app/shell/menu/use.ts
Danila Poyarkov 79aa6ba5dd refactor(app): move storage workspace navigation into File menu
- Replace the full-width editor header action with a shared browser and native menu command
- Localize the destination and cover menu schema and browser navigation
2026-08-03 17:42:39 +03:00

91 lines
3.2 KiB
TypeScript

import { tryOnScopeDispose } from '@vueuse/core'
import { useEditorCommands, useI18n } from '@open-pencil/vue'
import type { EditorCommandId } from '@open-pencil/vue'
import { useEditorStore } from '@/app/editor/active-store'
import { openSettingsDialog } from '@/app/settings/dialog'
import { createSharedEditorMenuActions } from '@/app/shell/menu/editor-actions'
import { importFileDialog, openFileDialog } from '@/app/shell/menu/files'
import { openStorageWorkspace } from '@/app/shell/menu/navigation'
import { APP_MENU_SCHEMA, type AppMenuEntry } from '@/app/shell/menu/schema'
import { createSelectionMenuActions } from '@/app/shell/menu/selection-actions'
import { useAppTheme } from '@/app/shell/theme'
import { checkForAppUpdate } from '@/app/shell/updater'
import { createTab, closeTab, activeTab } from '@/app/tabs'
import { isTauri } from '@/app/tauri/env'
function commandMenuIds(entries: readonly AppMenuEntry[]): EditorCommandId[] {
return entries.flatMap((entry) => {
if (entry.type === 'separator') return []
return [...(entry.command ? [entry.command] : []), ...commandMenuIds(entry.sub ?? [])]
})
}
const store = useEditorStore()
const COMMAND_MENU_IDS = new Set<EditorCommandId>(
APP_MENU_SCHEMA.flatMap((group) => commandMenuIds(group.items))
)
export { importFileDialog, openFileDialog }
export { openFileFromPath } from '@/app/shell/menu/files'
export function useMenu() {
if (!isTauri()) return
let unlisten: (() => void) | undefined
const { setTheme } = useAppTheme()
const { dialogs } = useI18n()
const { runCommand } = useEditorCommands()
const actions: Partial<Record<string, () => void>> = {
new: () => createTab(),
open: () => void openFileDialog(),
'open-storage-workspace': () => {
void import('@/router').then(({ default: router }) => openStorageWorkspace(router))
},
close: () => {
if (activeTab.value) closeTab(activeTab.value.id)
},
save: () => void store.saveFigFile(),
'save-as': () => void store.saveFigFileAs(),
'export-selection': () => {
if (store.state.selectedIds.size > 0) void store.exportSelection(1, 'png')
},
'export-png': () => {
if (store.state.selectedIds.size > 0) void store.exportSelection(1, 'png')
},
'export-svg': () => {
if (store.state.selectedIds.size > 0) void store.exportSelection(1, 'svg')
},
'export-pptx': () => {
if (store.state.selectedIds.size > 0) void store.exportSelection(1, 'pptx')
},
'export-fig': () => {
if (store.state.selectedIds.size > 0) void store.exportSelection(1, 'fig')
},
autosave: () => {
store.state.autosaveEnabled = !store.state.autosaveEnabled
},
...createSelectionMenuActions(store),
'check-updates': () => void checkForAppUpdate({ messages: dialogs }),
settings: openSettingsDialog,
...createSharedEditorMenuActions(setTheme)
}
void import('@tauri-apps/api/event').then(({ listen }) => {
return listen<string>('menu-event', (event) => {
if (COMMAND_MENU_IDS.has(event.payload as EditorCommandId)) {
runCommand(event.payload as EditorCommandId)
return
}
actions[event.payload]?.()
}).then((fn) => {
unlisten = fn
return undefined
})
})
tryOnScopeDispose(() => unlisten?.())
}