- Introduced .editorconfig for consistent coding styles across the project. - Added .golangci.yml for Go linting configuration. - Updated AGENTS.md to clarify project structure and components. - Enhanced CONTRIBUTING.md with Makefile usage for common tasks. - Updated Dockerfiles to use Go 1.24 and improved build instructions. - Refined README.md and deployment documentation for clarity. - Added testing documentation in testing.md for backend and frontend tests. - Introduced Makefile for streamlined development commands and tasks.
168 lines
6.6 KiB
Vue
168 lines
6.6 KiB
Vue
<template>
|
|
<div
|
|
class="absolute left-3 top-[10%] z-[502] flex min-w-[3rem] min-h-[3rem] transition-all duration-300 ease-out"
|
|
:class="panelCollapsed ? 'w-12' : 'w-64'"
|
|
>
|
|
<div
|
|
class="rounded-xl bg-base-100/80 backdrop-blur-xl border border-base-300/50 shadow-xl overflow-hidden transition-all duration-300 flex flex-col"
|
|
:class="panelCollapsed ? 'w-12 items-center py-2' : 'w-56'"
|
|
>
|
|
<div v-show="!panelCollapsed" class="flex flex-col p-4 gap-4 flex-1 min-w-0">
|
|
<!-- Zoom -->
|
|
<section class="flex flex-col gap-2">
|
|
<h3 class="text-xs font-semibold uppercase tracking-wider text-base-content/70">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"
|
|
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"
|
|
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"
|
|
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">Display</h3>
|
|
<label class="label cursor-pointer justify-start gap-2 py-0 hover:bg-base-200/50 rounded-lg px-2 -mx-2">
|
|
<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">
|
|
<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">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">
|
|
<option value="">Select map</option>
|
|
<option v-for="m in maps" :key="m.ID" :value="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">
|
|
<option :value="-1">None</option>
|
|
<option v-for="m in maps" :key="'overlay-' + m.ID" :value="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">
|
|
<option value="">Select quest giver</option>
|
|
<option v-for="q in questGivers" :key="q.id" :value="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">
|
|
<option value="">Select player</option>
|
|
<option v-for="p in players" :key="p.id" :value="p.id">{{ p.name }}</option>
|
|
</select>
|
|
</fieldset>
|
|
</section>
|
|
</div>
|
|
<button
|
|
type="button"
|
|
class="btn btn-ghost btn-sm btn-square shrink-0 m-1 transition-all duration-200 hover:scale-105"
|
|
:title="panelCollapsed ? 'Expand panel' : 'Collapse panel'"
|
|
:aria-label="panelCollapsed ? 'Expand panel' : 'Collapse panel'"
|
|
@click.stop="panelCollapsed = !panelCollapsed"
|
|
>
|
|
<icons-icon-chevron-right v-if="panelCollapsed" />
|
|
<icons-icon-panel-left v-else />
|
|
</button>
|
|
</div>
|
|
</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[]
|
|
}>(),
|
|
{ maps: () => [], questGivers: () => [], players: () => [] }
|
|
)
|
|
|
|
const emit = defineEmits<{
|
|
zoomIn: []
|
|
zoomOut: []
|
|
resetView: []
|
|
}>()
|
|
|
|
const showGridCoordinates = defineModel<boolean>('showGridCoordinates', { default: false })
|
|
const hideMarkers = defineModel<boolean>('hideMarkers', { default: false })
|
|
const panelCollapsed = ref(false)
|
|
const selectedMapId = defineModel<number | null>('selectedMapId', { default: null })
|
|
const overlayMapId = defineModel<number>('overlayMapId', { default: -1 })
|
|
const selectedMarkerId = defineModel<number | null>('selectedMarkerId', { default: null })
|
|
const selectedPlayerId = defineModel<number | null>('selectedPlayerId', { default: null })
|
|
|
|
// String bindings for selects with placeholder ('' ↔ null)
|
|
const selectedMapIdSelect = computed({
|
|
get() {
|
|
const v = selectedMapId.value
|
|
return v == null ? '' : String(v)
|
|
},
|
|
set(v: string) {
|
|
selectedMapId.value = v === '' ? null : Number(v)
|
|
},
|
|
})
|
|
const selectedMarkerIdSelect = computed({
|
|
get() {
|
|
const v = selectedMarkerId.value
|
|
return v == null ? '' : String(v)
|
|
},
|
|
set(v: string) {
|
|
selectedMarkerId.value = v === '' ? null : Number(v)
|
|
},
|
|
})
|
|
const selectedPlayerIdSelect = computed({
|
|
get() {
|
|
const v = selectedPlayerId.value
|
|
return v == null ? '' : String(v)
|
|
},
|
|
set(v: string) {
|
|
selectedPlayerId.value = v === '' ? null : Number(v)
|
|
},
|
|
})
|
|
</script>
|