69217afce4
Added an event carousel to the homepage to display upcoming events dynamically. Integrated ICS parsing to fetch and format calendar data for future events. Enhanced layout and responsiveness with scroll functionality and improved styling.
228 lines
9.2 KiB
PHP
228 lines
9.2 KiB
PHP
<?php
|
|
|
|
function format_ics_date($date)
|
|
{
|
|
// Unterstützt sowohl ganztägige als auch Zeitangaben
|
|
if (strpos($date, 'T') !== false) {
|
|
$dt = DateTime::createFromFormat('Ymd\THis', substr($date, 0, 15));
|
|
|
|
return $dt ? $dt->format('d.m.Y H:i') : $date;
|
|
} else {
|
|
$dt = DateTime::createFromFormat('Ymd', $date);
|
|
|
|
return $dt ? $dt->format('d.m.Y') : $date;
|
|
}
|
|
}
|
|
|
|
$events = collection('termine');
|
|
|
|
// Nur Events mit DTSTART berücksichtigen
|
|
$events = array_filter($events, function ($event) {
|
|
return isset($event['DTSTART']) && ! empty($event['DTSTART']);
|
|
});
|
|
// Nach Datum sortieren
|
|
usort($events, function ($a, $b) {
|
|
return strcmp($a['DTSTART'], $b['DTSTART']);
|
|
});
|
|
|
|
// Aktuelles Datum
|
|
$today = (new DateTime())->format('Ymd');
|
|
|
|
// Nur zukünftige Termine anzeigen
|
|
$future_events = array_filter($events, function ($event) use ($today) {
|
|
return isset($event['DTSTART']) && $event['DTSTART'] >= $today;
|
|
});
|
|
|
|
// --- Deutsche Monatsnamen ---
|
|
$de_months = [
|
|
'01' => 'Januar',
|
|
'02' => 'Februar',
|
|
'03' => 'März',
|
|
'04' => 'April',
|
|
'05' => 'Mai',
|
|
'06' => 'Juni',
|
|
'07' => 'Juli',
|
|
'08' => 'August',
|
|
'09' => 'September',
|
|
'10' => 'Oktober',
|
|
'11' => 'November',
|
|
'12' => 'Dezember',
|
|
];
|
|
|
|
// --- Gruppierung aller Termine nach Jahr und Monat für die Sidebar ---
|
|
function group_events_by_year_month($events)
|
|
{
|
|
$grouped = [];
|
|
foreach ($events as $event) {
|
|
if ( ! isset($event['DTSTART'])) {
|
|
continue;
|
|
}
|
|
$date = $event['DTSTART'];
|
|
$year = substr($date, 0, 4);
|
|
$month = substr($date, 4, 2);
|
|
$grouped[$year][$month][] = $event;
|
|
}
|
|
krsort($grouped); // Jahre absteigend
|
|
foreach ($grouped as &$months) {
|
|
krsort($months); // Monate absteigend
|
|
}
|
|
|
|
return $grouped;
|
|
}
|
|
|
|
$all_events_grouped = group_events_by_year_month($events);
|
|
|
|
// --- Filter aus URL ---
|
|
$filter_jahr = $_GET['jahr'] ?? null;
|
|
$filter_monat = $_GET['monat'] ?? null;
|
|
if ($filter_jahr && $filter_monat) {
|
|
$filtered_events = array_filter($events, function ($event) use ($filter_jahr, $filter_monat) {
|
|
$date = $event['DTSTART'] ?? '';
|
|
|
|
return substr($date, 0, 4) === $filter_jahr && substr($date, 4, 2) === $filter_monat;
|
|
});
|
|
} elseif ($filter_jahr) {
|
|
$filtered_events = array_filter($events, function ($event) use ($filter_jahr) {
|
|
$date = $event['DTSTART'] ?? '';
|
|
|
|
return substr($date, 0, 4) === $filter_jahr;
|
|
});
|
|
} else {
|
|
$filtered_events = $future_events;
|
|
}
|
|
?>
|
|
|
|
<section class="py-24 bg-sf_grau-50">
|
|
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 flex flex-col md:flex-row gap-8">
|
|
<!-- Sidebar -->
|
|
<aside class="md:w-1/4 w-full mb-8 md:mb-0">
|
|
<div class="bg-white rounded-lg shadow p-4">
|
|
<h2 class="text-lg font-semibold mb-3">Termine nach Jahr/Monat</h2>
|
|
<ul class="space-y-1">
|
|
<?php
|
|
foreach ($all_events_grouped as $year => $months): ?>
|
|
<li class="mb-2">
|
|
<div class="flex items-center">
|
|
<a href="?jahr=<?php
|
|
echo $year; ?>"
|
|
class="font-bold text-sf_blau-600 focus:outline-none flex items-center group<?php
|
|
if ($filter_jahr === $year && ! $filter_monat) {
|
|
echo ' underline';
|
|
} ?><?php
|
|
if ($filter_jahr === $year && ! $filter_monat) {
|
|
echo ' selected';
|
|
} ?>" onclick="event.stopPropagation(); openYear('<?php
|
|
echo $year; ?>')">
|
|
<span><?php
|
|
echo $year; ?></span>
|
|
</a>
|
|
<button type="button" class="ml-1 focus:outline-none" onclick="toggleYear('<?php
|
|
echo $year; ?>')">
|
|
<svg class="w-4 h-4 transition-transform" id="arrow-<?php
|
|
echo $year; ?>" fill="none" stroke="currentColor" stroke-width="2"
|
|
viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
<ul class="ml-4 mt-1 hidden" id="months-<?php
|
|
echo $year; ?>">
|
|
<?php
|
|
foreach ($months as $month => $evts): ?>
|
|
<li>
|
|
<a href="?jahr=<?php
|
|
echo $year; ?>&monat=<?php
|
|
echo $month; ?>" class="text-sf_blau-500 hover:underline<?php
|
|
if ($filter_jahr === $year && $filter_monat === $month) {
|
|
echo ' font-bold underline selected';
|
|
} ?>">
|
|
<?php
|
|
echo $de_months[$month]; ?> (<?php
|
|
echo count($evts); ?>)
|
|
</a>
|
|
</li>
|
|
<?php
|
|
endforeach; ?>
|
|
</ul>
|
|
</li>
|
|
<?php
|
|
endforeach; ?>
|
|
</ul>
|
|
</div>
|
|
<script>
|
|
function toggleYear(year) {
|
|
var ul = document.getElementById('months-' + year);
|
|
var arrow = document.getElementById('arrow-' + year);
|
|
if (ul.classList.contains('hidden')) {
|
|
ul.classList.remove('hidden');
|
|
arrow.style.transform = 'rotate(90deg)';
|
|
} else {
|
|
ul.classList.add('hidden');
|
|
arrow.style.transform = '';
|
|
}
|
|
}
|
|
|
|
function openYear(year) {
|
|
var ul = document.getElementById('months-' + year);
|
|
var arrow = document.getElementById('arrow-' + year);
|
|
if (ul && ul.classList.contains('hidden')) {
|
|
ul.classList.remove('hidden');
|
|
arrow.style.transform = 'rotate(90deg)';
|
|
}
|
|
}
|
|
</script>
|
|
</aside>
|
|
<!-- Hauptinhalt Termine -->
|
|
<div class="md:w-3/4 w-full">
|
|
<?php
|
|
if (empty($filtered_events)): ?>
|
|
<div class="text-gray-500">Keine Termine gefunden.</div>
|
|
<?php
|
|
else: ?>
|
|
<div class="overflow-x-auto">
|
|
<table class="min-w-full border border-gray-200 bg-white rounded-lg shadow">
|
|
<thead>
|
|
<tr class="bg-gray-100">
|
|
<th class="py-2 px-4 border-b text-left">Datum</th>
|
|
<th class="py-2 px-4 border-b text-left">Uhrzeit</th>
|
|
<th class="py-2 px-4 border-b text-left">Titel</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php
|
|
foreach ($filtered_events as $event): ?>
|
|
<?php
|
|
$start = $event['DTSTART'] ?? '';
|
|
$end = $event['DTEND'] ?? '';
|
|
$summary = $event['SUMMARY'] ?? '';
|
|
$location = $event['LOCATION'] ?? '';
|
|
$desc = $event['DESCRIPTION'] ?? '';
|
|
$date = format_ics_date($start);
|
|
$time = (str_contains($start, 'T')) ? substr($date, 11) : 'ganztägig';
|
|
$date = substr($date, 0, 10);
|
|
?>
|
|
<tr class="hover:bg-gray-50">
|
|
<td class="py-2 px-4 border-b whitespace-nowrap"><?php
|
|
echo htmlspecialchars($date); ?></td>
|
|
<td class="py-2 px-4 border-b whitespace-nowrap"><?php
|
|
echo htmlspecialchars($time); ?></td>
|
|
<td class="py-2 px-4 border-b"><?php
|
|
echo htmlspecialchars($summary); ?></td>
|
|
</tr>
|
|
<?php
|
|
endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<?php
|
|
endif; ?>
|
|
</div>
|
|
</div>
|
|
<style>
|
|
.selected {
|
|
text-decoration: underline;
|
|
text-underline-offset: 3px;
|
|
font-weight: bold;
|
|
}
|
|
</style>
|
|
</section>
|