Added arrow navigation on calendar page

This commit is contained in:
Alexis
2025-08-24 15:02:42 +02:00
parent 8dff0763e9
commit 8c53616c79
4 changed files with 158 additions and 104 deletions

View File

@@ -8,8 +8,8 @@ import CenturyLayout from "./state/centennially/Layout.vue"
import DecadeLayout from "./state/decennially/Layout.vue"
import YearLayout from "./state/yearly/Layout.vue"
const { currentConfig, jumpToDate, selectedDate } = useCalendar()
const { isReadOnly } = storeToRefs(useCalendar())
const { currentConfig, jumpToDate, selectedDate, toPastFar, toPastNear, toFutureNear, toFutureFar } = useCalendar()
const { isReadOnly, calendarState } = storeToRefs(useCalendar())
const currentViewComponent: ComputedRef<Component> = computed<Component>(() => {
switch (currentConfig.viewType) {
@@ -31,6 +31,34 @@ const currentViewComponent: ComputedRef<Component> = computed<Component>(() => {
onMounted(() => {
jumpToDate(selectedDate)
})
// Key combos to navigate
const { arrowUp, arrowLeft, pageUp } = useMagicKeys()
const { arrowDown, arrowRight, pageDown } = useMagicKeys()
watch([arrowUp, arrowLeft], (k) => {
if (calendarState.value === 'active' && k[0] || k[1]) {
toPastNear()
}
})
watch([arrowDown, arrowRight], (k) => {
if (calendarState.value === 'active' && k[0] || k[1]) {
toFutureNear()
}
})
watch(pageUp!, (k) => {
if (calendarState.value === 'active' && k) {
toPastFar()
}
})
watch(pageDown!, (k) => {
if (calendarState.value === 'active' && k) {
toFutureFar()
}
})
</script>
<template>

View File

@@ -3,20 +3,8 @@ import { breakpointsTailwind, useBreakpoints } from "@vueuse/core"
import { PhPlus } from "@phosphor-icons/vue";
import { VisuallyHidden } from "radix-vue";
const isDialogOpen = ref<boolean>(false);
const { resetSkeleton } = useCalendar();
// Watch the popover state
watch(isDialogOpen, (hasOpened, _o) => {
if (hasOpened) {
resetSkeleton()
}
})
// Toggles the dialog
function toggleDialog() {
isDialogOpen.value = !isDialogOpen.value;
};
const { isCreatingEventModalOpen } = storeToRefs(useCalendar());
const { resetSkeleton, toggleCreatingEventModal } = useCalendar();
/**
* Prevents the modal from closing if's still loading
@@ -36,7 +24,7 @@ const breakpoints = useBreakpoints(
<UiButton
class="max-md:fixed max-md:bottom-8 max-md:right-8 max-md:z-50 max-md:size-14 max-md:rounded-xl"
:size="breakpoints.md.value ? 'default' : 'icon'"
@click="toggleDialog"
@click="toggleCreatingEventModal"
>
<PhPlus :size="breakpoints.md.value ? 18 : 24" weight="bold" />
@@ -47,7 +35,7 @@ const breakpoints = useBreakpoints(
</Transition>
</ClientOnly>
<UiDialog v-model:open="isDialogOpen">
<UiDialog v-model:open="isCreatingEventModalOpen">
<UiDialogContent
class="max-md:translate-0 max-md:inset-0 max-md:w-full max-md:block"
:trap-focus="true"
@@ -64,7 +52,7 @@ const breakpoints = useBreakpoints(
</UiDialogDescription>
</VisuallyHidden>
<CalendarFormCreateEvent @event-created="toggleDialog" />
<CalendarFormCreateEvent @event-created="toggleCreatingEventModal" />
</UiDialogContent>
</UiDialog>
</template>

View File

@@ -12,7 +12,7 @@ interface DirectionLabels {
futureFar: string
}
const { currentConfig, decrementViewMonth, incrementViewMonth, decrementViewYear, incrementViewYear } =
const { currentConfig, toPastFar, toPastNear, toFutureNear, toFutureFar } =
useCalendar()
const activeDirectionLabels: ComputedRef<DirectionLabels> = computed(() => {
@@ -51,90 +51,6 @@ const activeDirectionLabels: ComputedRef<DirectionLabels> = computed(() => {
}
}
})
function toPastFar(): void {
switch (currentConfig.viewType) {
case "month":
decrementViewYear()
break
case "year":
decrementViewYear(10)
break
case "decade":
decrementViewYear(100)
break
case "century":
default:
decrementViewYear(1000)
break
}
}
function toPastNear(): void {
switch (currentConfig.viewType) {
case "month":
decrementViewMonth()
break
case "year":
decrementViewYear()
break
case "decade":
decrementViewYear(10)
break
case "century":
default:
decrementViewYear(100)
break
}
}
function toFutureNear(): void {
switch (currentConfig.viewType) {
case "month":
incrementViewMonth()
break
case "year":
incrementViewYear()
break
case "decade":
incrementViewYear(10)
break
case "century":
default:
incrementViewYear(100)
break
}
}
function toFutureFar(): void {
switch (currentConfig.viewType) {
case "month":
incrementViewYear()
break
case "year":
incrementViewYear(10)
break
case "decade":
incrementViewYear(100)
break
case "century":
default:
incrementViewYear(1000)
break
}
}
</script>
<template>

View File

@@ -10,6 +10,8 @@ import type { CalendarEvent } from "@@/models/CalendarEvent"
import type { CalendarMonth } from "@@/models/CalendarMonth"
import type { Category } from "@@/models/Category"
type CalendarState = "active" | "idle"
type CalendarViewType = "month" | "year" | "decade" | "century"
type CalendarCurrentConfig = {
@@ -668,6 +670,90 @@ export const useCalendar = defineStore("calendar", () => {
currentEvents.value = computeCurrentEvents()
}, { deep: true, immediate: true })
function toPastFar(): void {
switch (currentConfig.value.viewType) {
case "month":
decrementViewYear()
break
case "year":
decrementViewYear(10)
break
case "decade":
decrementViewYear(100)
break
case "century":
default:
decrementViewYear(1000)
break
}
}
function toPastNear(): void {
switch (currentConfig.value.viewType) {
case "month":
decrementViewMonth()
break
case "year":
decrementViewYear()
break
case "decade":
decrementViewYear(10)
break
case "century":
default:
decrementViewYear(100)
break
}
}
function toFutureNear(): void {
switch (currentConfig.value.viewType) {
case "month":
incrementViewMonth()
break
case "year":
incrementViewYear()
break
case "decade":
incrementViewYear(10)
break
case "century":
default:
incrementViewYear(100)
break
}
}
function toFutureFar(): void {
switch (currentConfig.value.viewType) {
case "month":
incrementViewYear()
break
case "year":
incrementViewYear(10)
break
case "decade":
incrementViewYear(100)
break
case "century":
default:
incrementViewYear(1000)
break
}
}
/**
* Determines if the event can appear in the front end
*
@@ -805,6 +891,22 @@ export const useCalendar = defineStore("calendar", () => {
}
}
/**
* State for event modal creation
*/
const isCreatingEventModalOpen = ref<boolean>(false)
// Watch the popover state
watch(isCreatingEventModalOpen, (hasOpened, _o) => {
if (hasOpened) {
resetSkeleton()
}
})
function toggleCreatingEventModal() {
isCreatingEventModalOpen.value = !isCreatingEventModalOpen.value
}
/**
* State for event modal edition
*/
@@ -936,6 +1038,19 @@ export const useCalendar = defineStore("calendar", () => {
isCategoriesModalOpen.value = state
}
/**
* Handle the state of the active calendar for UI interactions
*/
const calendarState = ref<CalendarState>("active")
watch([isCategoriesModalOpen, isCreatingEventModalOpen, isDeleteEventModalOpen, isEditEventModalOpen, isAdvancedSearchOpen, isDraggingEvent], (values) => {
if (values.every(v => !v)) {
calendarState.value = 'active'
} else {
calendarState.value = 'idle'
}
})
return {
isReadOnly,
setReadStatus,
@@ -975,10 +1090,15 @@ export const useCalendar = defineStore("calendar", () => {
areDatesIdentical,
compareDates,
getRelativeString,
toPastFar,
toPastNear,
toFutureNear,
toFutureFar,
baseEvents,
allEvents,
categories,
currentEvents,
calendarState,
getRelativeEventFromDate,
getRelativeEventFromEvent,
cancelLatestRequest,
@@ -993,6 +1113,8 @@ export const useCalendar = defineStore("calendar", () => {
lastActiveEvent,
updateEventFromSkeleton,
deleteEventFromSkeleton,
isCreatingEventModalOpen,
toggleCreatingEventModal,
isEditEventModalOpen,
revealEditEventModal,
isDeleteEventModalOpen,