Enhance frontend components and introduce new features
- Updated PasswordInput component with improved styling and touch manipulation support. - Added new IconMenu component for consistent icon representation in the UI. - Refactored MapControls and introduced MapControlsContent for better organization and usability. - Implemented suppress-leaflet-deprecation plugin to handle known warnings in Firefox. - Enhanced default layout with a responsive drawer for mobile navigation and improved user experience.
This commit is contained in:
169
frontend-nuxt/components/map/MapControlsContent.vue
Normal file
169
frontend-nuxt/components/map/MapControlsContent.vue
Normal file
@@ -0,0 +1,169 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-4">
|
||||
<!-- Zoom -->
|
||||
<section class="flex flex-col gap-2">
|
||||
<h3 class="text-xs font-semibold uppercase tracking-wider text-base-content/70 flex items-center gap-1.5">
|
||||
<icons-icon-zoom-in class="size-3.5 opacity-80" aria-hidden="true" />
|
||||
Zoom
|
||||
</h3>
|
||||
<div class="flex items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline btn-sm btn-square transition-all duration-200 hover:scale-105 touch-manipulation"
|
||||
:class="touchFriendly ? 'min-h-10 min-w-10' : ''"
|
||||
title="Zoom in"
|
||||
aria-label="Zoom in"
|
||||
@click="$emit('zoomIn')"
|
||||
>
|
||||
<icons-icon-zoom-in />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline btn-sm btn-square transition-all duration-200 hover:scale-105 touch-manipulation"
|
||||
:class="touchFriendly ? 'min-h-10 min-w-10' : ''"
|
||||
title="Zoom out"
|
||||
aria-label="Zoom out"
|
||||
@click="$emit('zoomOut')"
|
||||
>
|
||||
<icons-icon-zoom-out />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline btn-sm btn-square transition-all duration-200 hover:scale-105 touch-manipulation"
|
||||
:class="touchFriendly ? 'min-h-10 min-w-10' : ''"
|
||||
title="Reset view — center map and minimum zoom"
|
||||
aria-label="Reset view"
|
||||
@click="$emit('resetView')"
|
||||
>
|
||||
<icons-icon-home />
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Display -->
|
||||
<section class="flex flex-col gap-2">
|
||||
<h3 class="text-xs font-semibold uppercase tracking-wider text-base-content/70 flex items-center gap-1.5">
|
||||
<icons-icon-eye class="size-3.5 opacity-80" aria-hidden="true" />
|
||||
Display
|
||||
</h3>
|
||||
<label class="label cursor-pointer justify-start gap-2 py-0 hover:bg-base-200/50 rounded-lg px-2 -mx-2 touch-manipulation" :class="touchFriendly ? 'min-h-11' : ''">
|
||||
<input v-model="showGridCoordinates" type="checkbox" class="checkbox checkbox-sm" />
|
||||
<span>Show grid coordinates</span>
|
||||
</label>
|
||||
<label class="label cursor-pointer justify-start gap-2 py-0 hover:bg-base-200/50 rounded-lg px-2 -mx-2 touch-manipulation" :class="touchFriendly ? 'min-h-11' : ''">
|
||||
<input v-model="hideMarkers" type="checkbox" class="checkbox checkbox-sm" />
|
||||
<span>Hide markers</span>
|
||||
</label>
|
||||
</section>
|
||||
<!-- Navigation -->
|
||||
<section class="flex flex-col gap-3">
|
||||
<h3 class="text-xs font-semibold uppercase tracking-wider text-base-content/70 flex items-center gap-1.5">
|
||||
<icons-icon-map-pin class="size-3.5 opacity-80" aria-hidden="true" />
|
||||
Navigation
|
||||
</h3>
|
||||
<fieldset class="fieldset">
|
||||
<label class="label py-0"><span>Jump to Map</span></label>
|
||||
<select
|
||||
v-model="selectedMapIdSelect"
|
||||
class="select select-sm w-full focus:ring-2 focus:ring-primary touch-manipulation"
|
||||
:class="touchFriendly ? 'min-h-11 text-base' : ''"
|
||||
>
|
||||
<option value="">Select map</option>
|
||||
<option v-for="m in maps" :key="m.ID" :value="String(m.ID)">{{ m.Name }}</option>
|
||||
</select>
|
||||
</fieldset>
|
||||
<fieldset class="fieldset">
|
||||
<label class="label py-0"><span>Overlay Map</span></label>
|
||||
<select
|
||||
v-model="overlayMapId"
|
||||
class="select select-sm w-full focus:ring-2 focus:ring-primary touch-manipulation"
|
||||
:class="touchFriendly ? 'min-h-11 text-base' : ''"
|
||||
>
|
||||
<option value="-1">None</option>
|
||||
<option v-for="m in maps" :key="'overlay-' + m.ID" :value="String(m.ID)">{{ m.Name }}</option>
|
||||
</select>
|
||||
</fieldset>
|
||||
<fieldset class="fieldset">
|
||||
<label class="label py-0"><span>Jump to Quest Giver</span></label>
|
||||
<select
|
||||
v-model="selectedMarkerIdSelect"
|
||||
class="select select-sm w-full focus:ring-2 focus:ring-primary touch-manipulation"
|
||||
:class="touchFriendly ? 'min-h-11 text-base' : ''"
|
||||
>
|
||||
<option value="">Select quest giver</option>
|
||||
<option v-for="q in questGivers" :key="q.id" :value="String(q.id)">{{ q.name }}</option>
|
||||
</select>
|
||||
</fieldset>
|
||||
<fieldset class="fieldset">
|
||||
<label class="label py-0"><span>Jump to Player</span></label>
|
||||
<select
|
||||
v-model="selectedPlayerIdSelect"
|
||||
class="select select-sm w-full focus:ring-2 focus:ring-primary touch-manipulation"
|
||||
:class="touchFriendly ? 'min-h-11 text-base' : ''"
|
||||
>
|
||||
<option value="">Select player</option>
|
||||
<option v-for="p in players" :key="p.id" :value="String(p.id)">{{ p.name }}</option>
|
||||
</select>
|
||||
</fieldset>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { MapInfo } from '~/types/api'
|
||||
|
||||
interface QuestGiver {
|
||||
id: number
|
||||
name: string
|
||||
}
|
||||
|
||||
interface Player {
|
||||
id: number
|
||||
name: string
|
||||
}
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
maps: MapInfo[]
|
||||
questGivers: QuestGiver[]
|
||||
players: Player[]
|
||||
touchFriendly?: boolean
|
||||
selectedMapIdSelect: string
|
||||
overlayMapId: number
|
||||
selectedMarkerIdSelect: string
|
||||
selectedPlayerIdSelect: string
|
||||
}>(),
|
||||
{ touchFriendly: false }
|
||||
)
|
||||
|
||||
const emit = defineEmits<{
|
||||
zoomIn: []
|
||||
zoomOut: []
|
||||
resetView: []
|
||||
'update:showGridCoordinates': [v: boolean]
|
||||
'update:hideMarkers': [v: boolean]
|
||||
'update:selectedMapIdSelect': [v: string]
|
||||
'update:overlayMapId': [v: number]
|
||||
'update:selectedMarkerIdSelect': [v: string]
|
||||
'update:selectedPlayerIdSelect': [v: string]
|
||||
}>()
|
||||
|
||||
const showGridCoordinates = defineModel<boolean>('showGridCoordinates', { required: true })
|
||||
const hideMarkers = defineModel<boolean>('hideMarkers', { required: true })
|
||||
|
||||
const selectedMapIdSelect = computed({
|
||||
get: () => props.selectedMapIdSelect,
|
||||
set: (v) => emit('update:selectedMapIdSelect', v),
|
||||
})
|
||||
const overlayMapId = computed({
|
||||
get: () => String(props.overlayMapId),
|
||||
set: (v) => emit('update:overlayMapId', v === '' ? -1 : Number(v)),
|
||||
})
|
||||
const selectedMarkerIdSelect = computed({
|
||||
get: () => props.selectedMarkerIdSelect,
|
||||
set: (v) => emit('update:selectedMarkerIdSelect', v),
|
||||
})
|
||||
const selectedPlayerIdSelect = computed({
|
||||
get: () => props.selectedPlayerIdSelect,
|
||||
set: (v) => emit('update:selectedPlayerIdSelect', v),
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user