Add maps fullscreen and enforce single-line search controls

This commit is contained in:
Nate committed 2026-03-16 15:03:27 -04:00
1 parent 5003d3ec09
commit 359e76bccb
3 files changed
+124 -30

No files matched your search

+75 -3
View File
@@ -122,6 +122,7 @@ const contrastToggle = document.getElementById('contrast-toggle');
const contrastStatus = document.getElementById('contrast-status');
const radarOpacityEl = document.getElementById('radar-opacity');
const lightningAgeEl = document.getElementById('lightning-age');
const mapsFullscreenBtn = document.getElementById('maps-fullscreen-btn');
// ── Helpers ──────────────────────────────────────────────────────────────────
const show = el => el.classList.remove('hidden');
@@ -466,6 +467,8 @@ document.querySelectorAll('.tab').forEach(btn => {
}
if (btn.dataset.tab === 'maps') {
setTimeout(refreshMapsOverview, 80);
} else {
setMapsFullscreen(false);
}
});
});
@@ -731,9 +734,33 @@ function createOverviewMap(mapEl) {
const radarLayer = L.tileLayer('https://tilecache.rainviewer.com/v2/radar/nowcast_0/256/{z}/{x}/{y}/2/1_1.png', {
maxZoom: 15,
opacity: Math.max(0.15, Math.min(0.9, state.radarOpacity / 100)),
opacity: Math.max(0.25, Math.min(0.9, state.radarOpacity / 100)),
}).addTo(map);
let lastRadarFramePath = null;
async function refreshRadarOverlay() {
try {
const r = await fetch('/api/radar/times');
if (!r.ok) return;
const data = await r.json();
const frames = [
...(data?.radar?.past || []),
...(data?.radar?.nowcast || []),
];
const latest = frames[frames.length - 1];
const path = latest?.path;
if (!path || path === lastRadarFramePath) return;
lastRadarFramePath = path;
radarLayer.setUrl(`https://tilecache.rainviewer.com${path}/256/{z}/{x}/{y}/2/1_1.png`);
} catch (e) {
console.warn('Maps radar overlay refresh failed', e);
}
}
refreshRadarOverlay();
setInterval(refreshRadarOverlay, 5 * 60 * 1000);
let marker = null;
function panTo(lat, lon, zoom) {
@@ -749,11 +776,11 @@ function createOverviewMap(mapEl) {
}
function setRadarOpacity(opacityPct) {
const normalized = Math.max(0.15, Math.min(0.9, Number(opacityPct) / 100));
const normalized = Math.max(0.25, Math.min(0.9, Number(opacityPct) / 100));
radarLayer.setOpacity(normalized);
}
return { map, panTo, setRadarOpacity };
return { map, panTo, setRadarOpacity, refreshRadarOverlay };
}
function clearLightningLayer() {
@@ -774,6 +801,7 @@ function refreshMapsOverview() {
if (!mapsOverview.map) return;
mapsOverview.map.invalidateSize();
mapsOverview.refreshRadarOverlay();
if (!state.currentCity) return;
@@ -906,6 +934,50 @@ function renderWindArrows(city) {
const mapsOverview = createOverviewMap(document.getElementById('map-overview'));
function setMapsFullscreen(active) {
const wrap = document.querySelector('#tab-maps .maps-wrap');
if (!wrap) return;
wrap.classList.toggle('is-fullscreen', active);
document.body.classList.toggle('map-fullscreen-lock', active);
if (mapsFullscreenBtn) {
mapsFullscreenBtn.textContent = active ? 'Exit fullscreen' : 'Fullscreen map';
}
setTimeout(() => {
if (mapsOverview?.map) mapsOverview.map.invalidateSize();
}, 100);
}
if (mapsFullscreenBtn) {
mapsFullscreenBtn.addEventListener('click', async () => {
const wrap = document.querySelector('#tab-maps .maps-wrap');
if (!wrap) return;
if (document.fullscreenElement === wrap) {
await document.exitFullscreen().catch(() => {});
setMapsFullscreen(false);
return;
}
if (wrap.requestFullscreen) {
try {
await wrap.requestFullscreen();
setMapsFullscreen(true);
return;
} catch {
// Some mobile browsers reject Fullscreen API; fallback below.
}
}
setMapsFullscreen(!wrap.classList.contains('is-fullscreen'));
});
}
document.addEventListener('fullscreenchange', () => {
const wrap = document.querySelector('#tab-maps .maps-wrap');
if (!wrap) return;
setMapsFullscreen(document.fullscreenElement === wrap);
});
// ── Rendering ────────────────────────────────────────────────────────────────
function renderDailyForecast(daily) {
const list = document.getElementById('daily-list');
+6
View File
@@ -158,6 +158,12 @@
<!-- ── TAB: MAPS ── -->
<div id="tab-maps" class="tab-panel hidden">
<div class="section-head">
<span class="section-label">Maps</span>
<span class="section-actions">
<button id="maps-fullscreen-btn" class="link-btn" type="button">Fullscreen map</button>
</span>
</div>
<div class="maps-wrap">
<div id="map-overview" class="radar-map map-overview"></div>
<div class="maps-controls">
+43 -27
View File
@@ -167,6 +167,7 @@ a:hover { text-decoration: underline; }
.search-row {
display: flex;
align-items: center;
flex-wrap: nowrap;
gap: 0;
border: 1px solid var(--line);
border-radius: var(--radius-lg);
@@ -195,6 +196,7 @@ button, input, select { font-family: var(--ui); }
}
.search-row button {
flex: 0 0 auto;
min-height: 46px;
border: none;
border-left: 1px solid var(--line);
@@ -205,18 +207,25 @@ button, input, select { font-family: var(--ui); }
#search-btn {
background: linear-gradient(180deg, #15445f 0%, #11344c 100%);
color: #f2f8fc;
text-transform: uppercase;
letter-spacing: 0.03em;
font-weight: 700;
min-width: 96px;
font-size: 0.78rem;
min-width: 52px;
width: 52px;
font-size: 0;
letter-spacing: 0;
text-transform: none;
padding: 0;
}
#search-btn::before {
content: '🔎';
font-size: 1rem;
line-height: 1;
}
#locate-btn,
#units-btn {
background: var(--surface) !important;
color: var(--ink) !important;
min-width: 50px;
min-width: 48px;
}
#locate-btn {
@@ -224,34 +233,15 @@ button, input, select { font-family: var(--ui); }
}
@media (max-width: 390px) {
#search-btn {
min-width: 84px;
font-size: 0.72rem;
}
#search-btn,
#locate-btn,
#units-btn {
min-width: 46px;
width: 46px;
padding: 0 0.5rem;
}
}
@media (max-width: 460px) {
#search-btn {
min-width: 48px;
font-size: 0;
letter-spacing: 0;
text-transform: none;
padding: 0;
}
#search-btn::before {
content: '🔎';
font-size: 1rem;
line-height: 1;
}
}
.suggestions {
list-style: none;
margin-top: 0.3rem;
@@ -668,6 +658,32 @@ button, input, select { font-family: var(--ui); }
padding: 0.35rem 0.55rem;
}
#maps-fullscreen-btn {
font-size: 0.78rem;
font-weight: 700;
}
body.map-fullscreen-lock {
overflow: hidden;
}
.maps-wrap.is-fullscreen {
position: fixed;
inset: 0;
z-index: 520;
margin: 0;
border-radius: 0;
border: none;
background: var(--paper);
overflow-y: auto;
padding: calc(0.65rem + env(safe-area-inset-top, 0px)) 0.65rem calc(0.65rem + env(safe-area-inset-bottom, 0px));
}
.maps-wrap.is-fullscreen .map-overview {
height: calc(100dvh - 210px);
min-height: 320px;
}
.wind-legend {
display: flex;
align-items: center;