refactor: code clean up
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
<script setup lang="ts" generic="S extends TimeSpanLabel">
|
||||
import { computed } from 'vue';
|
||||
import { spanToDays, type TimeSpanLabel } from '@/types/spans';
|
||||
import { daysVisibleRange, shiftLocalDays, shiftLocalMonths } from '@/utils/date';
|
||||
|
||||
const props = defineProps<{
|
||||
mode: 'days' | 'month';
|
||||
currentDate: Date;
|
||||
spans?: readonly S[];
|
||||
selectedSpan?: S;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:current-date': [date: Date];
|
||||
'update:span': [span: S];
|
||||
}>();
|
||||
|
||||
const spanDays = computed(() => props.selectedSpan ? spanToDays(props.selectedSpan) : 1);
|
||||
|
||||
function previousPeriod() {
|
||||
emit('update:current-date', props.mode === 'month'
|
||||
? shiftLocalMonths(props.currentDate, -1)
|
||||
: shiftLocalDays(props.currentDate, -spanDays.value));
|
||||
}
|
||||
|
||||
function nextPeriod() {
|
||||
emit('update:current-date', props.mode === 'month'
|
||||
? shiftLocalMonths(props.currentDate, 1)
|
||||
: shiftLocalDays(props.currentDate, spanDays.value));
|
||||
}
|
||||
|
||||
function goToToday() {
|
||||
emit('update:current-date', new Date());
|
||||
}
|
||||
|
||||
const periodLabel = computed(() => {
|
||||
if (props.mode === 'month') {
|
||||
return props.currentDate.toLocaleDateString('en-US', { month: 'long', year: 'numeric' });
|
||||
}
|
||||
|
||||
const range = daysVisibleRange(props.currentDate, spanDays.value);
|
||||
const start = new Date(range.start);
|
||||
const end = shiftLocalDays(new Date(range.end), -1);
|
||||
const formatOptions: Intl.DateTimeFormatOptions = { month: 'short', day: 'numeric' };
|
||||
|
||||
if (spanDays.value === 1) {
|
||||
return start.toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' });
|
||||
}
|
||||
|
||||
if (start.getMonth() === end.getMonth()) {
|
||||
return `${start.toLocaleDateString('en-US', formatOptions)} - ${end.getDate()}, ${start.getFullYear()}`;
|
||||
}
|
||||
|
||||
return `${start.toLocaleDateString('en-US', formatOptions)} - ${end.toLocaleDateString('en-US', formatOptions)}, ${end.getFullYear()}`;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="view-controls">
|
||||
<div class="view-navigation">
|
||||
<v-btn size="x-small" variant="text" icon="mdi-chevron-left" @click="previousPeriod" />
|
||||
<v-btn size="x-small" variant="tonal" @click="goToToday">Today</v-btn>
|
||||
<v-btn size="x-small" variant="text" icon="mdi-chevron-right" @click="nextPeriod" />
|
||||
<span class="current-period">{{ periodLabel }}</span>
|
||||
</div>
|
||||
<v-spacer />
|
||||
<div v-if="spans?.length" class="view-selector">
|
||||
<v-btn
|
||||
v-for="span in spans"
|
||||
:key="span"
|
||||
size="x-small"
|
||||
variant="text"
|
||||
:color="selectedSpan === span ? 'primary' : undefined"
|
||||
@click="emit('update:span', span)"
|
||||
>
|
||||
{{ span.toUpperCase() }}
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.view-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 4px 8px;
|
||||
border-bottom: 1px solid rgb(var(--v-border-color));
|
||||
background-color: rgb(var(--v-theme-surface));
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.view-navigation {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.current-period {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
margin-left: 8px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.view-selector {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user