Initial commit
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch } from 'vue'
|
||||
|
||||
interface Props {
|
||||
mode: 'edit' | 'view'
|
||||
startsOn?: string | null
|
||||
endsOn?: string | null
|
||||
timeless?: boolean | null
|
||||
timeZone?: string | null
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:startsOn': [date: string | null]
|
||||
'update:endsOn': [date: string | null]
|
||||
'update:timeless': [timeless: boolean | null]
|
||||
'update:timeZone': [timeZone: string | null]
|
||||
}>()
|
||||
|
||||
const timelessValue = computed({
|
||||
get: () => props.timeless ?? false,
|
||||
set: (value) => emit('update:timeless', value)
|
||||
})
|
||||
|
||||
const timeZoneValue = computed({
|
||||
get: () => props.timeZone ?? '',
|
||||
set: (value) => emit('update:timeZone', value || null)
|
||||
})
|
||||
|
||||
// Format helpers
|
||||
const formatDate = (date: Date): string => {
|
||||
return date.toISOString().split('T')[0]
|
||||
}
|
||||
|
||||
const formatTime = (date: Date): string => {
|
||||
return date.toTimeString().slice(0, 5)
|
||||
}
|
||||
|
||||
const formatDateTime = (isoString: string | null | undefined): string => {
|
||||
if (!isoString) return 'Not set'
|
||||
const date = new Date(isoString)
|
||||
return date.toLocaleString()
|
||||
}
|
||||
|
||||
const parseDateTime = (date: string, time: string): Date => {
|
||||
if (timelessValue.value) {
|
||||
return new Date(date)
|
||||
}
|
||||
return new Date(`${date}T${time}`)
|
||||
}
|
||||
|
||||
// Date/time fields
|
||||
const startDate = ref('')
|
||||
const startTime = ref('')
|
||||
const endDate = ref('')
|
||||
const endTime = ref('')
|
||||
|
||||
// Initialize date/time from props
|
||||
watch(() => props.startsOn, (newValue) => {
|
||||
if (newValue) {
|
||||
const start = new Date(newValue)
|
||||
startDate.value = formatDate(start)
|
||||
startTime.value = formatTime(start)
|
||||
} else {
|
||||
const now = new Date()
|
||||
startDate.value = formatDate(now)
|
||||
startTime.value = formatTime(now)
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
watch(() => props.endsOn, (newValue) => {
|
||||
if (newValue) {
|
||||
const end = new Date(newValue)
|
||||
endDate.value = formatDate(end)
|
||||
endTime.value = formatTime(end)
|
||||
} else {
|
||||
const later = new Date(Date.now() + 60 * 60 * 1000)
|
||||
endDate.value = formatDate(later)
|
||||
endTime.value = formatTime(later)
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
// Update parent when date/time changes
|
||||
watch([startDate, startTime], () => {
|
||||
if (props.mode === 'edit') {
|
||||
emit('update:startsOn', parseDateTime(startDate.value, startTime.value).toISOString())
|
||||
}
|
||||
})
|
||||
|
||||
watch([endDate, endTime], () => {
|
||||
if (props.mode === 'edit') {
|
||||
emit('update:endsOn', parseDateTime(endDate.value, endTime.value).toISOString())
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="event-editor-section">
|
||||
<div class="text-subtitle-1 mb-2">Date & Time</div>
|
||||
|
||||
<!-- Read-only view -->
|
||||
<div v-if="mode === 'view'">
|
||||
<div class="mb-2 pa-2">
|
||||
<div class="mb-1"><strong>Starts:</strong> {{ formatDateTime(startsOn) }}</div>
|
||||
<div class="mb-1"><strong>Ends:</strong> {{ formatDateTime(endsOn) }}</div>
|
||||
<div v-if="timelessValue" class="mb-1">
|
||||
<v-chip size="small" color="info" variant="tonal">
|
||||
<v-icon start size="small">mdi-calendar-blank</v-icon>
|
||||
All Day Event
|
||||
</v-chip>
|
||||
</div>
|
||||
<div v-if="timeZoneValue" class="text-caption text-grey">Time Zone: {{ timeZoneValue }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Edit view -->
|
||||
<div v-else>
|
||||
<v-checkbox
|
||||
v-model="timelessValue"
|
||||
label="All day event"
|
||||
density="compact"
|
||||
class="mb-2"
|
||||
/>
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="text-subtitle-2 mb-2">Start</div>
|
||||
<v-row dense>
|
||||
<v-col cols="12" md="6">
|
||||
<v-text-field
|
||||
v-model="startDate"
|
||||
label="Start Date"
|
||||
type="date"
|
||||
variant="outlined"
|
||||
density="compact"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col v-if="!timelessValue" cols="12" md="6">
|
||||
<v-text-field
|
||||
v-model="startTime"
|
||||
label="Start Time"
|
||||
type="time"
|
||||
variant="outlined"
|
||||
density="compact"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="text-subtitle-2 mb-2">End</div>
|
||||
<v-row dense>
|
||||
<v-col cols="12" md="6">
|
||||
<v-text-field
|
||||
v-model="endDate"
|
||||
label="End Date"
|
||||
type="date"
|
||||
variant="outlined"
|
||||
density="compact"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col v-if="!timelessValue" cols="12" md="6">
|
||||
<v-text-field
|
||||
v-model="endTime"
|
||||
label="End Time"
|
||||
type="time"
|
||||
variant="outlined"
|
||||
density="compact"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
|
||||
<v-text-field
|
||||
v-model="timeZoneValue"
|
||||
label="Time Zone"
|
||||
variant="outlined"
|
||||
density="compact"
|
||||
hint="e.g., America/New_York"
|
||||
persistent-hint
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.event-editor-section {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user