Umsetzung von AP0-AP6 aus dev/2026-08-28/entwicklungsplan.md sowie der vorab gefundenen Befunde T1 und B1-B13. Befunde - CmsContentSeeder überschrieb bei jedem Lauf alle redaktionellen Inhalte; jetzt Redaktionsschutz plus gezielter Relaunch-Seeder (B1) - Magazin-CMS war nicht ans Frontend angebunden, Artikel jetzt über Slugs mit 301 von den alten numerischen URLs (B2) - Vier veröffentlichte Display-Playlists zeigten auf b2in.test und wären live nicht ladbar gewesen (B13) - Info-Tablet speicherte geleerte Öffnungszeiten nicht (T1) - /service und /portfolio lieferten seit Februar 500 (B12) Website - Startseite neu strukturiert und umgetextet, eigene Seite /marken mit Detailseite je Kernmarke, /netzwerk und Altrouten leiten dorthin - Galerie je Marke, getrennt nach realisierten Projekten und Visualisierungen; ohne gesetzte Kategorie gilt ein Bild als Entwurf - Seite /referenzen, gespeist aus den Markengalerien - Showroom-Display im 9:16-Rahmen über eine schreibgeschützte Embed-Route ohne Preview-Token - Terminanfrage-Widget auf allen Seiten, Markenauswahl aus dem CMS, WhatsApp per Klick-zum-Chat-Link mit vorbereitetem Text - FAQ, Über-uns, Kontakt und Magazin inhaltlich auf Interior umgestellt Sonstiges - Vorschau-Instanzen liefern noindex und verlinken sich bei unbekanntem Host auf sich selbst statt auf eine fremde Domain - Seeder-Zugangsdaten aus dem Code in die Konfiguration (B8) - Ablauf für die Vorschau: dev/2026-08-28/preview-deployment.md 833 Tests grün (3084 Assertions), Pint sauber. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
51 lines
2.3 KiB
PHP
51 lines
2.3 KiB
PHP
@php
|
|
if (!function_exists('renderHeroIcon')) {
|
|
function renderHeroIcon($iconName, $style = 'outline', $color = 'text-secondary')
|
|
{
|
|
$iconPath = public_path("heroicons/optimized/24/{$style}/{$iconName}.svg");
|
|
$fallbackPath = public_path('heroicons/optimized/24/outline/sparkles.svg');
|
|
|
|
if (file_exists($iconPath)) {
|
|
return str_replace('<svg', '<svg class="w-10 h-10 ' . $color . '"', file_get_contents($iconPath));
|
|
}
|
|
|
|
if (file_exists($fallbackPath)) {
|
|
return str_replace('<svg', '<svg class="w-10 h-10 ' . $color . '"', file_get_contents($fallbackPath));
|
|
}
|
|
|
|
return '';
|
|
}
|
|
}
|
|
@endphp
|
|
|
|
<section class="section-padding {{ $bg }}" id="wege">
|
|
<div class="container-padding">
|
|
<div class="text-center mb-16 slide-up delay-300">
|
|
<h2 class="text-section-title">{!! $content['title'] ?? '' !!}</h2>
|
|
@if (!empty($content['subtitle']))
|
|
<p class="text-large text-muted-foreground mt-4 max-w-2xl mx-auto">{{ $content['subtitle'] }}</p>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="grid md:grid-cols-2 gap-8 lg:gap-12 slide-up delay-400">
|
|
@foreach ($content['cards'] ?? [] as $index => $card)
|
|
<div class="card-elevated rounded-2xl p-8 flex flex-col" wire:key="audience-card-{{ $index }}">
|
|
<div class="w-20 h-20 icon-secondary-linear glow-soft rounded-2xl flex items-center justify-center mb-6">
|
|
{!! renderHeroIcon($card['icon'] ?? 'home', 'outline', 'text-secondary-foreground') !!}
|
|
</div>
|
|
|
|
<h3 class="text-xl font-medium mb-3">{{ $card['title'] ?? '' }}</h3>
|
|
<p class="text-muted-foreground leading-relaxed grow">{!! $card['description'] ?? '' !!}</p>
|
|
|
|
@if (!empty($card['button_text']))
|
|
<div class="pt-6">
|
|
<a href="{{ $card['button_link'] ?? '/contact' }}" class="btn-primary-accent px-6 py-3 inline-block">
|
|
{{ $card['button_text'] }}
|
|
</a>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
</section>
|