Last active
January 11, 2019 07:07
-
-
Save ClickerMonkey/b9ffa574b54c8f9b94207df4d06f7804 to your computer and use it in GitHub Desktop.
Playground: v-calendar-daily
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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