df531908f3
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
112 lines
3.0 KiB
Vue
112 lines
3.0 KiB
Vue
<script setup lang="ts">
|
|
import { ref } from 'vue';
|
|
import MonthView from './MonthView.vue';
|
|
import DaysView from './DaysView.vue';
|
|
import AgendaView from './AgendaView.vue';
|
|
import EventViewerPopup from './EventViewerPopup.vue';
|
|
import {
|
|
type AgendaViewSpan,
|
|
type DaysViewSpan
|
|
} from '@/types/spans';
|
|
import type { EntityObject } from '@ChronoManager/models/entity';
|
|
import type { CollectionObject } from '@ChronoManager/models/collection';
|
|
|
|
const props = defineProps<{
|
|
view: 'days' | 'month' | 'agenda';
|
|
currentDate: Date;
|
|
calendars: CollectionObject[];
|
|
initialDaysSpan?: DaysViewSpan;
|
|
initialAgendaViewSpan?: AgendaViewSpan;
|
|
}>();
|
|
|
|
const emit = defineEmits<{
|
|
'event-click': [event: EntityObject];
|
|
'date-click': [date: Date];
|
|
'update:current-date': [date: Date];
|
|
'update:days-span': [span: DaysViewSpan];
|
|
'update:agenda-span': [span: AgendaViewSpan];
|
|
}>();
|
|
|
|
// Popup state
|
|
const hoveredEvent = ref<EntityObject | null>(null);
|
|
const popupPosition = ref({ x: 0, y: 0 });
|
|
const showPopup = ref(false);
|
|
let hideTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
|
|
function handleEventHover(data: { event: MouseEvent; entity: EntityObject }) {
|
|
if (hideTimeout) {
|
|
clearTimeout(hideTimeout);
|
|
hideTimeout = null;
|
|
}
|
|
hoveredEvent.value = data.entity;
|
|
popupPosition.value = {
|
|
x: data.event.clientX,
|
|
y: data.event.clientY
|
|
};
|
|
showPopup.value = true;
|
|
}
|
|
|
|
function hidePopup() {
|
|
hideTimeout = setTimeout(() => {
|
|
showPopup.value = false;
|
|
hoveredEvent.value = null;
|
|
}, 200);
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="calendar-view-container">
|
|
<EventViewerPopup
|
|
:event="hoveredEvent"
|
|
:position="popupPosition"
|
|
:visible="showPopup"
|
|
@click="$emit('event-click', $event)"
|
|
/>
|
|
<MonthView
|
|
v-if="view === 'month'"
|
|
:current-date="currentDate"
|
|
:calendars="calendars"
|
|
@event-click="$emit('event-click', $event)"
|
|
@date-click="$emit('date-click', $event)"
|
|
@event-hover="handleEventHover"
|
|
@event-hover-end="hidePopup"
|
|
@update:current-date="$emit('update:current-date', $event)"
|
|
/>
|
|
<DaysView
|
|
v-else-if="view === 'days'"
|
|
:current-date="currentDate"
|
|
:calendars="calendars"
|
|
:initial-span="initialDaysSpan"
|
|
@event-click="$emit('event-click', $event)"
|
|
@date-click="$emit('date-click', $event)"
|
|
@event-hover="handleEventHover"
|
|
@event-hover-end="hidePopup"
|
|
@update:span="$emit('update:days-span', $event)"
|
|
@update:current-date="$emit('update:current-date', $event)"
|
|
/>
|
|
<AgendaView
|
|
v-else-if="view === 'agenda'"
|
|
:calendars="calendars"
|
|
:current-date="currentDate"
|
|
:initial-span="initialAgendaViewSpan"
|
|
@event-click="$emit('event-click', $event)"
|
|
@update:span="$emit('update:agenda-span', $event)"
|
|
@update:current-date="$emit('update:current-date', $event)"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.calendar-view-container {
|
|
height: 100%;
|
|
width: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.calendar-view-container > * {
|
|
flex: 1;
|
|
min-height: 0;
|
|
}
|
|
</style>
|