import { Controller } from '@hotwired/stimulus'; import L from 'leaflet'; import 'leaflet/dist/leaflet.min.css'; L.Icon.Default.mergeOptions({ iconUrl: '/leaflet/marker-icon.png', iconRetinaUrl: '/leaflet/marker-icon-2x.png', shadowUrl: '/leaflet/marker-shadow.png', }); export default class extends Controller { connect() { this.map = L.map(this.element).setView([51.0543, 3.7174], 13); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap contributors', maxZoom: 19, }).addTo(this.map); this.popup = null; this.loadSubjects(); this.map.on('click', (e) => this.openPopup(e.latlng)); } loadSubjects() { fetch('/api/subjects') .then(r => r.json()) .then(data => { data.payload.subjects.forEach(s => { if (s.latitude && s.longitude) { this.addMarker(s.latitude, s.longitude, s.name); } }); }); } openPopup(latlng) { if (this.popup) { this.popup.remove(); } const content = this.buildPopupContent(latlng); this.popup = L.popup({ closeOnClick: false, autoClose: false, minWidth: 280 }) .setLatLng(latlng) .setContent(content) .openOn(this.map); // Autofocus after Leaflet inserts the DOM this.popup.once('add', () => { const input = this.popup.getElement()?.querySelector('.add-place-input'); if (input) input.focus(); }); } buildPopupContent(latlng) { const container = document.createElement('div'); container.className = 'add-place-popup'; container.innerHTML = `
Add a place