Update frontend components for accessibility and functionality improvements

- Modified docker-compose.dev.yml to conditionally run npm install based on the presence of package-lock.json.
- Upgraded Nuxt version in package-lock.json from 3.21.1 to 4.3.1 for enhanced features.
- Enhanced ConfirmModal component with aria-modal attribute for better accessibility.
- Updated MapErrorBoundary component's error message for clarity.
- Added role and aria-label attributes to MapView and MapSearch components for improved screen reader support.
- Refactored various components to manage focus behavior on modal close, enhancing user experience.
- Improved ToastContainer styling for better responsiveness and visibility.
- Updated layout components to include skip navigation links for improved accessibility.
This commit is contained in:
2026-03-04 01:00:56 +03:00
parent 47b81c8f22
commit adfdfd01c4
22 changed files with 2703 additions and 1140 deletions

View File

@@ -1,10 +1,17 @@
<template>
<dialog ref="modalRef" class="modal" @cancel="$emit('close')">
<dialog
ref="modalRef"
class="modal"
aria-modal="true"
aria-labelledby="coord-set-modal-title"
@cancel="$emit('close')"
@close="onDialogClose"
>
<div class="modal-box transition-all duration-200" @click.stop>
<h3 class="font-bold text-lg">Rewrite tile coords</h3>
<h3 id="coord-set-modal-title" class="font-bold text-lg">Rewrite tile coords</h3>
<p class="py-2">From ({{ coordSetFrom.x }}, {{ coordSetFrom.y }}) to:</p>
<div class="flex gap-2">
<input v-model.number="localTo.x" type="number" class="input flex-1" placeholder="X" />
<input ref="firstInputRef" v-model.number="localTo.x" type="number" class="input flex-1" placeholder="X" />
<input v-model.number="localTo.y" type="number" class="input flex-1" placeholder="Y" />
</div>
<div class="modal-action">
@@ -31,14 +38,20 @@ const emit = defineEmits<{
}>()
const modalRef = ref<HTMLDialogElement | null>(null)
const firstInputRef = ref<HTMLInputElement | null>(null)
const localTo = ref({ x: props.coordSet.x, y: props.coordSet.y })
let previousActiveElement: HTMLElement | null = null
watch(
() => props.open,
(open) => {
if (open) {
previousActiveElement = (import.meta.client ? document.activeElement : null) as HTMLElement | null
localTo.value = { x: props.coordSet.x, y: props.coordSet.y }
nextTick(() => modalRef.value?.showModal())
nextTick(() => {
modalRef.value?.showModal()
firstInputRef.value?.focus()
})
} else {
modalRef.value?.close()
}
@@ -46,6 +59,12 @@ watch(
{ immediate: true }
)
function onDialogClose() {
if (import.meta.client && previousActiveElement && typeof previousActiveElement.focus === 'function' && document.contains(previousActiveElement)) {
nextTick(() => previousActiveElement?.focus())
}
}
watch(
() => props.coordSet,
(c) => {