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:
@@ -1,5 +1,5 @@
|
||||
import type L from 'leaflet'
|
||||
import { HnHMaxZoom } from '~/lib/LeafletCustomTypes'
|
||||
import { HnHMaxZoom, TileSize } from '~/lib/LeafletCustomTypes'
|
||||
import { createMarker, type MapMarker, type MarkerData, type MapViewRef } from '~/lib/Marker'
|
||||
import { createCharacter, type MapCharacter, type CharacterData, type CharacterMapViewRef } from '~/lib/Character'
|
||||
import {
|
||||
@@ -14,6 +14,15 @@ import type { Marker as ApiMarker, Character as ApiCharacter } from '~/types/api
|
||||
|
||||
type SmartTileLayerInstance = InstanceType<typeof SmartTileLayer>
|
||||
|
||||
function escapeHtml(s: string): string {
|
||||
return s
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''')
|
||||
}
|
||||
|
||||
export interface MapLayersOptions {
|
||||
/** Leaflet API (from dynamic import). Required for creating markers and characters without static leaflet import. */
|
||||
L: typeof import('leaflet')
|
||||
@@ -28,6 +37,8 @@ export interface MapLayersOptions {
|
||||
getTrackingCharacterId: () => number
|
||||
setTrackingCharacterId: (id: number) => void
|
||||
onMarkerContextMenu: (clientX: number, clientY: number, id: number, name: string) => void
|
||||
/** Called when user clicks "Add to saved locations" in marker popup. Receives marker id and getter to resolve marker. */
|
||||
onAddMarkerToBookmark?: (markerId: number, getMarkerById: (id: number) => MapMarker | undefined) => void
|
||||
/** Resolves relative marker icon path to absolute URL. If omitted, relative paths are used. */
|
||||
resolveIconUrl?: (path: string) => string
|
||||
/** Fallback icon URL when a marker image fails to load. */
|
||||
@@ -62,6 +73,7 @@ export function createMapLayers(options: MapLayersOptions): MapLayersManager {
|
||||
getTrackingCharacterId,
|
||||
setTrackingCharacterId,
|
||||
onMarkerContextMenu,
|
||||
onAddMarkerToBookmark,
|
||||
resolveIconUrl,
|
||||
fallbackIconUrl,
|
||||
} = options
|
||||
@@ -112,7 +124,30 @@ export function createMapLayers(options: MapLayersOptions): MapLayersManager {
|
||||
(marker: MapMarker) => {
|
||||
if (marker.map === getCurrentMapId() || marker.map === overlayLayer.map) marker.add(ctx)
|
||||
marker.setClickCallback(() => {
|
||||
if (marker.leafletMarker) map.setView(marker.leafletMarker.getLatLng(), HnHMaxZoom)
|
||||
if (marker.leafletMarker) {
|
||||
if (onAddMarkerToBookmark) {
|
||||
const gridX = Math.floor(marker.position.x / TileSize)
|
||||
const gridY = Math.floor(marker.position.y / TileSize)
|
||||
const div = document.createElement('div')
|
||||
div.className = 'map-marker-popup text-sm'
|
||||
div.innerHTML = `
|
||||
<p class="font-medium mb-1">${escapeHtml(marker.name)}</p>
|
||||
<p class="text-base-content/70 text-xs mb-2 font-mono">${gridX}, ${gridY}</p>
|
||||
<button type="button" class="btn btn-primary btn-xs w-full">Add to saved locations</button>
|
||||
`
|
||||
const btn = div.querySelector('button')
|
||||
if (btn) {
|
||||
btn.addEventListener('click', () => {
|
||||
onAddMarkerToBookmark(marker.id, findMarkerById)
|
||||
marker.leafletMarker?.closePopup()
|
||||
})
|
||||
}
|
||||
marker.leafletMarker.unbindPopup()
|
||||
marker.leafletMarker.bindPopup(div, { minWidth: 140, autoPan: true }).openPopup()
|
||||
} else {
|
||||
map.setView(marker.leafletMarker.getLatLng(), HnHMaxZoom)
|
||||
}
|
||||
}
|
||||
})
|
||||
marker.setContextMenu((mev: L.LeafletMouseEvent) => {
|
||||
mev.originalEvent.preventDefault()
|
||||
|
||||
Reference in New Issue
Block a user