feat: collapsible flood outlook (P.1 only by default) + dashboard fixes
CI/CD Pipeline - Northern Thailand Ping River Monitor / Test Suite (3.11) (push) Failing after 25s
CI/CD Pipeline - Northern Thailand Ping River Monitor / Build Docker Image (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Integration Test with Services (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Deploy to Staging (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Deploy to Production (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Performance Test (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Code Quality (push) Successful in 15s
CI/CD Pipeline - Northern Thailand Ping River Monitor / Cleanup (push) Successful in 1s
CI/CD Pipeline - Northern Thailand Ping River Monitor / Test Suite (3.11) (push) Failing after 25s
CI/CD Pipeline - Northern Thailand Ping River Monitor / Build Docker Image (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Integration Test with Services (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Deploy to Staging (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Deploy to Production (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Performance Test (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Code Quality (push) Successful in 15s
CI/CD Pipeline - Northern Thailand Ping River Monitor / Cleanup (push) Successful in 1s
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.
This commit is contained in:
@@ -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 @@
|
||||
<div class="stage-strip" id="p1-stages"></div>
|
||||
<div class="p1-peak" style="margin-top:7px">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.</div>
|
||||
</div>
|
||||
<div class="forecast-grid" id="forecast-grid"></div>
|
||||
<button type="button" class="zones-button" id="forecast-expand" style="display:none;margin-top:12px">Show all station forecasts ▾</button>
|
||||
<div class="forecast-grid" id="forecast-grid" style="display:none"></div>
|
||||
</section>
|
||||
|
||||
<section class="map-card" id="history-card" style="margin-top:14px;padding:20px">
|
||||
@@ -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 = `<span class="station-code" style="background:${color}">${escapeHtml(sensor.station_code)}</span><span class="station-name"><strong>${escapeHtml(sensor.station_name)}</strong><span>${escapeHtml(sensor.river_name || 'Ping basin')} · ThaiWater</span></span><span class="flow-value">${percent == null ? '—' : percent.toFixed(0) + '%'}<span>bank level</span></span>`;
|
||||
const codeClass = sensor.station_code.length > 5 ? 'station-code long' : 'station-code';
|
||||
row.innerHTML = `<span class="${codeClass}" style="background:${color}">${escapeHtml(sensor.station_code)}</span><span class="station-name"><strong>${escapeHtml(sensor.station_name)}</strong><span>${escapeHtml(sensor.river_name || 'Ping basin')} · ThaiWater</span></span><span class="flow-value">${percent == null ? '—' : percent.toFixed(0) + '%'}<span>bank level</span></span>`;
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user