95 lines
3.4 KiB
Vue
95 lines
3.4 KiB
Vue
<script setup lang="ts">
|
||
import Loading from '@/components/Loading.vue';
|
||
import {formatDate} from '@ztimson/utils';
|
||
import {onMounted, ref} from 'vue';
|
||
import {api, BASE} from '../services/api';
|
||
|
||
const days = ref<any[]>()
|
||
const filler = [1, 2, 3, 4, 5];
|
||
|
||
function dir(deg: number) {
|
||
if(deg > 22.5 && deg <= 67.5) return 'NE';
|
||
if(deg > 67.5 && deg <= 112.5) return 'E';
|
||
if(deg > 112.5 && deg <= 157.5) return 'SE';
|
||
if(deg > 157.5 && deg <= 202.5) return 'S';
|
||
if(deg > 202.5 && deg <= 247.5) return 'SW';
|
||
if(deg > 247.5 && deg <= 292.5) return 'W';
|
||
if(deg > 292.5 && deg <= 337.5) return 'NW';
|
||
return 'N';
|
||
}
|
||
|
||
onMounted(async () => {
|
||
const start = new Date(), end = new Date();
|
||
start.setDate(start.getDate() + 1);
|
||
end.setDate(end.getDate() + 5);
|
||
days.value = await api.daily(start, end);
|
||
})
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.forecast-wrap {
|
||
width: 100%;
|
||
}
|
||
|
||
.strip {
|
||
display: flex;
|
||
gap: 8px;
|
||
overflow-x: auto;
|
||
padding-bottom: 6px;
|
||
width: 100%;
|
||
}
|
||
|
||
.day {
|
||
flex: 0 0 100px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 4px;
|
||
padding: 10px 8px;
|
||
border-radius: 10px;
|
||
background: var(--surface);
|
||
border: 1px solid var(--border);
|
||
}
|
||
|
||
.day-name { font-size: 10px; color: var(--text-muted); font-weight: 600; text-transform: uppercase; text-align: center; }
|
||
.day-icon { width: 36px; height: 36px; object-fit: contain; }
|
||
.day-label { font-size: 10px; color: var(--text-muted); text-align: center; line-height: 1.2; }
|
||
.day-temps { display: flex; gap: 6px; font-size: 13px; font-weight: 600; color: var(--text); }
|
||
.day-low { color: var(--text-muted); font-weight: 400; }
|
||
.day-humid { font-size: 11px; color: var(--text-muted); }
|
||
.day-wind { font-size: 11px; color: var(--text-muted); }
|
||
.day-rain { font-size: 11px; color: var(--text-muted); }
|
||
.day-precip { font-size: 9px; color: var(--text-muted); }
|
||
</style>
|
||
|
||
<template>
|
||
<div class="forecast-wrap">
|
||
<div v-if="days?.length" class="strip">
|
||
<div v-for="d in days" class="day">
|
||
<div class="day-name">{{ formatDate('ddd, MMM D', d.time) }}</div>
|
||
<img :src="BASE + '/api/icon/' + d.icon" class="day-icon" :alt="(d.label?.toString() || '')" />
|
||
<div class="day-label">{{ d.label }}</div>
|
||
<div class="day-temps">
|
||
<span>↑{{ ~~(d.temperature_max) + '°' || '—' }}</span>
|
||
<span class="day-low">↓{{ ~~(d.temperature_min) + '°' || '—' }}</span>
|
||
</div>
|
||
<div class="day-humid align-x">🌡️ {{ ~~(d.humidity) || 0 }}%</div>
|
||
<div class="day-wind align-x">🍃 {{ ~~(d.wind_gusts as any) || 0 }} Kph ({{dir(d.wind_dir as any)}})</div>
|
||
<div class="day-rain align-x">🌧️ {{ d.precipitation_chance || 0 }}% ({{ (d.precipitation as any || 0).toFixed(1) }}mm)</div>
|
||
</div>
|
||
</div>
|
||
<div v-else class="strip">
|
||
<div v-for="d in filler" class="day">
|
||
<div class="br-2 overflow-hidden pos-rel my-2" style="height: 50px; width: 50px;"><Loading /></div>
|
||
<div class="day-temps mb-2">
|
||
<div class="br-2 overflow-hidden pos-rel" style="width: 50px; height: 1em"><Loading/></div>
|
||
<div class="br-2 overflow-hidden pos-rel" style="width: 50px; height: 1em"><Loading/></div>
|
||
</div>
|
||
<div class="w-100 br-2 overflow-hidden pos-rel mb-2" style="height: 1em"><Loading/></div>
|
||
<div class="w-100 br-2 overflow-hidden pos-rel mb-2" style="height: 1em"><Loading/></div>
|
||
<div class="w-100 br-2 overflow-hidden pos-rel mb-2" style="height: 1em"><Loading/></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|