added calendar and implemented bridge between small and big calendar
This commit is contained in:
@@ -4,11 +4,14 @@
|
|||||||
"": {
|
"": {
|
||||||
"name": "nuxt-app",
|
"name": "nuxt-app",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@iconify-json/lucide": "^1.2.42",
|
||||||
"@internationalized/date": "^3.8.0",
|
"@internationalized/date": "^3.8.0",
|
||||||
"@nuxt/eslint": "1.3.0",
|
"@nuxt/eslint": "1.3.0",
|
||||||
"@nuxt/test-utils": "3.18.0",
|
"@nuxt/test-utils": "3.18.0",
|
||||||
"@nuxt/ui": "3.1.1",
|
"@nuxt/ui": "3.1.1",
|
||||||
|
"@types/moment": "^2.13.0",
|
||||||
"eslint": "^9.0.0",
|
"eslint": "^9.0.0",
|
||||||
|
"moment": "^2.30.1",
|
||||||
"nuxt": "^3.17.2",
|
"nuxt": "^3.17.2",
|
||||||
"nuxt-app": "file:",
|
"nuxt-app": "file:",
|
||||||
"typescript": "^5.6.3",
|
"typescript": "^5.6.3",
|
||||||
@@ -192,6 +195,8 @@
|
|||||||
|
|
||||||
"@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.2", "", {}, "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ=="],
|
"@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.2", "", {}, "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ=="],
|
||||||
|
|
||||||
|
"@iconify-json/lucide": ["@iconify-json/lucide@1.2.42", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-exkRygF4yd6e5q966TXJQc/b+MAu3iQb8LeExCjl2JoP4/RlpudkYpg1AIZVCVCjAiElDYmVJYDWiJXPLkFN/g=="],
|
||||||
|
|
||||||
"@iconify/collections": ["@iconify/collections@1.0.545", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-LQprSmX6Wp69insYYSHM6bj5ZF4gT4ZwoqX9UXdCxGxRMzRpaNzQZUZ++2kP0wnOg3lX2ocMla8ns8oRPzxO2g=="],
|
"@iconify/collections": ["@iconify/collections@1.0.545", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-LQprSmX6Wp69insYYSHM6bj5ZF4gT4ZwoqX9UXdCxGxRMzRpaNzQZUZ++2kP0wnOg3lX2ocMla8ns8oRPzxO2g=="],
|
||||||
|
|
||||||
"@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="],
|
"@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="],
|
||||||
@@ -468,6 +473,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/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=="],
|
||||||
|
|
||||||
"@types/normalize-package-data": ["@types/normalize-package-data@2.4.4", "", {}, "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA=="],
|
"@types/normalize-package-data": ["@types/normalize-package-data@2.4.4", "", {}, "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA=="],
|
||||||
@@ -1392,6 +1399,8 @@
|
|||||||
|
|
||||||
"module-definition": ["module-definition@5.0.1", "", { "dependencies": { "ast-module-types": "^5.0.0", "node-source-walk": "^6.0.1" }, "bin": { "module-definition": "bin/cli.js" } }, "sha512-kvw3B4G19IXk+BOXnYq/D/VeO9qfHaapMeuS7w7sNUqmGaA6hywdFHMi+VWeR9wUScXM7XjoryTffCZ5B0/8IA=="],
|
"module-definition": ["module-definition@5.0.1", "", { "dependencies": { "ast-module-types": "^5.0.0", "node-source-walk": "^6.0.1" }, "bin": { "module-definition": "bin/cli.js" } }, "sha512-kvw3B4G19IXk+BOXnYq/D/VeO9qfHaapMeuS7w7sNUqmGaA6hywdFHMi+VWeR9wUScXM7XjoryTffCZ5B0/8IA=="],
|
||||||
|
|
||||||
|
"moment": ["moment@2.30.1", "", {}, "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how=="],
|
||||||
|
|
||||||
"mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="],
|
"mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="],
|
||||||
|
|
||||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||||
|
|||||||
18
web/components/ui/MainContent.vue
Normal file
18
web/components/ui/MainContent.vue
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { Moment } from 'moment';
|
||||||
|
import Calendar from './calendar/Calendar.vue'
|
||||||
|
import { Event } from '~/utils/event';
|
||||||
|
import { UCard } from '#components';
|
||||||
|
|
||||||
|
const events = defineModel<Event[]>('events', { required: true })
|
||||||
|
const date = defineModel<Moment>('date', { required: true })
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<UCard class="flex grow" :ui="{ body: 'w-full h-full' }">
|
||||||
|
<Calendar v-model:events="events" v-model:date="date"></Calendar>
|
||||||
|
</UCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
@@ -2,13 +2,29 @@
|
|||||||
import { CalendarDate } from '@internationalized/date';
|
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 { Moment } from 'moment';
|
||||||
|
import moment from 'moment';
|
||||||
|
|
||||||
const selectedDate = shallowRef(new CalendarDate(2024, 6, 29));
|
const dropDownItems = ref<DropdownMenuItem[]>([
|
||||||
|
{ label: "Profile", icon: "i-lucide-user" },
|
||||||
const dropDownItems = ref<DropDownMenuItems>([
|
{ label: "Settings", icon: "i-lucide-settings" }
|
||||||
{label: "Profile", icon: "i-lucide-user"}
|
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const date = defineModel<Moment>('date', { required: true })
|
||||||
|
|
||||||
|
const selectedDate = computed({
|
||||||
|
get() {
|
||||||
|
return new CalendarDate(date.value.year(), date.value.month() + 1, date.value.date())
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
if (value === undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
date.value = moment(value.toString());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
todos: string[]
|
todos: string[]
|
||||||
}>()
|
}>()
|
||||||
@@ -17,35 +33,32 @@ defineProps<{
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<UCard class="flex w-64 h-full">
|
<UCard class="flex w-64 h-full">
|
||||||
<div class="flex flex-col h-full w-full">
|
<div class="flex flex-col h-full w-full gap-5">
|
||||||
<header>
|
<header class="flex flex-col gap-2">
|
||||||
<Title1>Calendar</Title1>
|
<Title1>Calendar</Title1>
|
||||||
<UCalendar v-model="selectedDate" />
|
<UCalendar v-model="selectedDate" />
|
||||||
</header>
|
</header>
|
||||||
<div class="flex flex-col grow justify-between">
|
<div class="flex flex-col grow justify-between">
|
||||||
<div>
|
<div class="flex flex-col gap-2">
|
||||||
<Title1>Todos</Title1>
|
<Title1>Todos</Title1>
|
||||||
<div class="flex gap-2 flex-col">
|
<div class="flex gap-2 flex-col">
|
||||||
<ListItem v-for="todo in todos">{{ todo }}</ListItem>
|
<ListItem v-for="todo in todos">{{ todo }}</ListItem>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<UButton class="w-full flex justify-center">
|
<UButton size="xl" class="w-full flex justify-center">
|
||||||
+
|
+
|
||||||
</UButton>
|
</UButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<footer class="pt-4">
|
<footer class="pt-4">
|
||||||
<UDropdownMenu
|
<UDropdownMenu :items="dropDownItems" size="xl" :ui="{
|
||||||
:items="dropDownItems"
|
content: 'w-60'
|
||||||
:ui="{
|
}">
|
||||||
content: 'w-full'
|
<UButton variant="ghost" class="flex gap-1 items-center w-full text-text">
|
||||||
}"
|
|
||||||
>
|
|
||||||
<UButton class="flex gap-1 items-center">
|
|
||||||
<UAvatar src="https://github.com/benjamincanac.png" />
|
<UAvatar src="https://github.com/benjamincanac.png" />
|
||||||
Sebastian Peinbauer
|
Sebastian Peinbauer
|
||||||
</Ubutton>
|
</UButton>
|
||||||
</UDropdownMenu>
|
</UDropdownMenu>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ 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 moment, { type Moment } from 'moment';
|
||||||
|
import { Event } from '~/utils/event';
|
||||||
|
|
||||||
const events = defineModel<Event[]>('events', { required: true })
|
const events = defineModel<Event[]>('events', { required: true })
|
||||||
const date = ref(moment())
|
const date = defineModel<Moment>('date', { required: true })
|
||||||
const draggedEvent = ref<DraggedEvent | undefined>()
|
const draggedEvent = ref<DraggedEvent | undefined>()
|
||||||
|
|
||||||
type Day = {
|
type Day = {
|
||||||
@@ -105,8 +106,8 @@ function quickCreate(date: Moment, timespan: Timespan) {
|
|||||||
<div class="calendar flex flex-row w-full flex-1 items-stretch">
|
<div class="calendar flex flex-row w-full flex-1 items-stretch">
|
||||||
<CalendarHeader :seperators="seperators" />
|
<CalendarHeader :seperators="seperators" />
|
||||||
|
|
||||||
<CalendarCollumn v-for="day in days" :seperators="seperators" :day="day.date" :events="day.events" v-model:draggedEvent="draggedEvent"
|
<CalendarCollumn v-for="day in days" :seperators="seperators" :day="day.date" :events="day.events"
|
||||||
@quick-create="quickCreate" />
|
v-model:draggedEvent="draggedEvent" @quick-create="quickCreate" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -92,13 +92,13 @@ 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 bg-gray-600 h-18 text-white border-b-2 border-white">
|
<div class="flex justify-center items-center flex-col h-18 border-b-2 border-text">
|
||||||
<div>{{ props.day.format('dd').toUpperCase() }}</div>
|
<div>{{ props.day.format('dd').toUpperCase() }}</div>
|
||||||
<div>{{ props.day.date() }}</div>
|
<div>{{ props.day.date() }}</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="bg-gray-600 text-white relative flex flex-col grow items-center">
|
@dragend="dragDrop" class="relative flex flex-col grow items-center">
|
||||||
<CalendarSeperator v-for="sep in seperators" :seperator="sep">
|
<CalendarSeperator v-for="sep in seperators" :seperator="sep">
|
||||||
<hr class="w-full">
|
<hr class="w-full">
|
||||||
</CalendarSeperator>
|
</CalendarSeperator>
|
||||||
@@ -109,7 +109,8 @@ 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)" class="absolute w-11/12 top-20 bg-black opacity-45 rounded-lg"
|
<div v-if="draggedEvent !== undefined && draggedEvent.date.isSame(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>
|
:style="{ height: `${draggedEvent.height}px`, top: `${draggedEvent.top}px` }"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ defineProps<{
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col h-full grow">
|
<div class="flex flex-col h-full w-32">
|
||||||
<div class="flex justify-center items-center bg-gray-600 h-18 text-white border-b-white border-b-2">vue-calendar
|
<div class="flex justify-center items-center h-18 border-b-text border-b-2">vue-calendar
|
||||||
</div>
|
</div>
|
||||||
<div class="calendar-legend bg-gray-600 text-white relative flex flex-col grow justify-evenly">
|
<div class="calendar-legend relative flex flex-col grow justify-evenly">
|
||||||
<CalendarSeperator v-for="sep in seperators" :seperator="sep">
|
<CalendarSeperator v-for="sep in seperators" :seperator="sep">
|
||||||
{{ sep.text }}
|
{{ sep.text }}
|
||||||
</CalendarSeperator>
|
</CalendarSeperator>
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ const relativePositionOf = function (time: Moment) {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :style="{top: relativePositionOf(seperator.time)}" class="h-10 w-full flex justify-center items-center text-white border-white absolute -translate-y-1/2">
|
<div :style="{ top: relativePositionOf(seperator.time) }"
|
||||||
|
class="h-10 w-full flex justify-center items-center border-white absolute -translate-y-1/2">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -10,11 +10,14 @@
|
|||||||
"postinstall": "nuxt prepare"
|
"postinstall": "nuxt prepare"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@iconify-json/lucide": "^1.2.42",
|
||||||
"@internationalized/date": "^3.8.0",
|
"@internationalized/date": "^3.8.0",
|
||||||
"@nuxt/eslint": "1.3.0",
|
"@nuxt/eslint": "1.3.0",
|
||||||
"@nuxt/test-utils": "3.18.0",
|
"@nuxt/test-utils": "3.18.0",
|
||||||
"@nuxt/ui": "3.1.1",
|
"@nuxt/ui": "3.1.1",
|
||||||
|
"@types/moment": "^2.13.0",
|
||||||
"eslint": "^9.0.0",
|
"eslint": "^9.0.0",
|
||||||
|
"moment": "^2.30.1",
|
||||||
"nuxt": "^3.17.2",
|
"nuxt": "^3.17.2",
|
||||||
"nuxt-app": "file:",
|
"nuxt-app": "file:",
|
||||||
"typescript": "^5.6.3",
|
"typescript": "^5.6.3",
|
||||||
|
|||||||
@@ -1,24 +1,18 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import moment from 'moment';
|
||||||
|
import MainContent from '~/components/ui/MainContent.vue';
|
||||||
import Sidebar from '~/components/ui/Sidebar.vue';
|
import Sidebar from '~/components/ui/Sidebar.vue';
|
||||||
import Calendar from '~/components/ui/calendar/Calendar.vue'
|
|
||||||
import moment, { type Moment } from 'moment';
|
|
||||||
|
|
||||||
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(moment())
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
date.value.subtract(10,"days")
|
|
||||||
})
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="h-screen w-screen p-4 flex flex-row gap-5">
|
<div class="h-screen w-screen p-4 flex flex-row gap-5">
|
||||||
<Sidebar :todos="todos" />
|
<Sidebar :todos="todos" v-model:date="date" />
|
||||||
<div class="flex grow">
|
<MainContent v-model:events="events" v-model:date="date" />
|
||||||
<Calendar v-model:events="events" v-model:date="date"></Calendar>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -19,21 +19,10 @@ export type AnonymousEvent = {
|
|||||||
to: Moment
|
to: Moment
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SerializableEvent = {
|
|
||||||
title: string,
|
|
||||||
from: string,
|
|
||||||
to: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export type EventWithCollisions = Event & {
|
export type EventWithCollisions = Event & {
|
||||||
collisions: number
|
collisions: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export type EventDimensions = {
|
|
||||||
from: number,
|
|
||||||
to: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export function percentToPixelDimensions(dimensions: EventDimensions, totalHeight: number): EventDimensions {
|
export function percentToPixelDimensions(dimensions: EventDimensions, totalHeight: number): EventDimensions {
|
||||||
return {
|
return {
|
||||||
from: (dimensions.from / 100) * totalHeight,
|
from: (dimensions.from / 100) * totalHeight,
|
||||||
|
|||||||
Reference in New Issue
Block a user