added calendar and implemented bridge between small and big calendar

This commit is contained in:
2025-05-11 21:13:56 +02:00
parent f8cb42962a
commit 555aca0a99
10 changed files with 77 additions and 48 deletions

View File

@@ -4,11 +4,14 @@
"": {
"name": "nuxt-app",
"dependencies": {
"@iconify-json/lucide": "^1.2.42",
"@internationalized/date": "^3.8.0",
"@nuxt/eslint": "1.3.0",
"@nuxt/test-utils": "3.18.0",
"@nuxt/ui": "3.1.1",
"@types/moment": "^2.13.0",
"eslint": "^9.0.0",
"moment": "^2.30.1",
"nuxt": "^3.17.2",
"nuxt-app": "file:",
"typescript": "^5.6.3",
@@ -192,6 +195,8 @@
"@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/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/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/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=="],
"moment": ["moment@2.30.1", "", {}, "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how=="],
"mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],

View 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>

View File

@@ -2,13 +2,29 @@
import { CalendarDate } from '@internationalized/date';
import ListItem from './ListItem.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<DropDownMenuItems>([
{label: "Profile", icon: "i-lucide-user"}
const dropDownItems = ref<DropdownMenuItem[]>([
{ label: "Profile", icon: "i-lucide-user" },
{ label: "Settings", icon: "i-lucide-settings" }
])
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<{
todos: string[]
}>()
@@ -17,35 +33,32 @@ defineProps<{
<template>
<UCard class="flex w-64 h-full">
<div class="flex flex-col h-full w-full">
<header>
<div class="flex flex-col h-full w-full gap-5">
<header class="flex flex-col gap-2">
<Title1>Calendar</Title1>
<UCalendar v-model="selectedDate" />
</header>
<div class="flex flex-col grow justify-between">
<div>
<div class="flex flex-col gap-2">
<Title1>Todos</Title1>
<div class="flex gap-2 flex-col">
<ListItem v-for="todo in todos">{{ todo }}</ListItem>
</div>
</div>
<div class="flex">
<UButton class="w-full flex justify-center">
<UButton size="xl" class="w-full flex justify-center">
+
</UButton>
</div>
</div>
<footer class="pt-4">
<UDropdownMenu
:items="dropDownItems"
:ui="{
content: 'w-full'
}"
>
<UButton class="flex gap-1 items-center">
<UDropdownMenu :items="dropDownItems" size="xl" :ui="{
content: 'w-60'
}">
<UButton variant="ghost" class="flex gap-1 items-center w-full text-text">
<UAvatar src="https://github.com/benjamincanac.png" />
Sebastian Peinbauer
</Ubutton>
</UButton>
</UDropdownMenu>
</footer>
</div>

View File

@@ -3,9 +3,10 @@ import { computed, ref } from 'vue';
import CalendarHeader from './CalendarHeader.vue';
import CalendarCollumn from './CalendarCollumn.vue';
import moment, { type Moment } from 'moment';
import { Event } from '~/utils/event';
const events = defineModel<Event[]>('events', { required: true })
const date = ref(moment())
const date = defineModel<Moment>('date', { required: true })
const draggedEvent = ref<DraggedEvent | undefined>()
type Day = {
@@ -18,7 +19,7 @@ const week = computed(() => {
})
function pushEventWithCollisionUpdate(array: CollissionWrapper[], event: Event, collisions: CollissionWrapper[], collisionCount: number) {
array.push({event: event, collisions: collisionCount })
array.push({ event: event, collisions: collisionCount })
for (let collision of collisions) {
collision.collisions = collisionCount
@@ -105,8 +106,8 @@ function quickCreate(date: Moment, timespan: Timespan) {
<div class="calendar flex flex-row w-full flex-1 items-stretch">
<CalendarHeader :seperators="seperators" />
<CalendarCollumn v-for="day in days" :seperators="seperators" :day="day.date" :events="day.events" v-model:draggedEvent="draggedEvent"
@quick-create="quickCreate" />
<CalendarCollumn v-for="day in days" :seperators="seperators" :day="day.date" :events="day.events"
v-model:draggedEvent="draggedEvent" @quick-create="quickCreate" />
</div>
</div>

View File

@@ -92,13 +92,13 @@ function dragDrop(_: DragEvent) {
<template>
<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.date() }}</div>
</div>
<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">
<hr class="w-full">
</CalendarSeperator>
@@ -109,7 +109,8 @@ function dragDrop(_: DragEvent) {
<CalendarEvent v-for="event in column" :event="event" :columnIndex="index" @move="eventMove" />
</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>
</div>
</div>

View File

@@ -10,10 +10,10 @@ defineProps<{
</script>
<template>
<div class="flex flex-col h-full grow">
<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 flex-col h-full w-32">
<div class="flex justify-center items-center h-18 border-b-text border-b-2">vue-calendar
</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">
{{ sep.text }}
</CalendarSeperator>

View File

@@ -12,7 +12,8 @@ const relativePositionOf = function (time: Moment) {
</script>
<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 />
</div>
</template>

View File

@@ -10,11 +10,14 @@
"postinstall": "nuxt prepare"
},
"dependencies": {
"@iconify-json/lucide": "^1.2.42",
"@internationalized/date": "^3.8.0",
"@nuxt/eslint": "1.3.0",
"@nuxt/test-utils": "3.18.0",
"@nuxt/ui": "3.1.1",
"@types/moment": "^2.13.0",
"eslint": "^9.0.0",
"moment": "^2.30.1",
"nuxt": "^3.17.2",
"nuxt-app": "file:",
"typescript": "^5.6.3",

View File

@@ -1,24 +1,18 @@
<script setup lang="ts">
import moment from 'moment';
import MainContent from '~/components/ui/MainContent.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 events = ref([])
const date = ref(moment())
onMounted(() => {
date.value.subtract(10,"days")
})
</script>
<template>
<div class="h-screen w-screen p-4 flex flex-row gap-5">
<Sidebar :todos="todos" />
<div class="flex grow">
<Calendar v-model:events="events" v-model:date="date"></Calendar>
</div>
<Sidebar :todos="todos" v-model:date="date" />
<MainContent v-model:events="events" v-model:date="date" />
</div>
</template>

View File

@@ -19,21 +19,10 @@ export type AnonymousEvent = {
to: Moment
}
export type SerializableEvent = {
title: string,
from: string,
to: string
}
export type EventWithCollisions = Event & {
collisions: number
}
export type EventDimensions = {
from: number,
to: number
}
export function percentToPixelDimensions(dimensions: EventDimensions, totalHeight: number): EventDimensions {
return {
from: (dimensions.from / 100) * totalHeight,