Commit Graph
113 Commits
Author SHA1 Message Date
Nate EmmertandClaude Sonnet 5.5 27106a2eab Dashboard Records tab: plain-language records
Publish Container / publish (push) Successful in 3m8s
Replaces the collapsed panel of look-alike cards with a guided view: an intro explaining what a record is
(and that records are 'so far' with a 12-month coverage strip), cards grouped by theme with a plain
explanation, date/time, how long ago, descriptors (gust/UV/rain intensity), today-vs-record and
next-closest days, NEW badges for records set in the last 14 days, one month-by-month table with
temperature-range and rain bars (latest 12, show all), and year / same-month tables only when
there is more than a year of data. Removes duplicate cards and the redundant Monthly Summary panel.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 10:56:01 -04:00
Nate EmmertandClaude Sonnet 5.5 9515d1af00 Dashboard coverage: count 5-minute slots with data, not readings vs the recent interval
Publish Container / publish (push) Successful in 2m29s
Coverage divided each day's reading count by 1440/median-recent-interval, so days logged at a
slower pace (100 s, 120 s) showed as 50-60% complete once uploads sped up to 60 s. Each day now
records which of its 288 five-minute slots have a reading (backfilled from raw files on startup),
so coverage is independent of upload interval. Older days without slot data fall back to the old maths.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 10:46:44 -04:00
Nate EmmertandClaude Sonnet 5.5 b8ce8ce149 Account page: add Settings link
Publish Container / publish (push) Successful in 2m44s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-16 07:35:33 -04:00
Nate EmmertandClaude Sonnet 5.5 dee245ea27 Dashboard: always show Settings link; non-admins get an explanation of their role
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-16 07:34:32 -04:00
Nate EmmertandClaude Sonnet 5.5 2efc945192 Radar: switch to RainViewer (IEM blocks heavy tile use), cleaner Map tab
Publish Container / publish (push) Successful in 2m40s
- /api/radar/times serves RainViewer frames (cached 2 min), IEM NEXRAD only as fallback;
  sources honour maxNativeZoom so tiles overzoom instead of going blank
- Map tab opens with radar + location dot only; wind/AQI/alerts/temp/sun/lightning are opt-in,
  readout chips follow their toggles
- Bolder location dot
- Satellite (GIBS) layer: new storage key, never persisted by storm taps, radar always draws above it

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 16:38:00 -04:00
Nate EmmertandClaude Sonnet 5.5 13985344ed Storm cards show live GOES infrared satellite; replace the dead RainViewer satellite toggle
Publish Container / publish (push) Successful in 2m19s
RainViewer's satellite feed is empty, so the Clouds toggle never drew anything and ground
radar doesn't reach open ocean. Use NASA GIBS GOES-West/East infrared tiles instead,
auto-enabled when flying to a storm, default off otherwise.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 16:01:03 -04:00
Nate EmmertandClaude Sonnet 5.5 a185d10e1c Fix storm cards not flying to the storm: stop waiting on the one-shot map 'load' event
Publish Container / publish (push) Successful in 2m34s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 15:52:59 -04:00
Nate EmmertandClaude Sonnet 5.5 fda8dca435 Performance: stop iPhone freezes (blur over live map, runaway animation, eager charts)
Publish Container / publish (push) Successful in 2m57s
Main app
- No backdrop-filter over the live map, animated sky, or sticky headings (it re-blurs every
  frame; on iPhone that is a classic stutter/lock-up); top/bottom bars keep a light 8px blur
- Sky effect only draws while the hero is on screen and the Now tab is active, ~30fps cap,
  fewer particles on phones; fixed a stale animation-frame id that could stop restarts

Dashboard
- Charts are built only when the Charts tab is opened (was ~11 charts on every page load),
  and the 2-minute refresh no longer rebuilds them in the background
- On phones: max 360 points per chart (was 720), no entry animation, device pixel ratio capped at 2
- Lighter header blur, none on small buttons/cards

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 15:29:14 -04:00
Nate EmmertandClaude Sonnet 5.5 dde59e3865 Station tab: explain what the station is
Publish Container / publish (push) Successful in 2m13s
- 'What is this station?' card: a personal weather station measuring real conditions on site
  (not a forecast), how it differs from the Now tab, update cadence, what Live/Offline mean
- Lists the instruments this station actually reports (temp/humidity, wind, rain, pressure,
  sun, indoor), using the station's real name
- Open for new visitors, remembers once closed; empty state and Now-tab badge/tab hover explain it too

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 15:16:33 -04:00
Nate EmmertandClaude Sonnet 5.5 eaff2f55c8 Location: say why it failed, retry once, show permission status
Publish Container / publish (push) Successful in 2m15s
The ⌖ button reported 'Location access denied' for every failure, including timeouts and
no-GPS-fix errors that have nothing to do with permission.

- Specific messages for denied / no fix / timeout, with the exact iPhone steps (Safari tab vs
  installed web app) and the error code for diagnosis
- One patient high-accuracy retry for slow or cold GPS fixes (a real denial is not retried)
- Live permission status line under the search row (allowed / not asked / blocked)
- Mentions Safari content blockers as a possible cause

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 15:07:19 -04:00
Nate EmmertandClaude Sonnet 5.5 0cbebfef2a Cache-proof asset URLs and inline iOS touch icon
Publish Container / publish (push) Successful in 2m42s
A reverse proxy in front of the app serves stale copies of static files for hours (live app.js and
sw.js were old next to new HTML). iOS also showed a letter tile (N / S) because its separate
icon download failed.

- HTML pages are served through a versioner: every local script/stylesheet/icon/manifest gets a
  content-hash query (app.js?v=…), so any change is a URL no proxy or phone has cached
- Service worker URL versioned too; SW offline lookups tolerate the query string; cache v15
- The 180px apple-touch-icon is embedded in each page as a data: URI, so the Home Screen icon
  no longer depends on a second network request

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 14:33:40 -04:00
Nate EmmertandClaude Sonnet 5.5 f21c91527c Serve PWA icons from fresh /icons/v2/ URLs with every iOS size
Publish Container / publish (push) Successful in 2m43s
iOS showed a letter tile ('N') when adding to the Home Screen. The live files were fine, but a
reverse proxy in front of the app serves static files with a long cache lifetime (live icon.svg
and sw.js were stale) and iOS remembers a failed icon per URL.

- New versioned URLs no proxy/phone has cached; old paths kept for existing installs
- apple-touch-icon declared at 180/167/152/120 (opaque 8-bit RGB PNGs) for app and dashboard
- 180px icon also listed in both manifests; notification icons and root fallbacks use v2
- Service worker cache bumped

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 14:22:05 -04:00
Nate EmmertandClaude Sonnet 5.5 19479daece Dashboard pages: iOS icon + Home Screen title everywhere; root icon fallbacks
Publish Container / publish (push) Successful in 2m11s
- setup/recover/settings pages now declare the dashboard touch icon and 'Station' title
- /apple-touch-icon.png, /apple-touch-icon-precomposed.png and /favicon.ico serve real icons
  (iOS falls back to these when a page declares none; they used to 404/204)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 14:15:19 -04:00
Nate EmmertandClaude Sonnet 5.5 023e6cb03c New PWA icons: slate/blue weather icon, distinct dashboard icon, safe-zone maskable
Publish Container / publish (push) Successful in 1m59s
- Redrawn sun-and-cloud icon in the current palette; artwork sits inside the maskable safe zone
  (the old one was clipped by round/squircle masks and used the old warm colours)
- Separate 'any' and 'maskable' manifest entries; opaque iOS touch icons
- Station Dashboard gets its own chart icon so both installed apps are distinguishable
- Vector favicon + PNG fallback; icons verified served by both manifests

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 14:13:01 -04:00
Nate EmmertandClaude Sonnet 5.5 72a4a3fe38 Alerts tab: fix hurricane/tropical storm bugs; rich alert cards matching the dashboard
Publish Container / publish (push) Successful in 2m44s
Hurricane / tropical storm fixes
- NHC intensity is in knots: show real mph (80 kt = 92 mph) instead of mislabelled 'mph'
- Real Saffir-Simpson category from wind (was always cat 1); subtropical, post-tropical and
  potential-cyclone types no longer shown as 'depression'; each storm shows movement
  (direction + mph, previously a non-existent field), distance from you, update time, advisory link
- Forecast track points coloured by their own forecast strength (not the current class)
- Map click handlers registered once (popups stacked on every refresh); overlays wait for the
  map to settle instead of silently not drawing while tiles load; stale renders superseded
- Subtropical/tropical advice added to alert guidance; escaped storm names

Alert cards (active alerts only)
- What it's for, area, window, time remaining, plain-language meaning, what to do, and a
  Full details expander (headline, text, instructions, severity/urgency/certainty, issuer)
- No longer drops alerts beyond 6 per severity group; expired alerts are filtered out
- Shared plain-language alert glossary (alert-info.js, 64 products incl. tropical and surge)
  now used by both the app and the dashboard history

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 14:00:41 -04:00
Nate EmmertandClaude Sonnet 5.5 8252017417 Map tab: full-bleed map with floating glass controls (Apple Weather style)
Publish Container / publish (push) Successful in 2m58s
- Map fills everything between the top bar and bottom nav; no page scroll on this tab
- Floating round controls (layers, my location, full screen), readout chips top-left,
  layers sheet beside the controls, weather summary + radar timeline floating at the bottom
- Safe-area aware in full-screen mode; zoom buttons tucked away on touch devices

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 13:48:13 -04:00
Nate EmmertandClaude Sonnet 5.5 4f47d67a7e Map tab: much bigger map with its own remembered view
Publish Container / publish (push) Successful in 2m12s
- Map fills the screen (was a 56vh strip); timeline and details sit below it
- No longer snaps back to the main-page radar's location/zoom on every refresh or tab switch;
  starts as a wider regional view, remembers pan/zoom, and recentres only when the location changes
- New 'My location' button

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 13:43:04 -04:00
Nate EmmertandClaude Sonnet 5.5 acdcd6a2c5 Log official NWS observations for a reference ZIP and overlay them on the dashboard
Publish Container / publish (push) Successful in 2m33s
- Resolves ZIP (default 24550) to the nearest NWS observation station; logs every observation
  (normalised imperial values + raw METAR), back-fills ~7 days, snapshots the hourly forecast
  every 3h, and logs alerts for that point
- Chart overlay (temp, humidity/dew point, wind, pressure) with an NWS toggle in the History bar
- 'Official NWS observation' card on the Now tab comparing against your station
- Settings: change the reference ZIP and see logging status
- Exact-unit conversions for NWS values (verified against known conversions)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 13:41:02 -04:00
Nate EmmertandClaude Sonnet 5.5 5ed673bacc Install-as-app guide and iPhone safe-area support
Publish Container / publish (push) Successful in 2m51s
- Install banner (phones), Settings guide and dialog with iPhone/iPad and Android steps,
  native Install button where supported; steps also on the dashboard Account page
- apple-touch-icon now a PNG (iOS ignores SVG icons)
- Shared pwa-safe.css: dark cap behind the status bar/Dynamic Island in the installed app,
  inset-aware offline banner, pull-to-refresh, bottom bars, full-screen map, dialogs
- Landscape-aware content gutters; measured top-bar height; viewport-fit=cover on every page

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 13:34:22 -04:00
Nate EmmertandClaude Sonnet 5.5 114386a1b2 Alert history: say what each alert is for, where, and when
Publish Container / publish (push) Successful in 3m33s
- Plain-language meaning for common NWS products, shown in the row and expanded view
- Details column: reason, area, severity, effective window; click for full text/instructions
- New alerts log area, severity, urgency, certainty and sender
- Older entries are filled in from NWS by alert id (cached in data/alert-details.json);
  alerts NWS no longer serves fall back to the built-in meaning

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 13:28:28 -04:00
Nate EmmertandClaude Sonnet 5.5 72d813bd61 Records: month and year records with the period as the headline
Publish Container / publish (push) Successful in 3m55s
- Wettest/driest/hottest/coldest/windiest month and wettest/hottest/coldest/windiest year,
  each naming the period (e.g. 'September 2026') and flagging partial periods
- Average-based records prefer complete periods; counterparts say what they're waiting for
- 'Records by calendar month (any year)' table with the date/year of each record

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 13:21:55 -04:00
Nate EmmertandClaude Sonnet 5.5 6e285bfef1 Show the first-recorded date on the All history button tooltip
Publish Container / publish (push) Successful in 2m54s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 13:17:46 -04:00
Nate EmmertandClaude Sonnet 5.5 00336c6ce1 Add 'All' history range to the dashboard and pressure tendency chart
Publish Container / publish (push) Successful in 2m45s
- /api/station/history?range=all returns everything on disk, bucketed (cached 60s)
- Year-aware axis labels for 1y/2y/3y/All
- Pressure tendency widens its change window to the bucket size on long ranges and says so

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 13:17:33 -04:00
Nate EmmertandClaude Sonnet 5.5 fc390b0bb1 Pressure tendency chart: own range and change-window controls
Publish Container / publish (push) Successful in 2m28s
Range: same as page / 6h / 24h / 2d / 7d / 30d. Change over: 1h / 3h / 6h / 12h / 24h.
Choices persist in localStorage.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 13:16:05 -04:00
Nate EmmertandClaude Sonnet 5.5 74198330d9 Fix mouse-wheel scrolling in the main app and the dashboard sun arc
Publish Container / publish (push) Successful in 2m55s
- overscroll-behavior moved from <body> to <html>: with html+body both overflow-x:hidden,
  body is a scroll container and the rule blocked wheel scrolling from reaching the page
- sunTimes returned the neighbouring day's sunrise/sunset (julian-day rounding), so midday
  looked like night; align results to the requested local day

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 13:12:41 -04:00
Nate EmmertandClaude Sonnet 5.5 a9fc20cef4 Let the mouse wheel scroll the page over charts and the embedded radar
Publish Container / publish (push) Successful in 3m16s
Chart zoom now needs Ctrl+scroll (or pinch); the embedded radar uses cooperative gestures.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 13:09:19 -04:00
Nate EmmertandClaude Sonnet 5.5 2fb467d2e5 Weather proxy: fall back to the classic request if 15-minute data is rejected
Publish Container / publish (push) Successful in 3m19s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 12:56:31 -04:00
Nate EmmertandClaude Sonnet 5.5 fd61e35b56 Redesign main app: slim top bar, dynamic sky hero, nowcast, scrub chart, unified palette
- One slate/blue palette across the app, dashboard, account/login pages (data colours
  stay orange = warm, blue = cool on the dashboard)
- Slim sticky top bar with location chip, gear (settings) and ? (learn); 4-tab nav
  (Now, Station, Map, Alerts) with a thumb-reach bottom bar on phones
- Hero sky gradient by condition/time with rain, storm, snow and star effects
  (respects reduced motion); keeps the searched city and badges when temps come from your station
- One-line summary, 'Next 2 hours' bars and rain countdown from 15-minute precipitation,
  rain/cold-aware 'Bring' chips; yesterday + 'vs usual' context from the station
- Scrubbable hourly chart (temp, rain chance, wind), 7-day range bars, AQI gauge,
  details tiles instead of drawers, taller radar with location marker + alert polygons
- Skeleton loading instead of a full-screen spinner, sticky section headers, safe areas
- Server: minutely_15 precipitation, public /api/station/summary

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 12:56:18 -04:00
Nate EmmertandClaude Sonnet 5.5 1830fb2e2b Merge /conditions into the app as a Station tab
- New Station tab (top tabs, bottom nav, swipe order) carrying the old /conditions look:
  radar-ring hero, condition pill, wind compass, atmosphere/precip/solar cards, indoor
- Scoped sl-* styles and station-live.js; units follow the app's metric/imperial setting
- Empty/error states when no station is connected
- /conditions now 301-redirects to /?tab=station; removed conditions.html,
  /api/conditions/public and the old My Station drawer
- /api/ambient-config also returns the station name
- Dashboard and settings links updated; SW cache v8; manifest shortcut for Station
- Drops an indoor-temp block in applyStationOverlay that referenced an out-of-scope helper

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 12:45:47 -04:00
Nate EmmertandClaude Sonnet 5.5 7dea2734ea Sessions: 180-day lifetime with sliding renewal
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 12:40:15 -04:00
Nate EmmertandClaude Sonnet 5.5 1566ac2897 Add user management with admin and viewer roles
- data/users.json store; existing single account migrates to first admin
- Roles: admin (settings, import, users) and viewer (read-only, own password)
- Live role/disabled lookup; per-user session epoch so password changes,
  resets and disabling sign that user out everywhere
- Login brute-force lockout (5 fails -> 5 min), constant-time unknown-user check
- /api/users CRUD with last-admin and self-lockout safeguards
- Account page (own password + admin user management); role-aware header
- Min password length 8; recovery token resets the primary admin and clears lockouts

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 12:34:13 -04:00
Nate EmmertandClaude Sonnet 5.5 b3f1061f5c Keep dashboard panels permanently expanded
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 12:27:20 -04:00
Nate EmmertandClaude Sonnet 5.5 1ad2dbb860 Redesign dashboard: tabs, insights, rain, sun/moon, zoomable charts
- Tab bar (bottom nav on phones) splitting Now / Charts / Rain / Records / Insights
- Unified tiles with vs-yesterday deltas, hero 24h trace, wind compass, today hi/lo
- Highlights chips, sun & moon card, station health card
- Charts: min/max envelope for long ranges (server-side bucketing), pinch/wheel zoom,
  pressure tendency, indoor vs outdoor, clear-sky solar overlay
- Rain tab: daily + cumulative, monthly totals; calendar heatmaps (temp/rain/gust)
- Insights: period trends, station normals, diurnal range, coverage, seasonal wind roses
- Server: /api/station/daily, history ?points= bucketing, 2d range, daily avg + wind
  histogram aggregates; fix dry days never recording rain=0

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 12:25:08 -04:00
Nate EmmertandClaude Sonnet 5.5 a97d104d14 Persistent station records, backups, and iPhone-friendly dashboard
- Keep per-day extremes in data/records.json (merge-only) and derive all-time,
  notable-day, monthly and yearly records from it; rebuild from raw files at startup
- Use station maxdailygust for true gust extremes
- Add /api/station/backup.jsonl, records-backup.json and records/rebuild
- Dashboard: safe-area insets, 44px touch targets, scrollable nav/range bars,
  chart touch-action, standalone PWA manifest + apple meta tags

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 12:14:25 -04:00
Nate EmmertandClaude Sonnet 5.5 4c2c619fb6 Dedupe station readings and group rain stats by local day
- Share a disk-backed per-day dateutc set between live recorder and backfill
- Validate timestamps before saving; dedupe existing files at startup and on read
- Use station-local day (not UTC) for rain totals, streaks, degree days and
  monthly summary so dailyrainin resets line up (Sept rain was 4.37in vs 2.24in)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 12:10:11 -04:00
Nate EmmertandClaude Sonnet 5.5 528dec753d Make dashboard alerts short with click-to-expand full details
Publish Container / publish (push) Successful in 2m50s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 11:45:50 -04:00
Nate EmmertandClaude Sonnet 4.6 fc93079109 Fix hurricane overlay ordering and map-load guard
Publish Container / publish (push) Successful in 2m52s
- Move renderHurricaneOverlay call to after track layers so position
  circles render on top of the track line and dots
- Add map.loaded() guard to avoid overlay being silently skipped
  if the map style hasn't finished initializing

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-02 10:19:18 -04:00
Nate EmmertandClaude Sonnet 4.6 3af4c1df4b Add NHC forecast track to hurricane click-to-map
Publish Container / publish (push) Successful in 2m6s
- Parse NHC forecast advisory text (FORECAST VALID / OUTLOOK VALID lines)
  to extract real forecast positions at 9–117h intervals with wind speeds
- Render forecast track as dashed line + clickable dots (wind on click)
- Auto-fit map bounds to show the full 5-day track after loading
- Fix buildStyle to use OpenFreeMap vector tile URLs without API key

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-02 10:11:22 -04:00
Nate EmmertandClaude Sonnet 4.6 8b9d3639af Fix map basemap tiles and add hurricane click-to-map feature
Publish Container / publish (push) Successful in 2m18s
- Replace CARTO basemap tiles (now require API key) with OpenFreeMap
  vector tiles (positron for light, liberty for dark) — no key needed
- Add click handlers on hurricane panel cards to fly to storm on map
- Add flyToHurricane(): switches to map tab, enables hurricane overlay,
  flies to storm coords, shows popup with storm details
- Add /api/hurricanes/track proxy to fetch NHC GIS 5-day forecast track
  line and render it as a dashed overlay on the map

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-02 09:52:35 -04:00
Nate EmmertandClaude Sonnet 4.6 de9cb41d8b Log NWS alerts to history regardless of push subscribers
Publish Container / publish (push) Successful in 2m55s
The alert history log was only populated inside the subscriber loop,
so it stayed empty when no push subscriptions existed. Now the cron
always checks and logs active NWS alerts for the dashboard location
before the subscriber early-return.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-02 08:37:14 -04:00
Nate EmmertandClaude Sonnet 4.6 5f7e490a6e Fix NWS alerts not showing when no location is configured
Publish Container / publish (push) Successful in 1m55s
- Show a prompt linking to Settings instead of silently hiding the
  alerts section when no lat/lon is saved
- Clear the alert cache when location is saved so alerts appear
  immediately without waiting for the 5-minute cache to expire

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-02 08:20:31 -04:00
Nate EmmertandClaude Sonnet 4.6 47f60e72f7 Move all settings to dedicated /dashboard/settings page
Publish Container / publish (push) Successful in 2m22s
Extracts API keys, alert thresholds, station name/location, data
export/import, and password change into a standalone settings page.
Dashboard gains a Settings nav link; the accordion at the bottom
is removed along with its now-orphaned JS and CSS.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-02 08:08:16 -04:00
Nate EmmertandClaude Sonnet 4.6 97dfae86ab Add alert history dashboard endpoint and UI panel
Publish Container / publish (push) Successful in 2m33s
GET /api/dashboard/alert-history?days=N reads daily .jsonl files from
data/alerts/ and returns entries newest-first. Dashboard gets a lazy-loaded
collapsible panel with a table showing time, type (NWS/threshold badge),
event name, and details, with 7d/30d/90d range selector.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-02 08:01:41 -04:00
Nate EmmertandClaude Sonnet 4.6 926f280a28 Add persistent alert history log to data/alerts/
Publish Container / publish (push) Successful in 2m55s
NWS alerts and all threshold firings are now appended to daily .jsonl
files in data/alerts/ (same pattern as data/station/). NWS alerts are
deduplicated by alert ID across subscribers to avoid duplicate log lines.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-02 07:59:58 -04:00
Nate EmmertandClaude Sonnet 4.6 826bb0f606 Add comprehensive dashboard polish: animations, blur, gradients, skeleton
Visual enhancements:
- Sticky header: backdrop-filter blur + box-shadow on scroll
- Live green pulsing dot next to Updated timestamp
- Section cards: gradient border (accent→border→cool via padding-box trick)
- Stat tiles: hover lift (translateY -2px + shadow)
- Skeleton shimmer on all stat tiles until first data arrives
- Value flash animation (fade+slide up) on every data refresh
- Hero temperature: count-up animation when value changes
- Fix set() to preserve trend arrow spans (was being wiped by textContent=)
- Wind rose petals: entrance animation growing in over 650ms
- Chart cards + today bar: hover lift
- Records panel: gold border + ★ badge on records set within last 30 days
- Range/refresh/settings buttons: already had press+glow from prior commit

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-24 16:03:19 -04:00
Nate EmmertandClaude Sonnet 4.6 70eda46b85 Apply button polish to all dashboard interactive elements
Range buttons, refresh, and settings action buttons now get:
- backdrop-filter: blur(10px) frosted glass base
- cubic-bezier(.2,0,0,1) iOS-style easing
- box-shadow glow ring on hover
- scale(0.95) press effect on :active

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-24 15:54:34 -04:00
Nate EmmertandClaude Sonnet 4.6 344f0dd48e Add press effect, glow, arrow slide, easing, and backdrop blur to nav buttons
- :active scale(0.95) press feel on all nav buttons
- box-shadow glow ring on hover (accent @ 20% opacity)
- cubic-bezier(.2,0,0,1) iOS-style snap easing on all transitions
- backdrop-filter: blur(10px) frosted glass base on all buttons
- Dashboard → arrow wraps in <span class="arr"> and slides 2px right on hover

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-24 15:51:37 -04:00
Nate EmmertandClaude Sonnet 4.6 3c927b3e27 Use semi-transparent accent fill on nav button hover
color-mix(accent 18%, transparent) keeps text readable and gives a
ghost-button tint instead of a full solid fill.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-24 15:49:03 -04:00
Nate EmmertandClaude Sonnet 4.6 e4a5a9c4bb Style nav links as buttons across all three pages
Replace plain text/opacity links with bordered pill buttons that fill
with accent color on hover — consistent across main app, conditions,
and dashboard headers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-24 15:47:01 -04:00
Nate EmmertandClaude Sonnet 4.6 f67e38857e Improve navigation between main app, conditions, and dashboard
- Main app: split tagline into attribution + Station/Dashboard nav pills (always visible, styled with border/hover)
- Conditions page: add Dashboard → link and ← App back-link in header
- Dashboard: add Conditions link, rename App → ← Weather in header nav

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-24 15:43:26 -04:00