Skip to content

Instantly share code, notes, and snippets.

@kb10uy
Last active March 30, 2018 09:43
Show Gist options
  • Save kb10uy/3f61d140b1ae191d0442e8a5809af15e to your computer and use it in GitHub Desktop.
Save kb10uy/3f61d140b1ae191d0442e8a5809af15e to your computer and use it in GitHub Desktop.
Needs ts-loader and sass-loader.
<template>
<div class="datetimepicker">
<div class="view">
<input type="text" class="preview" :value="previewText" readonly>
<button class="change-button" @click="openPicker">⏰</button>
</div>
<transition name="fade">
<div class="picker" v-if="shown">
<div class="date">
<div class="month-selector">
<button @click="moveMonth(-1)">&lt;&lt;</button>
<span class="current">{{ year }}年 {{ month + 1 }}月</span>
<button @click="moveMonth(1)">&gt;&gt;</button>
</div>
<table class="calendar">
<thead>
<tr>
<th class="sunday">日</th>
<th>月</th>
<th>火</th>
<th>水</th>
<th>木</th>
<th>金</th>
<th class="saturday">土</th>
</tr>
</thead>
<tbody>
<tr v-for="week in weeks" :key="week.reduce((a, c) => a + c)">
<td v-for="d in week" :key="d"
@click.stop="pickDay(d)"
:class="{ today: d === day }">
{{ d }}
</td>
</tr>
</tbody>
</table>
</div>
<div class="time">
<table>
<tbody>
<tr class="buttons">
<td><button @click="moveHours(10)">+10</button></td>
<td></td>
<td><button @click="moveMinutes(10)">+10</button></td>
<td></td>
<td><button @click="moveSeconds(10)">+10</button></td>
</tr>
<tr class="buttons">
<td><button @click="moveHours(1)">+1</button></td>
<td></td>
<td><button @click="moveMinutes(1)">+1</button></td>
<td></td>
<td><button @click="moveSeconds(1)">+1</button></td>
</tr>
<tr class="preview">
<td>{{ hours.toString().padStart(2, '0') }}</td>
<td>:</td>
<td>{{ minutes.toString().padStart(2, '0') }}</td>
<td>:</td>
<td>{{ seconds.toString().padStart(2, '0') }}</td>
</tr>
<tr class="buttons">
<td><button @click="moveHours(-1)">-1</button></td>
<td></td>
<td><button @click="moveMinutes(-1)">-1</button></td>
<td></td>
<td><button @click="moveSeconds(-1)">-1</button></td>
</tr>
<tr class="buttons">
<td><button @click="moveHours(-10)">-10</button></td>
<td></td>
<td><button @click="moveMinutes(-10)">-10</button></td>
<td></td>
<td><button @click="moveSeconds(-10)">-10</button></td>
</tr>
</tbody>
</table>
</div>
</div>
</transition>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
type DateTimePickerData = {
picked: Date;
shown: boolean;
weeks: number[][];
};
export default Vue.extend({
data(): DateTimePickerData {
return {
picked: new Date(),
shown: false,
weeks: [],
};
},
computed: {
previewText(): string {
return this.picked.toLocaleString();
},
year(): number {
return this.picked.getFullYear();
},
month(): number {
return this.picked.getMonth();
},
day(): number {
return this.picked.getDate();
},
hours(): number {
return this.picked.getHours();
},
minutes(): number {
return this.picked.getMinutes();
},
seconds(): number {
return this.picked.getSeconds();
},
},
watch: {
picked(newDate: Date, oldDate: Date) {
this.$emit('changed', newDate);
}
},
methods: {
openPicker() {
this.buildMonth();
this.shown = !this.shown;
},
buildMonth() {
this.weeks = [];
const allDays = new Date(this.year, this.month + 1, 0).getDate();
let dow = new Date(this.year, this.month, 1).getDay();
let target: number[] = [];
for (let i = 0; i < allDays; i++) {
target[dow] = i + 1;
if (++dow === 7) {
dow = 0;
this.weeks.push(target);
target = [];
}
}
if (target.length !== 0) {
const fill = 7 - target.length;
for (let i = 0; i < fill; i++) target.push(undefined);
this.weeks.push(target);
}
},
pickDay(d: number) {
if (!d) return;
this.picked = new Date(this.year, this.month, d, this.hours, this.minutes, this.seconds);
},
moveMonth(n: number) {
this.picked = new Date(this.year, this.month + n, 1, this.hours, this.minutes, this.seconds);
this.buildMonth();
},
moveHours(n: number) {
const oldMonth = this.month;
this.picked = new Date(this.year, this.month, this.day, this.hours + n, this.minutes, this.seconds);
if (oldMonth != this.month) this.buildMonth();
},
moveMinutes(n: number) {
const oldMonth = this.month;
this.picked = new Date(this.year, this.month, this.day, this.hours, this.minutes + n, this.seconds);
if (oldMonth != this.month) this.buildMonth();
},
moveSeconds(n: number) {
const oldMonth = this.month;
this.picked = new Date(this.year, this.month, this.day, this.hours, this.minutes, this.seconds + n);
if (oldMonth != this.month) this.buildMonth();
},
},
});
</script>
<style lang="scss" scoped>
.datetimepicker {
position: relative;
margin: 8px 0px;
.view {
display: flex;
.preview {
font-size: 24px;
margin: 0px;
padding: 0px;
height: 28px;
}
.change-button {
font-size: 24px;
height: 32px;
margin: 0px;
}
}
.picker {
position: absolute;
display: flex;
justify-content: space-between;
flex-direction: row;
align-items: center;
top: 36px;
z-index: 100;
background-color: #eee;
border: solid 1px #666;
border-radius: 4px;
.date {
margin: 8px;
width: 240px;
.month-selector {
display: flex;
flex-direction: row;
.current {
flex-grow: 1;
text-align: center;
}
}
.calendar {
width: 100%;
border: solid 1px #aaa;
border-collapse: collapse;
text-align: center;
background-color: #fff;
td,
th {
border: solid 1px #aaa;
empty-cells: show;
cursor: pointer;
}
.sunday {
color: #f00;
}
.saturday {
color: #00f;
}
.today {
background-color: #faa;
}
}
}
.time {
text-align: center;
margin: 8px;
margin-left: 0px;
.buttons > td {
margin: 0;
padding: 0;
button {
width: 100%;
font-size: 12pt;
}
}
.preview {
font-size: 24pt;
line-height: 1.2em;
}
}
}
}
.fade-enter-active, .fade-leave-active {
transition: opacity 0.2s;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment