first commit

This commit is contained in:
root
2025-11-30 19:49:01 +08:00
commit 8dcb2a5898
46 changed files with 14428 additions and 0 deletions

View File

@@ -0,0 +1,132 @@
<script setup lang="ts">
import { DateFormatter, getLocalTimeZone, CalendarDate, today } from '@internationalized/date'
import type { Range } from '~/types'
const df = new DateFormatter('en-US', {
dateStyle: 'medium'
})
const selected = defineModel<Range>({ required: true })
const ranges = [
{ label: 'Last 7 days', days: 7 },
{ label: 'Last 14 days', days: 14 },
{ label: 'Last 30 days', days: 30 },
{ label: 'Last 3 months', months: 3 },
{ label: 'Last 6 months', months: 6 },
{ label: 'Last year', years: 1 }
]
const toCalendarDate = (date: Date) => {
return new CalendarDate(
date.getFullYear(),
date.getMonth() + 1,
date.getDate()
)
}
const calendarRange = computed({
get: () => ({
start: selected.value.start ? toCalendarDate(selected.value.start) : undefined,
end: selected.value.end ? toCalendarDate(selected.value.end) : undefined
}),
set: (newValue: { start: CalendarDate | null, end: CalendarDate | null }) => {
selected.value = {
start: newValue.start ? newValue.start.toDate(getLocalTimeZone()) : new Date(),
end: newValue.end ? newValue.end.toDate(getLocalTimeZone()) : new Date()
}
}
})
const isRangeSelected = (range: { days?: number, months?: number, years?: number }) => {
if (!selected.value.start || !selected.value.end) return false
const currentDate = today(getLocalTimeZone())
let startDate = currentDate.copy()
if (range.days) {
startDate = startDate.subtract({ days: range.days })
} else if (range.months) {
startDate = startDate.subtract({ months: range.months })
} else if (range.years) {
startDate = startDate.subtract({ years: range.years })
}
const selectedStart = toCalendarDate(selected.value.start)
const selectedEnd = toCalendarDate(selected.value.end)
return selectedStart.compare(startDate) === 0 && selectedEnd.compare(currentDate) === 0
}
const selectRange = (range: { days?: number, months?: number, years?: number }) => {
const endDate = today(getLocalTimeZone())
let startDate = endDate.copy()
if (range.days) {
startDate = startDate.subtract({ days: range.days })
} else if (range.months) {
startDate = startDate.subtract({ months: range.months })
} else if (range.years) {
startDate = startDate.subtract({ years: range.years })
}
selected.value = {
start: startDate.toDate(getLocalTimeZone()),
end: endDate.toDate(getLocalTimeZone())
}
}
</script>
<template>
<UPopover :content="{ align: 'start' }" :modal="true">
<UButton
color="neutral"
variant="ghost"
icon="i-lucide-calendar"
class="data-[state=open]:bg-elevated group"
>
<span class="truncate">
<template v-if="selected.start">
<template v-if="selected.end">
{{ df.format(selected.start) }} - {{ df.format(selected.end) }}
</template>
<template v-else>
{{ df.format(selected.start) }}
</template>
</template>
<template v-else>
Pick a date
</template>
</span>
<template #trailing>
<UIcon name="i-lucide-chevron-down" class="shrink-0 text-dimmed size-5 group-data-[state=open]:rotate-180 transition-transform duration-200" />
</template>
</UButton>
<template #content>
<div class="flex items-stretch sm:divide-x divide-default">
<div class="hidden sm:flex flex-col justify-center">
<UButton
v-for="(range, index) in ranges"
:key="index"
:label="range.label"
color="neutral"
variant="ghost"
class="rounded-none px-4"
:class="[isRangeSelected(range) ? 'bg-elevated' : 'hover:bg-elevated/50']"
truncate
@click="selectRange(range)"
/>
</div>
<UCalendar
v-model="calendarRange"
class="p-2"
:number-of-months="2"
range
/>
</div>
</template>
</UPopover>
</template>