Enhance map components and improve build processes

- Updated Makefile to include `--build` flag for `docker-compose.dev.yml` and `--no-cache` for `docker-compose.prod.yml` to ensure fresh builds.
- Added new CSS styles for Leaflet tooltips and popups to utilize theme colors, enhancing visual consistency.
- Enhanced MapView component with new props for markers and current zoom level, improving marker management and zoom functionality.
- Introduced new icons for copy and info actions to improve user interface clarity.
- Updated MapBookmarks and MapControls components to support new features and improve user experience with bookmarks and zoom controls.
- Refactored MapSearch to display coordinates and improve marker search functionality.
This commit is contained in:
2026-03-04 12:49:31 +03:00
parent dda35baeca
commit fc42d86ca0
13 changed files with 267 additions and 46 deletions

View File

@@ -5,6 +5,8 @@
v-if="currentMapId != null && currentCoords != null"
:maps="maps"
:quest-givers="questGivers"
:markers="markers"
:overlay-map-id="props.overlayMapId"
:current-map-id="currentMapId"
:current-coords="currentCoords"
:touch-friendly="touchFriendly"
@@ -48,6 +50,19 @@
<icons-icon-home />
</button>
</div>
<div class="flex items-center gap-2">
<input
type="range"
:min="zoomMin"
:max="zoomMax"
:value="currentZoom"
class="range range-primary range-sm flex-1"
:class="touchFriendly ? 'range-lg' : ''"
aria-label="Zoom level"
@input="onZoomSliderInput($event)"
>
<span class="text-xs font-mono w-6 text-right" aria-hidden="true">{{ currentZoom }}</span>
</div>
</section>
<!-- Display -->
<section class="flex flex-col gap-2">
@@ -78,7 +93,16 @@
</select>
</fieldset>
<fieldset class="fieldset">
<label class="label py-0"><span>Overlay Map</span></label>
<label class="label py-0 flex items-center gap-1.5">
<span>Overlay Map</span>
<span
class="inline-flex text-base-content/60 cursor-help"
title="Overlay shows markers from another map on top of the current one."
aria-label="Overlay shows markers from another map on top of the current one."
>
<icons-icon-info class="size-3.5" />
</span>
</label>
<select
v-model="overlayMapId"
class="select select-sm w-full focus:ring-2 focus:ring-primary touch-manipulation"
@@ -89,22 +113,43 @@
</select>
</fieldset>
<fieldset class="fieldset">
<label class="label py-0"><span>Jump to Quest Giver</span></label>
<label class="label py-0"><span>Jump to</span></label>
<div class="join w-full flex">
<button
type="button"
class="btn btn-sm join-item flex-1 touch-manipulation"
:class="[jumpToTab === 'quest' ? 'btn-active' : 'btn-ghost', touchFriendly ? 'min-h-11 text-base' : '']"
aria-pressed="jumpToTab === 'quest'"
@click="jumpToTab = 'quest'"
>
Quest giver
</button>
<button
type="button"
class="btn btn-sm join-item flex-1 touch-manipulation"
:class="[jumpToTab === 'player' ? 'btn-active' : 'btn-ghost', touchFriendly ? 'min-h-11 text-base' : '']"
aria-pressed="jumpToTab === 'player'"
@click="jumpToTab = 'player'"
>
Player
</button>
</div>
<select
v-if="jumpToTab === 'quest'"
v-model="selectedMarkerIdSelect"
class="select select-sm w-full focus:ring-2 focus:ring-primary touch-manipulation"
class="select select-sm w-full focus:ring-2 focus:ring-primary touch-manipulation mt-1"
:class="touchFriendly ? 'min-h-11 text-base' : ''"
aria-label="Select quest giver"
>
<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-else
v-model="selectedPlayerIdSelect"
class="select select-sm w-full focus:ring-2 focus:ring-primary touch-manipulation"
class="select select-sm w-full focus:ring-2 focus:ring-primary touch-manipulation mt-1"
:class="touchFriendly ? 'min-h-11 text-base' : ''"
aria-label="Select player"
>
<option value="">Select player</option>
<option v-for="p in players" :key="p.id" :value="String(p.id)">{{ p.name }}</option>
@@ -126,9 +171,10 @@
</template>
<script setup lang="ts">
import type { MapInfo } from '~/types/api'
import type { MapInfo, Marker as ApiMarker } from '~/types/api'
import type { SelectedMarkerForBookmark } from '~/components/map/MapBookmarks.vue'
import MapBookmarks from '~/components/map/MapBookmarks.vue'
import { HnHMinZoom, HnHMaxZoom } from '~/lib/LeafletCustomTypes'
interface QuestGiver {
id: number
@@ -140,27 +186,33 @@ interface Player {
name: string
}
const zoomMin = HnHMinZoom
const zoomMax = HnHMaxZoom
const props = withDefaults(
defineProps<{
maps: MapInfo[]
questGivers: QuestGiver[]
players: Player[]
markers?: ApiMarker[]
touchFriendly?: boolean
selectedMapIdSelect: string
overlayMapId: number
selectedMarkerIdSelect: string
selectedPlayerIdSelect: string
currentZoom?: number
currentMapId?: number
currentCoords?: { x: number; y: number; z: number } | null
selectedMarkerForBookmark?: SelectedMarkerForBookmark
}>(),
{ touchFriendly: false, currentMapId: 0, currentCoords: null, selectedMarkerForBookmark: null }
{ touchFriendly: false, markers: () => [], currentZoom: 1, currentMapId: 0, currentCoords: null, selectedMarkerForBookmark: null }
)
const emit = defineEmits<{
zoomIn: []
zoomOut: []
resetView: []
setZoom: [level: number]
jumpToMarker: [id: number]
'update:hideMarkers': [v: boolean]
'update:selectedMapIdSelect': [v: string]
@@ -169,8 +221,16 @@ const emit = defineEmits<{
'update:selectedPlayerIdSelect': [v: string]
}>()
function onZoomSliderInput(event: Event) {
const value = (event.target as HTMLInputElement).value
const level = Number(value)
if (!Number.isNaN(level)) emit('setZoom', level)
}
const hideMarkers = defineModel<boolean>('hideMarkers', { required: true })
const jumpToTab = ref<'quest' | 'player'>('quest')
const selectedMapIdSelect = computed({
get: () => props.selectedMapIdSelect,
set: (v) => emit('update:selectedMapIdSelect', v),