Files
yourpart3/frontend/src/components/widgets/MiniCalendarWidget.vue

214 lines
4.5 KiB
Vue

<template>
<div v-if="calendarData" class="mini-calendar">
<div class="mini-calendar-header">
{{ monthName }} {{ calendarData.year }}
</div>
<div class="mini-calendar-weekdays">
<span v-for="day in weekdays" :key="day" class="mini-calendar-weekday">{{ day }}</span>
</div>
<div class="mini-calendar-days">
<span
v-for="(day, i) in calendarDays"
:key="i"
:class="getDayClasses(day)"
>
<template v-if="day">
{{ day }}
<span v-if="getDayIndicators(day)" class="day-indicators">
<span v-if="getDayIndicators(day).events" class="indicator event-indicator"></span>
<span v-if="getDayIndicators(day).birthdays" class="indicator birthday-indicator"></span>
</span>
</template>
</span>
</div>
<router-link to="/personal/calendar" class="mini-calendar-link">
Zum Kalender
</router-link>
</div>
<div v-else class="mini-calendar-empty">
Kalender wird geladen...
</div>
</template>
<script>
const MONTH_NAMES = [
'Januar', 'Februar', 'März', 'April', 'Mai', 'Juni',
'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'
];
export default {
name: 'MiniCalendarWidget',
props: {
data: { type: Object, default: null }
},
data() {
return {
weekdays: ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So']
};
},
computed: {
calendarData() {
return this.data;
},
monthName() {
if (!this.calendarData) return '';
return MONTH_NAMES[this.calendarData.month - 1];
},
calendarDays() {
if (!this.calendarData) return [];
const days = [];
const { firstDayOfWeek, daysInMonth } = this.calendarData;
// Add empty cells for days before the first day of month
for (let i = 1; i < firstDayOfWeek; i++) {
days.push(null);
}
// Add days of month
for (let i = 1; i <= daysInMonth; i++) {
days.push(i);
}
return days;
}
},
methods: {
getDayClasses(day) {
if (!day) return 'mini-calendar-day empty';
const classes = ['mini-calendar-day'];
if (this.calendarData && day === this.calendarData.today) {
classes.push('today');
}
const indicators = this.getDayIndicators(day);
if (indicators) {
if (indicators.events) classes.push('has-events');
if (indicators.birthdays) classes.push('has-birthdays');
}
return classes.join(' ');
},
getDayIndicators(day) {
if (!day || !this.calendarData || !this.calendarData.daysWithEvents) return null;
return this.calendarData.daysWithEvents[day] || null;
}
}
};
</script>
<style scoped>
.mini-calendar {
font-size: 0.85rem;
}
.mini-calendar-header {
text-align: center;
font-weight: 600;
color: #333;
margin-bottom: 10px;
}
.mini-calendar-weekdays {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 2px;
margin-bottom: 4px;
}
.mini-calendar-weekday {
text-align: center;
font-size: 0.75em;
color: #888;
font-weight: 500;
}
.mini-calendar-days {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 2px;
}
.mini-calendar-day {
position: relative;
text-align: center;
padding: 4px 2px;
border-radius: 4px;
cursor: default;
min-height: 24px;
display: flex;
align-items: center;
justify-content: center;
}
.mini-calendar-day.empty {
background: transparent;
}
.mini-calendar-day.today {
background: var(--color-primary-orange, #FFB84D);
color: #000;
font-weight: 600;
border-radius: 50%;
}
.mini-calendar-day.has-events:not(.today) {
background: #e3f2fd;
}
.mini-calendar-day.has-birthdays:not(.today) {
background: #fff3e0;
}
.mini-calendar-day.has-events.has-birthdays:not(.today) {
background: linear-gradient(135deg, #e3f2fd 50%, #fff3e0 50%);
}
.day-indicators {
position: absolute;
bottom: 1px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 2px;
}
.indicator {
width: 4px;
height: 4px;
border-radius: 50%;
}
.event-indicator {
background: #2196F3;
}
.birthday-indicator {
background: #FF9800;
}
.mini-calendar-link {
display: block;
text-align: center;
margin-top: 12px;
padding-top: 8px;
border-top: 1px solid #eee;
color: var(--color-primary-orange, #FFB84D);
text-decoration: none;
font-size: 0.85em;
}
.mini-calendar-link:hover {
text-decoration: underline;
}
.mini-calendar-empty {
color: #888;
text-align: center;
padding: 1rem;
font-style: italic;
}
</style>