Files
e-tib.com/components/LeafletMap.tsx
Marc Mintel 070f97dd6f
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 26s
Build & Deploy / 🧪 QA (push) Failing after 1m0s
Build & Deploy / 🏗️ Build (push) Has been skipped
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 6s
fix(i18n): fix reference page translation, fix map zoom, connect contact form to server action, fix english 404 links, fix certificate pdf links
2026-05-28 09:58:34 +02:00

82 lines
2.4 KiB
TypeScript

import React, { useEffect, useRef } from 'react';
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
// Fix for default marker icon in Leaflet with Next.js
if (typeof window !== 'undefined') {
const DefaultIcon = L.icon({
iconUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon.png',
shadowUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
});
L.Marker.prototype.options.icon = DefaultIcon;
}
export interface MapLocation {
name: string;
address: string;
lat: number;
lng: number;
}
interface LeafletMapProps {
locations: MapLocation[];
}
export default function LeafletMap({ locations }: LeafletMapProps) {
const mapRef = useRef<HTMLDivElement>(null);
const mapInstanceRef = useRef<L.Map | null>(null);
useEffect(() => {
if (!mapRef.current || mapInstanceRef.current || !locations.length) return;
// Calculate center based on markers or first marker
const firstLoc = locations[0];
const map = L.map(mapRef.current, {
center: [firstLoc.lat, firstLoc.lng],
zoom: locations.length === 1 ? 16 : 6,
scrollWheelZoom: false,
});
// Add tiles (Dark mode themed for industrial feel if possible, but standard OSM is safer for now)
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution:
'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
}).addTo(map);
const bounds = L.latLngBounds([]);
locations.forEach((loc) => {
const marker = L.marker([loc.lat, loc.lng]).addTo(map);
const popupContent = `
<div class="p-2">
<div class="text-primary font-bold border-b border-neutral-100 pb-1 mb-1">${loc.name}</div>
<div class="text-xs text-neutral-600">${loc.address.replace(/\n/g, '<br/>')}</div>
</div>
`;
marker.bindPopup(popupContent);
bounds.extend([loc.lat, loc.lng]);
});
// Fit bounds if more than 1 location
if (locations.length > 1) {
map.fitBounds(bounds, { padding: [50, 50] });
}
mapInstanceRef.current = map;
// Cleanup on unmount
return () => {
if (mapInstanceRef.current) {
mapInstanceRef.current.remove();
mapInstanceRef.current = null;
}
};
}, [locations]);
return <div ref={mapRef} className="h-full w-full z-0 rounded-2xl shadow-inner border border-neutral-200" />;
}