feat(presentation): wyszukiwarka lokalizacji + mapa (OSM/Leaflet)
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m39s
Testy / Build obrazu silnika B (swisseph) (pull_request) Failing after 28s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 21s
build / build (push) Successful in 57s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m47s
Testy / Build obrazu silnika B (swisseph) (push) Failing after 29s
Testy / Kontrola składni wszystkich warstw (push) Successful in 22s

QoL 2/2: pole „Szukaj miejsca" (nazwa/adres/POI) + interaktywna mapa na
formularzach horoskopu / interpretacji / kalendarza. Bez klucza API.

- geocode.py: proxy OSM/Nominatim PO STRONIE SERWERA (poprawny User-Agent,
  throttling ~1 req/s, cache TTL 1h) — endpointy /geocode i /reverse.
  Wolanie z serwera, nie z przegladarki: latwiej trzymac polityke Nominatim
  i dziala niezaleznie od secure-context (http://<ip>).
- _location_picker.html: wspolny partial (search + wyniki + mapa + atrybucja),
  wpiety includem do 3 formularzy z polami lat/lon.
- geo.js: Leaflet — wyszukiwanie (debounce), klik na wynik ustawia lat/lon i
  centruje mape, klik/drag pineski ustawia wspolrzedne + /reverse pokazuje
  nazwe; sync z „Tu i teraz" (now.js emituje event astrololo:coords).
- Leaflet 1.9.4 vendorowany lokalnie (static/vendor/leaflet, BSD-2-Clause,
  permisywny) — niezaleznosc od CDN; kafelki mapy z OSM. Marker jako divIcon
  (bez plikow PNG).
- styles.css: style pod ciemny motyw.

Zweryfikowane w przegladarce: domyslny widok (pineska na Szpitalu Barlickiego),
wyszukanie „Wawel Krakow" -> lista -> klik ustawia 50.0547/19.9361 i przesuwa
mape, klik w mape ustawia wspolrzedne + reverse wypelnia nazwe. Zero bledow
w konsoli. /geocode i /reverse zwracaja szpital; cache dziala.

Uwaga wdrozeniowa: pod prezentacji potrzebuje egressu do
nominatim.openstreetmap.org; przegladarki — do tile.openstreetmap.org.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit was merged in pull request #6.
This commit is contained in:
2026-07-21 03:26:03 +02:00
parent de5d58958c
commit a2aabd37a5
11 changed files with 940 additions and 1 deletions
@@ -0,0 +1,20 @@
{# Wyszukiwarka lokalizacji + interaktywna mapa (OpenStreetMap / Leaflet, bez klucza API).
Wklejana do formularzy z polami input[name=lat] / input[name=lon]. Samowystarczalna:
ładuje CSS/JS Leafleta (vendorowane lokalnie) oraz geo.js. Kafelki mapy lecą z OSM. #}
<link rel="stylesheet" href="/static/vendor/leaflet/leaflet.css">
<div class="geo" id="geoPicker">
<div class="geo-search">
<input type="search" id="geoSearch" autocomplete="off"
placeholder="Szukaj miejsca (np. Szpital Barlickiego, Łódź)…">
<button type="button" id="geoSearchBtn" class="ghost">Szukaj</button>
<button type="button" id="geoMapToggle" class="ghost">Ukryj mapę</button>
</div>
<ul id="geoResults" class="geo-results" hidden></ul>
<div id="map" class="geo-map"></div>
<p class="muted small geo-attrib">
Wyszukiwarka i mapa: © <a href="https://www.openstreetmap.org/copyright" target="_blank" rel="noopener">OpenStreetMap</a>
contributors (Nominatim). Kliknij mapę lub przeciągnij pineskę, by ustawić współrzędne.
</p>
</div>
<script defer src="/static/vendor/leaflet/leaflet.js"></script>
<script defer src="/static/geo.js"></script>
@@ -33,6 +33,7 @@
</select>
</label>
</div>
{% include "_location_picker.html" %}
<div class="opts">
<label><input type="checkbox" name="stations" value="true" {{ 'checked' if form.stations else '' }}>
licz stacje planet (wolniejsze)</label>
@@ -23,6 +23,7 @@
<input type="number" name="lon" step="0.0001" value="{{ form.lon if form.lon is not none else 0 }}">
</label>
</div>
{% include "_location_picker.html" %}
<div class="opts">
<label><input type="checkbox" name="group" value="true" {{ 'checked' if form.group else '' }}> grupuj identyczne opisy</label>
</div>
@@ -24,6 +24,7 @@
</label>
</div>
{% if location_label %}<p class="muted small">Wstępnie wpisano lokalizację: <strong>{{ location_label }}</strong> ({{ form.lat }}, {{ form.lon }}). Zmień pola lub kliknij „Tu i teraz".</p>{% endif %}
{% include "_location_picker.html" %}
<div class="grid">
<label>Zakres od
<input type="date" name="from_date" value="{{ form.from_date or '' }}" required>