dragging task in the calendar works visually
This commit is contained in:
@@ -6,6 +6,7 @@ import type { DateTime } from 'luxon';
|
||||
|
||||
const events = defineModel<Event[]>('events', { required: true })
|
||||
const date = defineModel<DateTime>('date', { required: true })
|
||||
const draggedTask = defineModel<DraggedTask | undefined>('draggedTask', { required: true })
|
||||
|
||||
const emits = defineEmits<{
|
||||
(e: 'createEvent', event: Event): void
|
||||
@@ -15,7 +16,9 @@ const emits = defineEmits<{
|
||||
|
||||
<template>
|
||||
<UCard class="flex grow" :ui="{ body: 'w-full h-full' }">
|
||||
<Calendar @create="(event) => emits('createEvent', event)"v-model:events="events" v-model:date="date"></Calendar>
|
||||
<Calendar @create="(event) => emits('createEvent', event)" v-model:events="events" v-model:date="date" ,
|
||||
v-model:dragged-task="draggedTask">
|
||||
</Calendar>
|
||||
</UCard>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import { DateTime } from 'luxon';
|
||||
|
||||
const colorMode = useColorMode();
|
||||
const toast = useToast()
|
||||
const instance = getCurrentInstance()
|
||||
|
||||
const currentTheme = ref<'dark' | 'system' | 'light'>(colorMode.preference as 'dark' | 'system' | 'light');
|
||||
const showTaskCreateModal = ref(false);
|
||||
@@ -20,6 +21,7 @@ const emits = defineEmits<{
|
||||
(e: 'createTask', task: Task): void
|
||||
(e: 'deleteTask', id: number): void
|
||||
(e: 'editTask', task: Task): void
|
||||
(e: 'scheduleTask', task: Task): void
|
||||
}>()
|
||||
|
||||
const isLight = computed(() => currentTheme.value === 'light');
|
||||
@@ -96,6 +98,7 @@ function deleteTask(task: Task) {
|
||||
|
||||
emits('deleteTask', task.id)
|
||||
}
|
||||
|
||||
function editTask(task: Task) {
|
||||
emits('editTask', task)
|
||||
}
|
||||
@@ -110,6 +113,10 @@ function openTaskEditModal(task: Task) {
|
||||
showTaskEditModal.value = true
|
||||
}
|
||||
|
||||
function scheduleTask(task: Task) {
|
||||
emits('scheduleTask', task)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -129,7 +136,8 @@ function openTaskEditModal(task: Task) {
|
||||
<Title1>Tasks</Title1>
|
||||
<div class="flex gap-2 flex-col">
|
||||
<ListItem v-for="task in todoTasks">
|
||||
<div class="flex w-full gap-4 items-center">
|
||||
<div class="flex w-full gap-4 items-center" @dragstart="scheduleTask(task)"
|
||||
draggable="true">
|
||||
<span
|
||||
class="grow overflow-scroll py-3 overflow-shadow flex flex-row gap-2 items-center">
|
||||
<UCheckbox v-model="task.done" @change="() => editTask(task)" />{{ task.title }}
|
||||
@@ -144,7 +152,8 @@ function openTaskEditModal(task: Task) {
|
||||
</ListItem>
|
||||
<USeparator label="Done" v-if="todoTasks.length !== 0" />
|
||||
<ListItem v-for="task in doneTasks">
|
||||
<div class="flex w-full gap-4 items-center">
|
||||
<div class="flex w-full gap-4 items-center" @dragstart="scheduleTask(task)"
|
||||
draggable="true">
|
||||
<span
|
||||
class="grow overflow-scroll py-3 overflow-shadow flex flex-row gap-2 items-center">
|
||||
<UCheckbox v-model="task.done" @change="() => editTask(task)" />{{ task.title }}
|
||||
|
||||
@@ -5,7 +5,7 @@ import * as z from 'zod';
|
||||
const open = defineModel<boolean>('open', { required: true })
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'submnitted', event: SimpleTask): void
|
||||
(e: 'submnitted', event: Task): void
|
||||
(e: 'canceled'): void
|
||||
}>()
|
||||
|
||||
@@ -63,14 +63,15 @@ function submit() {
|
||||
return
|
||||
}
|
||||
|
||||
emit('submnitted', {
|
||||
emit('submnitted', Task.fromSimpleTask({
|
||||
id: props.input.id,
|
||||
title: form.data.title,
|
||||
done: props.input.done ?? false,
|
||||
description: form.data.description,
|
||||
estimated_time: form.data.estimated_time,
|
||||
due_date: DateTime.fromISO(form.data.due_date)
|
||||
})
|
||||
due_date: DateTime.fromISO(form.data.due_date),
|
||||
scheduled_at: props.input.scheduled_at
|
||||
}))
|
||||
open.value = false
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import EventFormModal from '../EventFormModal.vue';
|
||||
|
||||
const events = defineModel<Event[]>('events', { required: true })
|
||||
const date = defineModel<DateTime>('date', { required: true })
|
||||
const draggedTask = defineModel<DraggedTask | undefined>('draggedTask', { required: true })
|
||||
const draggedEvent = ref<DraggedEvent | undefined>()
|
||||
const createInput = ref<Partial<SimpleEvent>>({})
|
||||
const createModalOpened = ref(false)
|
||||
@@ -161,7 +162,8 @@ function moveEvent(event: Event) {
|
||||
<EventFormModal action="edit" @submnitted="event => edit(event)" :input="editInput"
|
||||
v-model:open="editModalOpened" />
|
||||
|
||||
<UModal v-model:open="deleteModalOpened" title="Delete Event" description="Are you sure you want to delete this event?">
|
||||
<UModal v-model:open="deleteModalOpened" title="Delete Event"
|
||||
description="Are you sure you want to delete this event?">
|
||||
<template #footer>
|
||||
<UButton variant="solid" @click="deleteEvent">
|
||||
Delete
|
||||
@@ -176,8 +178,8 @@ function moveEvent(event: Event) {
|
||||
<CalendarHeader :seperators="seperators" />
|
||||
|
||||
<CalendarCollumn v-for="day in days" :seperators="seperators" :day="day.date" :events="day.events"
|
||||
:date="date" v-model:draggedEvent="draggedEvent" @quick-create="openCreateModal"
|
||||
@edit="openEditModal" @delete="openDeleteModal" @moved="moveEvent" />
|
||||
:date="date" v-model:draggedEvent="draggedEvent" @quick-create="openCreateModal" @edit="openEditModal"
|
||||
@delete="openDeleteModal" @moved="moveEvent" v-model:dragged-task="draggedTask" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -25,6 +25,7 @@ const startY = ref(0)
|
||||
const endY = ref(0)
|
||||
const column = useTemplateRef('column')
|
||||
const draggedEvent = defineModel<DraggedEvent | undefined>('draggedEvent')
|
||||
const draggedTask = defineModel<DraggedTask | undefined>('draggedTask')
|
||||
|
||||
const height = computed(() => {
|
||||
return Math.abs(endY.value - startY.value)
|
||||
@@ -83,6 +84,29 @@ function eventMove(mouseEvent: MouseEvent, event: Event) {
|
||||
}
|
||||
|
||||
function dragover(e: DragEvent) {
|
||||
drawDraggedEvent(e)
|
||||
drawDraggedTask(e)
|
||||
}
|
||||
|
||||
function drawDraggedTask(event: DragEvent) {
|
||||
if (draggedTask.value === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (draggedTask.value.dragInfo === undefined) {
|
||||
draggedTask.value.dragInfo = {
|
||||
height: (draggedTask.value.target.estimated_time / 60 / 24) * (column.value?.offsetHeight ?? 0),
|
||||
top: absoluteToRelativeY(event.clientY),
|
||||
date: props.day
|
||||
}
|
||||
drawDraggedTask(event)
|
||||
}
|
||||
|
||||
draggedTask.value.dragInfo.top = absoluteToRelativeY(event.clientY)
|
||||
draggedTask.value.dragInfo.date = props.day
|
||||
}
|
||||
|
||||
function drawDraggedEvent(event: DragEvent) {
|
||||
if (draggedEvent.value === undefined) {
|
||||
return
|
||||
}
|
||||
@@ -92,13 +116,13 @@ function dragover(e: DragEvent) {
|
||||
}
|
||||
|
||||
|
||||
draggedEvent.value.top = absoluteToRelativeY(e.clientY) - draggedEvent.value.offset
|
||||
draggedEvent.value.top = absoluteToRelativeY(event.clientY) - draggedEvent.value.offset
|
||||
}
|
||||
|
||||
function dragDrop(_: DragEvent) {
|
||||
draggedEvent.value?.target.updateWithDraggedEvent(draggedEvent.value, column.value?.offsetHeight ?? 0)
|
||||
|
||||
if (draggedEvent.value === undefined){
|
||||
if (draggedEvent.value === undefined) {
|
||||
draggedEvent.value = undefined
|
||||
return
|
||||
}
|
||||
@@ -134,6 +158,9 @@ function dragDrop(_: DragEvent) {
|
||||
<div v-if="draggedEvent !== undefined && draggedEvent.date.equals(props.day)"
|
||||
class="absolute w-11/12 top-20 bg-black opacity-45 rounded-lg"
|
||||
:style="{ height: `${draggedEvent.height}px`, top: `${draggedEvent.top}px` }"></div>
|
||||
<div v-if="draggedTask !== undefined && draggedTask.dragInfo !== undefined && draggedTask.dragInfo.date.equals(props.day)"
|
||||
class="absolute w-11/12 top-20 bg-black opacity-45 rounded-lg"
|
||||
:style="{ height: `${draggedTask.dragInfo.height}px`, top: `${draggedTask.dragInfo.top}px` }"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -8,6 +8,7 @@ import { Event, type SerializableEvent } from '~/utils/event';
|
||||
const date = ref<DateTime>(DateTime.now())
|
||||
const events = ref<Event[]>([])
|
||||
const tasks = ref<Task[]>([])
|
||||
const draggedTask = ref<DraggedTask | undefined>(undefined)
|
||||
|
||||
const { data: eventsResponse } = await useAsyncData<SerializableEvent[]>(
|
||||
'events',
|
||||
@@ -42,13 +43,18 @@ async function deleteTask(id: number) {
|
||||
await refresh()
|
||||
}
|
||||
|
||||
function scheduleTask(task: Task) {
|
||||
draggedTask.value = { target: task, dragInfo: undefined }
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="h-screen w-screen p-4 flex flex-row gap-5">
|
||||
<Sidebar v-if="tasks !== null" v-model:tasks="tasks" v-model:date="date" @create-task="postTask"
|
||||
@delete-task="deleteTask" />
|
||||
<MainContent v-if="events !== null" v-model:events="events" v-model:date="date" @create-event="postEvent" />
|
||||
@delete-task="deleteTask" @schedule-task="scheduleTask"/>
|
||||
<MainContent v-if="events !== null" v-model:events="events" v-model:date="date"
|
||||
v-model:dragged-task="draggedTask" @create-event="postEvent" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@ export class Task {
|
||||
public description: string,
|
||||
public done: boolean,
|
||||
public estimated_time: number,
|
||||
public due_date: DateTime | undefined
|
||||
public due_date: DateTime | undefined,
|
||||
public scheduled_at: DateTime | undefined
|
||||
) { }
|
||||
|
||||
static fromSimpleTask(simpleTask: SimpleTask) {
|
||||
@@ -17,7 +18,8 @@ export class Task {
|
||||
simpleTask.description,
|
||||
simpleTask.done,
|
||||
simpleTask.estimated_time,
|
||||
simpleTask.due_date
|
||||
simpleTask.due_date,
|
||||
simpleTask.scheduled_at
|
||||
)
|
||||
}
|
||||
|
||||
@@ -29,9 +31,18 @@ export class Task {
|
||||
serializableTask.description,
|
||||
serializableTask.done,
|
||||
serializableTask.estimated_time,
|
||||
DateTime.now()
|
||||
stringToDate(serializableTask.due_date),
|
||||
stringToDate(serializableTask.scheduled_at),
|
||||
)
|
||||
}
|
||||
|
||||
isPersistent() {
|
||||
return this.id !== undefined
|
||||
}
|
||||
|
||||
isScheduled() {
|
||||
return this.scheduled_at !== undefined
|
||||
}
|
||||
}
|
||||
|
||||
export type SimpleTask = {
|
||||
@@ -40,6 +51,7 @@ export type SimpleTask = {
|
||||
description: string
|
||||
done: boolean
|
||||
estimated_time: number
|
||||
scheduled_at: DateTime | undefined
|
||||
due_date: DateTime | undefined
|
||||
}
|
||||
|
||||
@@ -50,7 +62,24 @@ export type SerializableTask = {
|
||||
done: boolean
|
||||
estimated_time: number
|
||||
due_date: string | undefined
|
||||
scheduled_at: string | undefined
|
||||
created_at: string
|
||||
updated_at: string
|
||||
userid: string
|
||||
}
|
||||
|
||||
export type DraggedTask = {
|
||||
target: Task,
|
||||
dragInfo: {
|
||||
top: number,
|
||||
date: DateTime
|
||||
height: number
|
||||
} | undefined
|
||||
}
|
||||
|
||||
function stringToDate(date: string | undefined) {
|
||||
if (date === undefined) {
|
||||
return undefined
|
||||
}
|
||||
return DateTime.fromISO(date)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user