Quelltext des aktuellen Standes
<?php
use OpenNIT\Status\StatusManager;
$recent = $recent_incidents ?? [];
$brand = $brand ?? [];
$overall = $overall ?? ['key' => 'operational', 'label' => 'Alle Systeme betriebsbereit', 'all_ok' => true];
$e = fn($v) => htmlspecialchars((string)$v, ENT_QUOTES, 'UTF-8');
$dt = fn($v) => $v ? date('d.m.Y H:i', strtotime((string)$v)) : '';
// Optionale Zusatzblöcke oben auf der Seite. Nur auf der Vollseite (nicht im
// Embed) und nur wenn im Backend aktiviert. Zwei Einbindungen der Websuche:
// - box: kompakter Block über dem Status (klassische Statusseite)
// - start: Startseiten-Modus – Logo, große Suche und Status-Kurzinfo im
// Mittelpunkt (z. B. als Browser-Startseite für Mitarbeitende),
// die Status-Details folgen darunter.
$searchProviders = [
'google' => ['Google', 'https://www.google.com/search?q='],
'bing' => ['Bing', 'https://www.bing.com/search?q='],
'duckduckgo' => ['DuckDuckGo', 'https://duckduckgo.com/?q='],
'startpage' => ['Startpage', 'https://www.startpage.com/sp/search?query='],
'ecosia' => ['Ecosia', 'https://www.ecosia.org/search?q='],
];
$searchDefault = $brand['search_provider'] ?? 'google';
if (!isset($searchProviders[$searchDefault])) { $searchDefault = 'google'; }
$searchOn = !empty($brand['search_enabled']);
$startMode = $searchOn && ($brand['search_layout'] ?? 'box') === 'start';
$htmlContent = trim((string)($brand['html_content'] ?? ''));
$this->layout('layouts/status_public', [
'page_title' => $startMode ? 'Startseite' : ($page_title ?? 'Systemstatus'),
'embed' => false,
'brand' => $brand,
'start_mode' => $startMode,
]);
if ($searchOn):
// Fester, im Backend gewählter Anbieter – auf der Seite nicht änderbar.
$sp = $searchProviders[$searchDefault];
// Gemeinsames Suchformular beider Einbindungen. Im Startseiten-Modus mit
// Autofokus und Navigation im selben Tab (Startseiten-Verhalten), im
// kompakten Block weiterhin in einem neuen Tab.
$searchForm = function () use ($sp, $e, $startMode) { ?>
<form class="sp-search-form" data-search-url="<?= $e($sp[1]) ?>" data-search-target="<?= $startMode ? 'self' : 'blank' ?>" role="search">
<span class="sp-search-icon" aria-hidden="true">
<svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="7"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>
</span>
<input type="search" class="sp-search-input" placeholder="<?= $this->te('Im Web suchen mit {anbieter}…', ['anbieter' => $e($sp[0])]) ?>" aria-label="<?= $this->te('Suchbegriff') ?>" autocomplete="off"<?= $startMode ? ' autofocus' : '' ?>>
<button type="submit" class="sp-search-btn">
<svg class="sp-search-btn-icon" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="7"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>
<span><?= $this->t('Mit {anbieter} suchen', ['anbieter' => $e($sp[0])]) ?></span>
</button>
</form>
<?php };
?>
<?php if ($startMode): ?>
<!-- A) Startseiten-Modus: Logo + große Suche + Status-Kurzinfo im Mittelpunkt -->
<div class="sp-start-hero">
<?php if (!empty($app_logo)): ?>
<img src="<?= $e($app_logo) ?>" alt="<?= $e($app_name ?? 'OpenNIT') ?>" class="sp-start-logo">
<?php else: ?>
<div class="sp-start-appname"><?= $e($app_name ?? 'OpenNIT') ?></div>
<?php endif; ?>
<p class="sp-start-greeting" data-sp-greeting hidden></p>
<?php $searchForm(); ?>
<div class="sp-start-meta">
<a class="sp-pill sp-pill--<?= $e($overall['key']) ?> sp-start-chip" href="#status" title="<?= $this->te('Zum Systemstatus springen') ?>"><?= $e($overall['label']) ?></a>
<?php if (!empty($brand['support_url']) && !empty($brand['support_label'])): ?>
<a class="sp-start-chip sp-start-chip--support" href="<?= $e($brand['support_url']) ?>" target="_blank" rel="noopener"><?= $e($brand['support_label']) ?></a>
<?php endif; ?>
</div>
</div>
<?php else: ?>
<!-- A) Kompakte Websuche über dem Status (fester Anbieter) -->
<div class="sp-section sp-search sp-search--hero">
<h2 class="sp-search-title"><?= $this->te('Schnellsuche im Web') ?></h2>
<?php $searchForm(); ?>
</div>
<?php endif; ?>
<script>
(function () {
document.querySelectorAll('.sp-search-form').forEach(function (f) {
f.addEventListener('submit', function (ev) {
ev.preventDefault();
var q = f.querySelector('.sp-search-input').value.trim();
if (!q) { return; }
var url = f.getAttribute('data-search-url') + encodeURIComponent(q);
if (f.getAttribute('data-search-target') === 'self') {
window.location.href = url;
} else {
window.open(url, '_blank', 'noopener');
}
});
});
// Begrüßung im Startseiten-Modus clientseitig (Seite wird serverseitig gecacht)
var g = document.querySelector('[data-sp-greeting]');
if (g) {
var h = new Date().getHours();
var text = h >= 5 && h < 11 ? 'Guten Morgen' : (h >= 11 && h < 18 ? 'Guten Tag' : 'Guten Abend');
g.textContent = text + ' · ' + new Date().toLocaleDateString('de-DE', { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' });
g.hidden = false;
}
})();
</script>
<?php endif; ?>
<?php if (!empty($brand['html_enabled']) && $htmlContent !== ''): ?>
<!-- B) Frei befüllbarer HTML-Block (bewusst roh, vom Betreiber gepflegt) -->
<div class="sp-section sp-custom-html"><?= $brand['html_content'] ?></div>
<?php endif; ?>
<?php if ($startMode): ?>
<!-- Im Startseiten-Modus entfällt die Kopfzeile – Überschrift + Sprungziel hier -->
<h2 class="sp-section-title" id="status"><?= $this->t('Systemstatus') ?><?= !empty($brand['subtitle']) ? ' – ' . $e($brand['subtitle']) : '' ?></h2>
<?php endif; ?>
<?php include __DIR__ . '/_content.php'; ?>
<!-- Benachrichtigungen -->
<?php if (!empty($brand['subscribe'])): ?>
<div class="sp-section">
<h2 class="sp-section-title"><?= $this->te('Benachrichtigt werden') ?></h2>
<div class="sp-card sp-subscribe">
<p class="sp-subscribe-lead">
<?= $this->te('Wir schreiben Ihnen, sobald eine Störung beginnt oder behoben ist – sonst nie.') ?>
</p>
<!-- Ohne Sitzungs-Token: Die Seite wird zwischengespeichert und allen
Besuchern gleich ausgeliefert. Eingetragen wird eine Adresse erst
durch die Bestätigung aus ihrem Postfach. -->
<form class="sp-subscribe-form" method="POST" action="/status/subscribe">
<input type="email" name="email" class="sp-subscribe-input" required maxlength="255"
placeholder="<?= $this->te('ihre@adresse.de') ?>" aria-label="<?= $this->te('E-Mail-Adresse') ?>" autocomplete="email">
<button type="submit" class="sp-search-btn"><?= $this->te('Eintragen') ?></button>
</form>
<p class="sp-subscribe-note">
<?= $this->te('Sie erhalten zuerst ein Schreiben mit einem Bestätigungslink. Jede Nachricht enthält einen Link zum Abmelden.') ?>
</p>
</div>
</div>
<?php endif; ?>
<!-- Verlauf (zuletzt behoben) -->
<?php if (!empty($recent)): ?>
<div class="sp-section">
<h2 class="sp-section-title"><?= $this->te('Vergangene Störungen') ?></h2>
<div class="sp-card" style="padding: .25rem 1.15rem;">
<?php foreach ($recent as $inc): ?>
<div class="sp-history-item">
<span class="sp-history-title"><?= $e($inc['title']) ?></span>
<span class="sp-pill sp-pill--operational" style="margin-left:.4rem;"><?= $this->te('Behoben') ?></span>
<div class="sp-incident-meta"><?= $dt($inc['started_at']) ?> – <?= $this->te('{zeitpunkt} Uhr', ['zeitpunkt' => $dt($inc['resolved_at'])]) ?></div>
</div>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>