dev #2
| 
						 | 
				
			
			@ -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