From d29d49eac783ca6e6c8a1136e44d6c969386c6f5 Mon Sep 17 00:00:00 2001 From: grabowski Date: Tue, 11 Aug 2026 15:48:20 +0700 Subject: [PATCH] feat: collapsible flood outlook (P.1 only by default) + dashboard fixes The flood-risk card now shows just the Chiang Mai P.1 outlook; the per-station forecast grid collapses behind a Show/Hide expander. Fixes: the rain-layer toggle was unclickable (.map-overlay pointer-events:none now re-enabled on the legend), long HII station codes (MOU302, FOP015) wrap inside their chips instead of clipping, and the sensor panel sorts by bank percentage with no-data stations last. --- src/static/dashboard.html | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/static/dashboard.html b/src/static/dashboard.html index de8f10c..8da489a 100644 --- a/src/static/dashboard.html +++ b/src/static/dashboard.html @@ -77,6 +77,7 @@ .map-heading, .legend { background: rgba(255,255,255,.93); backdrop-filter: blur(9px); border: 1px solid rgba(207,224,218,.9); border-radius: 13px; padding: 11px 13px; box-shadow: 0 7px 20px rgba(22,58,68,.12); + pointer-events: auto; /* .map-overlay disables events; re-enable for the legend's rain toggle */ } .map-heading strong { display: block; font-size: .9rem; } .map-heading span { color: var(--muted); font-size: .72rem; } @@ -95,6 +96,7 @@ } .station-row:hover { background: #f1f7f5; transform: none; } .station-code { width: 40px; height: 40px; display: grid; place-items: center; border-radius: 11px; color: white; font-size: .68rem; font-weight: 850; } + .station-code.long { font-size: .55rem; word-break: break-all; line-height: 1.15; padding: 2px; text-align: center; } .station-name { overflow: hidden; } .station-name strong, .station-name span { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .station-name strong { font-size: .78rem; } @@ -253,7 +255,8 @@
Chance the river reaches each official inundation stage within 24 h — city flooding begins at stage 1 (3.70 m); each stage floods additional districts.
-
+ +
@@ -637,7 +640,9 @@ function renderThaiWaterSensors(sensors, existingCodes) { const container = $('thaiwater-sensors'); container.replaceChildren(); - const additional = sensors.filter((sensor) => !existingCodes.has(sensor.station_code)); + const additional = sensors + .filter((sensor) => !existingCodes.has(sensor.station_code)) + .sort((a, b) => (Number(b.bank_percent) || -1) - (Number(a.bank_percent) || -1)); $('thaiwater-count').textContent = `${additional.length} additional Ping basin stations · water level`; additional.forEach((sensor) => { const percent = sensor.bank_percent == null ? null : Number(sensor.bank_percent); @@ -666,7 +671,8 @@ const row = document.createElement('button'); row.type = 'button'; row.className = 'station-row'; - row.innerHTML = `${escapeHtml(sensor.station_code)}${escapeHtml(sensor.station_name)}${escapeHtml(sensor.river_name || 'Ping basin')} · ThaiWater${percent == null ? '—' : percent.toFixed(0) + '%'}bank level`; + const codeClass = sensor.station_code.length > 5 ? 'station-code long' : 'station-code'; + row.innerHTML = `${escapeHtml(sensor.station_code)}${escapeHtml(sensor.station_name)}${escapeHtml(sensor.river_name || 'Ping basin')} · ThaiWater${percent == null ? '—' : percent.toFixed(0) + '%'}bank level`; row.addEventListener('click', () => { state.map.flyTo(marker.getLatLng(), Math.max(state.map.getZoom(), 11), { duration: .8 }); marker.openPopup(); }); container.appendChild(row); }); @@ -1094,6 +1100,15 @@ const asOf = rows[0].as_of ? new Date(rows[0].as_of).toLocaleString([], { dateStyle: 'medium', timeStyle: 'short' }) : null; $('forecast-status').textContent = `Probability of exceeding warning / danger level within 6, 12 and 24 h` + (asOf ? ` · based on readings up to ${asOf}` : ''); + // Only the P.1 city outlook is shown by default; the per-station + // grid stays collapsed behind the expander. + const expand = $('forecast-expand'); + const others = stations.filter(({ code }) => code !== 'P.1').length; + expand.style.display = others ? 'inline-flex' : 'none'; + grid.style.display = state.forecastExpanded ? 'grid' : 'none'; + expand.textContent = state.forecastExpanded + ? 'Hide station forecasts ▴' + : `Show all ${stations.length} station forecasts ▾`; card.style.display = 'block'; } catch (error) { card.style.display = 'none'; @@ -1120,6 +1135,14 @@ $('refresh-button').addEventListener('click', loadDashboard); $('zones-toggle').addEventListener('click', toggleFloodZones); + $('forecast-expand').addEventListener('click', () => { + state.forecastExpanded = !state.forecastExpanded; + $('forecast-grid').style.display = state.forecastExpanded ? 'grid' : 'none'; + const count = $('forecast-grid').children.length; + $('forecast-expand').textContent = state.forecastExpanded + ? 'Hide station forecasts ▴' + : `Show all ${count} station forecasts ▾`; + }); $('rain-toggle').addEventListener('change', (event) => { if (!state.rainLayer) return; if (event.target.checked) state.rainLayer.addTo(state.map);