Skip to content

Instantly share code, notes, and snippets.

@ClickerMonkey
Last active January 11, 2019 07:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ClickerMonkey/b9ffa574b54c8f9b94207df4d06f7804 to your computer and use it in GitHub Desktop.
Save ClickerMonkey/b9ffa574b54c8f9b94207df4d06f7804 to your computer and use it in GitHub Desktop.
Playground: v-calendar-daily
<template>
<v-app class="panes">
<div class="left">
<v-select
label="Type"
v-model="type"
:items="typeOptions"
></v-select>
<v-checkbox
label="Dark"
v-model="dark"
></v-checkbox>
<v-select
label="Color"
v-model="color"
:items="colorOptions"
></v-select>
<v-menu ref="startMenu"
lazy
transition="scale-transition"
offset-y
full-width
min-width="290px"
v-model="startMenu"
:close-on-content-click="false"
:nudge-right="40"
:return-value.sync="start">
<v-text-field
slot="activator"
label="Start Date"
prepend-icon="event"
readonly
v-model="start"
></v-text-field>
<v-date-picker v-model="start" no-title scrollable>
<v-spacer></v-spacer>
<v-btn flat color="primary" @click="startMenu = false">Cancel</v-btn>
<v-btn flat color="primary" @click="$refs.startMenu.save(start)">OK</v-btn>
</v-date-picker>
</v-menu>
<v-menu ref="endMenu"
v-if="hasEnd"
lazy
transition="scale-transition"
offset-y
full-width
min-width="290px"
v-model="endMenu"
:close-on-content-click="false"
:nudge-right="40"
:return-value.sync="end">
<v-text-field
slot="activator"
label="End Date"
prepend-icon="event"
readonly
v-model="end"
></v-text-field>
<v-date-picker v-model="end" no-title scrollable>
<v-spacer></v-spacer>
<v-btn flat color="primary" @click="endMenu = false">Cancel</v-btn>
<v-btn flat color="primary" @click="$refs.endMenu.save(end)">OK</v-btn>
</v-date-picker>
</v-menu>
<v-menu ref="nowMenu"
lazy
transition="scale-transition"
offset-y
full-width
min-width="290px"
v-model="nowMenu"
:close-on-content-click="false"
:nudge-right="40"
:return-value.sync="now">
<v-text-field
slot="activator"
v-model="now"
label="Today"
prepend-icon="event"
readonly
></v-text-field>
<v-date-picker v-model="now" no-title scrollable>
<v-spacer></v-spacer>
<v-btn flat color="primary" @click="nowMenu = false">Cancel</v-btn>
<v-btn flat color="primary" @click="$refs.nowMenu.save(now)">OK</v-btn>
</v-date-picker>
</v-menu>
<v-select
label="Weekdays"
v-model="weekdays"
:items="weekdaysOptions"
></v-select>
<v-text-field
v-if="type === 'custom-weekly'"
label="Minimum Weeks"
type="number"
v-model="minWeeks"
></v-text-field>
<v-select
v-if="hasIntervals"
label="Intervals"
v-model="intervals"
:items="intervalsOptions"
></v-select>
<v-select
v-if="type === 'custom-daily'"
label="# of Days"
v-model="maxDays"
:items="maxDaysOptions"
></v-select>
<v-select
v-if="hasIntervals"
label="Styling"
v-model="styleInterval"
:items="styleIntervalOptions"
></v-select>
<v-btn @click="$refs.calendar.prev()">
<v-icon dark>keyboard_arrow_left</v-icon>
Prev
</v-btn>
<v-btn @click="$refs.calendar.next()">
Next
<v-icon right dark>keyboard_arrow_right</v-icon>
</v-btn>
<v-list two-line subheader dense>
<v-subheader inset>Last 5 Events</v-subheader>
<v-list-tile v-for="ev in events" :key="ev.id" avatar @click>
<v-list-tile-avatar>
<v-icon>{{ ev.icon }}</v-icon>
</v-list-tile-avatar>
<v-list-tile-content>
<v-list-tile-title>{{ ev.title }}</v-list-tile-title>
<v-list-tile-sub-title>{{ ev.subtitle }}</v-list-tile-sub-title>
</v-list-tile-content>
</v-list-tile>
</v-list>
</div>
<div class="right">
<v-calendar
ref="calendar"
:type="type"
:start="start"
:end="end"
:min-weeks="minWeeks"
:max-days="maxDays"
:now="now"
:dark="dark"
:weekdays="weekdays"
:first-interval="intervals.first"
:interval-minutes="intervals.minutes"
:interval-count="intervals.count"
:interval-height="intervals.height"
:interval-style="intervalStyle"
:show-interval-label="showIntervalLabel"
:color="color"
v-model="start"
v-on="listeners">
<template slot="day" slot-scope="day">
<div class="day"
v-if="day.day % 3 === 0"
@click.stop="addEvent(day, 'click', 'event')">
day slot {{ day.date }}
</div>
</template>
<template slot="dayHeader" slot-scope="day">
<div class="dayHeader"
v-if="day.weekday % 2"
@click.stop="addEvent(day, 'click', 'event')">
dayHeader slot {{ day.date }}
</div>
</template>
<template slot="dayBody" slot-scope="day">
<div class="dayBody"
v-if="day.weekday % 3 === 2"
@click.stop="addEvent(day, 'click', 'event')">
dayBody slot {{ day.date }}
</div>
</template>
</v-calendar>
<!--
<v-calendar-daily
v-if="type === 'daily'"
:start="start"
:max-days="maxDays"
:now="now"
:dark="dark"
:weekdays="weekdays"
:first-interval="intervals.first"
:interval-minutes="intervals.minutes"
:interval-count="intervals.count"
:interval-height="intervals.height"
:interval-style="intervalStyle"
:show-interval-label="showIntervalLabel"
:color="color"
v-on="listeners">
<template slot="dayHeader" slot-scope="day">
<div class="dayHeader"
v-if="day.weekday % 2"
@click.stop="addEvent(day, 'click', 'event')">
dayHeader slot {{ day.date }}
</div>
</template>
<template slot="dayBody" slot-scope="day">
<div class="dayBody"
v-if="day.weekday % 3 === 2"
@click.stop="addEvent(day, 'click', 'event')">
dayBody slot {{ day.date }}
</div>
</template>
</v-calendar-daily>
<v-calendar-weekly
v-if="type === 'weekly'"
:start="start"
:end="end"
:min-weeks="minWeeks"
:now="now"
:dark="dark"
:weekdays="weekdays"
:color="color"
v-on="listeners">
<template slot="day" slot-scope="day">
<div class="day"
v-if="day.day % 3 === 0"
@click.stop="addEvent(day, 'click', 'event')">
day slot {{ day.date }}
</div>
</template>
</v-calendar-weekly>
<v-calendar-monthly
v-if="type === 'monthly'"
:start="start"
:min-weeks="minWeeks"
:now="now"
:dark="dark"
:weekdays="weekdays"
:color="color"
v-on="listeners">
<template slot="day" slot-scope="day">
<div class="day"
v-if="day.day % 3 === 0"
@click.stop="addEvent(day, 'click', 'event')">
day slot {{ day.date }}
</div>
</template>
</v-calendar-monthly>
-->
</div>
</v-app>
</template>
<script>
let weekdaysDefault = [0, 1, 2, 3, 4, 5, 6]
let intervalsDefault = {
first: 0,
minutes: 60,
count: 24,
height: 40
}
let stylings = {
default (interval) {
return undefined
},
workday (interval) {
var inactive = interval.weekday === 0
|| interval.weekday === 6
|| interval.hour < 9
|| interval.hour >= 17
var startOfHour = interval.minute === 0
var dark = this.dark
var start = dark ? 'rgba(255,255,255,0.2)' : 'rgba(0,0,0,0.4)'
var mid = dark ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.1)'
return {
backgroundColor: inactive ? (dark ? 'rgba(0,0,0,0.4)' : 'rgba(0,0,0,0.05)') : undefined,
borderTop: startOfHour ? undefined : '1px dashed ' + mid
}
},
past (interval) {
return {
backgroundColor: interval.past ? ( this.dark ? 'rgba(0,0,0,0.4)' : 'rgba(0,0,0,0.05)' ) : undefined
}
}
}
let eventTypes = ['click', 'contextmenu', 'mousedown', 'mousemove', 'mouseup', 'mouseenter', 'mouseleave', 'touchstart', 'touchmove', 'touchend']
let eventSuffix = ['date', 'day', 'time', 'interval']
export default {
data: () => ({
dark: false,
startMenu: false,
start: '2018-09-12',
endMenu: false,
end: '2018-09-27',
nowMenu: false,
minWeeks: 1,
now: null,
listeners: {},
events: [],
type: 'month',
typeOptions: [
{ text: 'Day', value: 'day' },
{ text: '4 Day', value: '4day' },
{ text: 'Week', value: 'week' },
{ text: 'Month', value: 'month' },
{ text: 'Custom Daily', value: 'custom-daily' },
{ text: 'Custom Weekly', value: 'custom-weekly' }
],
/*
typeOptions: [
{ text: 'Daily', value: 'daily' },
{ text: 'Weekly', value: 'weekly' },
{ text: 'Monthly', value: 'monthly' }
],
*/
weekdays: weekdaysDefault,
weekdaysOptions: [
{ text: 'Sunday - Saturday', value: weekdaysDefault },
{ text: 'Mon, Wed, Fri', value: [1, 3, 5] },
{ text: 'Mon - Fri', value: [1, 2, 3, 4, 5] }
],
intervals: intervalsDefault,
intervalsOptions: [
{ text: 'Default', value: intervalsDefault },
{ text: 'Workday', value: { first: 16, minutes: 30, count: 20, height: 40 } }
],
maxDays: 7,
maxDaysOptions: [
{ text: '7 days', value: 7 },
{ text: '5 days', value: 5 },
{ text: '4 days', value: 4 },
{ text: '3 days', value: 3 }
],
styleInterval: 'default',
styleIntervalOptions: [
{ text: 'Default', value: 'default' },
{ text: 'Workday', value: 'workday' },
{ text: 'Past', value: 'past' }
],
color: 'primary',
colorOptions: [
{ text: 'Primary', value: 'primary' },
{ text: 'Secondary', value: 'secondary' },
{ text: 'Accent', value: 'accent' },
{ text: 'Red', value: 'red' },
{ text: 'Pink', value: 'pink' },
{ text: 'Purple', value: 'purple' },
{ text: 'Deep Purple', value: 'deep-purple' },
{ text: 'Indigo', value: 'indigo' },
{ text: 'Blue', value: 'blue' },
{ text: 'Light Blue', value: 'light-blue' },
{ text: 'Cyan', value: 'cyan' },
{ text: 'Teal', value: 'teal' },
{ text: 'Green', value: 'green' },
{ text: 'Light Green', value: 'light-green' },
{ text: 'Lime', value: 'lime' },
{ text: 'Yellow', value: 'yellow' },
{ text: 'Amber', value: 'amber' },
{ text: 'Orange', value: 'orange' },
{ text: 'Deep Orange', value: 'deep-orange' },
{ text: 'Brown', value: 'brown' },
{ text: 'Blue Gray', value: 'blue-gray' },
{ text: 'Gray', value: 'gray' },
{ text: 'Black', value: 'black' }
]
}),
computed: {
intervalStyle () {
return stylings[ this.styleInterval ].bind(this)
},
hasIntervals () {
return this.type in {
'week': 1, 'day': 1, '4day': 1, 'custom-daily': 1
}
},
hasEnd () {
return this.type in {
'custom-weekly': 1, 'custom-daily': 1
}
}
},
created() {
eventTypes.forEach(e => {
eventSuffix.forEach(s => {
this.listeners[`${e}:${s}`] = (day) => {
this.addEvent(day, e, s)
}
})
})
},
methods: {
addEvent (day, e, s) {
let lastEvent = this.events[0];
let eventInstance = {
id: Math.random(),
icon: s === 'day' ? 'calendar_today' : (s === 'time' ? 'access_time' : (s === 'interval' ? 'view_agenda' : 'event')),
title: e + ':' + s,
subtitle: s === 'interval' ? day.time : (day.date + (s === 'time' ? ' ' + day.time : ''))
}
if (!lastEvent || lastEvent.title !== eventInstance.title) {
if (this.events.length >= 5) {
this.events.pop()
}
} else {
this.events.shift()
}
this.events.unshift(eventInstance)
},
showIntervalLabel (interval) {
return interval.minute === 0
}
}
}
</script>
<style>
.panes {
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
}
.left {
position: fixed;
left: 0;
width: 300px;
top: 0;
bottom: 0;
border-right: #bdbdbd 1px solid;
padding: 8px;
}
.right {
position: fixed;
left: 300px;
top: 0;
bottom: 0;
right: 0;
}
.dayHeader {
margin: 0px 2px 2px 2px;
padding: 2px 6px;
background-color: #1976D2;
color: white;
user-select: none;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.dayBody {
position: absolute;
top: 400px;
height: 36px;
margin: 2px;
padding: 2px 6px;
background-color: #1976D2;
color: white;
left: 0;
right: 0;
user-select: none;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.day {
position: relative;
height: 24px;
margin: 0px;
padding: 0px 6px;
background-color: #1976D2;
color: white;
left: 0;
right: 0;
user-select: none;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
body, html, #app {
font-family: Roboto, sans-serif !important;
width: 100%;
height: 100%;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment