Split calendar and national days to components

This commit is contained in:
2024-12-19 21:31:47 +00:00
parent 28ed529cc0
commit 215be2d5f0
4 changed files with 213 additions and 171 deletions

View File

@@ -8,12 +8,14 @@ export {}
declare module 'vue' { declare module 'vue' {
export interface GlobalComponents { export interface GlobalComponents {
Almanac: typeof import('./src/components/Almanac.vue')['default'] Almanac: typeof import('./src/components/Almanac.vue')['default']
CalendarAgenda: typeof import('./src/components/CalendarAgenda.vue')['default']
CurrentLaundryStatus: typeof import('./src/components/CurrentLaundryStatus.vue')['default'] CurrentLaundryStatus: typeof import('./src/components/CurrentLaundryStatus.vue')['default']
CurrentPower: typeof import('./src/components/CurrentPower.vue')['default'] CurrentPower: typeof import('./src/components/CurrentPower.vue')['default']
CurrentWeather: typeof import('./src/components/CurrentWeather.vue')['default'] CurrentWeather: typeof import('./src/components/CurrentWeather.vue')['default']
DashboardItem: typeof import('./src/components/DashboardItem.vue')['default'] DashboardItem: typeof import('./src/components/DashboardItem.vue')['default']
Indoor: typeof import('./src/components/Indoor.vue')['default'] Indoor: typeof import('./src/components/Indoor.vue')['default']
IndoorSummary: typeof import('./src/components/IndoorSummary.vue')['default'] IndoorSummary: typeof import('./src/components/IndoorSummary.vue')['default']
NationalDays: typeof import('./src/components/NationalDays.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView'] RouterView: typeof import('vue-router')['RouterView']
TimeRange: typeof import('./src/components/TimeRange.vue')['default'] TimeRange: typeof import('./src/components/TimeRange.vue')['default']

View File

@@ -0,0 +1,148 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { useCalendarStore } from '@/stores/calendarStore';
import { format, startOfDay, endOfDay } from 'date-fns';
import CalendarDay from '@/models/calendar/calendar-day';
const props = defineProps(['days', 'refreshInterval']);
const calendarStore = useCalendarStore();
const calendarDays = ref([] as CalendarDay[]);
const calendarReady = ref(false);
function loadCalendar() {
const newCalendarDays = [] as CalendarDay[];
calendarStore.getUpcoming(props.days, true).then((upcoming) => {
const currentDay = startOfDay(new Date());
for (let i = 0; i < props.days; i++) {
const day = new Date(currentDay);
day.setDate(day.getDate() + i);
const entries = upcoming
.filter((entry) => {
const entryStart = startOfDay(entry.start);
const entryEnd = endOfDay(entry.end);
if (entry.isAllDay) {
return day > entryStart && day < entryEnd;
}
return day >= entryStart && day <= entryEnd;
})
.sort((a, b) => {
if (a.isHoliday == b.isHoliday) {
return a.summary.localeCompare(b.summary);
}
return (b.isHoliday ? 1 : 0) - (a.isHoliday ? 1 : 0);
});
newCalendarDays.push(new CalendarDay(day, entries));
}
calendarDays.value = newCalendarDays;
calendarReady.value = true;
});
}
loadCalendar();
setInterval(() => loadCalendar(), props.refreshInterval);
</script>
<template>
<div
class="calendar"
v-if="calendarReady">
<div class="calendar-header">
{{ 'Next ' + days + ' Days' }}
</div>
<ul class="calendar-day-list">
<li
class="calendar-day-item"
v-for="calendarDay in calendarDays">
<div>
<div class="calendar-day-item-header">
<span class="calendar-day-item-number">
{{ format(calendarDay.date, 'dd') }}
</span>
<span class="calendar-day-item-name">
{{ format(calendarDay.date, 'EEEE') }}
</span>
</div>
<ul
class="calendar-entry"
v-for="calendarEntry in calendarDay.entries"
:class="{ 'calendar-holiday': calendarEntry.isHoliday }">
<span>
{{ calendarEntry.summary }}
</span>
</ul>
</div>
</li>
</ul>
</div>
</template>
<style>
.calendar {
background-color: #121212;
border-radius: 10px;
display: flex;
flex: 1;
flex-direction: column;
}
.calendar-header {
font-size: 1.15em;
padding-top: 10px;
padding-bottom: 2px;
text-align: center;
}
.calendar-day-item-header {
display: flex;
align-items: center;
}
.calendar-day-item-number {
font-size: 1.25em;
padding-right: 0.5em;
}
.calendar-day-item-name {
font-size: 1em;
}
.calendar-day-list {
margin-left: 10px;
overflow: auto;
flex: 1;
}
.calendar-day-item:not(:last-child) {
padding-bottom: 2px;
}
.calendar-day-item:first-of-type {
color: #c75ec7;
}
.calendar-day-item:not(:first-child) {
padding-top: 4px;
}
.calendar-entry {
color: #ebebeb;
padding-left: 2em;
padding-bottom: 2px;
}
.calendar-holiday {
color: #5e83c7;
}
</style>

View File

@@ -0,0 +1,56 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { useCalendarStore } from '@/stores/calendarStore';
import { startOfDay, isEqual } from 'date-fns';
import NationalDayEntry from '@/models/calendar/national-day';
const calendarStore = useCalendarStore();
const nationalDays = ref([] as NationalDayEntry[]);
const nationalDaysReady = ref(false);
const loadedNationalDay = ref(null as Date | null);
function loadNationalDays() {
calendarStore.getNationalDays().then((data) => {
nationalDays.value = data.sort((a, b) => a.name.localeCompare(b.name));
loadedNationalDay.value = startOfDay(new Date());
nationalDaysReady.value = true;
});
}
loadNationalDays();
setInterval(() => {
if (loadedNationalDay.value && !isEqual(loadedNationalDay.value, startOfDay(new Date()))) {
loadNationalDays();
}
}, 10 * 1000);
</script>
<template>
<div
class="national-days"
v-if="nationalDaysReady">
<ul>
<li
class="national-day"
v-for="nationalDay in nationalDays">
{{ nationalDay.name }}
</li>
</ul>
</div>
</template>
<style>
.national-days {
background-color: #121212;
border-radius: 10px;
padding: 10px;
}
.national-day:not(:last-child) {
padding-bottom: 2px;
}
</style>

View File

@@ -4,12 +4,7 @@
import { useLaundryStore } from '@/stores/laundryStore'; import { useLaundryStore } from '@/stores/laundryStore';
import { usePowerStore } from '@/stores/powerStore'; import { usePowerStore } from '@/stores/powerStore';
import { useHomeAssistantStore } from '@/stores/homeAssistantStore'; import { useHomeAssistantStore } from '@/stores/homeAssistantStore';
import { useCalendarStore } from '@/stores/calendarStore'; import CalendarAgenda from '@/components/CalendarAgenda.vue';
import { format, startOfDay, endOfDay, isEqual } from 'date-fns';
import CalendarDay from '@/models/calendar/calendar-day';
import NationalDayEntry from '@/models/calendar/national-day';
const calendarDayCount = 7;
const weatherStore = useWeatherStore(); const weatherStore = useWeatherStore();
weatherStore.start(); weatherStore.start();
@@ -23,15 +18,7 @@
const homeAssistantStore = useHomeAssistantStore(); const homeAssistantStore = useHomeAssistantStore();
homeAssistantStore.start(); homeAssistantStore.start();
const calendarStore = useCalendarStore();
const currentTime = ref(new Date()); const currentTime = ref(new Date());
const calendarDays = ref([] as CalendarDay[]);
const calendarReady = ref(false);
const nationalDays = ref([] as NationalDayEntry[]);
const nationalDaysReady = ref(false);
const loadedNationalDay = ref(null as Date | null);
const timeFormatter = new Intl.DateTimeFormat('en-US', { hour: 'numeric', minute: '2-digit' }); const timeFormatter = new Intl.DateTimeFormat('en-US', { hour: 'numeric', minute: '2-digit' });
const dateFormatter = new Intl.DateTimeFormat('en-US', { weekday: 'long', month: 'long', day: 'numeric' }); const dateFormatter = new Intl.DateTimeFormat('en-US', { weekday: 'long', month: 'long', day: 'numeric' });
@@ -49,67 +36,7 @@
} }
} }
function loadCalendar() { setInterval(() => (currentTime.value = new Date()), 1000);
const newCalendarDays = [] as CalendarDay[];
calendarStore.getUpcoming(calendarDayCount, true).then((upcoming) => {
const currentDay = startOfDay(currentTime.value);
for (let i = 0; i < calendarDayCount; i++) {
const day = new Date(currentDay);
day.setDate(day.getDate() + i);
const entries = upcoming
.filter((entry) => {
const entryStart = startOfDay(entry.start);
const entryEnd = endOfDay(entry.end);
if (entry.isAllDay) {
return day > entryStart && day < entryEnd;
}
return day >= entryStart && day <= entryEnd;
})
.sort((a, b) => {
if (a.isHoliday == b.isHoliday) {
return a.summary.localeCompare(b.summary);
}
return (b.isHoliday ? 1 : 0) - (a.isHoliday ? 1 : 0);
});
newCalendarDays.push(new CalendarDay(day, entries));
}
calendarDays.value = newCalendarDays;
calendarReady.value = true;
});
}
loadCalendar();
function loadNationalDays() {
calendarStore.getNationalDays().then((data) => {
nationalDays.value = data.sort((a, b) => a.name.localeCompare(b.name));
loadedNationalDay.value = startOfDay(currentTime.value);
nationalDaysReady.value = true;
});
}
loadNationalDays();
setInterval(() => {
currentTime.value = new Date();
if (loadedNationalDay.value && !isEqual(loadedNationalDay.value, startOfDay(currentTime.value))) {
loadNationalDays();
}
}, 1000);
setInterval(() => loadCalendar(), 30 * 60 * 1000);
</script> </script>
<template> <template>
@@ -202,46 +129,11 @@
</div> </div>
</div> </div>
<div class="kiosk-content"> <div class="kiosk-content">
<div <CalendarAgenda
class="kiosk-calendar" class="kiosk-calendar"
v-if="calendarReady"> days="7"
<div class="kiosk-calendar-header"> :refresh-interval="30 * 60 * 1000" />
{{ 'Next ' + calendarDayCount + ' Days' }} <NationalDays class="kiosk-national-days" />
</div>
<ul class="kiosk-calendar-day-list">
<li
class="kiosk-calendar-day-item"
v-for="calendarDay in calendarDays">
<div>
<div class="kiosk-calendar-day-item-header">
<span class="kiosk-calendar-day-item-number">
{{ format(calendarDay.date, 'dd') }}
</span>
<span class="kiosk-calendar-day-item-name">
{{ format(calendarDay.date, 'EEEE') }}
</span>
</div>
<ul
class="kiosk-calendar-entry"
v-for="calendarEntry in calendarDay.entries"
:class="calendarEntry.isHoliday ? 'holiday' : ''">
<span>
{{ calendarEntry.summary }}
</span>
</ul>
</div>
</li>
</ul>
</div>
<div
class="kiosk-national-days"
v-if="nationalDaysReady">
<ul>
<li v-for="nationalDay in nationalDays">
{{ nationalDay.name }}
</li>
</ul>
</div>
</div> </div>
</v-container> </v-container>
</template> </template>
@@ -356,66 +248,14 @@
.kiosk-calendar { .kiosk-calendar {
grid-area: kiosk-calendar; grid-area: kiosk-calendar;
background-color: #121212; overflow: auto;
border-radius: 10px;
display: flex;
flex: 1;
flex-direction: column;
} }
.kiosk-national-days { .kiosk-national-days {
grid-area: kiosk-national-days; grid-area: kiosk-national-days;
background-color: #121212;
border-radius: 10px;
padding: 10px;
overflow: auto; overflow: auto;
} }
.kiosk-calendar-header {
font-size: 1.15em;
padding-top: 10px;
padding-bottom: 2px;
text-align: center;
}
.kiosk-calendar-day-item-header {
display: flex;
align-items: center;
}
.kiosk-calendar-day-item-number {
font-size: 1.25em;
padding-right: 0.5em;
}
.kiosk-calendar-day-item-name {
font-size: 1em;
}
.kiosk-calendar-day-list {
margin-left: 10px;
overflow: auto;
flex: 1;
}
.kiosk-calendar-day-item:not(:last-child) {
padding-bottom: 2px;
}
.kiosk-calendar-day-item:first-of-type {
color: #c75ec7;
}
.kiosk-calendar-day-item:not(:first-child) {
padding-top: 4px;
}
.kiosk-calendar-entry {
color: #ebebeb;
padding-left: 2em;
padding-bottom: 2px;
}
.warning { .warning {
color: #d09f27; color: #d09f27;
} }
@@ -423,8 +263,4 @@
.normal { .normal {
color: #208b20; color: #208b20;
} }
.holiday {
color: #5e83c7;
}
</style> </style>