Files
Walschleber-Kultour-CMS/programm.php
T
2026-01-11 15:40:15 +00:00

233 lines
11 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
require_once __DIR__ . '/functions.php';
$all = load_events();
$upcoming = array_values(array_filter($all, 'is_upcoming'));
usort($upcoming, 'by_datetime_asc');
$jsonld = render_event_jsonld_graph($upcoming);
?>
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Programm | <?= h(SITE_NAME) ?></title>
<meta name="description" content="Aktuelle Vorträge, Lesungen und Multivisionsshows in Walschleben <?= h(SITE_NAME) ?>. Termine, Inhalte, Tickets.">
<link rel="canonical" href="<?= h(BASE_URL) ?>/programm.php">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta property="og:title" content="Programm | <?= h(SITE_NAME) ?>">
<meta property="og:description" content="Aktuelle Vorträge, Lesungen und Multivisionsshows Termine & Infos.">
<meta property="og:type" content="website">
<meta property="og:url" content="<?= h(BASE_URL) ?>/programm.php">
<meta property="og:image" content="<?= h(BASE_URL . DEFAULT_OG_IMAGE) ?>">
<meta name="twitter:card" content="summary_large_image">
<script type="application/ld+json"><?= $jsonld ?></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="/assets/styles.css">
<link rel="icon" href="/assets/logo.png" sizes="32x32" type="image/png">
<style>
/* ===== Poster Cards (perfektionistischer Look) ===== */
.poster-card{
border:1px solid #e9edf3;
border-radius:1.1rem;
box-shadow:0 8px 28px rgba(0,0,0,.06);
transition:transform .18s ease, box-shadow .18s ease, border-color .18s ease;
background:#fff;
}
.poster-card:hover{ transform:translateY(-2px); box-shadow:0 12px 38px rgba(0,0,0,.10); cursor:pointer; }
.poster-media{
padding:1rem 1rem 0; display:flex; justify-content:center; align-items:center;
}
.poster-img{
display:block; margin:0 auto;
width:auto; height:auto; max-width:100%;
/* Bild bestimmt die Kachelhöhe harmonisch skaliert, aber nie beschnitten */
max-height: clamp(220px, 32vh, 420px);
object-fit:contain;
border-radius:.75rem;
box-shadow:0 6px 18px rgba(0,0,0,.08);
}
.poster-body{
text-align:center; padding:1rem 1.25rem 1.25rem;
}
.poster-date{ text-transform:uppercase; letter-spacing:.06em; }
.poster-title{ font-weight:800; line-height:1.15; margin:.25rem 0 .35rem; }
.poster-sub{ color:var(--muted); }
.poster-desc{ margin:.75rem auto 0; color:#344654; max-width:46ch; }
.poster-meta{ margin-top:.9rem; gap:.5rem; justify-content:center }
.poster-meta .badge{ font-weight:600 }
.top-ribbon{
position:absolute; top:12px; left:12px; background:var(--brand); color:#fff;
font-weight:700; padding:.28rem .55rem; border-radius:.5rem; font-size:.8rem;
box-shadow:0 6px 14px rgba(23,137,202,.25);
}
/* Modal Bild schön groß & mittig */
.modal-img{ max-height:90vh; width:auto; height:auto; object-fit:contain; display:block; margin:0 auto; }
.modal-body p{ white-space:pre-line; }
/* Tastatur-Focus sichtbar */
.poster-card:focus{ outline:3px solid rgba(23,137,202,.35); outline-offset:2px; }
</style>
</head>
<body>
<nav class="navbar navbar-expand-lg bg-body-tertiary border-bottom sticky-top">
<div class="container">
<a class="navbar-brand brand-logo" href="index.html">
<img src="/assets/logo.png" alt="Walschleber KulTour Logo" height="34" width="34">
<span><?= h(SITE_NAME) ?></span>
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#nav"><span class="navbar-toggler-icon"></span></button>
<div id="nav" class="collapse navbar-collapse">
<ul class="navbar-nav ms-auto">
<li class="nav-item"><a class="nav-link active" href="programm.php">Programm</a></li>
<li class="nav-item"><a class="nav-link" href="vergangene-vortraege.php">Vergangene Vorträge</a></li>
<li class="nav-item"><a class="nav-link" href="ueber-uns.html">Über uns</a></li>
<li class="nav-item"><a class="nav-link" href="kontakt.html">Kontakt</a></li>
</ul>
</div>
</div>
</nav>
<header class="py-5 bg-light border-bottom">
<div class="container">
<h1 class="display-6 mb-2">Programm</h1>
<p class="text-muted mb-0">Alle kommenden Termine auf einen Blick.</p>
</div>
</header>
<main class="container my-4">
<?php if (!$upcoming): ?>
<div class="alert alert-info">Derzeit sind keine zukünftigen Termine eingetragen.</div>
<?php else: ?>
<div class="d-flex justify-content-between align-items-center mb-3">
<div class="small text-muted">Sortierung: demnächst zuerst</div>
<a class="btn btn-brand btn-sm" href="vergangene-vortraege.php">Zum Archiv</a>
</div>
<div class="row g-4">
<?php foreach ($upcoming as $e): $mid = 'event-'.h($e['id']); ?>
<div class="col-md-6 col-lg-4">
<article class="poster-card position-relative h-100"
data-bs-toggle="modal" data-bs-target="#<?= $mid ?>"
tabindex="0" role="button" aria-label="Details zu <?= h($e['title']) ?> öffnen">
<?php if (!empty($e['image'])): ?>
<div class="poster-media">
<img class="poster-img" src="<?= h($e['image']) ?>" alt="<?= h($e['title']) ?>">
</div>
<?php endif; ?>
<div class="poster-body">
<span class="top-ribbon">Kommender Termin</span>
<div class="small text-muted poster-date mb-2">
<?= date('d.m.Y', strtotime($e['date'])) ?> · <?= h($e['time'] ?: '19:30') ?>
</div>
<h2 class="h5 poster-title"><?= h($e['title']) ?></h2>
<?php if (!empty($e['speaker'])): ?>
<div class="poster-sub small mb-2">mit <?= h($e['speaker']) ?></div>
<?php endif; ?>
<?php if (!empty($e['description'])): ?>
<p class="poster-desc"><?= nl2br(h(mb_strimwidth($e['description'], 0, 220, '…'))) ?></p>
<?php endif; ?>
<div class="d-flex flex-wrap poster-meta">
<?php if (!empty($e['venue_name'])): ?>
<span class="badge text-bg-light border"><?= h($e['venue_name']) ?></span>
<?php endif; ?>
<?php if (!empty($e['price'])): ?>
<span class="badge badge-accent">Eintritt: <?= h($e['price']) ?></span>
<?php endif; ?>
<?php if (!empty($e['doors_open'])): ?>
<span class="badge text-bg-light border">Einlass: <?= h($e['doors_open']) ?></span>
<?php endif; ?>
<?php if (!empty($e['tags'])): ?>
<span class="badge text-bg-light border"><?= h($e['tags']) ?></span>
<?php endif; ?>
</div>
<?php
$ticketUrl = null;
if (!empty($e['tickets_info']) && preg_match('~https?://[^\s]+~', $e['tickets_info'], $m)) {
$ticketUrl = $m[0];
}
?>
<?php if ($ticketUrl): ?>
<div class="mt-3">
<a class="btn btn-brand btn-sm" href="<?= h($ticketUrl) ?>" target="_blank" rel="noopener" onclick="event.stopPropagation()">Tickets sichern</a>
</div>
<?php elseif (!empty($e['tickets_info'])): ?>
<div class="mt-3 small text-muted"><strong>Tickets:</strong> <?= h($e['tickets_info']) ?></div>
<?php endif; ?>
<a href="#<?= $mid ?>" class="stretched-link" data-bs-toggle="modal" data-bs-target="#<?= $mid ?>" aria-hidden="true" tabindex="-1"></a>
</div>
</article>
</div>
<?php endforeach; ?>
</div>
<!-- Modals -->
<?php foreach ($upcoming as $e): $mid = 'event-'.h($e['id']); ?>
<div class="modal fade" id="<?= $mid ?>" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-xl modal-dialog-centered modal-fullscreen-sm-down">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title h4 mb-0"><?= h($e['title']) ?></h2>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Schließen"></button>
</div>
<div class="modal-body">
<?php if (!empty($e['image'])): ?>
<img src="<?= h($e['image']) ?>" alt="<?= h($e['title']) ?>" class="modal-img mb-3">
<?php endif; ?>
<p class="text-muted small mb-2">
<?= date('d.m.Y', strtotime($e['date'])) ?> · <?= h($e['time'] ?: '19:30') ?>
<?php if (!empty($e['speaker'])): ?> · mit <?= h($e['speaker']) ?><?php endif; ?>
</p>
<?php if (!empty($e['venue_name']) || !empty($e['venue_address'])): ?>
<p class="mb-2 text-center"><strong><?= h($e['venue_name']) ?></strong><?= !empty($e['venue_address']) ? ' · '.h($e['venue_address']) : '' ?></p>
<?php endif; ?>
<?php if (!empty($e['price']) || !empty($e['doors_open'])): ?>
<p class="mb-2 text-center">
<?php if (!empty($e['price'])): ?><span class="badge badge-accent">Eintritt: <?= h($e['price']) ?></span> <?php endif; ?>
<?php if (!empty($e['doors_open'])): ?><span class="badge text-bg-light border">Einlass: <?= h($e['doors_open']) ?></span><?php endif; ?>
</p>
<?php endif; ?>
<?php if (!empty($e['tags'])): ?>
<p class="mb-2 text-center"><span class="badge text-bg-light border"><?= h($e['tags']) ?></span></p>
<?php endif; ?>
<div class="poster-desc">
<?= render_rich_text($e['description'] ?? '') ?>
</div>
<?php if (!empty($ticketUrl)): ?>
<div class="text-center"><a class="btn btn-brand" href="<?= h($ticketUrl) ?>" target="_blank" rel="noopener">Tickets sichern</a></div>
<?php elseif (!empty($e['tickets_info'])): ?>
<div class="small text-center"><strong>Tickets:</strong> <?= h($e['tickets_info']) ?></div>
<?php endif; ?>
</div>
</div>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</main>
<footer class="py-4 border-top mt-5">
<div class="container small d-flex gap-3 flex-wrap align-items-center">
<span>&copy; <?= date('Y') ?> <?= h(SITE_NAME) ?></span>
<span class="separator">•</span><a href="impressum.html">Impressum</a>
<span class="separator">•</span><a href="datenschutz.html">Datenschutz</a>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>