ported to luxon library
This commit is contained in:
143
web/\
Normal file
143
web/\
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
import { DateTime } from "luxon"
|
||||||
|
import type { Moment } from "moment"
|
||||||
|
import moment from "moment"
|
||||||
|
|
||||||
|
export class Event {
|
||||||
|
private static readonly MINUTES_IN_DAY = 24 * 60
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public readonly title: string,
|
||||||
|
public from: DateTime,
|
||||||
|
public to: DateTime
|
||||||
|
) { }
|
||||||
|
|
||||||
|
|
||||||
|
getPercentDimensions(): EventDimensions {
|
||||||
|
const start_of_day = this.from.startOf('day')
|
||||||
|
const from_percentage = this.from.diff(start_of_day, 'minutes').minutes / Event.MINUTES_IN_DAY
|
||||||
|
const to_percentage = this.to.diff(start_of_day, 'minutes').minutes / Event.MINUTES_IN_DAY
|
||||||
|
return {
|
||||||
|
from: from_percentage * 100,
|
||||||
|
to: to_percentage * 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getPixelDimensions(maxHeight: number): EventDimensions {
|
||||||
|
const percentDimensions = this.getPercentDimensions()
|
||||||
|
return {
|
||||||
|
from: (percentDimensions.from / 100) * maxHeight,
|
||||||
|
to: (percentDimensions.to / 100) * maxHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromSimple(event: SimpleEvent): Event {
|
||||||
|
return new Event(event.title, event.from, event.to)
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromSerializable(event: SerializableEvent) {
|
||||||
|
return new Event(event.title, DateTime.fromISO(event.from), DateTime.fromISO(event.to))
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromPercentDimensions(title: string, dimensions: EventDimensions, date: DateTime): Event {
|
||||||
|
return new Event(
|
||||||
|
title,
|
||||||
|
date.startOf('day').plus({ minutes: (dimensions.from / 100) * Event.MINUTES_IN_DAY }),
|
||||||
|
date.startOf('day').plus({ minutes: (dimensions.to / 100) * Event.MINUTES_IN_DAY })
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromPixelDimensions(title: string, dimensions: EventDimensions, height: number, date: DateTime): Event {
|
||||||
|
const percentDimensions: EventDimensions = {
|
||||||
|
from: dimensions.from * 100 / height,
|
||||||
|
to: dimensions.to * 100 / height
|
||||||
|
}
|
||||||
|
|
||||||
|
return Event.fromPercentDimensions(title, percentDimensions, date)
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromDraggedEvent(draggedEvent: DraggedEvent, height: number): Event {
|
||||||
|
const pixelDimensions: EventDimensions = {
|
||||||
|
from: draggedEvent.top,
|
||||||
|
to: draggedEvent.top + draggedEvent.height
|
||||||
|
}
|
||||||
|
|
||||||
|
return Event.fromPixelDimensions(draggedEvent.target.title, pixelDimensions, height, draggedEvent.date)
|
||||||
|
}
|
||||||
|
|
||||||
|
updateWithDraggedEvent(draggedEvent: DraggedEvent, height: number): Event {
|
||||||
|
const newEventData = Event.fromDraggedEvent(draggedEvent, height)
|
||||||
|
|
||||||
|
this.from = newEventData.from
|
||||||
|
this.to = newEventData.to
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
toSimple(): SimpleEvent {
|
||||||
|
return {
|
||||||
|
title: this.title,
|
||||||
|
from: this.from,
|
||||||
|
to: this.to
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toSerializable(): SerializableEvent {
|
||||||
|
return {
|
||||||
|
title: this.title,
|
||||||
|
from: this.from.toISO() ?? '',
|
||||||
|
to: this.to.toISO() ?? ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
withCollisions(collisions: number = 0): CollissionWrapper {
|
||||||
|
return {
|
||||||
|
event: this,
|
||||||
|
collisions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toDraggedEvent(height: number, mouseY: number): DraggedEvent {
|
||||||
|
const pixelDimensions = this.getPixelDimensions(height)
|
||||||
|
const offset = mouseY - pixelDimensions.from
|
||||||
|
|
||||||
|
return {
|
||||||
|
date: moment(this.from).startOf('day'),
|
||||||
|
top: pixelDimensions.from,
|
||||||
|
height: pixelDimensions.to - pixelDimensions.from,
|
||||||
|
target: this,
|
||||||
|
offset: offset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export type EventDimensions = {
|
||||||
|
from: number,
|
||||||
|
to: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SimpleEvent = {
|
||||||
|
title: string,
|
||||||
|
from: DateTime,
|
||||||
|
to: DateTime
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SerializableEvent = {
|
||||||
|
title: string,
|
||||||
|
from: string,
|
||||||
|
to: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CollissionWrapper = {
|
||||||
|
event: Event,
|
||||||
|
collisions: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DraggedEvent = {
|
||||||
|
date: DateTime,
|
||||||
|
top: number,
|
||||||
|
height: number,
|
||||||
|
target: Event,
|
||||||
|
offset: number
|
||||||
|
}
|
||||||
@@ -10,8 +10,10 @@
|
|||||||
"@nuxt/test-utils": "3.18.0",
|
"@nuxt/test-utils": "3.18.0",
|
||||||
"@nuxt/ui": "3.1.1",
|
"@nuxt/ui": "3.1.1",
|
||||||
"@nuxtjs/color-mode": "3.5.2",
|
"@nuxtjs/color-mode": "3.5.2",
|
||||||
|
"@types/luxon": "^3.6.2",
|
||||||
"@types/moment": "^2.13.0",
|
"@types/moment": "^2.13.0",
|
||||||
"eslint": "^9.0.0",
|
"eslint": "^9.0.0",
|
||||||
|
"luxon": "^3.6.1",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"nuxt": "^3.17.2",
|
"nuxt": "^3.17.2",
|
||||||
"nuxt-app": "file:",
|
"nuxt-app": "file:",
|
||||||
@@ -474,6 +476,8 @@
|
|||||||
|
|
||||||
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
|
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
|
||||||
|
|
||||||
|
"@types/luxon": ["@types/luxon@3.6.2", "", {}, "sha512-R/BdP7OxEMc44l2Ex5lSXHoIXTB2JLNa3y2QISIbr58U/YcsffyQrYW//hZSdrfxrjRZj3GcUoxMPGdO8gSYuw=="],
|
||||||
|
|
||||||
"@types/moment": ["@types/moment@2.13.0", "", { "dependencies": { "moment": "*" } }, "sha512-DyuyYGpV6r+4Z1bUznLi/Y7HpGn4iQ4IVcGn8zrr1P4KotKLdH0sbK1TFR6RGyX6B+G8u83wCzL+bpawKU/hdQ=="],
|
"@types/moment": ["@types/moment@2.13.0", "", { "dependencies": { "moment": "*" } }, "sha512-DyuyYGpV6r+4Z1bUznLi/Y7HpGn4iQ4IVcGn8zrr1P4KotKLdH0sbK1TFR6RGyX6B+G8u83wCzL+bpawKU/hdQ=="],
|
||||||
|
|
||||||
"@types/node": ["@types/node@22.15.12", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-K0fpC/ZVeb8G9rm7bH7vI0KAec4XHEhBam616nVJCV51bKzJ6oA3luG4WdKoaztxe70QaNjS/xBmcDLmr4PiGw=="],
|
"@types/node": ["@types/node@22.15.12", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-K0fpC/ZVeb8G9rm7bH7vI0KAec4XHEhBam616nVJCV51bKzJ6oA3luG4WdKoaztxe70QaNjS/xBmcDLmr4PiGw=="],
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ import type { Moment } from 'moment';
|
|||||||
import Calendar from './calendar/Calendar.vue'
|
import Calendar from './calendar/Calendar.vue'
|
||||||
import { Event } from '~/utils/event';
|
import { Event } from '~/utils/event';
|
||||||
import { UCard } from '#components';
|
import { UCard } from '#components';
|
||||||
|
import type { DateTime } from 'luxon';
|
||||||
|
|
||||||
const events = defineModel<Event[]>('events', { required: true })
|
const events = defineModel<Event[]>('events', { required: true })
|
||||||
const date = defineModel<Moment>('date', { required: true })
|
const date = defineModel<DateTime>('date', { required: true })
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ import { CalendarDate } from '@internationalized/date';
|
|||||||
import ListItem from './ListItem.vue';
|
import ListItem from './ListItem.vue';
|
||||||
import Title1 from './Title1.vue';
|
import Title1 from './Title1.vue';
|
||||||
import type { DropdownMenuItem } from '@nuxt/ui';
|
import type { DropdownMenuItem } from '@nuxt/ui';
|
||||||
import type { Moment } from 'moment';
|
import { DateTime } from 'luxon';
|
||||||
import moment from 'moment';
|
|
||||||
|
|
||||||
const colorMode = useColorMode();
|
const colorMode = useColorMode();
|
||||||
const currentTheme = ref<'dark' | 'system' | 'light'>(colorMode.preference as 'dark' | 'system' | 'light');
|
const currentTheme = ref<'dark' | 'system' | 'light'>(colorMode.preference as 'dark' | 'system' | 'light');
|
||||||
@@ -56,17 +55,17 @@ const dropDownItems = computed<DropdownMenuItem[][]>(() => [
|
|||||||
]
|
]
|
||||||
])
|
])
|
||||||
|
|
||||||
const date = defineModel<Moment>('date', { required: true })
|
const date = defineModel<DateTime>('date', { required: true })
|
||||||
|
|
||||||
const selectedDate = computed({
|
const selectedDate = computed({
|
||||||
get() {
|
get() {
|
||||||
return new CalendarDate(date.value.year(), date.value.month() + 1, date.value.date())
|
return new CalendarDate(date.value.year, date.value.month, date.value.day)
|
||||||
},
|
},
|
||||||
set(value) {
|
set(value) {
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
date.value = moment(value.toString());
|
date.value = DateTime.fromISO(value.toString());
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -2,20 +2,20 @@
|
|||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import CalendarHeader from './CalendarHeader.vue';
|
import CalendarHeader from './CalendarHeader.vue';
|
||||||
import CalendarCollumn from './CalendarCollumn.vue';
|
import CalendarCollumn from './CalendarCollumn.vue';
|
||||||
import moment, { type Moment } from 'moment';
|
|
||||||
import { Event } from '~/utils/event';
|
import { Event } from '~/utils/event';
|
||||||
|
import { DateTime } from 'luxon';
|
||||||
|
|
||||||
const events = defineModel<Event[]>('events', { required: true })
|
const events = defineModel<Event[]>('events', { required: true })
|
||||||
const date = defineModel<Moment>('date', { required: true })
|
const date = defineModel<DateTime>('date', { required: true })
|
||||||
const draggedEvent = ref<DraggedEvent | undefined>()
|
const draggedEvent = ref<DraggedEvent | undefined>()
|
||||||
|
|
||||||
type Day = {
|
type Day = {
|
||||||
date: Moment
|
date: DateTime
|
||||||
events: CollissionWrapper[][]
|
events: CollissionWrapper[][]
|
||||||
}
|
}
|
||||||
|
|
||||||
const week = computed(() => {
|
const week = computed(() => {
|
||||||
return moment(date.value).startOf('isoWeek')
|
return date.value.startOf('week')
|
||||||
})
|
})
|
||||||
|
|
||||||
function pushEventWithCollisionUpdate(array: CollissionWrapper[], event: Event, collisions: CollissionWrapper[], collisionCount: number) {
|
function pushEventWithCollisionUpdate(array: CollissionWrapper[], event: Event, collisions: CollissionWrapper[], collisionCount: number) {
|
||||||
@@ -28,8 +28,9 @@ function pushEventWithCollisionUpdate(array: CollissionWrapper[], event: Event,
|
|||||||
|
|
||||||
const days = computed<Day[]>(() => {
|
const days = computed<Day[]>(() => {
|
||||||
return [1, 2, 3, 4, 5, 6, 7].map((i) => {
|
return [1, 2, 3, 4, 5, 6, 7].map((i) => {
|
||||||
|
const currentDate = date.value.startOf('week').plus({ day: i - 1 })
|
||||||
const filteredEvents = events.value.filter(
|
const filteredEvents = events.value.filter(
|
||||||
(event) => event.from >= moment(week.value).weekday(i).startOf('day') && event.to <= moment(week.value).weekday(i).endOf('day')
|
(event) => event.from >= currentDate.startOf('day') && event.to <= currentDate.endOf('day')
|
||||||
)
|
)
|
||||||
|
|
||||||
const sortedEvents = filteredEvents.sort((a, b) => a.from.valueOf() - b.from.valueOf())
|
const sortedEvents = filteredEvents.sort((a, b) => a.from.valueOf() - b.from.valueOf())
|
||||||
@@ -62,7 +63,7 @@ const days = computed<Day[]>(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
date: moment(week.value).weekday(i),
|
date: currentDate,
|
||||||
events: columns
|
events: columns
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -72,17 +73,22 @@ const emits = defineEmits<{
|
|||||||
(e: 'create', timespan: Event): void
|
(e: 'create', timespan: Event): void
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const hour = (num: number) => {
|
||||||
|
return DateTime.now().startOf('day').plus({ hours: num })
|
||||||
|
}
|
||||||
|
|
||||||
const seperators = ref<Seperator[]>([
|
const seperators = ref<Seperator[]>([
|
||||||
{ text: '3 AM', time: moment().hour(3) },
|
{ text: '3 AM', time: hour(3) },
|
||||||
{ text: '6 AM', time: moment().hour(6) },
|
{ text: '6 AM', time: hour(6) },
|
||||||
{ text: '9 AM', time: moment().hour(9) },
|
{ text: '9 AM', time: hour(9) },
|
||||||
{ text: '12 PM', time: moment().hour(12) },
|
{ text: '12 PM', time: hour(12) },
|
||||||
{ text: '3 PM', time: moment().hour(15) },
|
{ text: '3 PM', time: hour(15) },
|
||||||
{ text: '6 PM', time: moment().hour(18) },
|
{ text: '6 PM', time: hour(18) },
|
||||||
{ text: '9 PM', time: moment().hour(21) },
|
{ text: '9 PM', time: hour(21) },
|
||||||
])
|
])
|
||||||
|
|
||||||
function quickCreate(date: Moment, timespan: Timespan) {
|
|
||||||
|
function quickCreate(date: DateTime, timespan: Timespan) {
|
||||||
const eventTitle = prompt("Event title")
|
const eventTitle = prompt("Event title")
|
||||||
|
|
||||||
if (eventTitle === null) {
|
if (eventTitle === null) {
|
||||||
@@ -91,8 +97,8 @@ function quickCreate(date: Moment, timespan: Timespan) {
|
|||||||
|
|
||||||
const newEvent: Event = new Event(
|
const newEvent: Event = new Event(
|
||||||
eventTitle,
|
eventTitle,
|
||||||
moment(date).startOf('day').minutes(timespan.from * 24 * 60),
|
date.startOf('day').plus({ minutes: timespan.from * 24 * 60 }),
|
||||||
moment(date).startOf('day').minutes(timespan.to * 24 * 60)
|
date.startOf('day').plus({ minutes: timespan.to * 24 * 60 })
|
||||||
)
|
)
|
||||||
|
|
||||||
emits('create', newEvent)
|
emits('create', newEvent)
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref, useTemplateRef } from 'vue';
|
import { computed, ref, useTemplateRef } from 'vue';
|
||||||
import CalendarSeperator from './CalendarSeperator.vue';
|
import CalendarSeperator from './CalendarSeperator.vue';
|
||||||
import type { Moment } from 'moment';
|
|
||||||
import CalendarEvent from './CalendarEvent.vue';
|
import CalendarEvent from './CalendarEvent.vue';
|
||||||
import { Event } from '~/utils/event';
|
import { Event } from '~/utils/event';
|
||||||
import moment from 'moment';
|
import type { DateTime } from 'luxon';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
seperators: Seperator[],
|
seperators: Seperator[],
|
||||||
day: Moment
|
day: DateTime
|
||||||
events: CollissionWrapper[][]
|
events: CollissionWrapper[][]
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'quick-create', day: Moment, event: EventDimensions): void,
|
(e: 'quick-create', day: DateTime, event: EventDimensions): void,
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const isDragging = ref(false)
|
const isDragging = ref(false)
|
||||||
@@ -58,7 +57,7 @@ function mouseup(_: MouseEvent) {
|
|||||||
|
|
||||||
const timeFrom = Math.min(endY.value, startY.value) / column.value.offsetHeight
|
const timeFrom = Math.min(endY.value, startY.value) / column.value.offsetHeight
|
||||||
const timeTo = Math.max(endY.value, startY.value) / column.value.offsetHeight
|
const timeTo = Math.max(endY.value, startY.value) / column.value.offsetHeight
|
||||||
emit('quick-create', moment(props.day), {
|
emit('quick-create', props.day, {
|
||||||
from: timeFrom,
|
from: timeFrom,
|
||||||
to: timeTo
|
to: timeTo
|
||||||
})
|
})
|
||||||
@@ -76,7 +75,7 @@ function dragover(e: DragEvent) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!draggedEvent.value.date.isSame(props.day)) {
|
if (!draggedEvent.value.date.equals(props.day)) {
|
||||||
draggedEvent.value.date = props.day
|
draggedEvent.value.date = props.day
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,12 +93,12 @@ function dragDrop(_: DragEvent) {
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col h-full grow">
|
<div class="flex flex-col h-full grow">
|
||||||
<div class="flex justify-center items-center flex-col h-18 border-b-1 border-muted">
|
<div class="flex justify-center items-center flex-col h-18 border-b-1 border-muted">
|
||||||
<div>{{ props.day.format('dd').toUpperCase() }}</div>
|
<div>{{ props.day.toFormat('ccc').toUpperCase() }}</div>
|
||||||
<div>{{ props.day.date() }}</div>
|
<div>{{ props.day.day }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="col" ref="column" @mousedown="mousedown" @mouseup="mouseup" @mousemove="mouseover" @dragover="dragover"
|
<div id="col" ref="column" @mousedown="mousedown" @mouseup="mouseup" @mousemove="mouseover" @dragover="dragover"
|
||||||
@dragend="dragDrop" class="relative flex flex-col grow items-center">
|
@dragend="dragDrop" class="relative flex flex-col grow items-center select-none">
|
||||||
<CalendarSeperator v-for="sep in seperators" :seperator="sep">
|
<CalendarSeperator v-for="sep in seperators" :seperator="sep">
|
||||||
<hr class="w-full border-muted">
|
<hr class="w-full border-muted">
|
||||||
</CalendarSeperator>
|
</CalendarSeperator>
|
||||||
@@ -110,7 +109,7 @@ function dragDrop(_: DragEvent) {
|
|||||||
<CalendarEvent v-for="event in column" :event="event" :columnIndex="index" @move="eventMove" />
|
<CalendarEvent v-for="event in column" :event="event" :columnIndex="index" @move="eventMove" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="draggedEvent !== undefined && draggedEvent.date.isSame(props.day)"
|
<div v-if="draggedEvent !== undefined && draggedEvent.date.equals(props.day)"
|
||||||
class="absolute w-11/12 top-20 bg-black opacity-45 rounded-lg"
|
class="absolute w-11/12 top-20 bg-black opacity-45 rounded-lg"
|
||||||
:style="{ height: `${draggedEvent.height}px`, top: `${draggedEvent.top}px` }"></div>
|
:style="{ height: `${draggedEvent.height}px`, top: `${draggedEvent.top}px` }"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ function dragStart(e: DragEvent) {
|
|||||||
<div class="absolute rounded-lg h-0 top-20 bg-black opacity-45 p-2 flex flex-col z-10" @mousedown.stop
|
<div class="absolute rounded-lg h-0 top-20 bg-black opacity-45 p-2 flex flex-col z-10" @mousedown.stop
|
||||||
@mouseover.stop @mouseup.stop draggable="true" @dragstart="dragStart"
|
@mouseover.stop @mouseup.stop draggable="true" @dragstart="dragStart"
|
||||||
:style="{ top: `${top}%`, height: `${height}%`, left: `${left}%`, width: `${widht}%` }">
|
:style="{ top: `${top}%`, height: `${height}%`, left: `${left}%`, width: `${widht}%` }">
|
||||||
<div>{{ event.event.from.format('HH:mm') }} - {{ event.event.to.format('HH:mm') }}</div>
|
<div>{{ event.event.from.toFormat('HH:mm') }} - {{ event.event.to.toFormat('HH:mm') }}</div>
|
||||||
<div>{{ event.event.title }}</div>
|
<div>{{ event.event.title }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Moment } from 'moment';
|
import type { DateTime } from 'luxon';
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
seperator: Seperator
|
seperator: Seperator
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const relativePositionOf = function (time: Moment) {
|
const relativePositionOf = function (time: DateTime) {
|
||||||
return `${(time.hours() / 24) * 100}%`
|
return `${((time.hour) / 24) * 100}%`
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -16,8 +16,10 @@
|
|||||||
"@nuxt/test-utils": "3.18.0",
|
"@nuxt/test-utils": "3.18.0",
|
||||||
"@nuxt/ui": "3.1.1",
|
"@nuxt/ui": "3.1.1",
|
||||||
"@nuxtjs/color-mode": "3.5.2",
|
"@nuxtjs/color-mode": "3.5.2",
|
||||||
|
"@types/luxon": "^3.6.2",
|
||||||
"@types/moment": "^2.13.0",
|
"@types/moment": "^2.13.0",
|
||||||
"eslint": "^9.0.0",
|
"eslint": "^9.0.0",
|
||||||
|
"luxon": "^3.6.1",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"nuxt": "^3.17.2",
|
"nuxt": "^3.17.2",
|
||||||
"nuxt-app": "file:",
|
"nuxt-app": "file:",
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import moment from 'moment';
|
import { DateTime } from 'luxon';
|
||||||
import MainContent from '~/components/ui/MainContent.vue';
|
import MainContent from '~/components/ui/MainContent.vue';
|
||||||
import Sidebar from '~/components/ui/Sidebar.vue';
|
import Sidebar from '~/components/ui/Sidebar.vue';
|
||||||
|
|
||||||
const todos = ["Staistics", "Computer Graphics", "Webdev"]
|
const todos = ["Staistics", "Computer Graphics", "Webdev"]
|
||||||
const events = ref([])
|
const events = ref([])
|
||||||
const date = ref(moment())
|
const date = ref<DateTime>(DateTime.now())
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,19 @@
|
|||||||
import type { Moment } from "moment"
|
import { DateTime } from "luxon"
|
||||||
import moment from "moment"
|
|
||||||
|
|
||||||
export class Event {
|
export class Event {
|
||||||
private static readonly MINUTES_IN_DAY = 24 * 60
|
private static readonly MINUTES_IN_DAY = 24 * 60
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public readonly title: string,
|
public readonly title: string,
|
||||||
public from: Moment,
|
public from: DateTime,
|
||||||
public to: Moment
|
public to: DateTime
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
|
|
||||||
getPercentDimensions(): EventDimensions {
|
getPercentDimensions(): EventDimensions {
|
||||||
const start_of_day = moment(this.from).startOf('day')
|
const start_of_day = this.from.startOf('day')
|
||||||
const from_percentage = this.from.diff(start_of_day, 'minutes') / Event.MINUTES_IN_DAY
|
const from_percentage = (this.from.diff(start_of_day, 'minutes').minutes) / Event.MINUTES_IN_DAY
|
||||||
const to_percentage = this.to.diff(start_of_day, 'minutes') / Event.MINUTES_IN_DAY
|
const to_percentage = (this.to.diff(start_of_day, 'minutes').minutes) / Event.MINUTES_IN_DAY
|
||||||
return {
|
return {
|
||||||
from: from_percentage * 100,
|
from: from_percentage * 100,
|
||||||
to: to_percentage * 100
|
to: to_percentage * 100
|
||||||
@@ -34,18 +33,18 @@ export class Event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static fromSerializable(event: SerializableEvent) {
|
static fromSerializable(event: SerializableEvent) {
|
||||||
return new Event(event.title, moment(event.from), moment(event.to))
|
return new Event(event.title, DateTime.fromISO(event.from), DateTime.fromISO(event.to))
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromPercentDimensions(title: string, dimensions: EventDimensions, date: Moment): Event {
|
static fromPercentDimensions(title: string, dimensions: EventDimensions, date: DateTime): Event {
|
||||||
return new Event(
|
return new Event(
|
||||||
title,
|
title,
|
||||||
moment(date).startOf('day').minutes((dimensions.from / 100) * Event.MINUTES_IN_DAY),
|
date.startOf('day').plus({ minutes: (dimensions.from / 100) * Event.MINUTES_IN_DAY }),
|
||||||
moment(date).startOf('day').minutes((dimensions.to / 100) * Event.MINUTES_IN_DAY)
|
date.startOf('day').plus({ minutes: (dimensions.to / 100) * Event.MINUTES_IN_DAY })
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromPixelDimensions(title: string, dimensions: EventDimensions, height: number, date: Moment): Event {
|
static fromPixelDimensions(title: string, dimensions: EventDimensions, height: number, date: DateTime): Event {
|
||||||
const percentDimensions: EventDimensions = {
|
const percentDimensions: EventDimensions = {
|
||||||
from: dimensions.from * 100 / height,
|
from: dimensions.from * 100 / height,
|
||||||
to: dimensions.to * 100 / height
|
to: dimensions.to * 100 / height
|
||||||
@@ -84,8 +83,8 @@ export class Event {
|
|||||||
toSerializable(): SerializableEvent {
|
toSerializable(): SerializableEvent {
|
||||||
return {
|
return {
|
||||||
title: this.title,
|
title: this.title,
|
||||||
from: this.from.toISOString(),
|
from: this.from.toISO() ?? '',
|
||||||
to: this.to.toISOString()
|
to: this.to.toISO() ?? ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +100,7 @@ export class Event {
|
|||||||
const offset = mouseY - pixelDimensions.from
|
const offset = mouseY - pixelDimensions.from
|
||||||
|
|
||||||
return {
|
return {
|
||||||
date: moment(this.from).startOf('day'),
|
date: this.from.startOf('day'),
|
||||||
top: pixelDimensions.from,
|
top: pixelDimensions.from,
|
||||||
height: pixelDimensions.to - pixelDimensions.from,
|
height: pixelDimensions.to - pixelDimensions.from,
|
||||||
target: this,
|
target: this,
|
||||||
@@ -118,8 +117,8 @@ export type EventDimensions = {
|
|||||||
|
|
||||||
export type SimpleEvent = {
|
export type SimpleEvent = {
|
||||||
title: string,
|
title: string,
|
||||||
from: Moment,
|
from: DateTime,
|
||||||
to: Moment
|
to: DateTime
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SerializableEvent = {
|
export type SerializableEvent = {
|
||||||
@@ -134,7 +133,7 @@ export type CollissionWrapper = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type DraggedEvent = {
|
export type DraggedEvent = {
|
||||||
date: Moment,
|
date: DateTime,
|
||||||
top: number,
|
top: number,
|
||||||
height: number,
|
height: number,
|
||||||
target: Event,
|
target: Event,
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
|
import type { DateTime } from "luxon"
|
||||||
import type { Moment } from "moment"
|
import type { Moment } from "moment"
|
||||||
|
|
||||||
export type Seperator = {
|
export type Seperator = {
|
||||||
text: string,
|
text: string,
|
||||||
time: Moment
|
time: DateTime
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Timespan = {
|
export type Timespan = {
|
||||||
|
|||||||
Reference in New Issue
Block a user