feat: implement global context-aware keyboard shortcuts and modal keyboard support (Enter/Esc)

This commit is contained in:
Tiberiu Ichim 2026-02-20 18:28:37 +02:00
parent 696961ea4c
commit 791d78884d
7 changed files with 36 additions and 5 deletions

View file

@ -816,7 +816,7 @@ export default {
windowResize() { windowResize() {
this.executeRebuild() this.executeRebuild()
}, },
initListeners() {
window.addEventListener('resize', this.windowResize) window.addEventListener('resize', this.windowResize)
this.$nextTick(() => { this.$nextTick(() => {

View file

@ -1,5 +1,5 @@
<template> <template>
<modals-modal v-model="show" name="batchQuickMatch" :processing="processing" :width="500" :height="'unset'"> <modals-modal v-model="show" name="batchQuickMatch" :processing="processing" :width="500" :height="'unset'" @submit="doBatchQuickMatch">
<template #outer> <template #outer>
<div class="absolute top-0 left-0 p-5 w-2/3 overflow-hidden"> <div class="absolute top-0 left-0 p-5 w-2/3 overflow-hidden">
<p class="text-3xl text-white truncate">{{ title }}</p> <p class="text-3xl text-white truncate">{{ title }}</p>

View file

@ -108,6 +108,13 @@ export default {
if (this.$store.state.innerModalOpen) return if (this.$store.state.innerModalOpen) return
if (action === this.$hotkeys.Modal.CLOSE) { if (action === this.$hotkeys.Modal.CLOSE) {
this.show = false this.show = false
} else if (action === this.$hotkeys.Modal.SUBMIT) {
const activeElement = document.activeElement
// Don't submit if we are in a textarea or certain inputs
if (activeElement && ['TEXTAREA'].includes(activeElement.tagName)) {
return
}
this.$emit('submit')
} }
}, },
setShow() { setShow() {

View file

@ -1,5 +1,5 @@
<template> <template>
<modals-modal ref="modal" v-model="show" name="move-to-library" :width="400" :height="'unset'" :processing="processing"> <modals-modal ref="modal" v-model="show" name="move-to-library" :width="400" :height="'unset'" :processing="processing" @submit="moveItems">
<template #outer> <template #outer>
<div class="absolute top-0 left-0 p-5 w-2/3 overflow-hidden"> <div class="absolute top-0 left-0 p-5 w-2/3 overflow-hidden">
<p class="text-3xl text-white truncate">{{ $strings.LabelMoveToLibrary }}</p> <p class="text-3xl text-white truncate">{{ $strings.LabelMoveToLibrary }}</p>

View file

@ -1,5 +1,5 @@
<template> <template>
<modals-modal ref="modal" v-model="show" name="split-book" :width="600" :height="'unset'" :processing="processing"> <modals-modal ref="modal" v-model="show" name="split-book" :width="600" :height="'unset'" :processing="processing" @submit="submit">
<template #outer> <template #outer>
<div class="absolute top-0 left-0 p-5 w-2/3 overflow-hidden"> <div class="absolute top-0 left-0 p-5 w-2/3 overflow-hidden">
<p class="text-3xl text-white truncate">{{ $strings.HeaderSplitBook || 'Split Book' }}</p> <p class="text-3xl text-white truncate">{{ $strings.HeaderSplitBook || 'Split Book' }}</p>

View file

@ -115,6 +115,25 @@ export default {
this.$eventBus.$emit('showing-prompt', false) this.$eventBus.$emit('showing-prompt', false)
this.content.style.transform = 'scale(0)' this.content.style.transform = 'scale(0)'
this.el.remove() this.el.remove()
},
handleKeyDown(e) {
if (!this.show) return
if (e.key === 'Enter') {
const activeElement = document.activeElement
// If an input is focused, let it handle the enter key if it wants,
// but ui-checkbox is okay to override if needed.
// Actually for a simple confirm prompt, Enter should usually confirm.
if (activeElement && ['INPUT', 'TEXTAREA'].includes(activeElement.tagName) && activeElement.type !== 'checkbox') {
return
}
e.preventDefault()
e.stopPropagation()
this.confirm()
} else if (e.key === 'Escape') {
e.preventDefault()
e.stopPropagation()
this.nevermind()
}
} }
}, },
mounted() { mounted() {
@ -124,11 +143,14 @@ export default {
this.content.style.transition = 'transform 0.25s cubic-bezier(0.16, 1, 0.3, 1)' this.content.style.transition = 'transform 0.25s cubic-bezier(0.16, 1, 0.3, 1)'
this.el.style.opacity = 1 this.el.style.opacity = 1
this.el.remove() this.el.remove()
window.addEventListener('keydown', this.handleKeyDown)
}, },
beforeDestroy() { beforeDestroy() {
if (this.show) { if (this.show) {
this.$eventBus.$emit('showing-prompt', false) this.$eventBus.$emit('showing-prompt', false)
} }
window.removeEventListener('keydown', this.handleKeyDown)
} }
} }
</script> </script>

View file

@ -47,6 +47,7 @@ const Constants = {
} }
const KeyNames = { const KeyNames = {
13: 'Enter',
27: 'Escape', 27: 'Escape',
32: 'Space', 32: 'Space',
37: 'ArrowLeft', 37: 'ArrowLeft',
@ -77,7 +78,8 @@ const Hotkeys = {
Modal: { Modal: {
NEXT_PAGE: 'ArrowRight', NEXT_PAGE: 'ArrowRight',
PREV_PAGE: 'ArrowLeft', PREV_PAGE: 'ArrowLeft',
CLOSE: 'Escape' CLOSE: 'Escape',
SUBMIT: 'Enter'
} }
} }