feat: add selectable location search results
This commit is contained in:
parent
15bbb677d8
commit
628d73afd6
3 changed files with 76 additions and 2 deletions
42
src/app.js
42
src/app.js
|
|
@ -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)}`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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%;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue