where('token', '[A-Za-z0-9]{40,}') ->name('press-releases.preview'); // Gemeinsame Web-Routes für alle Landingpages // Jede Landing-Page hat das gleiche Gerüst, aber unterschiedliches Styling $applyWebDomainConfig = static function (string $domainKey): array { $domainConfig = config("domains.domains.{$domainKey}", []); config([ 'app.theme' => $domainConfig['theme'] ?? $domainKey, 'app.view_prefix' => $domainConfig['view_prefix'] ?? 'web', 'app.domain_name' => $domainConfig['domain_name'] ?? request()->getHost(), 'app.url' => $domainConfig['url'] ?? config('app.url'), ]); View::share('theme', $domainConfig['theme'] ?? $domainKey); View::share('viewPrefix', $domainConfig['view_prefix'] ?? 'web'); View::share('domainName', $domainConfig['domain_name'] ?? request()->getHost()); View::share('domainConfig', $domainConfig); View::share('domainUrl', $domainConfig['url'] ?? config('app.url')); View::share('assetUrl', DomainAssetContext::staticAssetOrigin($domainConfig)); DomainAssetContext::configureVite($domainConfig); return $domainConfig; }; $webHomeData = static function (Portal $primaryPortal): array { $portalValues = [$primaryPortal->value, Portal::Both->value]; $publishedQuery = static fn (): Builder => PressRelease::query() ->whereIn('portal', $portalValues) ->where('status', PressReleaseStatus::Published) ->where('language', 'de') ->whereNotNull('published_at') ->where('published_at', '<=', now()); $with = [ 'company', 'category.translations' => fn ($query) => $query->where('locale', 'de'), 'images' => fn ($query) => $query ->orderByDesc('is_preview') ->orderBy('sort_order') ->limit(1), ]; $oldestPublishedAt = $publishedQuery() ->oldest('published_at') ->value('published_at'); $leadRelease = $publishedQuery() ->with($with) ->orderByDesc('published_at') ->first(); $sideReleases = $publishedQuery() ->with($with) ->when($leadRelease, fn (Builder $query) => $query->where('id', '!=', $leadRelease->id)) ->orderByDesc('published_at') ->limit(4) ->get(); $mostReadReleases = $publishedQuery() ->orderByDesc('hits') ->orderByDesc('published_at') ->limit(4) ->get(['id', 'slug', 'title', 'hits', 'portal', 'language']); $activeNewsrooms = Company::query() ->whereIn('portal', $portalValues) ->where('is_active', true) ->whereHas('pressReleases', function (Builder $query) use ($portalValues): void { $query ->whereIn('portal', $portalValues) ->where('status', PressReleaseStatus::Published) ->where('language', 'de') ->whereNotNull('published_at') ->where('published_at', '>=', now()->subDays(7)); }) ->withCount([ 'pressReleases as recent_releases_count' => function (Builder $query) use ($portalValues): void { $query ->whereIn('portal', $portalValues) ->where('status', PressReleaseStatus::Published) ->where('language', 'de') ->whereNotNull('published_at') ->where('published_at', '>=', now()->subDays(7)); }, 'pressReleases as today_releases_count' => function (Builder $query) use ($portalValues): void { $query ->whereIn('portal', $portalValues) ->where('status', PressReleaseStatus::Published) ->where('language', 'de') ->whereDate('published_at', today()); }, ]) ->orderByDesc('today_releases_count') ->orderByDesc('recent_releases_count') ->limit(6) ->get() ->map(fn (Company $company): array => [ 'name' => $company->name, 'slug' => $company->slug, 'initial' => mb_strtoupper(mb_substr((string) $company->name, 0, 1)), 'count' => (int) $company->recent_releases_count, 'today' => (int) $company->today_releases_count > 0, ]); $industryIndex = Category::query() ->with(['translations' => fn ($query) => $query->where('locale', 'de')]) ->withCount([ 'pressReleases as recent_count' => function (Builder $query) use ($portalValues): void { $query ->whereIn('portal', $portalValues) ->where('status', PressReleaseStatus::Published) ->where('language', 'de') ->where('published_at', '>=', now()->subDays(7)) ->whereNotNull('published_at'); }, 'pressReleases as previous_count' => function (Builder $query) use ($portalValues): void { $query ->whereIn('portal', $portalValues) ->where('status', PressReleaseStatus::Published) ->where('language', 'de') ->where('published_at', '>=', now()->subDays(14)) ->where('published_at', '<', now()->subDays(7)); }, ]) ->whereIn('portal', $portalValues) ->where('is_active', true) ->whereNull('parent_id') ->orderByDesc('recent_count') ->limit(7) ->get() ->map(function (Category $category): ?array { $translation = $category->translations->first(); if (! $translation) { return null; } return [ 'name' => $translation->name, 'href' => $translation->slug ? route('kategorie', ['slug' => $translation->slug]) : route('kategorien'), 'count' => (int) ($category->recent_count ?? 0), 'delta' => (int) ($category->recent_count ?? 0) - (int) ($category->previous_count ?? 0), ]; }) ->filter() ->values(); return [ 'leadRelease' => $leadRelease, 'sideReleases' => $sideReleases, 'mostReadReleases' => $mostReadReleases, 'activeNewsrooms' => $activeNewsrooms, 'industryIndex' => $industryIndex, 'homeStats' => [ 'publishedCount' => $publishedQuery()->count(), 'publishedToday' => $publishedQuery()->whereDate('published_at', today())->count(), 'archiveSince' => $oldestPublishedAt ? (int) Carbon::parse($oldestPublishedAt)->format('Y') : null, ], ]; }; // Hauptseite - dynamisch basierend auf Domain Route::get('/', function () use ($applyWebDomainConfig, $webHomeData) { $domain = request()->getHost(); if (str_contains($domain, 'presseecho')) { $applyWebDomainConfig('presseecho'); return view('web.presseecho', $webHomeData(Portal::Presseecho)); } elseif (str_contains($domain, 'businessportal24')) { $applyWebDomainConfig('businessportal24'); return view('web.businessportal24', $webHomeData(Portal::Businessportal24)); } elseif (str_contains($domain, 'pressekonto')) { $applyWebDomainConfig('pressekonto'); return view('web.pressekonto'); } $applyWebDomainConfig('businessportal24'); return view('web.businessportal24', $webHomeData(Portal::Businessportal24)); })->name('home'); Route::get('/variant-1', function () { $domain = request()->getHost(); // Domain-basierte View-Auswahl if (str_contains($domain, 'presseecho')) { return view('web.presseecho'); } elseif (str_contains($domain, 'businessportal24')) { return view('web.businessportal24-variant-float-glow'); } return view('web.businessportal24-variant-float-glow'); })->name('variant-1'); Route::get('/variant-2', function () { $domain = request()->getHost(); // Domain-basierte View-Auswahl if (str_contains($domain, 'presseecho')) { return view('web.presseecho'); } elseif (str_contains($domain, 'businessportal24')) { return view('web.businessportal24-variant-glass-gradient'); } }); // Preise & Leistungen Route::get('/preise', function () { return view('web.preise'); })->name('preise'); // FAQ - Häufig gestellte Fragen Route::get('/faq', function () { return view('web.faq'); })->name('faq'); // Kontakt Route::get('/kontakt', function () { return view('web.kontakt'); })->name('kontakt'); // Über uns Route::get('/ueber-uns', function () { return view('web.ueber-uns'); })->name('ueber-uns'); // Veröffentlichen Route::get('/veroeffentlichen', function () { return view('web.veroeffentlichen'); })->name('veroeffentlichen'); // Kategorien Route::get('/kategorien', function () { return view('web.kategorien'); })->name('kategorien'); // Suche Route::get('/suche', function () { return view('web.suche'); })->name('suche'); // Services Route::get('/newsrooms', function () { return view('web.newsrooms'); })->name('newsrooms'); Route::get('/api', function () { return view('web.api'); })->name('api'); Route::get('/docs/api/v1', function () { return response((string) file_get_contents(base_path('docs/api/v1.yml')), 200, [ 'Content-Type' => 'application/yaml; charset=UTF-8', ]); })->name('docs.api.v1'); // Über uns - Unterseiten Route::get('/team', function () { return view('web.team'); })->name('team'); Route::get('/partner', function () { return view('web.partner'); })->name('partner'); Route::get('/karriere', function () { return view('web.karriere'); })->name('karriere'); Route::get('/presse', function () { return view('web.presse'); })->name('presse'); // Hilfe & Support Route::get('/hilfe', function () { return view('web.hilfe'); })->name('hilfe'); // Rechtliches Route::get('/impressum', function () { return view('web.impressum'); })->name('impressum'); Route::get('/datenschutz', function () { return view('web.datenschutz'); })->name('datenschutz'); Route::get('/agb', function () { return view('web.agb'); })->name('agb'); Route::get('/cookies', function () { return view('web.cookies'); })->name('cookies'); // Kategorie Seite (z.B. IT & Software) Route::get('/kategorie/{slug}', function ($slug) { return view('web.kategorie', ['categorySlug' => $slug]); })->name('kategorie'); // Release Detail Seite Route::get('/release/{slug}', function ($slug) { return view('web.release-detail', ['releaseSlug' => $slug]); })->name('release.detail');