123 lines
4.4 KiB
Vue
123 lines
4.4 KiB
Vue
<template>
|
|
<div class="flex max-w-md min-w-[320px] flex-1 flex-col gap-6">
|
|
<p class="text-center text-lg text-[var(--midnight-blue)]">Sélectionnez une date disponible</p>
|
|
|
|
<div class="flex items-center justify-between">
|
|
<button @click="handlePreviousMonth" class="rounded-full p-2 text-[var(--midnight-blue)] hover:bg-[var(--linen)]">
|
|
<svg fill="currentColor" height="24px" viewBox="0 0 256 256" width="24px" xmlns="http://www.w3.org/2000/svg">
|
|
<path d="M165.66,202.34a8,8,0,0,1-11.32,11.32l-80-80a8,8,0,0,1,0-11.32l80-80a8,8,0,0,1,11.32,11.32L91.31,128Z"></path>
|
|
</svg>
|
|
</button>
|
|
<h3 class="text-center text-2xl font-bold text-[var(--midnight-blue)]">{{ monthName }} {{ currentYear }}</h3>
|
|
<button @click="handleNextMonth" class="rounded-full p-2 text-[var(--midnight-blue)] hover:bg-[var(--linen)]">
|
|
<svg fill="currentColor" height="24px" viewBox="0 0 256 256" width="24px" xmlns="http://www.w3.org/2000/svg">
|
|
<path
|
|
d="M181.66,133.66l-80,80a8,8,0,0,1-11.32-11.32L164.69,128,90.34,53.66a8,8,0,0,1,11.32-11.32l80,80A8,8,0,0,1,181.66,133.66Z"
|
|
></path>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-7 gap-1">
|
|
<p v-for="day in dayNames" :key="day" class="p-3 text-center text-sm font-bold text-[var(--spiritual-earth)]">{{ day }}</p>
|
|
|
|
<div v-for="blank in firstDayOfMonth" :key="'blank-' + blank" class="col-start-auto"></div>
|
|
|
|
<button
|
|
v-for="day in daysInMonth"
|
|
:key="day"
|
|
@click="selectDay(day)"
|
|
:class="{
|
|
'rounded-full p-3 text-base font-medium hover:bg-[var(--linen)]': true,
|
|
'bg-[var(--spiritual-earth)] text-[var(--pure-white)] ring-2 ring-[var(--subtle-gold)] ring-offset-2 ring-offset-[var(--light-ivory)]':
|
|
isSelected(day),
|
|
'text-gray-400': isDisabled(day),
|
|
}"
|
|
:disabled="isDisabled(day)"
|
|
>
|
|
{{ day }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed, defineEmits, defineProps, ref, watch } from 'vue';
|
|
|
|
const props = defineProps({
|
|
selectedDate: {
|
|
type: Date,
|
|
default: () => new Date(),
|
|
},
|
|
});
|
|
|
|
const emit = defineEmits(['update:selectedDate']);
|
|
|
|
const today = new Date();
|
|
const currentMonth = ref(props.selectedDate.getMonth());
|
|
const currentYear = ref(props.selectedDate.getFullYear());
|
|
|
|
const dayNames = ['D', 'L', 'M', 'M', 'J', 'V', 'S'];
|
|
const monthNames = ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'];
|
|
|
|
const monthName = computed(() => {
|
|
return monthNames[currentMonth.value];
|
|
});
|
|
|
|
const firstDayOfMonth = computed(() => {
|
|
const date = new Date(currentYear.value, currentMonth.value, 1);
|
|
return date.getDay(); // 0 for Sunday, 1 for Monday...
|
|
});
|
|
|
|
const daysInMonth = computed(() => {
|
|
return new Date(currentYear.value, currentMonth.value + 1, 0).getDate();
|
|
});
|
|
|
|
const handlePreviousMonth = () => {
|
|
if (currentMonth.value === 0) {
|
|
currentMonth.value = 11;
|
|
currentYear.value--;
|
|
} else {
|
|
currentMonth.value--;
|
|
}
|
|
};
|
|
|
|
const handleNextMonth = () => {
|
|
if (currentMonth.value === 11) {
|
|
currentMonth.value = 0;
|
|
currentYear.value++;
|
|
} else {
|
|
currentMonth.value++;
|
|
}
|
|
};
|
|
|
|
const selectDay = (day: number) => {
|
|
const newDate = new Date(currentYear.value, currentMonth.value, day);
|
|
emit('update:selectedDate', newDate);
|
|
};
|
|
|
|
const isSelected = (day: number) => {
|
|
return (
|
|
day === props.selectedDate.getDate() &&
|
|
currentMonth.value === props.selectedDate.getMonth() &&
|
|
currentYear.value === props.selectedDate.getFullYear()
|
|
);
|
|
};
|
|
|
|
const isDisabled = (day: number) => {
|
|
const date = new Date(currentYear.value, currentMonth.value, day);
|
|
const todayAtMidnight = new Date(today.getFullYear(), today.getMonth(), today.getDate());
|
|
return date.getTime() < todayAtMidnight.getTime();
|
|
};
|
|
|
|
// Watch for changes in the prop to update internal state
|
|
watch(
|
|
() => props.selectedDate,
|
|
(newDate) => {
|
|
currentMonth.value = newDate.getMonth();
|
|
currentYear.value = newDate.getFullYear();
|
|
},
|
|
{ deep: true },
|
|
);
|
|
</script>
|