89 lines
3.3 KiB
Svelte
89 lines
3.3 KiB
Svelte
<script lang="ts">
|
|
let {
|
|
value = $bindable(''),
|
|
defaultTimeIndex = 36,
|
|
}: {
|
|
value?: string
|
|
defaultTimeIndex?: number
|
|
} = $props()
|
|
|
|
const months = [
|
|
'January', 'February', 'March', 'April', 'May', 'June',
|
|
'July', 'August', 'September', 'October', 'November', 'December',
|
|
]
|
|
|
|
const currentYear = new Date().getFullYear()
|
|
const years = Array.from({ length: 5 }, (_, i) => currentYear + i)
|
|
|
|
const timeOptions = Array.from({ length: 96 }, (_, i) => {
|
|
const hour = Math.floor(i / 4)
|
|
const minute = (i % 4) * 15
|
|
const ampm = hour < 12 ? 'AM' : 'PM'
|
|
const displayHour = hour % 12 === 0 ? 12 : hour % 12
|
|
return { value: i, label: `${displayHour}:${minute.toString().padStart(2, '0')} ${ampm}` }
|
|
})
|
|
|
|
const today = new Date()
|
|
let month = $state(today.getMonth())
|
|
let day = $state(today.getDate())
|
|
let year = $state(today.getFullYear())
|
|
let timeIndex = $state(defaultTimeIndex)
|
|
|
|
const daysInMonth = $derived(new Date(year, month + 1, 0).getDate())
|
|
|
|
$effect(() => {
|
|
if (day > daysInMonth) day = daysInMonth
|
|
})
|
|
|
|
$effect(() => {
|
|
const pad = (n: number) => n.toString().padStart(2, '0')
|
|
const hour = Math.floor(timeIndex / 4)
|
|
const minute = (timeIndex % 4) * 15
|
|
value = new Date(`${year}-${pad(month + 1)}-${pad(day)}T${pad(hour)}:${pad(minute)}`).toISOString()
|
|
})
|
|
</script>
|
|
|
|
<div class="rounded-2xl border border-base-300 bg-base-100 overflow-hidden shadow-sm">
|
|
<!-- Date section -->
|
|
<div class="px-4 pt-4 pb-3 border-b border-base-200">
|
|
<p class="flex items-center gap-1.5 text-primary text-xs font-bold uppercase tracking-widest mb-2.5">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" viewBox="0 0 20 20" fill="currentColor">
|
|
<path fill-rule="evenodd" d="M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z" clip-rule="evenodd" />
|
|
</svg>
|
|
Date
|
|
</p>
|
|
<div class="flex gap-2">
|
|
<select class="select select-sm bg-base-200 border-0 flex-1 font-medium" bind:value={month}>
|
|
{#each months as m, i}
|
|
<option value={i}>{m}</option>
|
|
{/each}
|
|
</select>
|
|
<select class="select select-sm bg-base-200 border-0 w-[4.5rem] font-medium" bind:value={day}>
|
|
{#each Array.from({ length: daysInMonth }, (_, i) => i + 1) as d}
|
|
<option value={d}>{d}</option>
|
|
{/each}
|
|
</select>
|
|
<select class="select select-sm bg-base-200 border-0 w-24 font-medium" bind:value={year}>
|
|
{#each years as y}
|
|
<option value={y}>{y}</option>
|
|
{/each}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Time section -->
|
|
<div class="px-4 pt-3 pb-4">
|
|
<p class="flex items-center gap-1.5 text-secondary text-xs font-bold uppercase tracking-widest mb-2.5">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" viewBox="0 0 20 20" fill="currentColor">
|
|
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z" clip-rule="evenodd" />
|
|
</svg>
|
|
Time
|
|
</p>
|
|
<select class="select select-sm bg-base-200 border-0 w-full font-medium" bind:value={timeIndex}>
|
|
{#each timeOptions as opt}
|
|
<option value={opt.value}>{opt.label}</option>
|
|
{/each}
|
|
</select>
|
|
</div>
|
|
</div>
|