Startseite und Heroes - Hero-Slideshow (11 Motive inkl. Febrü) mit Infokarte, Laufzeit-Linie, größeren Klickflächen, Goldrahmen und mobiler Karte unter dem Bild; Zeile über der Überschrift, neue Vertrauenspunkte - Hero-Stil auf Marken, Über uns und Kontakt übertragen, Breadcrumb entfernt - Gründer-Leiste, Vision-Box auf Ocker, Showroom-Display in Box mit „Größer ansehen“/Vollbild - Akzentfarbe #a8741f, größere Serif-Überschriften in der Interior-Welt - Marken: Bildpause mit Zitat; Vereine aktualisiert und verlinkt Inhalte - Lektorat aller angezeigten Texte, /about-Korrekturen, Rechtstexte (DDG, TDDDG, Hosting Hetzner) - Ablauf Maßanfertigung überall einheitlich, Magazin-Beitrag neu, alte Beiträge offline, deutsches Datum/Lesezeit, FAQ Projektausstattung, Otterpohl - Referenzen-Seite per CMS-Schalter ausblendbar CMS und Technik - Tote Sektionen, Felder, Seiten und Komponenten entfernt und archiviert (dev/2026-08-28/archiv-*) - Entwurf /entwurf, Farb-Schalter und /welcome entfernt; Test-Routen nur noch lokal - Seitenbaum-Beschreibungen geprüft, fehlende CMS-Felder ergänzt, Markenliste aus „Kernmarken“ - Admin-Bildvorschauen repariert, verwendete Bilder in die Mediathek übernommen - Seeder für das Deployment siehe dev/2026-08-28/entwicklungsplan.md Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
90 lines
3 KiB
PHP
90 lines
3 KiB
PHP
<?php
|
||
|
||
namespace App\Livewire\Web\Components\Sections;
|
||
|
||
use Livewire\Component;
|
||
|
||
/**
|
||
* Hero der Startseite: Text links, rechts eine ruhige Slideshow als Hauptelement des Rahmens
|
||
* (Abstimmung 07.10.2026, Vorbild dev/2026-08-28/Farbwelt und Stil.png).
|
||
*
|
||
* Die Bilder kommen aus der Liste `slides` der Sektion `home/hero` (je `image`, `label`, `caption`,
|
||
* `alt`, `active`) und laufen in dieser Reihenfolge. Die Infokarte über dem Bild zeigt je Slide
|
||
* Marke (`label`) und Motiv (`caption`), ohne Angaben die festen Texte `card_title`/`card_text`.
|
||
* Ist die Liste leer oder alles deaktiviert, steht das einzelne Bild `image` da wie früher.
|
||
*/
|
||
class Hero extends Component
|
||
{
|
||
/** @var array<string, mixed> */
|
||
public array $content = [];
|
||
|
||
/** @var array<int, array{image: string, alt: string, label: string, caption: string}> */
|
||
public array $slides = [];
|
||
|
||
public function mount(): void
|
||
{
|
||
$section = cms_theme_section('hero');
|
||
$this->content = is_array($section) ? $section : [];
|
||
$this->slides = self::activeSlides($this->content['slides'] ?? []) ?: $this->singleImage();
|
||
}
|
||
|
||
/**
|
||
* Gepflegte Slides ohne Bild oder mit `active` = aus fallen weg.
|
||
*
|
||
* @return array<int, array{image: string, alt: string, label: string, caption: string}>
|
||
*/
|
||
public static function activeSlides(mixed $list): array
|
||
{
|
||
$slides = [];
|
||
|
||
foreach ((array) $list as $slide) {
|
||
if (! is_array($slide) || trim((string) ($slide['image'] ?? '')) === '') {
|
||
continue;
|
||
}
|
||
|
||
if (array_key_exists('active', $slide) && ! filter_var($slide['active'], FILTER_VALIDATE_BOOLEAN)) {
|
||
continue;
|
||
}
|
||
|
||
$label = trim((string) ($slide['label'] ?? $slide['title'] ?? ''));
|
||
$caption = trim((string) ($slide['caption'] ?? ''));
|
||
|
||
$slides[] = [
|
||
'image' => (string) $slide['image'],
|
||
'alt' => trim((string) ($slide['alt'] ?? '')) ?: implode(' – ', array_filter([$label, $caption])),
|
||
'label' => $label,
|
||
'caption' => $caption,
|
||
];
|
||
}
|
||
|
||
return $slides;
|
||
}
|
||
|
||
/**
|
||
* @return array<int, array{image: string, alt: string, label: string, caption: string}>
|
||
*/
|
||
private function singleImage(): array
|
||
{
|
||
$image = trim((string) ($this->content['image'] ?? ''));
|
||
|
||
return $image === '' ? [] : [[
|
||
'image' => $image,
|
||
'alt' => (string) ($this->content['image_alt'] ?? ''),
|
||
'label' => '',
|
||
'caption' => '',
|
||
]];
|
||
}
|
||
|
||
/** Wechsel alle `interval` Sekunden, begrenzt auf 3–30 s (Standard 7 s). */
|
||
public function getIntervalMsProperty(): int
|
||
{
|
||
$seconds = (float) ($this->content['interval'] ?? 7);
|
||
|
||
return (int) round(max(3, min(30, $seconds)) * 1000);
|
||
}
|
||
|
||
public function render(): \Illuminate\View\View
|
||
{
|
||
return view('livewire.web.components.sections.hero');
|
||
}
|
||
}
|