Add all-day event functionality to CalendarView: Introduce a new section for displaying all-day events in both week and day views. Update localization files to include translations for 'All Day' in English and German. Enhance event handling methods to support all-day events, improving the overall calendar experience.

This commit is contained in:
Torsten Schulz (local)
2026-01-30 14:43:07 +01:00
parent ec75c7ecdb
commit 7635355e94
3 changed files with 133 additions and 0 deletions

View File

@@ -8,6 +8,7 @@
"selectedDays": "{count} Tage ausgewählt", "selectedDays": "{count} Tage ausgewählt",
"createEventForSelection": "Termin erstellen", "createEventForSelection": "Termin erstellen",
"clearSelection": "Auswahl aufheben", "clearSelection": "Auswahl aufheben",
"allDay": "Ganztägig",
"views": { "views": {
"month": "Monat", "month": "Monat",
"week": "Woche", "week": "Woche",

View File

@@ -8,6 +8,7 @@
"selectedDays": "{count} days selected", "selectedDays": "{count} days selected",
"createEventForSelection": "Create Event", "createEventForSelection": "Create Event",
"clearSelection": "Clear Selection", "clearSelection": "Clear Selection",
"allDay": "All Day",
"views": { "views": {
"month": "Month", "month": "Month",
"week": "Week", "week": "Week",

View File

@@ -87,6 +87,23 @@
<div :class="['day-date', { today: day.isToday }]">{{ day.dayNumber }}</div> <div :class="['day-date', { today: day.isToday }]">{{ day.dayNumber }}</div>
</div> </div>
</div> </div>
<!-- All-day events row -->
<div v-if="hasAnyAllDayEvents(weekDaysData)" class="all-day-row">
<div class="all-day-label">{{ $t('personal.calendar.allDay') }}</div>
<div class="all-day-events">
<div v-for="day in weekDaysData" :key="day.date" class="all-day-cell">
<div
v-for="event in getEventsForDateAllDay(day.date)"
:key="event.id"
class="all-day-event"
:style="{ backgroundColor: getCategoryColor(event.categoryId) }"
@click="editEvent(event)"
>
{{ event.title }}
</div>
</div>
</div>
</div>
<div class="time-slots-container"> <div class="time-slots-container">
<div class="time-labels"> <div class="time-labels">
<div v-for="hour in hours" :key="hour" class="time-label"> <div v-for="hour in hours" :key="hour" class="time-label">
@@ -127,6 +144,23 @@
<div :class="['day-date', { today: day.isToday }]">{{ day.dayNumber }}</div> <div :class="['day-date', { today: day.isToday }]">{{ day.dayNumber }}</div>
</div> </div>
</div> </div>
<!-- All-day events row -->
<div v-if="hasAnyAllDayEvents(workWeekDaysData)" class="all-day-row">
<div class="all-day-label">{{ $t('personal.calendar.allDay') }}</div>
<div class="all-day-events">
<div v-for="day in workWeekDaysData" :key="day.date" class="all-day-cell">
<div
v-for="event in getEventsForDateAllDay(day.date)"
:key="event.id"
class="all-day-event"
:style="{ backgroundColor: getCategoryColor(event.categoryId) }"
@click="editEvent(event)"
>
{{ event.title }}
</div>
</div>
</div>
</div>
<div class="time-slots-container"> <div class="time-slots-container">
<div class="time-labels"> <div class="time-labels">
<div v-for="hour in workHours" :key="hour" class="time-label"> <div v-for="hour in workHours" :key="hour" class="time-label">
@@ -164,6 +198,21 @@
{{ currentDayData.dayNumber }}. {{ $t(`personal.calendar.months.${currentDayData.month}`) }} {{ currentDayData.year }} {{ currentDayData.dayNumber }}. {{ $t(`personal.calendar.months.${currentDayData.month}`) }} {{ currentDayData.year }}
</div> </div>
</div> </div>
<!-- All-day events for this day -->
<div v-if="getEventsForDateAllDay(currentDateStr).length > 0" class="all-day-section">
<div class="all-day-label">{{ $t('personal.calendar.allDay') }}</div>
<div class="all-day-events-day">
<div
v-for="event in getEventsForDateAllDay(currentDateStr)"
:key="event.id"
class="all-day-event"
:style="{ backgroundColor: getCategoryColor(event.categoryId) }"
@click="editEvent(event)"
>
{{ event.title }}
</div>
</div>
</div>
<div class="time-slots-container single-day"> <div class="time-slots-container single-day">
<div class="time-labels"> <div class="time-labels">
<div v-for="hour in hours" :key="hour" class="time-label"> <div v-for="hour in hours" :key="hour" class="time-label">
@@ -595,6 +644,17 @@ export default {
return dateStr >= eventStart && dateStr <= eventEnd; return dateStr >= eventStart && dateStr <= eventEnd;
}); });
}, },
getEventsForDateAllDay(dateStr) {
return this.events.filter(event => {
if (!event.allDay) return false;
const eventStart = event.startDate;
const eventEnd = event.endDate || event.startDate;
return dateStr >= eventStart && dateStr <= eventEnd;
});
},
hasAnyAllDayEvents(daysData) {
return daysData.some(day => this.getEventsForDateAllDay(day.date).length > 0);
},
getEventsForDateTime(dateStr, hour) { getEventsForDateTime(dateStr, hour) {
return this.events.filter(event => { return this.events.filter(event => {
if (event.allDay) return false; if (event.allDay) return false;
@@ -1003,6 +1063,77 @@ h2 {
background: #f8f8f8; background: #f8f8f8;
} }
// All-day events row (week/workweek views)
.all-day-row {
display: flex;
border-bottom: 1px solid #ddd;
background: #fafafa;
min-height: 40px;
}
.all-day-label {
width: 60px;
flex-shrink: 0;
padding: 8px 4px;
font-size: 0.75em;
color: #888;
text-align: right;
}
.all-day-events {
display: flex;
flex: 1;
}
.all-day-cell {
flex: 1;
padding: 4px;
border-left: 1px solid #eee;
display: flex;
flex-direction: column;
gap: 2px;
&:first-child {
border-left: none;
}
}
.all-day-event {
padding: 4px 8px;
border-radius: 4px;
font-size: 0.8em;
color: #fff;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
cursor: pointer;
&:hover {
opacity: 0.9;
}
}
// All-day section (day view)
.all-day-section {
display: flex;
border-bottom: 1px solid #ddd;
background: #fafafa;
padding: 8px 0;
}
.all-day-events-day {
flex: 1;
padding: 4px 8px;
display: flex;
flex-wrap: wrap;
gap: 8px;
.all-day-event {
flex: 0 0 auto;
max-width: 300px;
}
}
.time-header-spacer { .time-header-spacer {
width: 60px; width: 60px;
flex-shrink: 0; flex-shrink: 0;