diff --git a/static/app.css b/static/app.css index d5c9f5c..91586a0 100644 --- a/static/app.css +++ b/static/app.css @@ -681,6 +681,33 @@ footer { border-color: #4da3ff; } +.calendar-day-sunday, +.calendar-day-holiday { + background: #fff7f7; +} + +.calendar-day-today.calendar-day-sunday, +.calendar-day-today.calendar-day-holiday { + background: linear-gradient(135deg, #f7fbff 0%, #f7fbff 60%, #fff2f2 100%); +} + +.calendar-day-sunday .calendar-day-header, +.calendar-day-holiday .calendar-day-header { + color: #b93838; +} + +.calendar-holiday-badge { + display: inline-block; + margin-left: 6px; + padding: 2px 8px; + border-radius: 999px; + background: #ffe3e3; + color: #b93838; + font-size: 0.75rem; + font-weight: 700; + white-space: nowrap; +} + .calendar-day:last-child { border-bottom: none; } diff --git a/templates/calendar_section.html b/templates/calendar_section.html index 6cff064..d55bb5e 100644 --- a/templates/calendar_section.html +++ b/templates/calendar_section.html @@ -91,6 +91,63 @@ return `${year}-${month}-${day}`; }; + const holidayCache = new Map(); + + function calculateEasterSunday(year) { + const a = year % 19; + const b = Math.floor(year / 100); + const c = year % 100; + const d = Math.floor(b / 4); + const e = b % 4; + const f = Math.floor((b + 8) / 25); + const g = Math.floor((b - f + 1) / 3); + const h = (19 * a + b - d - g + 15) % 30; + const i = Math.floor(c / 4); + const k = c % 4; + const l = (32 + 2 * e + 2 * i - h - k) % 7; + const m = Math.floor((a + 11 * h + 22 * l) / 451); + const month = Math.floor((h + l - 7 * m + 114) / 31); + const day = ((h + l - 7 * m + 114) % 31) + 1; + return new Date(year, month - 1, day); + } + + function getGermanHolidays(year) { + if (holidayCache.has(year)) return holidayCache.get(year); + + const holidays = new Map(); + const add = (month, day, name) => { + holidays.set(toLocalISO(new Date(year, month - 1, day)), name); + }; + + add(1, 1, 'Neujahr'); + add(5, 1, 'Tag der Arbeit'); + add(10, 3, 'Tag der Deutschen Einheit'); + add(12, 25, '1. Weihnachtstag'); + add(12, 26, '2. Weihnachtstag'); + + const easterSunday = calculateEasterSunday(year); + const addOffset = (offset, name) => { + const d = new Date(easterSunday); + d.setDate(easterSunday.getDate() + offset); + holidays.set(toLocalISO(d), name); + }; + + addOffset(-2, 'Karfreitag'); + addOffset(0, 'Ostersonntag'); + addOffset(1, 'Ostermontag'); + addOffset(39, 'Christi Himmelfahrt'); + addOffset(49, 'Pfingstsonntag'); + addOffset(50, 'Pfingstmontag'); + + holidayCache.set(year, holidays); + return holidays; + } + + function getHolidayName(date) { + const holidays = getGermanHolidays(date.getFullYear()); + return holidays.get(toLocalISO(date)) || ''; + } + function getCalendarRange() { const weeks = window._calendarIsAdmin ? 12 : 4; const start = new Date(); @@ -121,6 +178,9 @@ const date = new Date(start); date.setDate(start.getDate() + i); const isoDate = toLocalISO(date); + const isSunday = date.getDay() === 0; + const holidayName = getHolidayName(date); + const holidayBadge = holidayName ? `${holidayName}` : ''; const dayBlock = document.createElement('div'); dayBlock.className = 'calendar-day empty'; @@ -128,11 +188,17 @@ if (isoDate === toLocalISO(new Date())) { dayBlock.classList.add('calendar-day-today'); } + if (isSunday) { + dayBlock.classList.add('calendar-day-sunday'); + } + if (holidayName) { + dayBlock.classList.add('calendar-day-holiday'); + } dayBlock.innerHTML = `