132 lines
3.7 KiB
Vue
132 lines
3.7 KiB
Vue
<script setup>
|
|
import { selectedDate, changeDate, changeDay } from "@/store";
|
|
import { Swiper, SwiperSlide } from "swiper/vue";
|
|
import { Virtual } from "swiper";
|
|
import { ref, watch } from "vue";
|
|
import { getDateSkippingWeekend, setUTCMidnight } from "@/util";
|
|
import ScrollableContainer from "@/components/scrollable-container.vue";
|
|
|
|
defineProps({
|
|
element: {
|
|
required: true,
|
|
},
|
|
});
|
|
|
|
// Get swiper element
|
|
const swiperModules = ref([Virtual]);
|
|
const swiperElement = ref();
|
|
function setSwiper(swiper) {
|
|
swiperElement.value = swiper;
|
|
}
|
|
|
|
// Load current, previous and next day
|
|
const loadedDates = ref([
|
|
getDateSkippingWeekend(new Date(selectedDate.value.getTime() - 86400000)),
|
|
new Date(selectedDate.value.getTime()),
|
|
getDateSkippingWeekend(new Date(selectedDate.value.getTime() + 86400000)),
|
|
]);
|
|
|
|
// Load left or right date on slide change
|
|
function slideChange(swiper) {
|
|
const activeSlide = swiper.activeIndex;
|
|
// Only trigger data refresh if date is different
|
|
const newSelectedDate = loadedDates.value[activeSlide];
|
|
if (selectedDate.value.getTime() != newSelectedDate.getTime())
|
|
selectedDate.value = newSelectedDate;
|
|
// Check if current slide is the last one
|
|
if (activeSlide == loadedDates.value.length - 1) {
|
|
// Append next day to loadedDates
|
|
const lastDate = loadedDates.value.at(-1);
|
|
loadedDates.value.push(getDateSkippingWeekend(calculateDate(lastDate, 1)));
|
|
}
|
|
}
|
|
function slideChangeEnd(swiper) {
|
|
const activeSlide = swiper.activeIndex;
|
|
// Check if the current slide is the first one
|
|
if (activeSlide == 0) {
|
|
// Prepend the previous day to loadedDates
|
|
// and slide to the next slide without transition
|
|
// so the same day as before is shown
|
|
const lastDate = loadedDates.value[0];
|
|
loadedDates.value = [
|
|
getDateSkippingWeekend(calculateDate(lastDate, -1)),
|
|
...loadedDates.value,
|
|
];
|
|
swiper.slideTo(activeSlide + 1, 0);
|
|
}
|
|
}
|
|
// Also check if a day needs to be prepended
|
|
// if the user releases the card later because
|
|
// a different event is fired for that
|
|
function slideResetEnd(swiper) {
|
|
slideChangeEnd(swiper);
|
|
}
|
|
|
|
// Helper functions
|
|
function calculateDate(date, offset) {
|
|
return new Date(date.getTime() + 86400000 * offset);
|
|
}
|
|
function calculateSlide(date) {
|
|
return loadedDates.value.findIndex((e) => e.getTime() == date.getTime());
|
|
}
|
|
function slideToDate(date) {
|
|
const slide = calculateSlide(date);
|
|
if (slide != -1) swiperElement.value.slideTo(slide);
|
|
else {
|
|
// If the slide is not loaded yet reset
|
|
// loaded dates and load that date
|
|
loadedDates.value = [calculateDate(date, -1), date, calculateDate(date, 1)];
|
|
swiperElement.value.slideTo(1, 0);
|
|
}
|
|
selectedDate.value = date;
|
|
}
|
|
|
|
// Watch for slide change instructions
|
|
watch(changeDay, (change) => {
|
|
if (change == 0) return;
|
|
const calculatedDate = calculateDate(selectedDate.value, change);
|
|
slideToDate(getDateSkippingWeekend(calculatedDate));
|
|
changeDay.value = 0;
|
|
});
|
|
watch(changeDate, (date) => {
|
|
slideToDate(setUTCMidnight(date));
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<swiper
|
|
:modules="swiperModules"
|
|
:slides-per-view="1"
|
|
:space-between="50"
|
|
:initial-slide="1"
|
|
:virtual="true"
|
|
@slide-change-transition-end="slideChangeEnd"
|
|
@slide-reset-transition-end="slideResetEnd"
|
|
@slide-change="slideChange"
|
|
@swiper="setSwiper"
|
|
>
|
|
<swiper-slide
|
|
v-for="(date, index) in loadedDates"
|
|
:key="index"
|
|
:virtualIndex="index"
|
|
>
|
|
<ScrollableContainer>
|
|
<component :is="element" :date="date" />
|
|
</ScrollableContainer>
|
|
</swiper-slide>
|
|
</swiper>
|
|
</template>
|
|
|
|
<style>
|
|
@import "swiper/css";
|
|
</style>
|
|
|
|
<style scoped>
|
|
.swiper {
|
|
padding: 5px 10px 0px 10px;
|
|
z-index: 0;
|
|
height: 100%;
|
|
box-sizing: border-box;
|
|
}
|
|
</style>
|