feat: 新增键盘快捷键设置
Sync source to CNB / Sync Git ref (push) Skipped

- 设置页新增「键盘快捷键」分类,可自定义快捷键绑定
- 支持快速滚动(Home/End/PageUp/PageDown)与导航跳转(Ctrl/Cmd+数字)
- 快捷键绑定与开关按动作独立持久化,默认关闭
- 新增 ui 包 keybinding 组件与工具(KeybindingModal/KeybindingChips 等)
This commit is contained in:
AxTps committed 2026-10-11 11:14:46 +08:00
1 parent 47bdb1e79c
commit 2e92887eb2
24 files changed
+2432 -5

No files matched your search

+1
View File
@@ -30,3 +30,4 @@ export * from './use-loading-state-core'
export * from './use-ready-state'
export * from './use-server-image'
export * from './virtual-scroll'
export * from './use-keybinding-labels'
@@ -0,0 +1,54 @@
import { computed } from 'vue'
import {
bindingParts,
bindingText,
type KeyBinding,
type KeybindingLabels,
} from '../utils/keybinding'
import { MOUSE_CODE_MESSAGES } from '../utils/keybinding-catalog'
import { defineMessages, useVIntl } from './i18n'
const messages = defineMessages({
mod: { id: 'ui.keybinding-modal.mod', defaultMessage: 'Ctrl/Cmd' },
shift: { id: 'ui.keybinding-modal.shift', defaultMessage: 'Shift' },
alt: { id: 'ui.keybinding-modal.alt', defaultMessage: 'Alt' },
})
/**
* The names a combination is built from, in the reader's language. Shared so a
* shortcut reads the same wherever it is shown.
*/
export function useKeybindingLabels() {
const { formatMessage } = useVIntl()
return computed<KeybindingLabels>(() => ({
mod: formatMessage(messages.mod),
shift: formatMessage(messages.shift),
alt: formatMessage(messages.alt),
mouseButton: Object.fromEntries(
Object.entries(MOUSE_CODE_MESSAGES).map(([code, message]) => [code, formatMessage(message)]),
),
wheelUp: formatMessage(MOUSE_CODE_MESSAGES.WheelUp),
wheelDown: formatMessage(MOUSE_CODE_MESSAGES.WheelDown),
}))
}
/** Splits a combination into the pieces a key cap is drawn for. */
export function useBindingParts(binding: () => KeyBinding | null) {
const labels = useKeybindingLabels()
return computed(() => {
const value = binding()
return value ? bindingParts(value, labels.value) : []
})
}
export function useBindingText(binding: () => KeyBinding | null) {
const labels = useKeybindingLabels()
return computed(() => {
const value = binding()
return value ? bindingText(value, labels.value) : ''
})
}