b2in/routes/web.php
Kevin Adametz fcb10be120 Interior-Feinschliff: Hero-Slideshow, Lektorat, Rechtstexte, Aufräumen und Korrekturen 08.10.
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>
2026-10-08 14:00:15 +00:00

251 lines
9.5 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
use App\Livewire\Cabinet\QuickStatus;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Livewire\Volt\Volt;
// Gemeinsame Web-Routes für alle Pages)
// Jede Landing-Page hat das gleiche Gerüst, aber unterschiedliches Styling
// Hauptseite - lädt automatisch das richtige Theme basierend auf der Domain
Route::get('/', function () {
$theme = config('app.theme', 'b2in');
// Use theme-specific view if it exists (e.g., web.b2a, web.stileigentum)
if ($theme === 'b2in') {
return view('web.home');
}
if (view()->exists('web.'.$theme)) {
return view('web.'.$theme);
}
// Fallback to the default home view
return view('web.home');
})->name('home');
// Weitere gemeinsame Webseiten hier...
Route::get('/about', function () {
return view('web.about');
})->name('about');
Route::get('/ecosystem', function () {
return redirect('/partner', 301);
})->name('ecosystem');
$loadAziziContent = fn (): array => json_decode(
file_get_contents(resource_path('lang/de/immobilien-azizi.json')),
true,
512,
JSON_THROW_ON_ERROR,
);
$isAziziSourcePreview = function (Request $request): bool {
if (! $request->query->has('dev')) {
return false;
}
return ! in_array(strtolower((string) $request->query('dev')), ['0', 'false', 'off', 'no'], true);
};
Route::get('/immobilien', function (Request $request) use ($isAziziSourcePreview, $loadAziziContent) {
$content = $loadAziziContent();
$dev = $isAziziSourcePreview($request);
$devQuery = $dev;
$overviewRouteName = 'immobilien';
$detailRouteName = 'immobilien.show';
return view('web.dev.immobilien-azizi', compact('content', 'dev', 'devQuery', 'overviewRouteName', 'detailRouteName'));
})->name('immobilien');
// Immobilien-Welt: eigenes Magazin, eigene Über-uns-Seite und eigene FAQ. Muessen vor der
// Projekt-Detailroute stehen, sonst wuerde diese die Pfade als Projekt-Slug lesen.
Route::get('/immobilien/magazin', function () {
return view('web.magazin', ['world' => 'immobilien']);
})->name('immobilien.magazin');
Route::get('/immobilien/ueber-b2in', function () {
return view('web.immobilien-about');
})->name('immobilien.about');
Route::get('/immobilien/faq', function () {
return view('web.faq', ['section' => 'faq_immobilien']);
})->name('immobilien.faq');
Route::get('/immobilien/kontakt', function () {
return view('web.contact', ['world' => 'immobilien']);
})->name('immobilien.contact');
Route::get('/immobilien/{slug}', function (Request $request, string $slug) use ($isAziziSourcePreview, $loadAziziContent) {
$content = $loadAziziContent();
$dev = $isAziziSourcePreview($request);
$devQuery = $dev;
$overviewRouteName = 'immobilien';
$project = collect($content['projects'] ?? [])->firstWhere('slug', $slug);
abort_unless($project, 404);
return view('web.dev.immobilien-azizi-show', compact('content', 'project', 'dev', 'devQuery', 'overviewRouteName'));
})->name('immobilien.show');
// Die Netzwerk-Seite geht im Abschnitt "Mehr als Marken: unser Netzwerk" auf /marken auf.
// Alte Links und Rankings laufen per 301 dorthin; die View liegt seit 06.10.2026 in
// dev/2026-08-28/archiv-2026-10-06/.
Route::get('/netzwerk', function () {
return redirect('/marken', 301);
})->name('netzwerk');
Route::get('/interior', function () {
return redirect('/marken', 301);
})->name('interior');
Route::get('/partner', function () {
return redirect('/marken', 301);
})->name('partner');
Route::get('/magazin', function () {
return view('web.magazin');
})->name('magazin');
// Alte numerische Magazin-URLs (/magazin/1 … /magazin/5) dauerhaft auf den Slug umleiten.
// Muss vor der Slug-Route stehen, sonst wuerde diese die Ziffern selbst schlucken.
Route::get('/magazin/{id}', function (string $id) {
$slug = \App\Models\CmsArticle::slugForLegacyId($id);
abort_unless($slug !== null, 404);
return redirect()->route('magazin.detail', ['slug' => $slug], 301);
})->whereNumber('id')->name('magazin.detail.legacy');
Route::get('/magazin/{slug}', function (string $slug) {
// Die Detailseite rendert in der Welt ihres Beitrags (Dubai-Themen bleiben blau). Die Welt
// muss vor dem Rendern feststehen, weil Kopf- und Fusszeile sie in mount() festhalten.
$article = \App\Models\CmsArticle::forFrontend()[$slug] ?? null;
abort_unless($article !== null, 404);
b2in_world_set($article['world'] ?? 'interior');
return view('web.magazin-detail', compact('slug'));
})->name('magazin.detail');
// Kernmarken: Uebersichtsseite und Detailseite je Marke.
Route::get('/marken', function () {
return view('web.marken');
})->name('marken');
Route::get('/marken/{slug}', function (string $slug) {
$brands = \App\Models\CmsBrand::forFrontend();
abort_unless(isset($brands[$slug]), 404);
$brand = $brands[$slug];
$brandTitle = $brand['name'].' – '.$brand['tagline'].' | B2in Interior';
$brandDescription = trim(strip_tags((string) $brand['teaser']));
return view('web.marken-show', compact('slug', 'brandTitle', 'brandDescription'));
})->name('marken.show');
// Referenzen: realisierte Projekte aus den Markengalerien plus der Showroom-Feed.
// Lässt sich im CMS-Modul „Referenzen“ ausblenden – dann 404 und kein Menüpunkt.
Route::get('/referenzen', function () {
abort_unless(references_page_enabled(), 404);
return view('web.referenzen');
})->name('referenzen');
// Schreibgeschuetzte Einbettung eines Displays (nur veroeffentlichte Playlists, kein Token).
Route::get('/embed/display/{display}', [\App\Http\Controllers\DisplayEmbedController::class, 'show'])
->name('display.embed');
Route::get('/contact', function () {
return view('web.contact');
})->name('contact');
// Verwaiste Seiten: ihre Content-Sektionen (hero_image, content_section_left/right, portfolio)
// existieren in keiner Lang-Datei mehr und die Seiten liefern seitdem 500. Sie werden wie die
// anderen stillgelegten Seiten dauerhaft umgeleitet; die Views liegen in dev/2026-08-28/archiv-2026-10-06/.
Route::get('/service', function () {
return redirect('/marken', 301);
})->name('service');
Route::get('/portfolio', function () {
return redirect('/immobilien', 301);
})->name('portfolio');
Route::get('/faq', function () {
return view('web.faq');
})->name('faq');
// Rechtliche Seiten
Route::get('/impressum', function () {
return view('web.impressum');
})->name('impressum');
Route::get('/privacy', function () {
return view('web.privacy');
})->name('privacy');
Route::get('/terms', function () {
return view('web.terms');
})->name('terms');
Route::get('/cookie-policy', function () {
return view('web.cookie-policy');
})->name('cookie-policy');
// Theme Demo Route
Route::get('/theme-demo', function () {
return view('web.theme-demo');
})->name('theme-demo');
// Dev: Sitemap und Quellvorschau der Immobilien-Seite
Route::prefix('dev')->group(function () use ($loadAziziContent) {
Route::get('/sitemap', fn () => view('web.dev.sitemap'))->name('dev.sitemap');
Route::get('/immobilien-azizi', function () use ($loadAziziContent) {
$content = $loadAziziContent();
$dev = true;
$devQuery = false;
$overviewRouteName = 'dev.immobilien-azizi';
$detailRouteName = 'dev.immobilien-azizi.show';
return view('web.dev.immobilien-azizi', compact('content', 'dev', 'devQuery', 'overviewRouteName', 'detailRouteName'));
})->name('dev.immobilien-azizi');
Route::get('/immobilien-azizi/{slug}', function (string $slug) use ($loadAziziContent) {
$content = $loadAziziContent();
$project = collect($content['projects'] ?? [])->firstWhere('slug', $slug);
abort_unless($project, 404);
$dev = true;
$devQuery = false;
$overviewRouteName = 'dev.immobilien-azizi';
return view('web.dev.immobilien-azizi-show', compact('content', 'project', 'dev', 'devQuery', 'overviewRouteName'));
})->name('dev.immobilien-azizi.show');
});
// Pfad-basierte Theme-Routen für lokale Entwicklung wurden entfernt
// Die Themensauswahl wird nun über den ThemeServiceProvider gesteuert (Domain oder ?theme=... GET-Parameter)
Route::get('/partner/invitation/expired/{token}', function (string $token) {
$invitation = \App\Models\PartnerInvitation::with('role')->where('token', $token)->firstOrFail();
return view('partner.invitation-expired', compact('invitation'));
})->name('partner.invitation.expired');
Route::get('/partner/invitation/used/{token}', function (string $token) {
$invitation = \App\Models\PartnerInvitation::with('role')->where('token', $token)->firstOrFail();
return view('partner.invitation-used', compact('invitation'));
})->name('partner.invitation.used');
Volt::route('/partner/invitation/{token}', 'partner.invitation-accept')
->name('partner.invitation.accept');
Volt::route('/partner/create-account', 'partner.create-account')
->name('partner.create.account');
// Öffentliche Registrierung per QR-/Code (Landing, code-check)
Volt::route('/reg/{role}', 'reg.landing')
->name('registration.landing');
Volt::route('/registration/thank-you', 'reg.thank-you')
->name('registration.thank-you');
// Partner Setup Wizard & Daten
Route::middleware('auth')->group(function () {
Volt::route('/partner/setup', 'partner.setup-wizard')
->name('partner.setup.wizard');
});
// Cabinet Quick-Status – key-geschützte Mini-App für schnellen Statuswechsel
Route::get('/info/status', QuickStatus::class)->name('cabinet.quick-status');
// Authentifizierungs-Routen werden in domains.php eingebunden
// require __DIR__ . '/auth.php';