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

@ -143,6 +143,56 @@ class KioskTest extends TestCase
$this->assertSame(0, $settings['qos']['down']);
}
public function testAppearanceFallsBackToSystemLogo(): void
{
$db = new FakeKioskDb(['logo_url' => 'uploads/global.png']);
$look = \Kiosk::appearance($db, $this->kiosk());
$this->assertSame('uploads/global.png', $look['logo']);
$this->assertSame('', $look['background']);
$this->assertSame('', $look['accent'], 'Ohne eigene Farbe bleibt das Design-System zuständig');
$this->assertSame('light', $look['card']);
}
public function testAppearanceUsesOwnValues(): void
{
$db = new FakeKioskDb(['logo_url' => 'uploads/global.png']);
$kiosk = $this->kiosk([
'logo_url' => 'uploads/hotel.svg',
'background_url' => 'uploads/lobby.jpg',
'bg_overlay' => 60,
'accent_color' => '#0F766E',
'card_style' => 'dark',
]);
$look = \Kiosk::appearance($db, $kiosk);
$this->assertSame('uploads/hotel.svg', $look['logo']);
$this->assertSame('uploads/lobby.jpg', $look['background']);
$this->assertSame(0.6, $look['overlay']);
$this->assertSame('#0f766e', $look['accent']);
$this->assertSame('dark', $look['card']);
}
public function testAppearanceRejectsUnsafeColour(): void
{
$db = new FakeKioskDb();
// Der Wert landet in einem style-Attribut nur echte Hex-Farben durch.
$look = \Kiosk::appearance($db, $this->kiosk(['accent_color' => 'red;background:url(evil)']));
$this->assertSame('', $look['accent']);
}
public function testAppearanceClampsOverlay(): void
{
$db = new FakeKioskDb();
$this->assertSame(0.9, \Kiosk::appearance($db, $this->kiosk(['bg_overlay' => 250]))['overlay']);
$this->assertSame(0.0, \Kiosk::appearance($db, $this->kiosk(['bg_overlay' => -10]))['overlay']);
}
public function testPublicUrl(): void
{
$token = \Kiosk::newToken();