Skip to content

Instantly share code, notes, and snippets.

@Nicklas2751
Created May 26, 2020 18:54
Show Gist options
  • Save Nicklas2751/da1fbe81878df7bb531fa4978c0ce7a8 to your computer and use it in GitHub Desktop.
Save Nicklas2751/da1fbe81878df7bb531fa4978c0ce7a8 to your computer and use it in GitHub Desktop.
The vuetify event calendar example with typescript
<template>
<v-row class="fill-height">
<v-col>
<v-sheet height="64">
<v-toolbar flat color="white">
<v-btn outlined class="mr-4" color="grey darken-2" @click="setToday">Today</v-btn>
<v-btn fab text small color="grey darken-2" @click="prev">
<v-icon small>mdi-chevron-left</v-icon>
</v-btn>
<v-btn fab text small color="grey darken-2" @click="next">
<v-icon small>mdi-chevron-right</v-icon>
</v-btn>
<v-toolbar-title>{{ title }}</v-toolbar-title>
<v-spacer></v-spacer>
<v-menu bottom right>
<template v-slot:activator="{ on }">
<v-btn outlined color="grey darken-2" v-on="on">
<span>{{ typeToLabel[type] }}</span>
<v-icon right>mdi-menu-down</v-icon>
</v-btn>
</template>
<v-list>
<v-list-item @click="type = 'day'">
<v-list-item-title>Day</v-list-item-title>
</v-list-item>
<v-list-item @click="type = 'week'">
<v-list-item-title>Week</v-list-item-title>
</v-list-item>
<v-list-item @click="type = 'month'">
<v-list-item-title>Month</v-list-item-title>
</v-list-item>
<v-list-item @click="type = '4day'">
<v-list-item-title>4 days</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</v-toolbar>
</v-sheet>
<v-sheet height="600">
<v-calendar
ref="calendar"
v-model="focus"
color="primary"
:events="events"
:event-color="getEventColor"
:now="today"
:type="type"
@click:event="showEvent"
@click:more="viewDay"
@click:date="viewDay"
@change="updateRange"
></v-calendar>
<v-menu
v-model="selectedOpen"
:close-on-content-click="false"
:activator="selectedElement"
offset-x
>
<v-card color="grey lighten-4" min-width="350px" flat>
<v-toolbar :color="selectedEvent.color" dark>
<v-btn icon>
<v-icon>mdi-pencil</v-icon>
</v-btn>
<v-toolbar-title v-html="selectedEvent.name"></v-toolbar-title>
<v-spacer></v-spacer>
<v-btn icon>
<v-icon>mdi-heart</v-icon>
</v-btn>
<v-btn icon>
<v-icon>mdi-dots-vertical</v-icon>
</v-btn>
</v-toolbar>
<v-card-text>
<span v-html="selectedEvent.details"></span>
</v-card-text>
<v-card-actions>
<v-btn text color="secondary" @click="selectedOpen = false">Cancel</v-btn>
</v-card-actions>
</v-card>
</v-menu>
</v-sheet>
</v-col>
</v-row>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
@Component
export default class Calendar extends Vue {
focus = ''
type = 'month'
today = ''
typeToLabel = {
month: 'Month',
week: 'Week',
day: 'Day',
'4day': '4 Days'
}
start: Start | null = null
end: End | null = null
selectedEvent = {}
selectedElement = null
selectedOpen = false
events: Event[] = []
colors = ['blue', 'indigo', 'deep-purple', 'cyan', 'green', 'orange', 'grey darken-1']
names = ['Meeting', 'Holiday', 'PTO', 'Travel', 'Event', 'Birthday', 'Conference', 'Party']
get title () {
const { start, end } = this
if (!start || !end) {
return ''
}
const startMonth = this.monthFormatter(start)
const endMonth = this.monthFormatter(end)
const suffixMonth = startMonth === endMonth ? '' : endMonth
const startYear = start.year
const endYear = end.year
const suffixYear = startYear === endYear ? '' : endYear
const startDay = start.day + this.nth(start.day)
const endDay = end.day + this.nth(end.day)
switch (this.type) {
case 'month':
return `${startMonth} ${startYear}`
case 'week':
case '4day':
return `${startMonth} ${startDay} ${startYear} - ${suffixMonth} ${endDay} ${suffixYear}`
case 'day':
return `${startMonth} ${startDay} ${startYear}`
}
return ''
}
get monthFormatter () {
return this.calendarInstance.getFormatter({
timeZone: 'UTC', month: 'long'
})
}
mounted () {
this.calendarInstance.checkChange()
}
viewDay ({ date }: { date: string}) {
this.focus = date
this.type = 'day'
}
getEventColor (event: Event) {
return event.color
}
setToday () {
this.focus = this.today
}
prev () {
this.calendarInstance.prev()
}
next () {
this.calendarInstance.next()
}
showEvent ({ nativeEvent, event }: { nativeEvent: any; event: Event}) {
const open = () => {
this.selectedEvent = event
this.selectedElement = nativeEvent.target
setTimeout(() => (this.selectedOpen = true), 10)
}
if (this.selectedOpen) {
this.selectedOpen = false
setTimeout(open, 10)
} else {
open()
}
nativeEvent.stopPropagation()
}
updateRange ({ start, end }: {start: Start; end: End}) {
const events: Event[] = []
const min = new Date(`${start.date}T00:00:00`)
const max = new Date(`${end.date}T23:59:59`)
const days = (max.getTime() - min.getTime()) / 86400000
const eventCount = this.rnd(days, days + 20)
for (let i = 0; i < eventCount; i++) {
const allDay = this.rnd(0, 3) === 0
const firstTimestamp = this.rnd(min.getTime(), max.getTime())
const first = new Date(firstTimestamp - (firstTimestamp % 900000))
const secondTimestamp = this.rnd(2, allDay ? 288 : 8) * 900000
const second = new Date(first.getTime() + secondTimestamp)
events.push({
name: this.names[this.rnd(0, this.names.length - 1)],
start: this.formatDate(first, !allDay),
end: this.formatDate(second, !allDay),
color: this.colors[this.rnd(0, this.colors.length - 1)]
})
}
this.start = start
this.end = end
this.events = events
}
nth (d: number) {
return d > 3 && d < 21
? 'th'
: ['th', 'st', 'nd', 'rd', 'th', 'th', 'th', 'th', 'th', 'th'][d % 10]
}
rnd (a: number, b: number) {
return Math.floor((b - a + 1) * Math.random()) + a
}
formatDate (a: Date, withTime: boolean) {
return withTime
? `${a.getFullYear()}-${a.getMonth() + 1}-${a.getDate()} ${a.getHours()}:${a.getMinutes()}`
: `${a.getFullYear()}-${a.getMonth() + 1}-${a.getDate()}`
}
private get calendarInstance (): Vue & { prev: () => void; next: () => void; checkChange: () => void; getFormatter: (format: any) => any } {
return this.$refs.calendar as Vue & { prev: () => void; next: () => void; checkChange: () => void; getFormatter: (format: any) => any }
}
}
export type Start = {
date: string;
time: string;
year: number;
month: number;
day: number;
hour: number;
minute: number;
weekday: number;
hasDay: boolean;
hasTime: boolean;
past: boolean;
present: boolean;
future: boolean;
}
export type End = {
date: string;
time: string;
year: number;
month: number;
day: number;
hour: number;
minute: number;
weekday: number;
hasDay: boolean;
hasTime: boolean;
past: boolean;
present: boolean;
future: boolean;
}
export type Event = {
name: string;
start: string;
end: string;
color: string;
}
</script>
@Vadimnick
Copy link

Thank you buddy!

@EmanuelAngelo
Copy link

Can you help me?

@Nicklas2751
Copy link
Author

@EmanuelAngelo What help do you need?

@EmanuelAngelo
Copy link

@Nicklas2751
how can I do to put the schedules and they will not collide?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment