65 lines
1.6 KiB
Vue
65 lines
1.6 KiB
Vue
<script setup lang="ts">
|
|
import { ref, computed } from 'vue'
|
|
import { Calendar } from '@/components/ui/calendar'
|
|
import { Button } from '@/components/ui/button'
|
|
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
|
|
import { CalendarIcon } from 'lucide-vue-next'
|
|
import { cn } from '@/lib/utils'
|
|
|
|
interface Props {
|
|
modelValue?: Date | string | null
|
|
placeholder?: string
|
|
disabled?: boolean
|
|
format?: string
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
placeholder: 'Pick a date',
|
|
format: 'PPP',
|
|
})
|
|
|
|
const emit = defineEmits<{
|
|
'update:modelValue': [value: Date | null]
|
|
}>()
|
|
|
|
const value = computed({
|
|
get: () => {
|
|
if (!props.modelValue) return undefined
|
|
return props.modelValue instanceof Date ? props.modelValue : new Date(props.modelValue)
|
|
},
|
|
set: (date) => {
|
|
emit('update:modelValue', date || null)
|
|
},
|
|
})
|
|
|
|
const formatDate = (date: Date | undefined) => {
|
|
if (!date) return props.placeholder
|
|
return date.toLocaleDateString('en-US', {
|
|
year: 'numeric',
|
|
month: 'long',
|
|
day: 'numeric',
|
|
})
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<Popover>
|
|
<PopoverTrigger as-child>
|
|
<Button
|
|
variant="outline"
|
|
:class="cn(
|
|
'w-full justify-start text-left font-normal',
|
|
!value && 'text-muted-foreground'
|
|
)"
|
|
:disabled="disabled"
|
|
>
|
|
<CalendarIcon class="mr-2 h-4 w-4" />
|
|
{{ formatDate(value) }}
|
|
</Button>
|
|
</PopoverTrigger>
|
|
<PopoverContent class="w-auto p-0">
|
|
<Calendar v-model="value" initial-focus />
|
|
</PopoverContent>
|
|
</Popover>
|
|
</template>
|