iceshrimp-legacy/src/client/app/desktop/views/components/calendar.vue
2018-09-26 20:28:13 +09:00

260 lines
5.4 KiB
Vue

<template>
<div class="mk-calendar" :data-melt="design == 4 || design == 5">
<template v-if="design == 0 || design == 1">
<button @click="prev" title="%i18n:@prev%">%fa:chevron-circle-left%</button>
<p class="title">{{ '%i18n:@title%'.replace('{1}', year).replace('{2}', month) }}</p>
<button @click="next" title="%i18n:@next%">%fa:chevron-circle-right%</button>
</template>
<div class="calendar">
<template v-if="design == 0 || design == 2 || design == 4">
<div class="weekday"
v-for="(day, i) in Array(7).fill(0)"
:data-today="year == today.getFullYear() && month == today.getMonth() + 1 && today.getDay() == i"
:data-is-donichi="i == 0 || i == 6"
>{{ weekdayText[i] }}</div>
</template>
<div v-for="n in paddingDays"></div>
<div class="day" v-for="(day, i) in days"
:data-today="isToday(i + 1)"
:data-selected="isSelected(i + 1)"
:data-is-out-of-range="isOutOfRange(i + 1)"
:data-is-donichi="isDonichi(i + 1)"
@click="go(i + 1)"
:title="isOutOfRange(i + 1) ? null : '%i18n:@go%'"
>
<div>{{ i + 1 }}</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
const eachMonthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
function isLeapYear(year) {
return !(year & (year % 25 ? 3 : 15));
}
export default Vue.extend({
props: {
design: {
default: 0
},
start: {
type: Date,
required: false
}
},
data() {
return {
today: new Date(),
year: new Date().getFullYear(),
month: new Date().getMonth() + 1,
selected: new Date(),
weekdayText: [
'%i18n:common.weekday-short.sunday%',
'%i18n:common.weekday-short.monday%',
'%i18n:common.weekday-short.tuesday%',
'%i18n:common.weekday-short.wednesday%',
'%i18n:common.weekday-short.thursday%',
'%i18n:common.weekday-short.friday%',
'%i18n:common.weekday-short.saturday%'
]
};
},
computed: {
paddingDays(): number {
const date = new Date(this.year, this.month - 1, 1);
return date.getDay();
},
days(): number {
let days = eachMonthDays[this.month - 1];
// うるう年なら+1日
if (this.month == 2 && isLeapYear(this.year)) days++;
return days;
}
},
methods: {
isToday(day) {
return this.year == this.today.getFullYear() && this.month == this.today.getMonth() + 1 && day == this.today.getDate();
},
isSelected(day) {
return this.year == this.selected.getFullYear() && this.month == this.selected.getMonth() + 1 && day == this.selected.getDate();
},
isOutOfRange(day) {
const test = (new Date(this.year, this.month - 1, day)).getTime();
return test > this.today.getTime() ||
(this.start ? test < (this.start as any).getTime() : false);
},
isDonichi(day) {
const weekday = (new Date(this.year, this.month - 1, day)).getDay();
return weekday == 0 || weekday == 6;
},
prev() {
if (this.month == 1) {
this.year = this.year - 1;
this.month = 12;
} else {
this.month--;
}
},
next() {
if (this.month == 12) {
this.year = this.year + 1;
this.month = 1;
} else {
this.month++;
}
},
go(day) {
if (this.isOutOfRange(day)) return;
const date = new Date(this.year, this.month - 1, day, 23, 59, 59, 999);
this.selected = date;
this.$emit('chosen', this.selected);
}
}
});
</script>
<style lang="stylus" scoped>
root(isDark)
color isDark ? #c5ced6 : #777
background var(--face)
box-shadow var(--shadow)
border-radius var(--round)
overflow hidden
&[data-melt]
background transparent !important
border none !important
> .title
z-index 1
margin 0
padding 0 16px
text-align center
line-height 42px
font-size 0.9em
font-weight bold
color isDark ? #c5ced6 : #888
box-shadow 0 1px rgba(#000, 0.07)
if isDark
background #313543
> [data-fa]
margin-right 4px
> button
position absolute
z-index 2
top 0
padding 0
width 42px
font-size 0.9em
line-height 42px
color isDark ? #9baec8 : #ccc
&:hover
color isDark ? #b2c1d5 : #aaa
&:active
color isDark ? #b2c1d5 : #999
&:first-of-type
left 0
&:last-of-type
right 0
> .calendar
display flex
flex-wrap wrap
padding 16px
*
user-select none
> div
width calc(100% * (1/7))
text-align center
line-height 32px
font-size 14px
&.weekday
color isDark ? #43d5dc : #19a2a9
&[data-is-donichi]
color isDark ? #ff6679 : #ef95a0
&[data-today]
box-shadow 0 0 0 1px isDark ? #43d5dc : #19a2a9 inset
border-radius 6px
&[data-is-donichi]
box-shadow 0 0 0 1px isDark ? #ff6679 : #ef95a0 inset
&.day
cursor pointer
color isDark ? #c5ced6 : #777
> div
border-radius 6px
&:hover > div
background rgba(#000, isDark ? 0.1 : 0.025)
&:active > div
background rgba(#000, isDark ? 0.2 : 0.05)
&[data-is-donichi]
color isDark ? #ff6679 : #ef95a0
&[data-is-out-of-range]
cursor default
color rgba(isDark ? #c5ced6 : #777, 0.5)
&[data-is-donichi]
color rgba(isDark ? #ff6679 : #ef95a0, 0.5)
&[data-selected]
font-weight bold
> div
background rgba(#000, isDark ? 0.1 : 0.025)
&:active > div
background rgba(#000, isDark ? 0.2 : 0.05)
&[data-today]
> div
color var(--primaryForeground)
background var(--primary)
&:hover > div
background var(--primaryLighten10)
&:active > div
background var(--primaryDarken10)
.mk-calendar[data-darkmode]
root(true)
.mk-calendar:not([data-darkmode])
root(false)
</style>