156 lines
7.2 KiB
PHP
156 lines
7.2 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Aufruf-Seite der Stadionzeitung (Live-Seite) — eine redaktionelle Content-
|
||
|
|
* Seite für einen Handlungsaufruf, zuerst gebaut für den Helferaufruf zum
|
||
|
|
* Sportfest, bewusst GENERISCH gehalten (nicht `sportfest`), damit sie später
|
||
|
|
* auch für andere Feste (Weihnachtsfeier o. Ä.) taugt.
|
||
|
|
*
|
||
|
|
* Der Inhalt ist KEIN Skript-Input: er wird wie Vorwort/Interview im Chat
|
||
|
|
* gepflegt und lebt im `aufruf`-Feld der Ausgabe in data/stadionzeitung.json:
|
||
|
|
* kicker kleine Zeile über der Überschrift (z. B. „Sportfest 2026")
|
||
|
|
* heading Überschrift der Seite
|
||
|
|
* intro Vorspann (Lese-Serif, wie Vorwort/Interview) — String ODER
|
||
|
|
* Liste von Zeilen (mehrere Zeilen = ein Absatz mit <br>)
|
||
|
|
* tasks_title Überschrift über der Aufgaben-Liste (optional)
|
||
|
|
* tasks[] wobei Hilfe gebraucht wird
|
||
|
|
* contacts_intro Zeile über den Ansprechpartnern (optional)
|
||
|
|
* contacts[] NAMEN — Nummer/Foto zieht die Seite per Namensabgleich aus
|
||
|
|
* data/ansprechpartner.json (geteilte Quelle, nie duplizieren;
|
||
|
|
* wie die Kontakt-Seite bewusst live statt Snapshot: ein Fest
|
||
|
|
* betrifft ohnehin die Zukunft, alte Nummern nützen niemandem)
|
||
|
|
* link interner Slug fürs Ziel (z. B. „veranstaltungen/sportfest-2026"),
|
||
|
|
* liefert Link-Zeile + QR im CTA-Fuß
|
||
|
|
* poster optional, kleines Plakat rechts neben Intro + Aufgaben
|
||
|
|
* (Varianten-Set {base,widths,alt} oder {src,…}) — z. B. das
|
||
|
|
* Sportfest-Vorderplakat aus data/veranstaltungen.json
|
||
|
|
* bin/stadionzeitung-add.php trägt das Feld über erneute Läufe weiter (wie
|
||
|
|
* `vorwort`/`interview`), plant die Seite nur ein wenn das Feld existiert und
|
||
|
|
* erzeugt den QR (qr-aufruf.png im Ausgaben-Ordner) aus `link`.
|
||
|
|
*
|
||
|
|
* Props: $issue (Eintrag aus data/stadionzeitung.json)
|
||
|
|
*/
|
||
|
|
$issue = $issue ?? [];
|
||
|
|
$aufruf = $issue['aufruf'] ?? null;
|
||
|
|
if (!is_array($aufruf)) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
$slug = (string) ($issue['slug'] ?? '');
|
||
|
|
$heading = trim((string) ($aufruf['heading'] ?? 'Mach mit'));
|
||
|
|
$kicker = trim((string) ($aufruf['kicker'] ?? 'Mitmachen'));
|
||
|
|
// intro darf ein String ODER eine Liste von Zeilen sein — mehrere Zeilen
|
||
|
|
// werden als EIN Absatz mit weichen Umbrüchen (<br>) gesetzt, damit ein kurzer
|
||
|
|
// Aufruf bewusst zeilenweise stehen kann statt als Fließblock.
|
||
|
|
$introLines = array_values(array_filter(
|
||
|
|
array_map(static fn ($l): string => trim((string) $l), (array) ($aufruf['intro'] ?? [])),
|
||
|
|
static fn (string $l): bool => $l !== ''
|
||
|
|
));
|
||
|
|
$tasksTitle = trim((string) ($aufruf['tasks_title'] ?? ''));
|
||
|
|
$tasks = array_values(array_filter(
|
||
|
|
array_map(static fn ($t): string => trim((string) $t), $aufruf['tasks'] ?? []),
|
||
|
|
static fn (string $t): bool => $t !== ''
|
||
|
|
));
|
||
|
|
$contactsIntro = trim((string) ($aufruf['contacts_intro'] ?? ''));
|
||
|
|
$link = trim((string) ($aufruf['link'] ?? ''));
|
||
|
|
$ctaLabel = trim((string) ($aufruf['cta_label'] ?? 'Alle Infos'));
|
||
|
|
$ctaTitle = trim((string) ($aufruf['cta_title'] ?? ''));
|
||
|
|
|
||
|
|
// Kontakte per Namensabgleich aus der geteilten Quelle auflösen (Nummer/Foto),
|
||
|
|
// die Reihenfolge folgt dem `contacts`-Feld. Ein unbekannter Name bleibt als
|
||
|
|
// reiner Name stehen (kein Fehler), damit ein Tippfehler die Seite nicht kippt.
|
||
|
|
$byName = [];
|
||
|
|
foreach (json_load('ansprechpartner')['persons'] ?? [] as $person) {
|
||
|
|
$name = (string) ($person['name'] ?? '');
|
||
|
|
if ($name !== '') {
|
||
|
|
$byName[$name] = $person;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
$contacts = [];
|
||
|
|
foreach ($aufruf['contacts'] ?? [] as $name) {
|
||
|
|
$name = trim((string) $name);
|
||
|
|
if ($name === '') {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
$contacts[] = $byName[$name] ?? ['name' => $name];
|
||
|
|
}
|
||
|
|
|
||
|
|
$qr = ($slug !== '' && is_file(PUBLIC_PATH . "/assets/img/stadionzeitung/{$slug}/qr-aufruf.png"))
|
||
|
|
? "img/stadionzeitung/{$slug}/qr-aufruf.png"
|
||
|
|
: null;
|
||
|
|
$linkLabel = $link !== '' ? club_domain($link) : '';
|
||
|
|
|
||
|
|
// Optionales kleines Plakat rechts neben Intro + Aufgaben (z. B. das Sportfest-
|
||
|
|
// Vorderplakat) — Varianten-Set {base,widths,alt} oder Einzeldatei {src,…}.
|
||
|
|
$poster = $aufruf['poster'] ?? null;
|
||
|
|
if (!is_array($poster) || (empty($poster['base']) && empty($poster['src']))) {
|
||
|
|
$poster = null;
|
||
|
|
}
|
||
|
|
?>
|
||
|
|
<div class="stadionzeitung-aufruf">
|
||
|
|
<header class="stadionzeitung-page__head">
|
||
|
|
<p class="stadionzeitung-page__kicker"><?= e($kicker) ?></p>
|
||
|
|
<h2 class="stadionzeitung-page__heading"><?= e($heading) ?></h2>
|
||
|
|
</header>
|
||
|
|
<span class="stadionzeitung-page__rule" aria-hidden="true"></span>
|
||
|
|
<div class="stadionzeitung-aufruf__cols<?= $poster ? ' stadionzeitung-aufruf__cols--poster' : '' ?>">
|
||
|
|
<div class="stadionzeitung-aufruf__col-main">
|
||
|
|
<?php if ($introLines !== []): ?>
|
||
|
|
<p class="stadionzeitung-aufruf__intro"><?= implode('<br>', array_map('e', $introLines)) ?></p>
|
||
|
|
<?php endif; ?>
|
||
|
|
<?php if ($tasks !== []): ?>
|
||
|
|
<div class="stadionzeitung-aufruf__tasks">
|
||
|
|
<?php if ($tasksTitle !== ''): ?>
|
||
|
|
<p class="stadionzeitung-aufruf__tasks-title"><?= e($tasksTitle) ?></p>
|
||
|
|
<?php endif; ?>
|
||
|
|
<ul class="stadionzeitung-aufruf__task-list">
|
||
|
|
<?php foreach ($tasks as $task): ?>
|
||
|
|
<li class="stadionzeitung-aufruf__task"><?= icon('check2', 'stadionzeitung-aufruf__task-icon') ?><span><?= e($task) ?></span></li>
|
||
|
|
<?php endforeach; ?>
|
||
|
|
</ul>
|
||
|
|
</div>
|
||
|
|
<?php endif; ?>
|
||
|
|
</div>
|
||
|
|
<?php if ($poster): ?>
|
||
|
|
<?php component('img', ['image' => $poster, 'sizes' => '150px', 'class' => 'stadionzeitung-aufruf__poster']); ?>
|
||
|
|
<?php endif; ?>
|
||
|
|
</div>
|
||
|
|
<?php if ($contacts !== []): ?>
|
||
|
|
<div class="stadionzeitung-aufruf__contacts">
|
||
|
|
<?php if ($contactsIntro !== ''): ?>
|
||
|
|
<p class="stadionzeitung-aufruf__contacts-intro"><?= e($contactsIntro) ?></p>
|
||
|
|
<?php endif; ?>
|
||
|
|
<ul class="stadionzeitung-aufruf__contact-list">
|
||
|
|
<?php foreach ($contacts as $contact): ?>
|
||
|
|
<li class="stadionzeitung-aufruf__contact">
|
||
|
|
<span class="stadionzeitung-aufruf__contact-name"><?= e((string) ($contact['name'] ?? '')) ?></span>
|
||
|
|
<?php if (!empty($contact['phone'])): ?>
|
||
|
|
<span class="stadionzeitung-aufruf__contact-phone"><?= icon('telephone', 'stadionzeitung-aufruf__contact-icon') ?><?= e((string) $contact['phone']) ?></span>
|
||
|
|
<?php elseif (!empty($contact['email'])): ?>
|
||
|
|
<span class="stadionzeitung-aufruf__contact-phone"><?= icon('envelope', 'stadionzeitung-aufruf__contact-icon') ?><?= e((string) $contact['email']) ?></span>
|
||
|
|
<?php endif; ?>
|
||
|
|
</li>
|
||
|
|
<?php endforeach; ?>
|
||
|
|
</ul>
|
||
|
|
</div>
|
||
|
|
<?php endif; ?>
|
||
|
|
<?php if ($linkLabel !== ''): ?>
|
||
|
|
<div class="stadionzeitung-page__cta">
|
||
|
|
<div class="stadionzeitung-page__cta-text">
|
||
|
|
<p class="stadionzeitung-page__cta-label"><?= e($ctaLabel) ?></p>
|
||
|
|
<?php if ($ctaTitle !== ''): ?>
|
||
|
|
<p class="stadionzeitung-page__cta-title"><?= e($ctaTitle) ?></p>
|
||
|
|
<?php endif; ?>
|
||
|
|
<p class="stadionzeitung-page__cta-link"><?= e($linkLabel) ?></p>
|
||
|
|
</div>
|
||
|
|
<?php if ($qr !== null): ?>
|
||
|
|
<div class="stadionzeitung-page__cta-abriss">
|
||
|
|
<img class="stadionzeitung-page__cta-qr" src="<?= e(asset($qr)) ?>" alt="" width="60" height="60" loading="lazy" decoding="async">
|
||
|
|
<span class="stadionzeitung-page__cta-scan">Scan mich</span>
|
||
|
|
</div>
|
||
|
|
<?php endif; ?>
|
||
|
|
</div>
|
||
|
|
<?php endif; ?>
|
||
|
|
</div>
|