187 lines
3.9 KiB
Vue
187 lines
3.9 KiB
Vue
`<script setup lang="ts">
|
|
import GraphModal from '@/components/GraphModal.vue';
|
|
import HourlyForecast from '@/components/HourlyForecast.vue';
|
|
import Moon from '@/components/Moon.vue';
|
|
import Precipitation from '@/components/Precipitation.vue';
|
|
import Seismic from '@/components/Seismic.vue';
|
|
import Sun from '@/components/Sun.vue';
|
|
import Wind from '@/components/Wind.vue';
|
|
import {BASE, useWeather} from '@/services/api.ts';
|
|
import {formatDate} from '@ztimson/utils';
|
|
import {onMounted, onUnmounted, provide, ref} from 'vue';
|
|
import MapView from '../components/MapView.vue';
|
|
import CurrentWeather from '../components/CurrentWeather.vue';
|
|
import ForecastStrip from '../components/ForecastStrip.vue';
|
|
|
|
const day = ref(formatDate('dddd'));
|
|
const date = ref(formatDate('MMMM D'));
|
|
const time = ref(formatDate('h:mm A'));
|
|
const props = defineProps<{dark: boolean}>();
|
|
const selectedMetric = ref<string | null>(null);
|
|
let clock: ReturnType<typeof setInterval>;
|
|
|
|
provide('openGraph', (key: string) => selectedMetric.value = key);
|
|
|
|
onMounted(async () => {
|
|
useWeather();
|
|
clock = setInterval(() => {
|
|
day.value = formatDate('dddd');
|
|
date.value = formatDate('MMMM D');
|
|
time.value = formatDate('h:mm A');
|
|
}, 1000);
|
|
});
|
|
|
|
onUnmounted(() => {
|
|
clearInterval(clock);
|
|
});
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.dashboard {
|
|
display: flex;
|
|
height: 100vh;
|
|
overflow: hidden;
|
|
background: var(--bg);
|
|
color: var(--text);
|
|
}
|
|
|
|
.map-col {
|
|
flex: 1;
|
|
min-width: 0;
|
|
padding: 16px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.panel-col {
|
|
width: 380px;
|
|
padding: 16px;
|
|
overflow-y: auto;
|
|
border-left: 1px solid var(--border);
|
|
|
|
&::-webkit-scrollbar {
|
|
width: 4px;
|
|
}
|
|
|
|
&::-webkit-scrollbar-thumb {
|
|
background: var(--border);
|
|
border-radius: 2px;
|
|
}
|
|
}
|
|
|
|
.group-label {
|
|
font-size: 10px;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.1em;
|
|
color: var(--text-muted);
|
|
margin-top: 4px;
|
|
margin-bottom: 2px;
|
|
padding: 0 2px;
|
|
}
|
|
|
|
.metric-grid {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 8px;
|
|
min-width: 0;
|
|
|
|
> * {
|
|
flex: 1 1 140px; // grow, shrink, min width before wrapping
|
|
min-width: 0;
|
|
}
|
|
}
|
|
|
|
.loading-bar {
|
|
height: 2px;
|
|
background: var(--accent);
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
z-index: 9999;
|
|
animation: pulse 1s infinite;
|
|
}
|
|
|
|
@keyframes pulse {
|
|
0%, 100% {
|
|
opacity: 1;
|
|
}
|
|
50% {
|
|
opacity: 0.4;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.dashboard {
|
|
flex-direction: column;
|
|
overflow-y: auto;
|
|
overflow-x: hidden; // ← added
|
|
height: 100dvh;
|
|
}
|
|
|
|
.map-col {
|
|
width: 100%;
|
|
height: 100vw;
|
|
min-height: 100vw;
|
|
padding: 8px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.panel-col {
|
|
width: 100%;
|
|
flex-shrink: 0;
|
|
border-left: none;
|
|
border-top: 1px solid var(--border);
|
|
overflow-y: visible;
|
|
overflow-x: hidden; // ← added
|
|
-webkit-overflow-scrolling: touch;
|
|
box-sizing: border-box; // ← added
|
|
|
|
&::before {
|
|
display: none;
|
|
}
|
|
|
|
&::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<template>
|
|
<div class="dashboard">
|
|
<div class="map-col">
|
|
<MapView :dark="props.dark"/>
|
|
</div>
|
|
|
|
<div class="panel-col">
|
|
<div class="flex-r align-items-center gap-3 mb-3">
|
|
<div class="pe-3" style="border-right: 2px solid var(--border)">
|
|
<h2 class="fs-6 m-0" style="line-height: 1em">{{time}}</h2>
|
|
</div>
|
|
<div class="flex-c">
|
|
<h1 class="m-0 fs-2" style="line-height: 1em">{{day}}</h1>
|
|
<h2 class="m-0 fs-1 fg-muted" style="line-height: 1em">{{date}}</h2>
|
|
</div>
|
|
</div>
|
|
<CurrentWeather class="mb-3" />
|
|
<HourlyForecast class="mb-3" />
|
|
<ForecastStrip class="mb-3" />
|
|
|
|
<Seismic class="mb-3" />
|
|
<Precipitation class="mb-3" />
|
|
<Wind class="mb-3" />
|
|
<Sun class="mb-3" />
|
|
<Moon class="mb-3" />
|
|
|
|
<div class="align-x">
|
|
<a :href="BASE + '/docs'" style="font-size: 0.75em;" target="_blank">OpenAPI Docs</a> | <a href="https://zakscode.com" style="font-size: 0.75em;" target="_blank">ZaksCode</a>
|
|
</div>
|
|
</div>
|
|
|
|
<GraphModal :metric-key="selectedMetric" @close="selectedMetric = null" />
|
|
</div>
|
|
</template>
|
|
`
|