diff --git a/css/components.css b/css/components.css
index ede237e..da7e7ba 100644
--- a/css/components.css
+++ b/css/components.css
@@ -60,6 +60,11 @@
align-items: center;
}
+.btn--active {
+ background: var(--color-primary);
+ color: #fff;
+}
+
.btn--danger {
background: var(--color-danger);
color: #fff;
diff --git a/css/layout.css b/css/layout.css
index 9b65d7d..7c62b29 100644
--- a/css/layout.css
+++ b/css/layout.css
@@ -51,6 +51,41 @@
background: var(--color-border);
}
+.map-panel__map--picking {
+ cursor: crosshair;
+}
+
+.map-picking-hint {
+ position: absolute;
+ top: calc(var(--space-sm) + 40px);
+ left: var(--space-sm);
+ z-index: 1000;
+ display: flex;
+ align-items: center;
+ gap: var(--space-sm);
+ background: var(--color-surface);
+ color: var(--color-primary-dark);
+ padding: var(--space-sm) var(--space-md);
+ border-radius: var(--radius-sm);
+ box-shadow: var(--shadow-card);
+ font-size: 0.85rem;
+}
+
+.map-picking-hint[hidden] {
+ display: none;
+}
+
+.map-picking-hint__cancel {
+ flex-shrink: 0;
+ border: none;
+ background: transparent;
+ color: var(--color-primary-dark);
+ font-weight: 600;
+ text-decoration: underline;
+ cursor: pointer;
+ padding: 0;
+}
+
.list-panel {
padding: var(--space-md);
overflow-y: auto;
diff --git a/index.html b/index.html
index d209887..fbc7502 100644
--- a/index.html
+++ b/index.html
@@ -48,6 +48,9 @@
+
@@ -58,6 +61,13 @@
📥 KI-Ausflugsziele importieren
+
+
+ Klicke auf die Karte, um den Standort auszuwählen.
+
+
diff --git a/js/main.js b/js/main.js
index 9a74a2f..2d9da46 100644
--- a/js/main.js
+++ b/js/main.js
@@ -2,7 +2,14 @@
(function () {
const { initStore } = EventMap.store;
- const { initMap, centerOnCoords, requestUserLocation } = EventMap.map;
+ const {
+ initMap,
+ centerOnCoords,
+ requestUserLocation,
+ startLocationPicking,
+ stopLocationPicking,
+ isPickingLocation,
+ } = EventMap.map;
const {
initList,
initDetail,
@@ -76,6 +83,50 @@
});
}
+ function setupPickLocationButton() {
+ const button = document.getElementById('pick-location-btn');
+ const hint = document.getElementById('map-picking-hint');
+ const cancelBtn = document.getElementById('map-picking-cancel-btn');
+ if (!button || !hint || !cancelBtn) return;
+
+ const defaultLabel = button.textContent;
+
+ function endPicking() {
+ button.textContent = defaultLabel;
+ button.classList.remove('btn--active');
+ hint.hidden = true;
+ }
+
+ function beginPicking() {
+ button.textContent = 'Klicke auf die Karte …';
+ button.classList.add('btn--active');
+ hint.hidden = false;
+
+ startLocationPicking({
+ onPick: ({ lat, lng }) => {
+ EventMap.store.setState({ userLocation: { lat, lng } });
+ EventMap.store.updateSettings({ userConsentGeo: true });
+ endPicking();
+ },
+ onCancel: endPicking,
+ });
+ }
+
+ button.addEventListener('click', () => {
+ if (isPickingLocation()) {
+ stopLocationPicking();
+ endPicking();
+ } else {
+ beginPicking();
+ }
+ });
+
+ cancelBtn.addEventListener('click', () => {
+ stopLocationPicking();
+ endPicking();
+ });
+ }
+
function setupAddPlaceButton() {
const button = document.getElementById('add-place-btn');
if (!button) return;
@@ -115,6 +166,7 @@
initImport('import-modal');
setupGeolocationButton();
setupManualLocationButton();
+ setupPickLocationButton();
setupAddPlaceButton();
setupPromptGeneratorButton();
setupImportButton();
diff --git a/js/map/mapController.js b/js/map/mapController.js
index 82a82ab..3ab1455 100644
--- a/js/map/mapController.js
+++ b/js/map/mapController.js
@@ -102,6 +102,57 @@
return map;
}
+ let pickingActive = false;
+ let pickingClickHandler = null;
+ let pickingEscHandler = null;
+
+ /**
+ * Aktiviert den "Standort auf Karte wählen"-Modus: der nächste Klick auf
+ * die Karte liefert die geklickten Koordinaten an onPick. Escape oder ein
+ * erneuter Aufruf von stopLocationPicking() bricht ab (onCancel).
+ * @param {{onPick?: (loc:{lat:number,lng:number}) => void, onCancel?: () => void}} [handlers]
+ */
+ function startLocationPicking({ onPick, onCancel } = {}) {
+ if (!map || pickingActive) return;
+ pickingActive = true;
+ map.getContainer().classList.add('map-panel__map--picking');
+
+ pickingClickHandler = (event) => {
+ const { lat, lng } = event.latlng;
+ stopLocationPicking();
+ if (onPick) onPick({ lat, lng });
+ };
+ map.once('click', pickingClickHandler);
+
+ pickingEscHandler = (event) => {
+ if (event.key === 'Escape') {
+ stopLocationPicking();
+ if (onCancel) onCancel();
+ }
+ };
+ document.addEventListener('keydown', pickingEscHandler);
+ }
+
+ /** Beendet den Standort-Auswahlmodus, ohne onPick/onCancel selbst aufzurufen. */
+ function stopLocationPicking() {
+ if (!pickingActive || !map) return;
+ pickingActive = false;
+ map.getContainer().classList.remove('map-panel__map--picking');
+
+ if (pickingClickHandler) {
+ map.off('click', pickingClickHandler);
+ pickingClickHandler = null;
+ }
+ if (pickingEscHandler) {
+ document.removeEventListener('keydown', pickingEscHandler);
+ pickingEscHandler = null;
+ }
+ }
+
+ function isPickingLocation() {
+ return pickingActive;
+ }
+
/** Initialisiert die Karte im Element mit der übergebenen id. */
function initMap(containerId) {
// Leaflet leert den Container beim Initialisieren nicht selbst - den
@@ -175,5 +226,8 @@
EventMap.map.centerOnPlace = centerOnPlace;
EventMap.map.centerOnCoords = centerOnCoords;
EventMap.map.getMapInstance = getMapInstance;
+ EventMap.map.startLocationPicking = startLocationPicking;
+ EventMap.map.stopLocationPicking = stopLocationPicking;
+ EventMap.map.isPickingLocation = isPickingLocation;
EventMap.map.initMap = initMap;
})();