ldc-boutique-cnc-sable/resources/ts/fo/components/MapLocationDisplay.vue
2026-10-27 09:58:12 +01:00

106 lines
2.7 KiB
Vue

<template>
<div class="map-location-display">
<div
ref="mapContainer"
class="map-container rounded shadow-sm"
/>
</div>
</template>
<script setup lang="ts">
import {
icon,
map as leafMap, marker as leafMarker, Marker, tileLayer
} from "leaflet";
import markerIcon2x from "leaflet/dist/images/marker-icon-2x.png";
import markerIcon from "leaflet/dist/images/marker-icon.png";
import markerShadow from "leaflet/dist/images/marker-shadow.png";
import "leaflet/dist/leaflet.css";
import { onBeforeMount, onMounted, ref, shallowRef, useAttrs } from "vue";
defineOptions({ name: "MapLocationDisplay" });
const attrs = useAttrs();
const mapContainer = ref<HTMLElement | null>(null);
const map = shallowRef<L.Map | null>(null);
const lat = ref<number | null>(null);
const lng = ref<number | null>(null);
const storeName = ref<string>("");
const storeAddress = ref<string>("");
const phone = ref<string>("");
const defaultIcon = icon({
iconUrl: markerIcon,
iconRetinaUrl: markerIcon2x,
shadowUrl: markerShadow,
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
Marker.prototype.options.icon = defaultIcon;
onBeforeMount(() => {
if (!attrs.json) {
throw new Error("this component requires json");
}
});
onMounted(() => {
const json = String(attrs.json ?? "{}");
const data = JSON.parse(json);
lat.value = data.lat ? Number.parseFloat(data.lat) : null;
lng.value = data.lng ? Number.parseFloat(data.lng) : null;
storeName.value = data.name || "";
storeAddress.value = data.address || "";
phone.value = data.phone || "";
if (lat.value && lng.value) {
initMap();
}
});
const initMap = () => {
if (!mapContainer.value || !lat.value || !lng.value) return;
const position: [number, number] = [lat.value, lng.value];
map.value = leafMap(
mapContainer.value,
{
// * Prevent scroll issues
scrollWheelZoom: false
}).setView(position, 15);
tileLayer(
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
{attribution: "&copy; <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a>",}
).addTo(map.value);
const marker = leafMarker(position).addTo(map.value);
if (storeName.value || storeAddress.value) {
const popupContent = `
<div class="text-center">
<strong class="leaflet-popup-title">${storeName.value}</strong>
<span>${storeAddress.value}</span><br>
<a href="tel:${phone.value}">${phone.value}</a>
</div>
`;
marker.bindPopup(popupContent).openPopup();
}
};
</script>
<style lang="scss" scoped>
.map-location-display {
.map-container {
height: 350px;
width: 100%;
z-index: 1;
}
}
</style>