diff --git a/backend/static/css/components.css b/backend/static/css/components.css index bfa052e..9b23c1a 100644 --- a/backend/static/css/components.css +++ b/backend/static/css/components.css @@ -2339,24 +2339,50 @@ html.modal-open { } .rk-nearby-group { margin-bottom: var(--space-3); + border: 1px solid var(--c-border-light); + border-radius: var(--radius-md); + overflow: hidden; } -.rk-nearby-group-label { - font-size: var(--text-sm); - font-weight: var(--weight-medium); - color: var(--c-text-secondary); - margin-bottom: var(--space-1); +.rk-nearby-group-header { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + padding: var(--space-2) var(--space-3); + background: var(--c-surface-2); + border: none; + cursor: pointer; + font-size: var(--text-sm); + font-weight: var(--weight-semibold); + color: var(--c-text); + text-align: left; + -webkit-tap-highlight-color: transparent; } +.rk-nearby-group-header:hover { background: var(--c-border-light); } +.rk-nearby-items { padding: var(--space-1) 0; } .rk-nearby-item { display: flex; - flex-wrap: wrap; + align-items: center; + justify-content: space-between; gap: var(--space-2); - align-items: baseline; - padding: var(--space-1) 0; + padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--c-border-light); + width: 100%; + background: none; + border-left: none; + border-right: none; + border-top: none; + text-align: left; + font: inherit; } .rk-nearby-item:last-child { border-bottom: none; } -.rk-nearby-name { font-size: var(--text-sm); color: var(--c-text); } -.rk-nearby-detail { font-size: var(--text-xs); color: var(--c-text-muted); } +.rk-nearby-item--link { + cursor: pointer; + -webkit-tap-highlight-color: transparent; +} +.rk-nearby-item--link:hover { background: var(--c-surface-2); } +.rk-nearby-name { font-size: var(--text-sm); color: var(--c-text); display: block; } +.rk-nearby-detail { font-size: var(--text-xs); color: var(--c-text-muted); display: block; margin-top: 1px; } .rk-nearby-phone { color: var(--c-primary); text-decoration: none; } /* Hundetauglichkeit-Auswahl im Formular */ diff --git a/backend/static/js/app.js b/backend/static/js/app.js index bc0759b..6a8ad75 100644 --- a/backend/static/js/app.js +++ b/backend/static/js/app.js @@ -3,7 +3,7 @@ Router, State-Management, Navigation, Initialisierung. ============================================================ */ -const APP_VER = '226'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen +const APP_VER = '227'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen const App = (() => { diff --git a/backend/static/js/pages/routes.js b/backend/static/js/pages/routes.js index 7781401..e3901cb 100644 --- a/backend/static/js/pages/routes.js +++ b/backend/static/js/pages/routes.js @@ -34,12 +34,11 @@ window.Page_routes = (() => { const TERRAIN_LABEL = { wald: '🌲 Wald', asphalt: '🛣️ Asphalt', wiese: '🌿 Wiese', mix: '🔀 Mix' }; const HUNDE_LABEL = { eingeschränkt: '🐾', gut: '🐾🐾', sehr_gut: '🐾🐾🐾', premium: '🐾🐾🐾🐾' }; - // POI-Typen die entlang einer Route gezeigt werden + // POI-Typen entlang der Route — nur relevante/interessante Orte const NEARBY_TYPES = [ - { type: 'restaurant', icon: '🍽️', label: 'Restaurant/Café' }, - { type: 'parkplatz', icon: '🅿️', label: 'Parkplatz' }, - { type: 'drinking_water', icon: '💧', label: 'Wasserstelle' }, - { type: 'bank', icon: '🪑', label: 'Bank' }, + { type: 'restaurant', icon: '🍽️', label: 'Restaurant/Café' }, + { type: 'tierarzt', icon: '🏥', label: 'Tierarzt' }, + { type: 'shop', icon: '🐾', label: 'Zoobedarf' }, ]; // _esc und _emptyState ersetzt durch UI.escape() / UI.emptyState() @@ -936,7 +935,6 @@ window.Page_routes = (() => { if (!el) return; if (!pois.length) { el.innerHTML = ''; return; } - // Gruppieren nach Typ const byType = {}; pois.forEach(p => { const key = p._label; @@ -944,22 +942,64 @@ window.Page_routes = (() => { byType[key].items.push(p); }); + let gIdx = 0; el.innerHTML = `
${UI.icon('map-pin')} Entlang der Route
- ${Object.values(byType).map(group => ` -
-
${group.icon} ${UI.escape(group.label)} (${group.items.length})
- ${group.items.slice(0, 5).map(p => ` -
- ${UI.escape(p.name || group.label)} - ${p.opening_hours ? `${UI.icon('clock')} ${UI.escape(p.opening_hours)}` : ''} - ${p.phone ? `${UI.icon('phone')} ${UI.escape(p.phone)}` : ''} + ${Object.values(byType).map(group => { + const id = `rk-ng-${gIdx++}`; + return ` +
+ +
+ ${group.items.map(p => ` + + `).join('')}
- `).join('')} - ${group.items.length > 5 ? `
+${group.items.length-5} weitere
` : ''} -
- `).join('')} +
`; + }).join('')} `; + + // Einklapp-Logik + el.querySelectorAll('.rk-nearby-group-header').forEach(btn => { + const target = document.getElementById(btn.dataset.target); + const chevron = btn.querySelector('.rk-nearby-chevron'); + let open = true; + btn.addEventListener('click', () => { + open = !open; + target.style.display = open ? '' : 'none'; + chevron.style.transform = open ? '' : 'rotate(-90deg)'; + }); + }); + + // POI auf Karte zeigen + el.querySelectorAll('.rk-nearby-item--link').forEach(btn => { + btn.addEventListener('click', () => { + const lat = parseFloat(btn.dataset.lat); + const lon = parseFloat(btn.dataset.lon); + const name = btn.dataset.name; + const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent); + const url = isIOS + ? `maps://maps.apple.com/?q=${encodeURIComponent(name)}&ll=${lat},${lon}` + : `https://www.google.com/maps/search/?api=1&query=${lat},${lon}`; + window.open(url, '_blank'); + }); + }); } // ----------------------------------------------------------