Compare/calendar mobile polish: overflow fix, sheet load button, 6-yr default, country in names (#80)
- Fix the mobile width blow-out: the distribution grid item (.cmp-dist-row) had no min-width:0, so each row expanded to the 9–10-column connected bar chart's min-content and widened the whole page (zoom-out, clipped filter sheet). Add grid-template-columns: minmax(0,1fr) + min-width:0 so the strip scrolls inside its own .ct-strip, and tighten .ct-col to 34px on phones. - Add a Load/Refresh button inside the compare filter sheet's date-range block, wired to the same refresh()/isDirty(); editing the range on mobile no longer needs the sheet closed. The existing button stays in the controls (loads added places). - Default date range on both pages is now January six years back → the present. On the calendar this is an explicit chunked range (the months=24 path is server-capped at ~2yr). - Names now include country: reverse_geocode appends it to the place label; revgeo cache key gets a v2 prefix and PAYLOAD_VER bumps to p2 so labels/payloads repopulate. - Location names read as a hierarchy: compact chips show just the lead segment (full name in the title/aria), and each ranked card shows the lead segment bold over a muted "city · region · country" line. Frontend + a small backend name/cache change; no schema migration.
This commit is contained in:
parent
46c90914b3
commit
576a239723
4 changed files with 12 additions and 6 deletions
|
|
@ -587,8 +587,12 @@ def reverse_geocode(lat: float, lon: float) -> str | None:
|
||||||
city = (a.get("city") or a.get("town") or a.get("village")
|
city = (a.get("city") or a.get("town") or a.get("village")
|
||||||
or a.get("hamlet") or a.get("county"))
|
or a.get("hamlet") or a.get("county"))
|
||||||
region = a.get("state") or a.get("province") or a.get("region")
|
region = a.get("state") or a.get("province") or a.get("region")
|
||||||
|
country = a.get("country")
|
||||||
# dict.fromkeys drops duplicates (e.g. neighbourhood == city) in order.
|
# dict.fromkeys drops duplicates (e.g. neighbourhood == city) in order.
|
||||||
parts = dict.fromkeys(p for p in (neighborhood, city, region) if p)
|
# Country trails the neighbourhood/city/region so the label reads as a full
|
||||||
|
# hierarchy ("West Seattle, Seattle, Washington, United States"); the
|
||||||
|
# frontend leads with the first part and mutes the rest.
|
||||||
|
parts = dict.fromkeys(p for p in (neighborhood, city, region, country) if p)
|
||||||
label = ", ".join(parts) or None
|
label = ", ".join(parts) or None
|
||||||
except Exception: # noqa: BLE001 - reverse geocoding is a nicety, never fatal
|
except Exception: # noqa: BLE001 - reverse geocoding is a nicety, never fatal
|
||||||
label = None
|
label = None
|
||||||
|
|
|
||||||
4
store.py
4
store.py
|
|
@ -124,7 +124,9 @@ REVGEO_MISS_TTL = 3600.0 # a "no label" result may be transient (rate limit)
|
||||||
|
|
||||||
|
|
||||||
def revgeo_key(lat: float, lon: float) -> str:
|
def revgeo_key(lat: float, lon: float) -> str:
|
||||||
return f"{round(lat, 3)},{round(lon, 3)}"
|
# The "v2:" prefix versions the label format: v1 rows (no country) are bypassed
|
||||||
|
# and re-fetched so names pick up the trailing country component.
|
||||||
|
return f"v2:{round(lat, 3)},{round(lon, 3)}"
|
||||||
|
|
||||||
|
|
||||||
def get_revgeo(key: str) -> tuple[bool, str | None]:
|
def get_revgeo(key: str) -> tuple[bool, str | None]:
|
||||||
|
|
|
||||||
|
|
@ -34,10 +34,10 @@ def test_put_payload_rejects_nan(tmp_store):
|
||||||
|
|
||||||
def test_revgeo_round_trip(tmp_store):
|
def test_revgeo_round_trip(tmp_store):
|
||||||
key = tmp_store.revgeo_key(47.60623, -122.33305)
|
key = tmp_store.revgeo_key(47.60623, -122.33305)
|
||||||
assert key == "47.606,-122.333"
|
assert key == "v2:47.606,-122.333" # v2: label format now carries country
|
||||||
assert tmp_store.get_revgeo(key) == (False, None)
|
assert tmp_store.get_revgeo(key) == (False, None)
|
||||||
tmp_store.put_revgeo(key, "Belltown, Seattle, Washington")
|
tmp_store.put_revgeo(key, "Belltown, Seattle, Washington, United States")
|
||||||
assert tmp_store.get_revgeo(key) == (True, "Belltown, Seattle, Washington")
|
assert tmp_store.get_revgeo(key) == (True, "Belltown, Seattle, Washington, United States")
|
||||||
|
|
||||||
|
|
||||||
def test_revgeo_cached_miss_retries_after_ttl(tmp_store):
|
def test_revgeo_cached_miss_retries_after_ttl(tmp_store):
|
||||||
|
|
|
||||||
2
views.py
2
views.py
|
|
@ -24,7 +24,7 @@ OBS_COLS = ("tmax", "tmin", "precip", "feels", "humid", "wind", "gust")
|
||||||
# The version is part of every derived-store validity token, so one bump
|
# The version is part of every derived-store validity token, so one bump
|
||||||
# atomically orphans all pre-upgrade cached payloads instead of letting a stale
|
# atomically orphans all pre-upgrade cached payloads instead of letting a stale
|
||||||
# row whose history_end happens to match keep serving the old shape.
|
# row whose history_end happens to match keep serving the old shape.
|
||||||
PAYLOAD_VER = "p1"
|
PAYLOAD_VER = "p2" # p2: place labels now carry the trailing country component
|
||||||
|
|
||||||
CAL_MAX_SPAN_DAYS = 732 # ~2 years — the most a single calendar request will grade
|
CAL_MAX_SPAN_DAYS = 732 # ~2 years — the most a single calendar request will grade
|
||||||
# (the frontend splits longer spans into 2-year chunks)
|
# (the frontend splits longer spans into 2-year chunks)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue