feat: implement SingleWeekPicker component and update App.vue to use it
All checks were successful
Publish to npm / publish (push) Successful in 36s
All checks were successful
Publish to npm / publish (push) Successful in 36s
This commit is contained in:
parent
8232a1af3f
commit
d94d3a76f1
|
@ -1,14 +1,13 @@
|
|||
<script setup lang="ts">
|
||||
import {SingleDatePicker} from '../src'
|
||||
import {SingleWeekPicker} from '../src'
|
||||
import {ref} from 'vue'
|
||||
|
||||
const date = ref(new Date())
|
||||
const value = ref({weekYear: 2022, weekNum: 1})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>{{date.toDateString()}}</div>
|
||||
<div class="container">
|
||||
<SingleDatePicker :available-range="[new Date(2025, 0, 1), null]" v-model:model-value="date" @close="console.log('close')" />
|
||||
<SingleWeekPicker v-model="value" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
211
src/components/SingleWeekPicker.vue
Normal file
211
src/components/SingleWeekPicker.vue
Normal file
|
@ -0,0 +1,211 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, defineProps, toRefs, onMounted, getCurrentInstance, watch } from 'vue'
|
||||
import { generateUniqueId, applyColor, getL10Weekday, getCalendarDates, calculateWeekNum } from '../utils'
|
||||
|
||||
interface SingleWeekPickerPropsColorScheme {
|
||||
mainColor: string
|
||||
accentColor: string
|
||||
borderColor: string
|
||||
hoverColor: string
|
||||
reversedColor: string
|
||||
}
|
||||
interface SingleWeekPickerModelValue {
|
||||
weekYear: number
|
||||
weekNum: number
|
||||
}
|
||||
|
||||
const selectMonth = ref(false)
|
||||
const uniqueId = generateUniqueId()
|
||||
const currentMonth = ref(new Date().getMonth())
|
||||
const currentYear = ref(new Date().getFullYear())
|
||||
const l10nDays = ref<string[]>([])
|
||||
const calendarWeeks = ref<Date[][]>([])
|
||||
const props = defineProps({
|
||||
/**
|
||||
* The color scheme of the component
|
||||
*
|
||||
* @description Customize the color scheme of the component.
|
||||
*
|
||||
* The object should contain the following properties:
|
||||
*
|
||||
* - `mainColor`: The main color of the panel, including the text color and the border color.
|
||||
* - `accentColor`: The accent color of the panel, including the background color of the selected date.
|
||||
* - `borderColor`: The border color of the panel, including the divider color between the header and the body.
|
||||
* - `hoverColor`: The hover color of the panel, including the hover background color of the date.
|
||||
* - `reversedColor`: The reversed color of the panel, including the text color of the selected date.
|
||||
*
|
||||
* @see {@link https://datenel.js.org/guide/vue/components/SingleWeekPicker.html#colorscheme}
|
||||
*
|
||||
* @default { mainColor: '#000000', accentColor: '#000000', borderColor: '#e0e0e0', hoverColor: '#00000017', reversedColor: '#ffffff' }
|
||||
*/
|
||||
colorScheme: {
|
||||
type: Object as () => SingleWeekPickerPropsColorScheme,
|
||||
default: () => ({
|
||||
mainColor: '#000000',
|
||||
accentColor: '#000000',
|
||||
borderColor: '#e0e0e0',
|
||||
hoverColor: '#00000017',
|
||||
reversedColor: '#ffffff',
|
||||
}),
|
||||
required: false,
|
||||
},
|
||||
/**
|
||||
* Localization
|
||||
* @description The language code that will be used to localize the panel.
|
||||
*
|
||||
* Accept standard ISO 639-1 language code, such as 'zh-CN', 'en-US', 'ja-JP', etc. Note
|
||||
* that it will not effect to the screen reader, but the screen reader will still read the
|
||||
* date in the user’s language.
|
||||
*
|
||||
* @see {@link https://datenel.js.org/guide/vue/components/SingleWeekPicker.html#localization}
|
||||
* @default navigator.language
|
||||
*/
|
||||
localization: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
/**
|
||||
* The model value of the component
|
||||
*
|
||||
* @description The model value of the component.
|
||||
*
|
||||
* @see {@link https://datenel.js.org/guide/vue/components/SingleWeekPicker.html#modelvalue}
|
||||
*/
|
||||
modelValue: {
|
||||
type: Object as () => SingleWeekPickerModelValue,
|
||||
required: false,
|
||||
},
|
||||
})
|
||||
|
||||
const { colorScheme, localization } = toRefs(props)
|
||||
const emit = defineEmits(['update:modelValue', 'close'])
|
||||
const hasCloseListener = getCurrentInstance()?.vnode?.props?.onClose !== undefined
|
||||
|
||||
onMounted(() => {
|
||||
applyColor(uniqueId, colorScheme.value)
|
||||
l10nDays.value = getL10Weekday(localization?.value || navigator.languages[0])
|
||||
|
||||
if (props.modelValue) {
|
||||
let weekYear = props.modelValue.weekYear
|
||||
let weekNum = props.modelValue.weekNum
|
||||
if (weekYear < 100) weekYear = Number(`20${weekYear}`)
|
||||
if (weekNum < 1 || weekNum > 53)
|
||||
console.warn('The week number should be between 1 and 53.')
|
||||
else {
|
||||
const date = new Date(weekYear, 0, 1)
|
||||
date.setDate(date.getDate() + (weekNum - 1) * 7)
|
||||
currentMonth.value = date.getMonth()
|
||||
currentYear.value = date.getFullYear()
|
||||
}
|
||||
} else {
|
||||
currentMonth.value = new Date().getMonth()
|
||||
currentYear.value = new Date().getFullYear()
|
||||
}
|
||||
|
||||
const dates = getCalendarDates(currentMonth.value, currentYear.value)
|
||||
let weeks: Date[][] = []
|
||||
for (let i = 0; i < dates.length; i += 7)
|
||||
weeks.push(dates.slice(i, i + 7))
|
||||
calendarWeeks.value = weeks
|
||||
})
|
||||
|
||||
watch(colorScheme, newVal => {
|
||||
applyColor(uniqueId, newVal)
|
||||
})
|
||||
|
||||
watch([currentMonth, currentYear], () => {
|
||||
const dates = getCalendarDates(currentMonth.value, currentYear.value)
|
||||
let weeks: Date[][] = []
|
||||
for (let i = 0; i < dates.length; i += 7)
|
||||
weeks.push(dates.slice(i, i + 7))
|
||||
calendarWeeks.value = weeks
|
||||
})
|
||||
|
||||
function goToLastMonth() {
|
||||
if (currentMonth.value === 0) {
|
||||
currentMonth.value = 11
|
||||
currentYear.value -= 1
|
||||
} else {
|
||||
currentMonth.value -= 1
|
||||
}
|
||||
}
|
||||
|
||||
function goToNextMonth() {
|
||||
if (currentMonth.value === 11) {
|
||||
currentMonth.value = 0
|
||||
currentYear.value += 1
|
||||
} else {
|
||||
currentMonth.value += 1
|
||||
}
|
||||
}
|
||||
|
||||
function closePanel() {
|
||||
emit('close')
|
||||
}
|
||||
|
||||
function selectWeek(weekYear: number, weekNum: number) {
|
||||
emit('update:modelValue', { weekYear, weekNum })
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :id="`__datenel-${uniqueId}`" class='datenel-component'>
|
||||
<div v-if="selectMonth"></div>
|
||||
|
||||
<div v-else>
|
||||
<div class='__datenel_header'>
|
||||
<button class='__datenel_stepper' @click="goToLastMonth()"
|
||||
:aria-label="`Go to last month, ${new Date(currentYear, currentMonth - 1).toLocaleString('default', { month: 'long', year: 'numeric' })}`"><svg
|
||||
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path
|
||||
d="M10.8284 12.0007L15.7782 16.9504L14.364 18.3646L8 12.0007L14.364 5.63672L15.7782 7.05093L10.8284 12.0007Z">
|
||||
</path>
|
||||
</svg></button>
|
||||
<button class='__datenel_indicator' @click="selectMonth = true"
|
||||
:aria-label="`You are now at ${new Date(currentYear, currentMonth).toLocaleString('default', { month: 'long', year: 'numeric' })}. Click here to quick-select month or year.`">
|
||||
{{ new Date(currentYear, currentMonth).toLocaleString('default', { month: 'long', year: 'numeric' }) }}
|
||||
</button>
|
||||
<button class='__datenel_stepper' @click="goToNextMonth()"
|
||||
:aria-label="`Go to next month, ${new Date(currentYear, currentMonth + 1).toLocaleString('default', { month: 'long', year: 'numeric' })}`"><svg
|
||||
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path
|
||||
d="M13.1717 12.0007L8.22192 7.05093L9.63614 5.63672L16.0001 12.0007L9.63614 18.3646L8.22192 16.9504L13.1717 12.0007Z">
|
||||
</path>
|
||||
</svg></button>
|
||||
</div>
|
||||
|
||||
<div class="__datenel_body">
|
||||
<div class="__datenel_week-indicator">
|
||||
<div class="__datenel_item __datenel_title">Wk</div>
|
||||
|
||||
<div v-for="week in calendarWeeks" :class="`__datenel_item ${false ? '__datenel_active' : ''}`" :key="calculateWeekNum(week[0]).weekNum" @click="() => {}">
|
||||
{{ calculateWeekNum(week[0]).weekNum }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='__datenel_calendar-view-body __datenel_flex' aria-live="polite">
|
||||
<div class="__datenel_listitem">
|
||||
<div v-for="(_, index) in Array.from({ length: 7 })" class='__datenel_item __datenel_day-indicator' :key="index">{{l10nDays[index]}}</div>
|
||||
</div>
|
||||
|
||||
<button v-for="(week, index) in calendarWeeks" :class="`__datenel_listitem ${ modelValue && (modelValue.weekNum === calculateWeekNum(week[0]).weekNum && modelValue.weekYear === calculateWeekNum(week[0]).weekYear) ? '__datenel_active' : ''}`" :key="index" @click="selectWeek(calculateWeekNum(week[0]).weekYear, calculateWeekNum(week[0]).weekNum)" :aria-label="`Select week ${calculateWeekNum(week[0]).weekNum} of the year ${calculateWeekNum(week[0]).weekYear}, from ${week[0].toLocaleString(localization, { dateStyle: `full` })} to ${week[6].toLocaleString(localization, { weekday: 'long' })}, ${week[6].toLocaleString(localization, { month: 'long' })} ${week[6].getDate()}, ${week[6].getFullYear()}`">
|
||||
<div
|
||||
v-for="date in week"
|
||||
:class="`__datenel_item __datenel_date ${currentMonth !== date.getMonth() && '__datenel_extra-month'}`"
|
||||
:key="date.getDate()"
|
||||
>
|
||||
{{date.getDate()}}
|
||||
<svg v-if="date.toDateString() === new Date().toDateString()" xmlns="http://www.w3.org/2000/svg" class='__datenel_today-indicator' viewBox="0 0 24 24" fill="currentColor"><path d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z"></path></svg>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class='__datenel_sr-only' @click="closePanel" v-if="hasCloseListener">Close the panel</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use '../style.scss' as *;
|
||||
</style>
|
|
@ -1 +1,2 @@
|
|||
export { default as SingleDatePicker } from './components/SingleDatePicker.vue'
|
||||
export { default as SingleDatePicker } from './components/SingleDatePicker.vue'
|
||||
export { default as SingleWeekPicker } from './components/SingleWeekPicker.vue'
|
|
@ -5,7 +5,6 @@ export default (date: Date): { weekYear: number, weekNum: number } => {
|
|||
tempDate.setDate(tempDate.getDate() + 4 - (tempDate.getDay() || 7))
|
||||
|
||||
const forthDay = new Date(tempDate.getFullYear(), 0, 4)
|
||||
console.log(forthDay)
|
||||
forthDay.setDate(forthDay.getDate() + 4 - (forthDay.getDay() || 7))
|
||||
|
||||
const diffInDays = Math.floor((tempDate.getTime() - forthDay.getTime()) / (24 * 60 * 60 * 1000))
|
||||
|
|
Loading…
Reference in New Issue
Block a user