added overflow for tasks and overflow shadow to all overflows. also
minimum drag distance is now 10px
This commit is contained in:
@@ -1,6 +1,13 @@
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui";
|
||||
|
||||
.overflow-shadow {
|
||||
overflow-x: auto;
|
||||
position: relative;
|
||||
mask-image: linear-gradient(to right, rgba(0,0,0,1) 90%, rgba(0,0,0,0));
|
||||
-webkit-mask-image: linear-gradient(to right, rgba(0,0,0,1) 90%, rgba(0,0,0,0));
|
||||
}
|
||||
|
||||
:root {
|
||||
--ui-primary: #C02942;
|
||||
--ui-text-dimmed: var(--ui-color-neutral-400);
|
||||
|
||||
@@ -71,6 +71,7 @@ function submit() {
|
||||
}
|
||||
|
||||
emit('submnitted', {
|
||||
id: props.input.id,
|
||||
title: form.data.title,
|
||||
description: form.data.description,
|
||||
from: DateTime.fromISO(form.data.from),
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UCard class="[&>*]:p-3">
|
||||
<UCard class="[&>*]:p-3 w-full">
|
||||
<slot />
|
||||
</UCard>
|
||||
</template>
|
||||
|
||||
@@ -75,19 +75,19 @@ const selectedDate = computed({
|
||||
})
|
||||
|
||||
type Task = {
|
||||
id: number
|
||||
userid: string
|
||||
title: string
|
||||
description: string
|
||||
done: number
|
||||
estimated_time: string
|
||||
due_date: string
|
||||
created_at: string
|
||||
updated_at: string
|
||||
id: number
|
||||
userid: string
|
||||
title: string
|
||||
description: string
|
||||
done: number
|
||||
estimated_time: string
|
||||
due_date: string
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
defineProps<{
|
||||
todos: Task[]
|
||||
todos: Task[]
|
||||
}>()
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ function editTodo() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UCard class="flex w-64 h-full">
|
||||
<UCard class="flex w-64 h-full" :ui="{ body: 'w-full' }">
|
||||
<div class="flex flex-col h-full w-full gap-5">
|
||||
<header class="flex flex-col gap-2">
|
||||
<Title1>Calendar</Title1>
|
||||
@@ -120,20 +120,37 @@ function editTodo() {
|
||||
<Title1>Todos</Title1>
|
||||
<div class="flex gap-2 flex-col">
|
||||
<ListItem v-for="todo in todos">
|
||||
<div class="flex justify-between">
|
||||
<span>
|
||||
<div class="flex w-full gap-4 items-center">
|
||||
<span class="grow overflow-scroll py-3 overflow-shadow">
|
||||
{{ todo.title }}
|
||||
</span>
|
||||
<div class="flex gap-1">
|
||||
<UButton size="xs" color="neutral" class="flex justify-center" @click="editTodo">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-pencil"><path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"></path><path d="m15 5 4 4"></path></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15"
|
||||
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-pencil">
|
||||
<path
|
||||
d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z">
|
||||
</path>
|
||||
<path d="m15 5 4 4"></path>
|
||||
</svg>
|
||||
</UButton>
|
||||
<UButton size="xs" class="flex justify-center" color="primary" @click="() => deleteTodo(todo)">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-trash-2"><path d="M3 6h18"></path><path d="M19 6v14c0 1-2 2-2 2H7c-1 0-2-1-2-2V6"></path><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"></path><line x1="10" x2="10" y1="11" y2="17"></line><line x1="14" x2="14" y1="11" y2="17"></line></svg>
|
||||
<UButton size="xs" class="flex justify-center" color="primary"
|
||||
@click="() => deleteTodo(todo)">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15"
|
||||
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round"
|
||||
class="lucide lucide-trash-2">
|
||||
<path d="M3 6h18"></path>
|
||||
<path d="M19 6v14c0 1-2 2-2 2H7c-1 0-2-1-2-2V6"></path>
|
||||
<path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"></path>
|
||||
<line x1="10" x2="10" y1="11" y2="17"></line>
|
||||
<line x1="14" x2="14" y1="11" y2="17"></line>
|
||||
</svg>
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
</ListItem>
|
||||
</ListItem>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
@@ -157,4 +174,6 @@ function editTodo() {
|
||||
</UCard>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
|
||||
@@ -132,7 +132,19 @@ function openDeleteModal(event: Event) {
|
||||
function deleteEvent() {
|
||||
if (deleteContext.value === undefined) return
|
||||
emits('delete', deleteContext.value?.event)
|
||||
events.value = events.value.filter(e => e.title !== deleteContext.value?.event.title)
|
||||
console.log(events.value)
|
||||
events.value = events.value.filter(e => {
|
||||
if (e.id === undefined || deleteContext.value?.event.id === undefined) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (e.id === deleteContext.value?.event.id) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
deleteModalOpened.value = false
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,13 @@ function mouseup(_: MouseEvent) {
|
||||
|
||||
const timeFrom = Math.min(endY.value, startY.value) / column.value.offsetHeight
|
||||
const timeTo = Math.max(endY.value, startY.value) / column.value.offsetHeight
|
||||
|
||||
if (timeTo * column.value.offsetHeight - timeFrom * column.value.offsetHeight <= 10) {
|
||||
startY.value = 0
|
||||
endY.value = 0
|
||||
return
|
||||
}
|
||||
|
||||
emit('quick-create', props.day, {
|
||||
from: timeFrom,
|
||||
to: timeTo
|
||||
|
||||
@@ -64,7 +64,7 @@ function dragStart(e: DragEvent) {
|
||||
</template>
|
||||
<template #default>
|
||||
<div>{{ event.event.from.toFormat('HH:mm') }} - {{ event.event.to.toFormat('HH:mm') }}</div>
|
||||
<div class="overflow-scroll pb-5">
|
||||
<div class="overflow-scroll pb-5 overflow-shadow">
|
||||
{{ event.event.description }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import { Body } from '#components';
|
||||
import axios from 'axios';
|
||||
import { DateTime } from 'luxon';
|
||||
import MainContent from '~/components/ui/MainContent.vue';
|
||||
@@ -11,35 +10,35 @@ const date = ref<DateTime>(DateTime.now())
|
||||
const events = ref<Event[]>([])
|
||||
|
||||
const { data: eventsResponse } = await useAsyncData<SerializableEvent[]>(
|
||||
'events',
|
||||
() => axios.get('/events').then(res => res.data)
|
||||
'events',
|
||||
() => axios.get('/events').then(res => res.data)
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
events.value = eventsResponse.value?.map(Event.fromSerializable) ?? []
|
||||
events.value = eventsResponse.value?.map(Event.fromSerializable) ?? []
|
||||
})
|
||||
|
||||
type Task = {
|
||||
id: number
|
||||
userid: string
|
||||
title: string
|
||||
description: string
|
||||
done: number
|
||||
estimated_time: string
|
||||
due_date: string
|
||||
created_at: string
|
||||
updated_at: string
|
||||
id: number
|
||||
userid: string
|
||||
title: string
|
||||
description: string
|
||||
done: number
|
||||
estimated_time: string
|
||||
due_date: string
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
|
||||
const { data: tasks, refresh } = await useAsyncData<Task[]>(
|
||||
'tasks',
|
||||
() => {
|
||||
'tasks',
|
||||
() => {
|
||||
return axios.get("/tasks").then(result => {
|
||||
console.log(result.data)
|
||||
return result.data
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
async function postEvent(event: Event) {
|
||||
@@ -49,30 +48,31 @@ async function postEvent(event: Event) {
|
||||
|
||||
async function postTask(name: string) {
|
||||
console.log('posting Task')
|
||||
await axios.post('/task', {
|
||||
title: name,
|
||||
description: "",
|
||||
done: false,
|
||||
estimated_time: (new Date()).toISOString(), //TODO
|
||||
due_date: (new Date()).toISOString(),
|
||||
})
|
||||
await refresh()
|
||||
await axios.post('/task', {
|
||||
title: name,
|
||||
description: "",
|
||||
done: false,
|
||||
estimated_time: (new Date()).toISOString(), //TODO
|
||||
due_date: (new Date()).toISOString(),
|
||||
})
|
||||
await refresh()
|
||||
}
|
||||
|
||||
async function deleteTask(id: number) {
|
||||
console.log('deleting Task')
|
||||
await axios.delete(`/task/${id}`)
|
||||
await refresh()
|
||||
console.log('deleting Task')
|
||||
await axios.delete(`/task/${id}`)
|
||||
await refresh()
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="h-screen w-screen p-4 flex flex-row gap-5">
|
||||
<Sidebar v-if="tasks !== null" :todos="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"/>
|
||||
</div>
|
||||
<div class="h-screen w-screen p-4 flex flex-row gap-5">
|
||||
<Sidebar v-if="tasks !== null" :todos="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" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped></style>
|
||||
|
||||
@@ -4,7 +4,8 @@ export class Event {
|
||||
private static readonly MINUTES_IN_DAY = 24 * 60
|
||||
|
||||
constructor(
|
||||
public readonly title: string,
|
||||
public id: number | undefined,
|
||||
public title: string,
|
||||
public from: DateTime,
|
||||
public to: DateTime,
|
||||
public description: string
|
||||
@@ -39,15 +40,28 @@ export class Event {
|
||||
}
|
||||
|
||||
static fromSimple(event: SimpleEvent): Event {
|
||||
return new Event(event.title, event.from, event.to, event.description)
|
||||
return new Event(
|
||||
event.id,
|
||||
event.title,
|
||||
event.from,
|
||||
event.to,
|
||||
event.description
|
||||
)
|
||||
}
|
||||
|
||||
static fromSerializable(event: SerializableEvent) {
|
||||
return new Event(event.title, DateTime.fromISO(event.from), DateTime.fromISO(event.to), event.description)
|
||||
return new Event(
|
||||
event.id,
|
||||
event.title,
|
||||
DateTime.fromISO(event.from),
|
||||
DateTime.fromISO(event.to),
|
||||
event.description
|
||||
)
|
||||
}
|
||||
|
||||
static fromPercentDimensions(title: string, dimensions: EventDimensions, date: DateTime, description: string): Event {
|
||||
static fromPercentDimensions(id: number | undefined, title: string, dimensions: EventDimensions, date: DateTime, description: string): Event {
|
||||
return new Event(
|
||||
id,
|
||||
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 }),
|
||||
@@ -55,13 +69,13 @@ export class Event {
|
||||
)
|
||||
}
|
||||
|
||||
static fromPixelDimensions(title: string, dimensions: EventDimensions, height: number, date: DateTime, description: string): Event {
|
||||
static fromPixelDimensions(id: number | undefined, title: string, dimensions: EventDimensions, height: number, date: DateTime, description: string): Event {
|
||||
const percentDimensions: EventDimensions = {
|
||||
from: dimensions.from * 100 / height,
|
||||
to: dimensions.to * 100 / height
|
||||
}
|
||||
|
||||
return Event.fromPercentDimensions(title, percentDimensions, date, description)
|
||||
return Event.fromPercentDimensions(id, title, percentDimensions, date, description)
|
||||
}
|
||||
|
||||
static fromDraggedEvent(draggedEvent: DraggedEvent, height: number): Event {
|
||||
@@ -71,6 +85,7 @@ export class Event {
|
||||
}
|
||||
|
||||
return Event.fromPixelDimensions(
|
||||
draggedEvent.target.id,
|
||||
draggedEvent.target.title,
|
||||
pixelDimensions,
|
||||
height,
|
||||
@@ -91,6 +106,7 @@ export class Event {
|
||||
|
||||
toSimple(): SimpleEvent {
|
||||
return {
|
||||
id: this.id,
|
||||
title: this.title,
|
||||
from: this.from,
|
||||
to: this.to,
|
||||
@@ -100,6 +116,7 @@ export class Event {
|
||||
|
||||
toSerializable(): SerializableEvent {
|
||||
return {
|
||||
id: this.id,
|
||||
title: this.title,
|
||||
from: this.from.toISO() ?? '',
|
||||
to: this.to.toISO() ?? '',
|
||||
@@ -135,6 +152,7 @@ export type EventDimensions = {
|
||||
}
|
||||
|
||||
export type SimpleEvent = {
|
||||
id: number | undefined,
|
||||
title: string,
|
||||
from: DateTime,
|
||||
to: DateTime
|
||||
@@ -142,6 +160,7 @@ export type SimpleEvent = {
|
||||
}
|
||||
|
||||
export type SerializableEvent = {
|
||||
id: number | undefined,
|
||||
title: string,
|
||||
from: string,
|
||||
to: string
|
||||
|
||||
Reference in New Issue
Block a user