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.
-
+ Show all station forecasts ▾
+
@@ -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);