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>
251 lines
9.5 KiB
PHP
251 lines
9.5 KiB
PHP
<?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';
|