335 lines
27 KiB
HTML
335 lines
27 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
|
<title>Weather</title>
|
|
<link rel="manifest" href="/manifest.json">
|
|
<link rel="apple-touch-icon" href="/icons/icon.svg">
|
|
<meta name="theme-color" content="#f5f2ec" media="(prefers-color-scheme: light)">
|
|
<meta name="theme-color" content="#191510" media="(prefers-color-scheme: dark)">
|
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
|
<meta name="apple-mobile-web-app-title" content="Weather">
|
|
<meta name="mobile-web-app-capable" content="yes">
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link href="https://fonts.googleapis.com/css2?family=DM+Mono:wght@300;400;500&family=Playfair+Display:wght@400;500&display=swap" rel="stylesheet">
|
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
|
|
<link rel="stylesheet" href="style.css">
|
|
</head>
|
|
<body>
|
|
<div class="app">
|
|
|
|
<header class="masthead">
|
|
<h1>Weather</h1>
|
|
<nav class="tabs">
|
|
<button class="tab active" data-tab="conditions">Conditions</button>
|
|
<button class="tab" data-tab="radar-full">Radar</button>
|
|
<button class="tab" data-tab="maps">Maps</button>
|
|
<button class="tab" data-tab="alerts">Alerts</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">
|
|
<span class="loading-dot"></span>Fetching weather data…
|
|
</div>
|
|
|
|
<!-- ΓöÇΓöÇ TAB: CONDITIONS ΓöÇΓöÇ -->
|
|
<div id="tab-conditions" class="tab-panel">
|
|
<div id="weather" class="hidden">
|
|
|
|
<div class="loc-header">
|
|
<div>
|
|
<div id="loc-name" class="loc-name"></div>
|
|
<div id="loc-sub" class="loc-sub"></div>
|
|
</div>
|
|
<div class="loc-actions">
|
|
<div id="loc-time" class="loc-time"></div>
|
|
<button id="share-btn" class="link-btn" type="button">Share location</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ΓöÇΓöÇ HERO ΓöÇΓöÇ -->
|
|
<div class="hero">
|
|
<div class="hero-left">
|
|
<div id="cur-icon" class="hero-icon"></div>
|
|
<div id="cur-desc" class="hero-desc"></div>
|
|
<div id="cur-precip" class="hero-sub"></div>
|
|
</div>
|
|
<div class="hero-center">
|
|
<div class="hero-temp"><span id="cur-temp">--</span><span class="deg">┬░F</span></div>
|
|
<div class="feels">Feels like <span id="cur-feels">--</span>┬░F</div>
|
|
</div>
|
|
<div class="hero-right">
|
|
<div class="hero-hilo">
|
|
<div class="hilo-item">
|
|
<span class="hilo-arrow">Γåæ</span>
|
|
<span id="cur-hi">--</span>┬░
|
|
<div class="hilo-label">High</div>
|
|
</div>
|
|
<div class="hilo-divider"></div>
|
|
<div class="hilo-item">
|
|
<span class="hilo-arrow">Γåô</span>
|
|
<span id="cur-lo">--</span>┬░
|
|
<div class="hilo-label">Low</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ΓöÇΓöÇ SUN & MOON TIMELINE ΓöÇΓöÇ -->
|
|
<div class="sun-section">
|
|
<div class="sun-timeline-wrap">
|
|
<div class="sun-endpoint">
|
|
<span class="sun-ep-icon">🌅</span>
|
|
<span id="sunrise-val" class="sun-ep-time">--</span>
|
|
</div>
|
|
<div class="sun-track-wrap">
|
|
<div class="sun-track">
|
|
<div class="sun-progress" id="sun-progress"></div>
|
|
<div class="sun-dot" id="sun-dot">☀️</div>
|
|
</div>
|
|
</div>
|
|
<div class="sun-endpoint">
|
|
<span class="sun-ep-icon">🌇</span>
|
|
<span id="sunset-val" class="sun-ep-time">--</span>
|
|
</div>
|
|
</div>
|
|
<div class="moon-row">
|
|
<span class="moon-emoji">🌙</span>
|
|
<span id="moon-phase-val">--</span>
|
|
<span class="daylight-info" id="daylight-info">--</span>
|
|
</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>
|
|
</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>
|
|
|
|
<!-- ΓöÇΓöÇ MORE DETAILS DRAWER ΓöÇΓöÇ -->
|
|
<details class="details-drawer">
|
|
<summary class="drawer-summary">More Details <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">UV Index</div>
|
|
<div class="stat-val"><span id="cur-uv">--</span></div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-label">Cloud Cover</div>
|
|
<div class="stat-val"><span id="cur-cloud">--</span><span class="stat-unit">%</span></div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-label">US AQI</div>
|
|
<div class="stat-val"><span id="aqi-us">--</span></div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-label">PM2.5</div>
|
|
<div class="stat-val"><span id="pm25">--</span></div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-label">Pollen</div>
|
|
<div class="stat-val"><span id="pollen">--</span></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</details>
|
|
|
|
<!-- ΓöÇΓöÇ WHAT TO BRING ΓöÇΓöÇ -->
|
|
<div class="section-head" style="margin-top:1.5rem">
|
|
<span class="section-label">What to Bring</span>
|
|
</div>
|
|
<div id="recommendations" class="recs-grid"></div>
|
|
|
|
<!-- Embedded radar panel -->
|
|
<div class="section-head">
|
|
<span class="section-label">Radar</span>
|
|
<span class="section-note">
|
|
<button class="link-btn" id="open-radar-tab">Open full radar →</button>
|
|
</span>
|
|
</div>
|
|
<div class="radar-embed-wrap">
|
|
<div id="radar-embed" class="radar-map"></div>
|
|
<div class="radar-controls">
|
|
<button id="embed-play" class="radar-btn play-btn" title="Play/Pause">Γû╢</button>
|
|
<button id="embed-layer" class="radar-btn layer-btn" title="Toggle radar/satellite">R</button>
|
|
<div class="radar-timeline" id="embed-timeline"></div>
|
|
<span id="embed-timestamp" class="radar-ts">--</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 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>
|
|
</div>
|
|
<div id="hourly-scroll" class="hourly-scroll">
|
|
<div id="hourly-track" class="hourly-track"></div>
|
|
</div>
|
|
|
|
<!-- 7-day -->
|
|
<div class="section-head">
|
|
<span class="section-label">7-Day Forecast</span>
|
|
</div>
|
|
<div id="daily-list" class="daily-list"></div>
|
|
|
|
<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> ┬╖
|
|
Updated <span id="updated-at"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ΓöÇΓöÇ TAB: FULL RADAR ΓöÇΓöÇ -->
|
|
<div id="tab-radar-full" class="tab-panel hidden">
|
|
<div class="radar-full-wrap">
|
|
<div id="radar-full" class="radar-map radar-map-full"></div>
|
|
<div class="radar-controls radar-controls-full">
|
|
<button id="full-play" class="radar-btn play-btn" title="Play/Pause">Γû╢</button>
|
|
<button id="full-layer" class="radar-btn layer-btn" title="Toggle radar/satellite">R</button>
|
|
<div class="radar-timeline" id="full-timeline"></div>
|
|
<span id="full-timestamp" class="radar-ts">--</span>
|
|
<div class="radar-legend">
|
|
<span class="legend-label">Light</span>
|
|
<div class="legend-bar"></div>
|
|
<span class="legend-label">Heavy</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<p class="radar-attribution">Radar tiles © <a href="https://www.rainviewer.com" target="_blank">RainViewer</a> · Map © <a href="https://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a></p>
|
|
</div>
|
|
|
|
<!-- ΓöÇΓöÇ TAB: MAPS ΓöÇΓöÇ -->
|
|
<div id="tab-maps" class="tab-panel hidden">
|
|
<div class="maps-wrap">
|
|
<div id="map-overview" class="radar-map map-overview"></div>
|
|
<div class="maps-meta">
|
|
<div class="maps-card">
|
|
<div class="stat-label">Data Source Location</div>
|
|
<div id="maps-location" class="maps-value">--</div>
|
|
</div>
|
|
<div class="maps-card">
|
|
<div class="stat-label">Current Wind</div>
|
|
<div id="maps-wind" class="maps-value">--</div>
|
|
</div>
|
|
</div>
|
|
<p class="panel-note">Toggle lightning strikes and wind overlay in Settings.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ΓöÇΓöÇ TAB: ALERTS ΓöÇΓöÇ -->
|
|
<div id="tab-alerts" class="tab-panel hidden">
|
|
<div id="alerts-wrap" class="alerts-wrap hidden">
|
|
<div class="section-head">
|
|
<span class="section-label">Weather Alerts</span>
|
|
<button id="notify-btn" class="link-btn" type="button">Enable notifications</button>
|
|
</div>
|
|
<div id="alerts-list" class="alerts-list"></div>
|
|
</div>
|
|
<p id="alerts-empty" class="panel-note">No active alerts for this location.</p>
|
|
</div>
|
|
|
|
<!-- ΓöÇΓöÇ TAB: SETTINGS ΓöÇΓöÇ -->
|
|
<div id="tab-settings" class="tab-panel hidden">
|
|
<div class="settings-wrap">
|
|
<div class="saved-wrap">
|
|
<div class="saved-head">
|
|
<span>Saved locations</span>
|
|
<button id="save-current-btn" class="link-btn" type="button">Save current</button>
|
|
</div>
|
|
<div id="saved-locations" class="saved-locations"></div>
|
|
</div>
|
|
|
|
<div class="settings-row">
|
|
<span class="settings-label">Auto-detect location on startup</span>
|
|
<label class="auto-detect-toggle" for="auto-detect-toggle">
|
|
<input id="auto-detect-toggle" type="checkbox" checked>
|
|
<span>Enabled</span>
|
|
</label>
|
|
</div>
|
|
|
|
<div class="settings-row">
|
|
<span class="settings-label">Data source location</span>
|
|
<span id="settings-location" class="settings-value">--</span>
|
|
</div>
|
|
|
|
<div class="settings-row">
|
|
<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">Lightning strikes on map</span>
|
|
<label class="toggle-label" for="lightning-toggle">
|
|
<input id="lightning-toggle" type="checkbox">
|
|
<span id="lightning-status">Off</span>
|
|
</label>
|
|
</div>
|
|
|
|
<div class="settings-row">
|
|
<span class="settings-label">Wind overlay on map</span>
|
|
<label class="toggle-label" for="wind-toggle">
|
|
<input id="wind-toggle" type="checkbox">
|
|
<span id="wind-status">Off</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div><!-- .app -->
|
|
|
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
|
<script src="app.js"></script>
|
|
<script>
|
|
if ('serviceWorker' in navigator) {
|
|
navigator.serviceWorker.register('/sw.js');
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|