Add maps fullscreen and enforce single-line search controls
This commit is contained in:
1 parent
5003d3ec09
commit
359e76bccb
3 files changed
+124
-30
No files matched your search
+75
-3
@@ -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');
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user