feat: add selectable location search results

This commit is contained in:
Oliver 2026-02-15 14:16:54 +01:00
parent 15bbb677d8
commit 628d73afd6
No known key found for this signature in database
3 changed files with 76 additions and 2 deletions

View file

@ -15,6 +15,7 @@ const lonEl = document.getElementById("lon");
const searchQueryEl = document.getElementById("search-query");
const searchLocationEl = document.getElementById("search-location");
const searchStatusEl = document.getElementById("search-status");
const searchResultsEl = document.getElementById("search-results");
const mapEl = document.getElementById("map");
const loadScoreEl = document.getElementById("load-score");
const useLocationEl = document.getElementById("use-location");
@ -40,6 +41,8 @@ let lastHealthCheckAt = null;
let lastHealthLatencyMs = null;
let map = null;
let mapMarker = null;
let searchResults = [];
let selectedSearchIndex = -1;
const deviceToken = ensureDeviceToken();
initialize();
@ -166,6 +169,8 @@ async function fillLocationFromDevice() {
useLocationEl.disabled = true;
navigator.geolocation.getCurrentPosition(
(position) => {
selectedSearchIndex = -1;
renderSearchResults();
setCoordinates(position.coords.latitude, position.coords.longitude, { zoom: 16 });
searchStatusEl.textContent = "Aktueller Standort übernommen.";
useLocationEl.disabled = false;
@ -191,6 +196,8 @@ function initializeMap() {
}).addTo(map);
map.on("click", (event) => {
selectedSearchIndex = -1;
renderSearchResults();
setCoordinates(event.latlng.lat, event.latlng.lng, { fromMap: true });
searchStatusEl.textContent = "Position aus Karte übernommen.";
});
@ -252,20 +259,51 @@ async function searchLocation() {
const payload = await response.json();
if (!payload.results || !payload.results.length) {
searchResults = [];
selectedSearchIndex = -1;
renderSearchResults();
searchStatusEl.textContent = "Keine Treffer gefunden.";
return;
}
const best = payload.results[0];
searchResults = payload.results;
selectedSearchIndex = 0;
renderSearchResults();
const best = searchResults[0];
setCoordinates(best.lat, best.lon, { zoom: 16 });
searchStatusEl.textContent = `Treffer: ${best.display_name}`;
searchStatusEl.textContent = `Treffer ausgewählt: ${best.display_name}`;
} catch {
searchResults = [];
selectedSearchIndex = -1;
renderSearchResults();
searchStatusEl.textContent = "Suche fehlgeschlagen. Bitte später erneut versuchen.";
} finally {
searchLocationEl.disabled = false;
}
}
function renderSearchResults() {
searchResultsEl.innerHTML = "";
searchResults.forEach((result, index) => {
const li = document.createElement("li");
const button = document.createElement("button");
button.type = "button";
button.className = "search-result-btn";
if (index === selectedSearchIndex) {
button.classList.add("active");
}
button.textContent = result.display_name;
button.addEventListener("click", () => {
selectedSearchIndex = index;
setCoordinates(result.lat, result.lon, { zoom: 16 });
searchStatusEl.textContent = `Treffer ausgewählt: ${result.display_name}`;
renderSearchResults();
});
li.appendChild(button);
searchResultsEl.appendChild(li);
});
}
function cacheKey(lat, lon) {
return `${Number(lat).toFixed(4)}:${Number(lon).toFixed(4)}`;
}

View file

@ -40,6 +40,7 @@
</div>
</label>
<small id="search-status">Suche über OpenStreetMap Nominatim (DE).</small>
<ul id="search-results" class="search-results" aria-live="polite"></ul>
<div id="map" class="map"></div>
<div class="button-row">

View file

@ -141,6 +141,41 @@ input {
color: var(--muted);
}
.search-results {
list-style: none;
margin: 8px 0 0;
padding: 0;
border: 1px solid var(--line);
border-radius: 10px;
max-height: 190px;
overflow: auto;
background: #fff;
}
.search-results:empty {
display: none;
}
.search-result-btn {
width: 100%;
text-align: left;
border: 0;
border-bottom: 1px solid var(--line);
background: #fff;
color: var(--ink);
padding: 10px;
cursor: pointer;
}
.search-result-btn:last-child {
border-bottom: 0;
}
.search-result-btn:hover,
.search-result-btn.active {
background: #eef6fb;
}
.map {
margin-top: 8px;
width: 100%;