Display-Seiten individuell gestalten
Some checks are pending
CI / PHP Lint (push) Waiting to run
CI / PHP Lint (pull_request) Waiting to run
CI / PHP Lint-1 (pull_request) Waiting to run
CI / PHP Lint-1 (push) Waiting to run
CI / Unit Tests & Static Analysis (pull_request) Waiting to run
CI / Unit Tests & Static Analysis (push) Waiting to run

Jede Display-Seite bringt jetzt ihr eigenes Erscheinungsbild mit – der
Empfang sieht anders aus als der Tagungsraum nebenan:

- eigenes Logo (leer = Logo aus den Einstellungen)
- formatfüllendes Hintergrundbild mit einstellbarer Abdunklung (0–90 %),
  damit die Karte auf hellen Fotos lesbar bleibt
- eigene Akzentfarbe für den Knopf (leer = Farbe aus dem Design-Tab)
- Karte wahlweise hell oder dunkel; auf Fotos wirkt dunkel meist ruhiger

Logo und Hintergrund lassen sich hochladen oder als URL hinterlegen; beim
Löschen einer Display-Seite verschwinden die hochgeladenen Dateien mit.

Nebenbei aufgeräumt: das Bildfeld (Vorschau + Upload + URL + Entfernen)
lag als Funktion in admin/settings.php und wird jetzt von beiden Seiten
genutzt – Ui::imageField() für die Darstellung, Upload::resolveField()
für die Auswertung.

Sicherheit: die Akzentfarbe landet in einem style-Attribut, deshalb wird
sie sowohl beim Speichern als auch beim Ausgeben auf eine echte Hex-Farbe
geprüft; ein Test hält das fest.

Migration 0006, database.sql nachgezogen, 4 neue Tests (42 gesamt),
Screenshots ergänzt, Version 2.8.0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Friederich Loheide 2026-09-23 16:58:54 +00:00
parent 943e427150
commit 4159b92268
31 changed files with 405 additions and 82 deletions

View file

@ -87,9 +87,29 @@ if (!$notFound && $_SERVER['REQUEST_METHOD'] === 'POST') {
$headline = trim((string)($kiosk['headline'] ?? '')) ?: __('kiosk_default_headline');
$subline = trim((string)($kiosk['subline'] ?? '')) ?: __('kiosk_default_subline');
$logoUrl = $db->getSetting('logo_url', '');
$display = max(10, (int)($kiosk['display_seconds'] ?? Kiosk::DEFAULT_DISPLAY_SECONDS));
$selfUrl = $kiosk ? Kiosk::publicUrl($kiosk['token']) : '';
// Gestaltung dieser Display-Seite (eigene Werte, sonst die des Systems)
$look = $kiosk ? Kiosk::appearance($db, $kiosk) : ['logo'=>'','background'=>'','overlay'=>0.45,'accent'=>'','card'=>'light'];
$logoUrl = $look['logo'];
$bodyClass = 'kiosk-body';
$bodyStyle = '';
if ($look['background'] !== '') {
$bodyClass .= ' has-background';
$bodyStyle .= "--kiosk-bg:url('" . htmlspecialchars(Ui::mediaUrl($look['background']), ENT_QUOTES) . "');"
. '--kiosk-overlay:' . $look['overlay'] . ';';
}
if ($look['card'] === 'dark') {
$bodyClass .= ' kiosk-dark';
}
if ($look['accent'] !== '') {
// Nur die Akzentfarbe dieser Seite überschreiben der Rest bleibt Design-System.
$bodyStyle .= '--accent:' . $look['accent'] . ';'
. '--accent-hover:color-mix(in srgb, ' . $look['accent'] . ' 84%, #000);'
. '--accent-soft:color-mix(in srgb, ' . $look['accent'] . ' 14%, #fff);'
. '--accent-border:color-mix(in srgb, ' . $look['accent'] . ' 32%, #fff);';
}
?>
<!DOCTYPE html>
<html lang="<?= I18n::getLanguage() ?>">
@ -103,7 +123,7 @@ $selfUrl = $kiosk ? Kiosk::publicUrl($kiosk['token']) : '';
<?= Ui::script('assets/vendor/qrcodejs/qrcode.min.js') ?>
<?php endif; ?>
</head>
<body class="kiosk-body">
<body class="<?= $bodyClass ?>"<?= $bodyStyle !== '' ? ' style="' . $bodyStyle . '"' : '' ?>>
<?php if ($notFound): ?>
<main class="kiosk-stage">
@ -118,6 +138,9 @@ $selfUrl = $kiosk ? Kiosk::publicUrl($kiosk['token']) : '';
<?php elseif ($voucher): ?>
<main class="kiosk-stage">
<div class="kiosk-card kiosk-result">
<?php if ($logoUrl): ?>
<img class="kiosk-logo kiosk-logo-sm" src="<?= htmlspecialchars(Ui::mediaUrl($logoUrl)) ?>" alt="<?= htmlspecialchars($appTitle) ?>">
<?php endif; ?>
<p class="kiosk-eyebrow"><i class="fas fa-circle-check" aria-hidden="true"></i> <?= __('kiosk_ready') ?></p>
<div class="kiosk-code" id="voucherCode"><?= htmlspecialchars($voucher['code']) ?></div>
<div class="kiosk-meta">