Upgrade maps to MapLibre GL JS; compact header; move search to settings
- Replace Leaflet with MapLibre GL JS v4.7.1 across all map instances - CARTO dark/light and Esri satellite raster basemaps (no API key) - All overlays (hurricane, wildfire, SPC, wind arrows) ported to GeoJSON sources/layers - AQI, alert, temp, sun/moon markers via maplibregl.Marker with custom HTML - Radar animation pre-loads all frames on load for smoother playback - Compact loc-header: tighter padding and font sizes, all info preserved - Search bar moved from header to Settings tab under Location section - Service worker bumped to weather-v7 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
1863f6784b
commit
a25864d9ed
6 files changed
+1732
-343
No files matched your search
+170
-47
@@ -12,10 +12,12 @@
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||
<meta name="apple-mobile-web-app-title" content="NeCloud Weather">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
|
||||
<link rel="stylesheet" href="https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.css">
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="offline-banner" class="offline-banner hidden">No internet connection — showing cached data</div>
|
||||
<div id="ptr-indicator" class="ptr-indicator hidden">↓ Refreshing…</div>
|
||||
<div class="app">
|
||||
|
||||
<header class="masthead">
|
||||
@@ -23,25 +25,13 @@
|
||||
<nav class="tabs">
|
||||
<button class="tab active" data-tab="conditions">Conditions</button>
|
||||
<button class="tab" data-tab="unified-map">Map</button>
|
||||
<button class="tab" data-tab="alerts">Alerts</button>
|
||||
<button class="tab" data-tab="alerts">Alerts<span class="alert-badge hidden" id="alert-badge-nav"></span></button>
|
||||
<button class="tab" data-tab="learn">Learn</button>
|
||||
<button class="tab" data-tab="settings">Settings</button>
|
||||
</nav>
|
||||
<span class="tagline">Open-Meteo · RainViewer</span>
|
||||
</header>
|
||||
|
||||
<!-- Search bar (shared, always visible) -->
|
||||
<div class="search-wrap">
|
||||
<div class="search-row">
|
||||
<input id="search-input" type="text" placeholder="City, region, or country…" autocomplete="off" spellcheck="false">
|
||||
<button id="search-btn">Search</button>
|
||||
<button id="locate-btn" title="Use my location">⌖</button>
|
||||
<button id="units-btn" title="Toggle units">US</button>
|
||||
</div>
|
||||
<ul id="suggestions" class="suggestions hidden"></ul>
|
||||
<p id="error-msg" class="error hidden"></p>
|
||||
</div>
|
||||
|
||||
<!-- Loading -->
|
||||
<div id="loading" class="loading hidden">
|
||||
<div class="loading-container">
|
||||
@@ -123,38 +113,44 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── WIND & ATMOSPHERE ── -->
|
||||
<div class="section-head">
|
||||
<span class="section-label">Wind & Atmosphere</span>
|
||||
</div>
|
||||
<div class="card-group">
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">Wind</div>
|
||||
<div class="stat-val"><span id="cur-wind">--</span> <span class="stat-unit wind-unit">mph</span></div>
|
||||
<div class="stat-sub" id="cur-wind-dir">--</div>
|
||||
<!-- ── WIND & ATMOSPHERE (collapsed by default on mobile) ── -->
|
||||
<details class="details-drawer wind-drawer" id="wind-drawer">
|
||||
<summary class="drawer-summary">
|
||||
Wind & Atmosphere
|
||||
<span class="wind-drawer-peek" id="wind-drawer-peek"></span>
|
||||
<span class="drawer-chevron">›</span>
|
||||
</summary>
|
||||
<div class="drawer-body">
|
||||
<div class="card-group drawer-card-group">
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">Wind</div>
|
||||
<div class="stat-val"><span id="cur-wind">--</span> <span class="stat-unit wind-unit">mph</span></div>
|
||||
<div class="stat-sub" id="cur-wind-dir">--</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">Gusts</div>
|
||||
<div class="stat-val"><span id="cur-gust">--</span> <span class="stat-unit gust-unit">mph</span></div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">Humidity</div>
|
||||
<div class="stat-val"><span id="cur-hum">--</span><span class="stat-unit">%</span></div>
|
||||
<div class="stat-sub" id="hum-feel"></div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">Dewpoint</div>
|
||||
<div class="stat-val"><span id="cur-dew">--</span>°</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">Pressure</div>
|
||||
<div class="stat-val"><span id="cur-pres">--</span> <span class="stat-unit">hPa</span></div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">Visibility</div>
|
||||
<div class="stat-val"><span id="cur-vis">--</span> <span class="stat-unit vis-unit">mi</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">Gusts</div>
|
||||
<div class="stat-val"><span id="cur-gust">--</span> <span class="stat-unit gust-unit">mph</span></div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">Humidity</div>
|
||||
<div class="stat-val"><span id="cur-hum">--</span><span class="stat-unit">%</span></div>
|
||||
<div class="stat-sub" id="hum-feel"></div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">Dewpoint</div>
|
||||
<div class="stat-val"><span id="cur-dew">--</span>°</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">Pressure</div>
|
||||
<div class="stat-val"><span id="cur-pres">--</span> <span class="stat-unit">hPa</span></div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">Visibility</div>
|
||||
<div class="stat-val"><span id="cur-vis">--</span> <span class="stat-unit vis-unit">mi</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<!-- ── MORE DETAILS DRAWER ── -->
|
||||
<details class="details-drawer">
|
||||
@@ -211,11 +207,15 @@
|
||||
<!-- Hourly -->
|
||||
<div class="section-head" style="margin-top:1.5rem">
|
||||
<span class="section-label">Hourly Forecast</span>
|
||||
<span class="section-note">next 24 hours</span>
|
||||
<span class="section-note">
|
||||
<button id="hourly-feels-toggle" class="link-btn">Feels-like</button>
|
||||
<button id="hourly-extend-btn" class="link-btn">48h</button>
|
||||
</span>
|
||||
</div>
|
||||
<div id="hourly-scroll" class="hourly-scroll">
|
||||
<div id="hourly-track" class="hourly-track"></div>
|
||||
</div>
|
||||
<div id="precip-chart-wrap" class="precip-chart-wrap"></div>
|
||||
|
||||
<!-- 7-day -->
|
||||
<div class="section-head">
|
||||
@@ -224,6 +224,18 @@
|
||||
</div>
|
||||
<div id="daily-list" class="daily-list"></div>
|
||||
|
||||
<details class="details-drawer discussion-drawer" id="discussion-drawer">
|
||||
<summary class="drawer-summary">
|
||||
Forecaster's Discussion
|
||||
<span class="discussion-office" id="discussion-office"></span>
|
||||
<span class="drawer-chevron">›</span>
|
||||
</summary>
|
||||
<div class="drawer-body">
|
||||
<p class="discussion-meta" id="discussion-meta"></p>
|
||||
<pre class="discussion-text" id="discussion-text">Loading…</pre>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<div class="footer-note">
|
||||
Weather: <a href="https://open-meteo.com" target="_blank">Open-Meteo</a> ·
|
||||
Radar: <a href="https://www.rainviewer.com" target="_blank">RainViewer</a> ·
|
||||
@@ -307,6 +319,27 @@
|
||||
<span class="toggle-slider"></span>
|
||||
</span>
|
||||
</label>
|
||||
<label class="toggle-control">
|
||||
<span class="toggle-label">🌀 Hurricanes</span>
|
||||
<span class="switch-toggle">
|
||||
<input type="checkbox" id="toggle-hurricane" data-layer="hurricane">
|
||||
<span class="toggle-slider"></span>
|
||||
</span>
|
||||
</label>
|
||||
<label class="toggle-control">
|
||||
<span class="toggle-label">🔥 Wildfires</span>
|
||||
<span class="switch-toggle">
|
||||
<input type="checkbox" id="toggle-wildfire" data-layer="wildfire">
|
||||
<span class="toggle-slider"></span>
|
||||
</span>
|
||||
</label>
|
||||
<label class="toggle-control">
|
||||
<span class="toggle-label">🌪️ SPC Reports</span>
|
||||
<span class="switch-toggle">
|
||||
<input type="checkbox" id="toggle-spc" data-layer="spc">
|
||||
<span class="toggle-slider"></span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -369,6 +402,7 @@
|
||||
|
||||
<!-- ── TAB: ALERTS ── -->
|
||||
<div id="tab-alerts" class="tab-panel hidden">
|
||||
<div id="hurricane-panel" class="hurricane-panel"></div>
|
||||
<div id="alerts-wrap" class="alerts-wrap hidden">
|
||||
<div class="section-head">
|
||||
<span class="section-label">Weather Alerts</span>
|
||||
@@ -386,6 +420,20 @@
|
||||
<!-- ── TAB: SETTINGS ── -->
|
||||
<div id="tab-settings" class="tab-panel hidden">
|
||||
<div class="settings-wrap">
|
||||
|
||||
<!-- Location search — moved here from header -->
|
||||
<div class="settings-section-label">Location</div>
|
||||
<div class="search-wrap settings-search">
|
||||
<div class="search-row">
|
||||
<input id="search-input" type="text" placeholder="City, region, or country…" autocomplete="off" spellcheck="false">
|
||||
<button id="search-btn">Search</button>
|
||||
<button id="locate-btn" title="Use my location">⌖</button>
|
||||
<button id="units-btn" title="Toggle units">US</button>
|
||||
</div>
|
||||
<ul id="suggestions" class="suggestions hidden"></ul>
|
||||
<p id="error-msg" class="error hidden"></p>
|
||||
</div>
|
||||
|
||||
<div class="saved-wrap">
|
||||
<div class="saved-head">
|
||||
<span>Saved locations</span>
|
||||
@@ -411,6 +459,80 @@
|
||||
<span class="settings-label">Units</span>
|
||||
<button id="units-btn-settings" class="settings-btn" type="button">US</button>
|
||||
</div>
|
||||
|
||||
<div class="settings-row">
|
||||
<span class="settings-label">Theme</span>
|
||||
<div class="theme-toggle-group">
|
||||
<button class="theme-btn" data-theme="system">System</button>
|
||||
<button class="theme-btn" data-theme="light">Light</button>
|
||||
<button class="theme-btn" data-theme="dark">Dark</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-section-title">Push Notifications (ntfy)</div>
|
||||
<div class="settings-row settings-row--block">
|
||||
<div class="settings-row-head">
|
||||
<span class="settings-label">ntfy Topic URL</span>
|
||||
<button id="ntfy-test-btn" class="settings-btn" type="button">Test</button>
|
||||
</div>
|
||||
<input id="ntfy-url-input" class="settings-input" type="url"
|
||||
placeholder="https://ntfy.sh/my-weather-alerts"
|
||||
autocomplete="off" spellcheck="false">
|
||||
<p class="settings-help">
|
||||
Receive alerts on any device via the <a href="https://ntfy.sh" target="_blank" rel="noopener">ntfy app</a>.
|
||||
Enter your topic URL — alerts will be pushed here whenever new weather warnings are found.
|
||||
</p>
|
||||
<p id="ntfy-status" class="settings-help hidden"></p>
|
||||
</div>
|
||||
|
||||
<div class="settings-section-title">Web Push (Browser Notifications)</div>
|
||||
<div class="settings-row settings-row--block">
|
||||
<div class="settings-row-head">
|
||||
<span class="settings-label">Push alerts for saved location</span>
|
||||
<button id="push-subscribe-btn" class="settings-btn" type="button">Enable</button>
|
||||
</div>
|
||||
<p id="push-status" class="settings-help hidden"></p>
|
||||
</div>
|
||||
|
||||
<div class="settings-section-title">Alert Thresholds</div>
|
||||
<div class="settings-row settings-row--block">
|
||||
<div class="settings-row-head">
|
||||
<label class="settings-label" for="threshold-wind">Wind gust alert (mph)</label>
|
||||
<input id="threshold-wind" class="settings-input settings-input--short" type="number" min="0" max="200" placeholder="e.g. 40">
|
||||
</div>
|
||||
<div class="settings-row-head" style="margin-top:0.5rem">
|
||||
<label class="settings-label" for="threshold-temp-low">Freeze alert below (°F)</label>
|
||||
<input id="threshold-temp-low" class="settings-input settings-input--short" type="number" min="-60" max="60" placeholder="e.g. 32">
|
||||
</div>
|
||||
<div class="settings-row-head" style="margin-top:0.5rem">
|
||||
<label class="settings-label" for="threshold-aqi">AQI alert above</label>
|
||||
<input id="threshold-aqi" class="settings-input settings-input--short" type="number" min="0" max="500" placeholder="e.g. 100">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-section-title">Daily Digest</div>
|
||||
<div class="settings-row">
|
||||
<label class="settings-label" for="digest-hour">Send forecast at hour (local, 0–23)</label>
|
||||
<input id="digest-hour" class="settings-input settings-input--short" type="number" min="0" max="23" value="7">
|
||||
</div>
|
||||
|
||||
<div class="settings-section-title">Personal Weather Station</div>
|
||||
<div class="settings-row settings-row--block">
|
||||
<div class="settings-row-head">
|
||||
<span class="settings-label">PWS JSON URL</span>
|
||||
<button id="pws-save-btn" class="settings-btn" type="button">Save</button>
|
||||
</div>
|
||||
<input id="pws-url-input" class="settings-input" type="url"
|
||||
placeholder="http://192.168.1.x/weather.json"
|
||||
autocomplete="off" spellcheck="false">
|
||||
<p class="settings-help">Point to a local device that serves a JSON weather payload.</p>
|
||||
<p id="pws-status" class="settings-help hidden"></p>
|
||||
</div>
|
||||
|
||||
<div class="settings-row" id="pwa-install-row" style="display:none">
|
||||
<span class="settings-label">Install App</span>
|
||||
<button id="pwa-install-btn" class="settings-btn" type="button">Add to Home Screen</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1118,6 +1240,7 @@
|
||||
<button class="bottom-tab" data-tab="alerts" type="button">
|
||||
<span class="bottom-icon">⚠️</span>
|
||||
<span class="bottom-label">Alerts</span>
|
||||
<span class="alert-badge hidden" id="alert-badge-bottom"></span>
|
||||
</button>
|
||||
<button class="bottom-tab" data-tab="learn" type="button">
|
||||
<span class="bottom-icon">📘</span>
|
||||
@@ -1129,7 +1252,7 @@
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
||||
<script src="https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.js"></script>
|
||||
<script src="app.js"></script>
|
||||
<script>
|
||||
if ('serviceWorker' in navigator) {
|
||||
|
||||
Reference in new issue
Block a user