Stadionzeitung Ausgabe 2 (TSV Ködnitz, 15.08.): Entwurf + neue Aufruf-Seite
- Neue generische Live-Seite `aufruf` (erste Nutzung: Sportfest-Helferaufruf): Komponente, Dispatcher, Skript-Einbindung (Planung im Aufschlag, QR aus aufruf.link, Feld-Carryover), CSS, optionales kleines Poster rechts. - Ausgabe 2026-08-15-tsv-koednitz als ENTWURF: Vorwort (Benedikt, Revanche dezent), Interview (Ali, 3 Fragen), Sportfest-Helferseite mit Kontakten aus ansprechpartner.json; Rückseite/Cover wie Hutschdorf wiederverwendet. - Interview-Frage größer/prominenter gesetzt. - Sportfest-Plakat-Anzeige deaktiviert (redundant zur Helferseite) -> 40 Seiten. Sync-Dateien (instagram/matchcenter) bleiben gitignored, Snapshot wird beim Veröffentlichen auf dem Server eingefroren. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AFnFYLm2MoBskyk9mc84ZW
This commit is contained in:
155
app/components/stadionzeitung-aufruf.php
Normal file
155
app/components/stadionzeitung-aufruf.php
Normal file
@@ -0,0 +1,155 @@
|
||||
<?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>
|
||||
Reference in New Issue
Block a user