refactor part 1
This commit is contained in:
@@ -1,23 +1,36 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, onUnmounted, ref, computed } from 'vue'
|
||||
import { current, hourly, daily, fetchAll, loading } from '../services/weather'
|
||||
import { METRICS, GROUPS } from '../services/units'
|
||||
import MapView from '../components/MapView.vue'
|
||||
import CurrentWeather from '../components/CurrentWeather.vue'
|
||||
import ForecastStrip from '../components/ForecastStrip.vue'
|
||||
import MetricCard from '../components/MetricCard.vue'
|
||||
import GraphModal from '../components/GraphModal.vue'
|
||||
`<script setup lang="ts">
|
||||
import {formatDate} from '@ztimson/utils';
|
||||
import {onMounted, onUnmounted, ref, computed} from 'vue';
|
||||
import {current, hourly, daily, fetchAll, loading} from '../services/weather';
|
||||
import {METRICS, GROUPS} from '../services/units';
|
||||
import MapView from '../components/MapView.vue';
|
||||
import CurrentWeather from '../components/CurrentWeather.vue';
|
||||
import ForecastStrip from '../components/ForecastStrip.vue';
|
||||
import MetricCard from '../components/MetricCard.vue';
|
||||
import GraphModal from '../components/GraphModal.vue';
|
||||
|
||||
const props = defineProps<{ dark: boolean }>()
|
||||
const selectedMetric = ref<string | null>(null)
|
||||
let interval: ReturnType<typeof setInterval>
|
||||
const day = ref();
|
||||
const date = ref();
|
||||
const time = ref();
|
||||
const props = defineProps<{dark: boolean}>();
|
||||
const selectedMetric = ref<string | null>(null);
|
||||
let interval: ReturnType<typeof setInterval>;
|
||||
let clock: ReturnType<typeof setInterval>;
|
||||
|
||||
onMounted(async () => {
|
||||
await fetchAll()
|
||||
interval = setInterval(fetchAll, 60 * 1000)
|
||||
})
|
||||
clock = setInterval(() => {
|
||||
day.value = formatDate('dddd');
|
||||
date.value = formatDate('MMMM D');
|
||||
time.value = formatDate('h:mm A');
|
||||
}, 1000);
|
||||
await fetchAll();
|
||||
interval = setInterval(fetchAll, 60 * 1000);
|
||||
});
|
||||
|
||||
onUnmounted(() => clearInterval(interval))
|
||||
onUnmounted(() => {
|
||||
clearInterval(clock);
|
||||
clearInterval(interval);
|
||||
});
|
||||
|
||||
const groupedMetrics = computed(() => {
|
||||
return GROUPS.map(group => ({
|
||||
@@ -25,8 +38,8 @@ const groupedMetrics = computed(() => {
|
||||
keys: Object.entries(METRICS)
|
||||
.filter(([key, meta]) => meta.group === group && current.value[key] != null)
|
||||
.map(([key]) => key)
|
||||
})).filter(g => g.keys.length > 0)
|
||||
})
|
||||
})).filter(g => g.keys.length > 0);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@@ -56,8 +69,14 @@ const groupedMetrics = computed(() => {
|
||||
overflow-y: auto;
|
||||
border-left: 1px solid var(--border);
|
||||
|
||||
&::-webkit-scrollbar { width: 4px; }
|
||||
&::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
|
||||
&::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: var(--border);
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.group-label {
|
||||
@@ -78,7 +97,7 @@ const groupedMetrics = computed(() => {
|
||||
min-width: 0;
|
||||
|
||||
> * {
|
||||
flex: 1 1 140px; // grow, shrink, min width before wrapping
|
||||
flex: 1 1 140px; // grow, shrink, min width before wrapping
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
@@ -87,21 +106,27 @@ const groupedMetrics = computed(() => {
|
||||
height: 2px;
|
||||
background: var(--accent);
|
||||
position: fixed;
|
||||
top: 0; left: 0; right: 0;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 9999;
|
||||
animation: pulse 1s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.4; }
|
||||
0%, 100% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.4;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.dashboard {
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden; // ← added
|
||||
overflow-x: hidden; // ← added
|
||||
height: 100dvh;
|
||||
}
|
||||
|
||||
@@ -119,46 +144,61 @@ const groupedMetrics = computed(() => {
|
||||
border-left: none;
|
||||
border-top: 1px solid var(--border);
|
||||
overflow-y: visible;
|
||||
overflow-x: hidden; // ← added
|
||||
overflow-x: hidden; // ← added
|
||||
-webkit-overflow-scrolling: touch;
|
||||
box-sizing: border-box; // ← added
|
||||
box-sizing: border-box; // ← added
|
||||
|
||||
&::before { display: none; }
|
||||
&::-webkit-scrollbar { display: none; }
|
||||
&::before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<div class="dashboard">
|
||||
<div v-if="loading" class="loading-bar" />
|
||||
<div class="dashboard">
|
||||
<div v-if="loading" class="loading-bar"/>
|
||||
|
||||
<div class="map-col">
|
||||
<MapView :dark="props.dark" />
|
||||
</div>
|
||||
<div class="map-col">
|
||||
<MapView :dark="props.dark"/>
|
||||
</div>
|
||||
|
||||
<div class="panel-col">
|
||||
<CurrentWeather :data="current" />
|
||||
<ForecastStrip :days="daily" />
|
||||
<div class="panel-col">
|
||||
<div class="flex-r align-items-center gap-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 />
|
||||
<ForecastStrip :days="daily"/>
|
||||
|
||||
<template v-for="g in groupedMetrics" :key="g.group">
|
||||
<div class="group-label">{{ g.group }}</div>
|
||||
<div class="metric-grid">
|
||||
<MetricCard
|
||||
v-for="key in g.keys"
|
||||
:key="key"
|
||||
:metric-key="key"
|
||||
:data="current"
|
||||
@click="selectedMetric = key"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<template v-for="g in groupedMetrics" :key="g.group">
|
||||
<div class="group-label">{{ g.group }}</div>
|
||||
<div class="metric-grid">
|
||||
<MetricCard
|
||||
v-for="key in g.keys"
|
||||
:key="key"
|
||||
:metric-key="key"
|
||||
:data="current"
|
||||
@click="selectedMetric = key"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<GraphModal
|
||||
:metric-key="selectedMetric"
|
||||
:current-data="current"
|
||||
@close="selectedMetric = null"
|
||||
/>
|
||||
</div>
|
||||
<GraphModal
|
||||
:metric-key="selectedMetric"
|
||||
:current-data="current"
|
||||
@close="selectedMetric = null"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
`
|
||||
|
||||
Reference in New Issue
Block a user