Files
RawMark/web/src/app/commands.ts
T
eezd 919575f3e7 Add command palette and command registry
- Commands (with optional shortcuts and availability checks) are registered in one place;
  global shortcuts are dispatched from it, and plugins can use registerCommand later
- The quick switcher lists commands when the input starts with '>' (VS Code style),
  opened with Ctrl+Shift+P or F1 (Firefox reserves Ctrl+Shift+P), plus buttons in the
  sidebar footer and the mobile top bar; recently used commands come first
- Built-in commands: quick open, search, new note/folder, save, rename, delete, close tab,
  trash, log out
- Mount the trash dialog at the workspace level so it is not positioned inside the
  transformed mobile drawer
2026-10-17 12:14:11 +08:00

63 lines
2.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 命令注册表:命令面板列出的操作与全局快捷键都来自这里;插件也通过 registerCommand 添加命令
import { shallowReactive } from 'vue'
export interface Command {
id: string
title: string
/** 快捷键,如 'Mod+Shift+F'、'F1';Mod 在 Mac 上为 Cmd,其他平台为 Ctrl。第一个用于显示 */
keys?: string[]
/** 返回 false 时命令不可用:不在面板中列出,快捷键也不触发 */
when?: () => boolean
run: () => void
}
const commands = shallowReactive(new Map<string, Command>())
/** 注册命令,返回注销函数;id 重复时后注册的覆盖先注册的 */
export function registerCommand(cmd: Command): () => void {
commands.set(cmd.id, cmd)
return () => {
if (commands.get(cmd.id) === cmd) commands.delete(cmd.id)
}
}
export function availableCommands(): Command[] {
return [...commands.values()].filter((c) => c.when?.() ?? true)
}
export function runCommand(id: string) {
const cmd = commands.get(id)
if (cmd && (cmd.when?.() ?? true)) cmd.run()
}
const isMac = /Mac|iPhone|iPad/.test(navigator.platform)
export function matchKeys(e: KeyboardEvent, keys: string): boolean {
const parts = keys.split('+')
const key = parts.pop()!.toLowerCase()
return (
e.key.toLowerCase() === key &&
(isMac ? e.metaKey : e.ctrlKey) === parts.includes('Mod') &&
e.shiftKey === parts.includes('Shift') &&
e.altKey === parts.includes('Alt')
)
}
export function formatKeys(keys: string): string {
const parts = keys.split('+')
if (isMac) return parts.map((p) => ({ Mod: '⌘', Shift: '⇧', Alt: '⌥' })[p] ?? p).join('')
return parts.map((p) => (p === 'Mod' ? 'Ctrl' : p)).join('+')
}
/** 全局快捷键分发;编辑器等已处理的按键(defaultPrevented)和输入法组字中的按键不处理 */
export function handleShortcut(e: KeyboardEvent) {
if (e.defaultPrevented || e.isComposing) return
for (const cmd of availableCommands()) {
if (cmd.keys?.some((k) => matchKeys(e, k))) {
e.preventDefault()
cmd.run()
return
}
}
}