refactor part 1

This commit is contained in:
2026-06-23 22:17:01 -04:00
parent 214cf50908
commit d5bb7ff24f
18 changed files with 508 additions and 398 deletions

View File

@@ -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>
`