diff --git a/.gitignore b/.gitignore index 8ee54e8..9f860c6 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ coverage *.sw? *.tsbuildinfo +*~ diff --git a/CHANGELOG.md b/CHANGELOG.md index bf57eca..db28db8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.1.11 - 2025-10-06 +### Changed +- update source code info for about page + +## 0.1.10 - 2024-06-09 +### Changed +- Fix URL bug when refreshing weather radar. + +## 0.1.9 - 2024-06-09 +### Changed +- Warning notification should not butt up against forecast panel. +- Add timestamp param to bust cache when refreshing radar images. + +## 0.1.8 - 2024-06-09 +### Added +- Add link to national radar map (live image). +- Add refresh buttons to weather data pages. +### Changed +- Convert all view components to use Composition API. + +## 0.1.7 - 2024-06-08 +### Added +- Add basic support for active weather alerts. + ## 0.1.6 - 2024-06-08 ### Changed - Add proper About page. diff --git a/package-lock.json b/package-lock.json index da7cc0b..8dc30e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "myweather", - "version": "0.1.6", + "version": "0.1.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "myweather", - "version": "0.1.6", + "version": "0.1.11", "dependencies": { "@fortawesome/fontawesome-svg-core": "^6.5.2", "@fortawesome/free-solid-svg-icons": "^6.5.2", diff --git a/package.json b/package.json index c12ea00..46a5d15 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "myweather", - "version": "0.1.6", + "version": "0.1.11", "private": true, "type": "module", "scripts": { diff --git a/src/router/index.js b/src/router/index.js index 464d998..7430367 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -1,6 +1,7 @@ import { createRouter, createWebHistory } from 'vue-router' import HomeView from '../views/HomeView.vue' import WeatherView from '../views/WeatherView.vue' +import AlertsView from '../views/AlertsView.vue' import HourlyView from '../views/HourlyView.vue' import EditListView from '../views/EditListView.vue' @@ -17,6 +18,11 @@ const router = createRouter({ name: 'weather', component: WeatherView, }, + { + path: '/alerts', + name: 'alerts', + component: AlertsView, + }, { path: '/hourly', name: 'hourly', diff --git a/src/stores/weather.js b/src/stores/weather.js index c8c91ab..f02e4a9 100644 --- a/src/stores/weather.js +++ b/src/stores/weather.js @@ -10,6 +10,7 @@ const getDefaults = () => { coordinates, cityState, weather: null, + alerts: null, forecast: null, radarLatestURL: null, radarLoopURL: null, @@ -25,21 +26,26 @@ export const useWeatherStore = defineStore('weather', { actions: { - clearWeather() { - this.setCoordinates(null) - this.setCityState(null) + clearWeather(keepCoordinates) { + if (!keepCoordinates) { + this.setCoordinates(null) + this.setCityState(null) + } this.setWeather(null) this.setForecast(null) this.radarLatestURL = null this.radarLoopURL = null + this.alerts = null }, async getWeather() { if (!this.weather) { + let url + let response - const url = `https://api.weather.gov/points/${this.coordinates}` - const response = await fetch(url) + url = `https://api.weather.gov/points/${this.coordinates}` + response = await fetch(url) const weather = await response.json() if (weather.status == 404) { throw new Error(`Data not found for ${this.coordinates}`) @@ -57,6 +63,65 @@ export const useWeatherStore = defineStore('weather', { this.radarLoopURL = `https://radar.weather.gov/ridge/standard/${station}_loop.gif` this.setWeather(weather) + + // fetch zone to get its official id + url = weather.properties.forecastZone + response = await fetch(url) + const zone = await response.json() + + // fetch alerts for zone + url = `https://api.weather.gov/alerts/active/zone/${zone.properties.id}` + response = await fetch(url) + const zoneAlerts = await response.json() + + // fetch county to get its official id + url = weather.properties.county + response = await fetch(url) + const county = await response.json() + + // fetch alerts for county + url = `https://api.weather.gov/alerts/active/zone/${county.properties.id}` + response = await fetch(url) + const countyAlerts = await response.json() + + const newAlerts = {} + + // use latest timestamp from either zone or county + newAlerts.updated = zoneAlerts.updated + if (countyAlerts.updated > zoneAlerts.updated) { + newAlerts.updated = countyAlerts.updated + } + + // collect all alert "features" but de-duplicate them + newAlerts.features = {} + for (let feature of zoneAlerts.features) { + newAlerts.features[feature.properties.id] = feature + } + for (let feature of countyAlerts.features) { + newAlerts.features[feature.properties.id] = feature + } + newAlerts.features = Object.values(newAlerts.features) + + // put "likely" before "possible" alerts + newAlerts.features.sort((a, b) => { + + if (a.properties.certainty == 'Likely' && b.properties.certainty != 'Likely') { + return -1 + } + if (a.properties.certainty != 'Likely' && b.properties.certainty == 'Likely') { + return 1 + } + + // if (a.properties.certainty == b.properties.certainty) { + // return 0 + // } + + // TODO: what else should this do? + return 0 + }) + + // we have our final alerts + this.alerts = newAlerts } return this.weather @@ -66,7 +131,7 @@ export const useWeatherStore = defineStore('weather', { if (!this.forecast) { - const weather = await this.getWeather(this.coordinates) + const weather = await this.getWeather() const url = weather.properties.forecast const response = await fetch(url) diff --git a/src/views/AboutView.vue b/src/views/AboutView.vue index f04a514..c1deb33 100644 --- a/src/views/AboutView.vue +++ b/src/views/AboutView.vue @@ -2,17 +2,6 @@ import appsettings from '../appsettings' - -