Feature: Suchfeld in Routen, Events und Places

Alle drei Seiten haben jetzt ein debounced Suchfeld (300ms) mit
Lupe-Icon über der Liste. Die Suche filtert clientseitig:
- Routen: Name, Beschreibung, Username (bereits vorhandener State verbessert)
- Events: Titel, Ort, Beschreibung
- Places: Name, Adresse, Typ
Leerer Zustand zeigt passendes UI.emptyState() mit Suchbegriff.
SW by-v209, APP_VER 178.
This commit is contained in:
rene 2026-04-18 18:42:13 +02:00
parent 5acfa9d8f6
commit 6581a9a88c
3 changed files with 90 additions and 18 deletions

View file

@ -11,6 +11,7 @@ window.Page_places = (() => {
let _markers = [];
let _data = [];
let _activeTyp = null; // null = alle
let _search = '';
let _userPos = null;
// ----------------------------------------------------------
@ -61,6 +62,13 @@ window.Page_places = (() => {
</button>
</div>
<!-- Suche -->
<div class="diary-search-wrap" style="margin:var(--space-2) var(--space-3) 0" id="places-search-wrap">
<svg class="ph-icon diary-search-icon" aria-hidden="true"><use href="/icons/phosphor.svg#magnifying-glass"></use></svg>
<input type="search" class="diary-search-input" id="places-search"
placeholder="Orte durchsuchen…" autocomplete="off">
</div>
<!-- Karte -->
<div id="places-map" class="places-map"></div>
@ -95,6 +103,16 @@ window.Page_places = (() => {
_showForm(null);
});
// Suche mit Debounce
let _searchTimer = null;
document.getElementById('places-search')?.addEventListener('input', e => {
clearTimeout(_searchTimer);
_searchTimer = setTimeout(() => {
_search = e.target.value.trim().toLowerCase();
_applyFilter();
}, 300);
});
UI.loadLeaflet().then(_initMap);
}
@ -153,7 +171,16 @@ window.Page_places = (() => {
// Filter anwenden
// ----------------------------------------------------------
function _filtered() {
return _activeTyp ? _data.filter(p => p.typ === _activeTyp) : _data;
let list = _activeTyp ? _data.filter(p => p.typ === _activeTyp) : _data;
if (_search) {
const q = _search;
list = list.filter(p =>
(p.name || '').toLowerCase().includes(q) ||
(p.adresse|| '').toLowerCase().includes(q) ||
(p.typ || '').toLowerCase().includes(q)
);
}
return list;
}
function _applyFilter() {
@ -187,11 +214,12 @@ window.Page_places = (() => {
const items = _filtered();
if (!items.length) {
const msg = _search
? `Keine Orte gefunden für „${UI.escape(_search)}".`
: (_activeTyp ? 'Keine Orte in dieser Kategorie.' : 'Noch keine Orte eingetragen.');
list.innerHTML = `
<div class="places-list-inner">
<p style="color:var(--c-text-secondary);text-align:center;padding:var(--space-6)">
${_activeTyp ? 'Keine Orte in dieser Kategorie.' : 'Noch keine Orte eingetragen.'}
</p>
<p style="color:var(--c-text-secondary);text-align:center;padding:var(--space-6)">${msg}</p>
</div>`;
return;
}