fix: add keyboard shortcuts for event creation and management in Calendar components
This commit is contained in:
parent
1e99192448
commit
557dc1f94c
@ -177,6 +177,7 @@
|
||||
:debounce="500"
|
||||
:placeholder="__('Event title')"
|
||||
@change="sync"
|
||||
@keyup.enter="saveEvent"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex justify-between py-2.5 px-4.5 text-ink-gray-6">
|
||||
@ -372,7 +373,7 @@ import {
|
||||
CalendarActiveEvent as activeEvent,
|
||||
createDocumentResource,
|
||||
} from 'frappe-ui'
|
||||
import { ref, computed, watch, h } from 'vue'
|
||||
import { ref, computed, watch, h, onMounted, onBeforeUnmount } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const props = defineProps({
|
||||
@ -664,5 +665,61 @@ function updateEvent(_e) {
|
||||
Object.assign(_event.value, _e)
|
||||
}
|
||||
|
||||
// Keyboard shortcuts
|
||||
function isTypingEvent(e) {
|
||||
const el = e.target
|
||||
if (!el) return false
|
||||
const tag = el.tagName
|
||||
const editable = el.isContentEditable
|
||||
return (
|
||||
editable ||
|
||||
tag === 'INPUT' ||
|
||||
tag === 'TEXTAREA' ||
|
||||
tag === 'SELECT' ||
|
||||
(el.closest && el.closest('[contenteditable="true"]'))
|
||||
)
|
||||
}
|
||||
|
||||
function keydownHandler(e) {
|
||||
if (!show.value) return
|
||||
|
||||
// Esc always closes the panel
|
||||
if (e.key === 'Escape') {
|
||||
e.preventDefault()
|
||||
close()
|
||||
return
|
||||
}
|
||||
|
||||
if (!['details', 'edit'].includes(props.mode)) return
|
||||
if (isTypingEvent(e)) return
|
||||
|
||||
// Delete (no modifier) -> delete event
|
||||
if (e.key === 'Delete' || e.key === 'Backspace') {
|
||||
// Avoid capturing Backspace if it would navigate away when no focus
|
||||
e.preventDefault()
|
||||
deleteEvent()
|
||||
return
|
||||
}
|
||||
|
||||
// Cmd/Ctrl + D -> duplicate event
|
||||
if (
|
||||
(e.metaKey || e.ctrlKey) &&
|
||||
!e.shiftKey &&
|
||||
!e.altKey &&
|
||||
e.key.toLowerCase() === 'd'
|
||||
) {
|
||||
e.preventDefault()
|
||||
duplicateEvent()
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('keydown', keydownHandler)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('keydown', keydownHandler)
|
||||
})
|
||||
|
||||
defineExpose({ updateEvent })
|
||||
</script>
|
||||
|
||||
@ -113,6 +113,7 @@
|
||||
v-model="showEventPanel"
|
||||
v-model:event="event"
|
||||
:mode="mode"
|
||||
@new="newEvent"
|
||||
@save="saveEvent"
|
||||
@edit="editDetails"
|
||||
@delete="deleteEvent"
|
||||
@ -139,7 +140,7 @@ import {
|
||||
CalendarActiveEvent as activeEvent,
|
||||
call,
|
||||
} from 'frappe-ui'
|
||||
import { onMounted, ref, computed } from 'vue'
|
||||
import { onMounted, onBeforeUnmount, ref, computed } from 'vue'
|
||||
|
||||
const { user } = sessionStore()
|
||||
const { $dialog } = globalStore()
|
||||
@ -189,7 +190,7 @@ const event = ref({})
|
||||
const mode = ref('')
|
||||
|
||||
const isCreateDisabled = computed(() =>
|
||||
['edit', 'new-event', 'duplicate-event'].includes(mode.value),
|
||||
['edit', 'new', 'duplicate'].includes(mode.value),
|
||||
)
|
||||
|
||||
// Temp event helpers
|
||||
@ -325,6 +326,47 @@ onMounted(() => {
|
||||
showEventPanel.value = false
|
||||
})
|
||||
|
||||
// Global shortcut: Cmd/Ctrl + E -> new event (when not already creating/editing)
|
||||
function isTypingEvent(e) {
|
||||
const el = e.target
|
||||
if (!el) return false
|
||||
const tag = el.tagName
|
||||
const editable = el.isContentEditable
|
||||
return (
|
||||
editable ||
|
||||
tag === 'INPUT' ||
|
||||
tag === 'TEXTAREA' ||
|
||||
tag === 'SELECT' ||
|
||||
(el.closest && el.closest('[contenteditable="true"]'))
|
||||
)
|
||||
}
|
||||
|
||||
function calendarKeydown(e) {
|
||||
if (isTypingEvent(e)) return
|
||||
if (
|
||||
(e.metaKey || e.ctrlKey) &&
|
||||
!e.shiftKey &&
|
||||
!e.altKey &&
|
||||
e.key.toLowerCase() === 'e'
|
||||
) {
|
||||
if (isCreateDisabled.value) return
|
||||
e.preventDefault()
|
||||
newEvent({
|
||||
date: dayjs().format('YYYY-MM-DD'),
|
||||
time: dayjs().format('HH:mm'),
|
||||
isFullDay: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('keydown', calendarKeydown)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('keydown', calendarKeydown)
|
||||
})
|
||||
|
||||
function showDetails(e, reloadEvent = false) {
|
||||
openEvent(e, 'details', reloadEvent)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user