myweather/src/views/WeatherView.vue
2024-06-09 19:32:17 -05:00

214 lines
5.4 KiB
Vue

<script setup>
import { ref, computed, onActivated } from 'vue'
import { useRouter } from 'vue-router'
import { useWeatherStore } from '../stores/weather'
import { useLocationStore } from '../stores/location'
const router = useRouter()
const locationStore = useLocationStore()
const weatherStore = useWeatherStore()
const coordinates = ref(null)
const refreshing = ref(false)
const timestamp = ref(new Date().getTime())
const panelHeadingTitle = computed(() => {
if (!weatherStore.forecast) {
return "Forecast"
}
let generated = new Date(weatherStore.forecast.properties.generatedAt)
generated = generated.toLocaleTimeString('en-US', {timeStyle: 'short'})
return `Forecast @ ${generated}`
})
const radarLatestURL = computed(() => {
if (weatherStore.weather) {
return `${weatherStore.radarLatestURL}?t=${timestamp.value}`
}
})
const radarLoopURL = computed(() => {
if (weatherStore.weather) {
return `${weatherStore.radarLoopURL}?t=${timestamp.value}`
}
})
onActivated(() => {
if (!weatherStore.coordinates) {
router.push('/')
return
}
refreshing.value = true
fetchWeather().then(() => {
refreshing.value = false
})
})
async function coordinatesUpdated(coords) {
refreshing.value = true
weatherStore.clearWeather()
weatherStore.setCoordinates(coords)
await fetchWeather()
refreshing.value = false
}
async function fetchWeather() {
await weatherStore.getForecast()
coordinates.value = weatherStore.coordinates
}
async function refreshWeather() {
refreshing.value = true
weatherStore.clearWeather(true)
timestamp.value = new Date().getTime()
await fetchWeather()
refreshing.value = false
}
function getShortForecast(period) {
return period.shortForecast.replace(/Showers And Thunderstorms/g, 'T-storms')
}
function showHourly(period) {
router.push('/hourly')
}
</script>
<template>
<main>
<div style="display: flex; flex-direction: column;">
<div class="block"
style="display: flex; justify-content: space-between; align-items: center;">
<o-select v-if="weatherStore.weather"
v-model="coordinates"
@update:model-value="coordinatesUpdated">
<option v-for="location in locationStore.locations"
:key="location.coordinates"
:value="location.coordinates">
{{ location.cityState }}
</option>
</o-select>
<o-button variant="primary"
icon-left="refresh"
@click="refreshWeather()"
:disabled="refreshing">
{{ refreshing ? "Refreshing" : "Refresh" }}
</o-button>
</div>
<div v-if="weatherStore.alerts?.features?.length"
class="block">
<o-notification variant="warning"
icon="warning"
@click="$router.push('/alerts')"
style="cursor: pointer;">
<p class="has-text-weight-bold">Watches In Effect</p>
<p>Updated {{ new Date(weatherStore.alerts.updated).toLocaleTimeString('en-US', {timeStyle: 'short'}) }}</p>
</o-notification>
</div>
<nav class="panel weather-panel">
<p class="panel-heading">
{{ panelHeadingTitle }}
</p>
<div class="panel-block">
<div v-if="weatherStore.forecast"
style="display: flex; overflow-x: scroll;">
<div v-for="period in weatherStore.forecast.properties.periods"
:key="period.number"
class="weather-period is-size-7 has-text-weight-bold"
:class="{daytime: period.isDaytime}"
style="cursor: pointer;"
@click="showHourly(period)">
<p>{{ period.name }}</p>
<div>
<img :src="period.icon" />
</div>
<p>{{ getShortForecast(period) }}</p>
<p>
<span v-if="period.isDaytime">Hi</span>
<span v-else>Lo</span>
{{ period.temperature }} &deg; {{ period.temperatureUnit }}
</p>
</div>
</div>
<div v-if="!weatherStore.forecast">
fetching weather data...
</div>
</div>
</nav>
<nav class="panel weather-panel">
<div class="panel-heading"
style="display: flex; align-items: center; justify-content: space-between;">
<p>Radar</p>
<o-button tag="a"
href="https://radar.weather.gov/ridge/standard/CONUS-LARGE_loop.gif"
target="_blank"
icon-left="external-link">
National Radar
</o-button>
</div>
<div class="panel-block">
<div class="columns">
<div class="column">
<img :src="radarLatestURL" />
</div>
<div class="column">
<img :src="radarLoopURL" />
</div>
</div>
</div>
</nav>
</div>
</main>
</template>
<style scoped>
.weather-period {
width: 100px;
flex-shrink: 0;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
background-color: gray;
color: white;
padding: 0.5rem;
}
.weather-period.daytime {
background-color: white;
color: black;
}
</style>