Files
calendar/src/components/CalendarDay.vue

159 lines
3.5 KiB
Vue

<script setup>
import { computed } from 'vue'
import { formatDateCompact, fromLocalString } from '@/utils/date'
const props = defineProps({
day: Object,
dragging: { type: Boolean, default: false },
})
const formattedDate = computed(() => {
const date = fromLocalString(props.day.date)
return formatDateCompact(date)
})
</script>
<template>
<div
class="cell"
:style="props.dragging ? 'touch-action:none;' : 'touch-action:pan-y;'"
:class="[
props.day.monthClass,
{
today: props.day.isToday,
weekend: props.day.isWeekend,
firstday: props.day.isFirstDay,
selected: props.day.isSelected,
holiday: props.day.isHoliday,
},
]"
:data-date="props.day.date"
>
<span class="compact-date">{{ formattedDate }}</span>
<h1 class="day-number">{{ props.day.displayText }}</h1>
<span v-if="props.day.lunarPhase" class="lunar-phase">{{ props.day.lunarPhase }}</span>
<div v-if="props.day.holiday" class="holiday-info" dir="auto" :title="props.day.holiday.name">
{{ props.day.holiday.name }}
</div>
</div>
</template>
<style scoped>
.cell {
position: relative;
user-select: none;
display: grid;
/* Updated grid for centered day number */
grid-template-columns: 1fr;
grid-template-rows: 1fr auto;
/* Named grid areas */
grid-template-areas:
'day-number'
'holiday-info';
padding: 0.25em;
overflow: visible;
width: 100%;
height: var(--row-h);
font-weight: 700;
transition: background-color 0.15s ease;
align-items: center;
justify-items: center;
}
.cell h1.day-number {
position: absolute;
font-size: 5vmin;
font-weight: 800;
color: var(--ink);
transition: all 0.15s ease;
}
.cell.firstday h1.day-number {
font-weight: 400;
}
.cell.weekend h1.day-number {
color: var(--weekend);
}
.cell.firstday h1.day-number {
color: var(--firstday);
}
.cell.today::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: calc(100% + .2rem);
height: calc(100% + .2rem);
border-radius: 1rem;
background: transparent;
border: 0.3em solid var(--today);
z-index: 15;
pointer-events: none;
}
.cell.selected h1.day-number {
opacity: 0.3;
filter: brightness(1.2);
}
.cell {
background-image: linear-gradient(
135deg,
var(--holiday-grad-start, rgba(255, 255, 255, 0.3)) 0%,
var(--holiday-grad-end, rgba(255, 255, 255, 0)) 70%
);
}
@media (prefers-color-scheme: dark) {
.cell {
background-image: linear-gradient(
135deg,
var(--holiday-grad-start, rgba(255, 255, 255, 0.05)) 0%,
var(--holiday-grad-end, rgba(255, 255, 255, 0)) 70%
);
}
}
.lunar-phase {
grid-area: lunar-phase;
position: absolute;
inset-block-start: 0.5em;
inset-inline-end: 0.2em;
font-size: 0.8em;
opacity: 0.7;
}
.compact-date {
position: absolute;
top: 0.25em;
left: 0.25em;
inset-inline-end: 1rem; /* Space for lunar phase */
font-weight: 400;
color: var(--ink);
line-height: 1;
pointer-events: none;
}
.cell.weekend .compact-date {
color: var(--weekend);
}
.cell.firstday .compact-date {
color: var(--firstday);
}
.cell.today .compact-date {
color: var(--strong);
}
.cell.selected .compact-date {
color: var(--strong);
}
.holiday-info {
grid-area: holiday-info;
align-self: end;
overflow: hidden;
max-width: 100%;
color: var(--holiday);
font-size: 1em;
font-weight: 400;
line-height: 1.0;
padding-inline: 0.15em;
padding-block: 0;
pointer-events: auto;
}
</style>