From 787f848abad267d08acbfb45a2df5d89a2524195 Mon Sep 17 00:00:00 2001 From: EiSiMo Date: Thu, 23 Apr 2026 12:37:15 +0200 Subject: [PATCH] feat(ui): green map pin for applied flats, hide map reject after apply, lightbox image viewer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Map: replace Leaflet's default marker with a divIcon SVG pin coloured per state — green when the user has already successfully applied (status.chip === "ok"), brand-blue otherwise. Same condition also hides the action buttons in the popup, matching the list view, which already hid both Bewerben and Ablehnen on success — so the only remaining action on an applied flat is opening the original ad link. Image gallery: clicks now open a global lightbox modal instead of a new tab. The viewer fits each image into the viewport via max-width/height + object-fit: contain (uniform sizing regardless of source aspect), shows × top-right, prev/next arrows on the sides, ←/→/Esc keyboard nav, and click-on-backdrop to close. Prev arrow is hidden on the first image and next on the last. Tile changes from to ` + + ``; + } html += - `
` + + `` + `` + `` + - `` + + `` + `
`; + html += ``; } - html += - `
` + - `` + - `` + - `` + - `
`; - html += ``; + html += ``; return html; } +// Custom pin icon — divIcon with inline SVG so we can color it per-state +// without shipping marker images. Successful apply → green; everything else +// → brand blue. Sized + anchored to roughly match Leaflet's default pin. +function pinIcon(color) { + const svg = + `` + + `` + + `` + + ``; + return L.divIcon({ + className: "lazyflat-pin", + html: svg, + iconSize: [28, 38], + iconAnchor: [14, 38], + popupAnchor: [0, -34], + }); +} + function renderMarkers(payload) { if (!mapInstance) return; const { csrf, flats } = payload; @@ -106,7 +131,9 @@ function renderMarkers(payload) { flats.forEach((f) => { if (typeof f.lat !== "number" || typeof f.lng !== "number") return; - L.marker([f.lat, f.lng]) + const applied = !!(f.status && f.status.chip === "ok"); + const color = applied ? "#1f8a4a" : "#2f8ae0"; + L.marker([f.lat, f.lng], { icon: pinIcon(color) }) .addTo(markerLayer) .bindPopup(popupHtml(f, csrf), { minWidth: 240, closeButton: true }); }); diff --git a/web/templates/_wohnung_detail.html b/web/templates/_wohnung_detail.html index e3ea633..d6611b4 100644 --- a/web/templates/_wohnung_detail.html +++ b/web/templates/_wohnung_detail.html @@ -10,9 +10,9 @@
diff --git a/web/templates/base.html b/web/templates/base.html index 6e395a9..339b5f6 100644 --- a/web/templates/base.html +++ b/web/templates/base.html @@ -18,5 +18,20 @@ {% block body %}{% endblock %} + +{# Image lightbox — global so any flat-gallery on any page reuses the same modal. #} +