Web-Frontend: Umbau Spokes/Hub, Kontakt-Widget (contact-launcher)
Startseiten/Feeds/Kategorie/Rechtsseiten ueberarbeitet, Kontakt-Modal durch schwebendes contact-launcher-Widget ersetzt, legal-language-notice ergaenzt; Platzhalter-SVGs + Theme-CSS angepasst. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
fd8e050cb7
commit
d1939f6f2a
39 changed files with 1110 additions and 810 deletions
|
|
@ -33,15 +33,20 @@
|
|||
$readTime = max(1, (int) round($wordCount / 200));
|
||||
|
||||
$teaser = (string) Str::of(strip_tags((string) $release->text))->squish()->limit(180);
|
||||
$lead = filled($release->subtitle)
|
||||
? $release->subtitle
|
||||
: $teaser;
|
||||
|
||||
// Subline nur bei explizit gesetztem Untertitel — kein Fallback auf den Textanfang,
|
||||
// sonst erscheint der erste Absatz doppelt. Der Teaser dient nur der Meta-Description.
|
||||
$lead = $release->subtitle;
|
||||
|
||||
$image = $release->images->first();
|
||||
$imageUrl = $image?->variantUrl('detail') ?? $image?->variantUrl('card') ?? $image?->url();
|
||||
$imageCaption = $image?->description ?: $image?->title;
|
||||
$imageCredit = $image?->copyright ?: $image?->author;
|
||||
|
||||
// Ohne Pressefoto: die im User-Panel gewählte Platzhalter-Variante.
|
||||
// Null bei Altbeständen ohne Variante — dann generischer Hero-Fallback.
|
||||
$placeholderUrl = $imageUrl ? null : $release->chosenPlaceholderUrl();
|
||||
|
||||
$companyName = $company?->name;
|
||||
$companyInitial = $companyName ? mb_strtoupper(mb_substr($companyName, 0, 1)) : '·';
|
||||
$companyHref = $company?->slug ? route('newsroom', ['slug' => $company->slug]) : route('newsrooms');
|
||||
|
|
@ -75,7 +80,7 @@
|
|||
@endphp
|
||||
|
||||
@section('title', $release->title.' – '.$brandLabel)
|
||||
@section('meta_description', $lead)
|
||||
@section('meta_description', filled($lead) ? $lead : $teaser)
|
||||
@section('og_type', 'article')
|
||||
@if ($imageUrl)
|
||||
@section('og_image', $imageUrl)
|
||||
|
|
@ -154,6 +159,83 @@
|
|||
</nav>
|
||||
</div>
|
||||
|
||||
@if (! $imageUrl)
|
||||
{{-- Ohne Pressefoto: Headline direkt in der Platzhalter-Fläche der PM
|
||||
(gewählte Variante wie im User-Panel, sonst generischer Fallback). --}}
|
||||
<section class="max-w-layout mx-auto px-4 sm:px-6 lg:px-8 pt-[18px]">
|
||||
<article class="relative overflow-hidden bg-hero-grad">
|
||||
@if ($placeholderUrl)
|
||||
<img src="{{ $placeholderUrl }}" alt="" aria-hidden="true"
|
||||
class="absolute inset-0 h-full w-full object-cover" loading="eager">
|
||||
@else
|
||||
<x-web.hero-fallback />
|
||||
@endif
|
||||
|
||||
@if ($embargoAt)
|
||||
<div class="absolute top-5 left-5 sm:top-6 sm:left-9 flex items-center gap-2.5 flex-wrap">
|
||||
<span class="text-[9.5px] font-bold tracking-[0.18em] uppercase text-white px-2.5 py-[3px] border border-white/50 font-mono bg-black/25">
|
||||
● {{ __('web.detail.embargo_lifted') }}
|
||||
</span>
|
||||
<span class="text-[11px] text-white/70 font-mono">{{ $embargoAt->translatedFormat('j. F Y, H:i') }}</span>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="relative px-5 sm:px-9 pt-[110px] sm:pt-[150px] pb-7 sm:pb-9"
|
||||
style="background:linear-gradient(180deg,transparent,rgba(0,0,0,0.55) 55%,rgba(0,0,0,0.82));">
|
||||
<div class="flex items-center gap-3.5 mb-4 flex-wrap">
|
||||
@if ($categoryName)
|
||||
<a href="{{ $categoryHref }}" class="bp-cat cursor-pointer transition-colors" style="color:#FF8B6F;">{{ $categoryName }}</a>
|
||||
<span class="w-1 h-1 rounded-full bg-white/40" aria-hidden="true"></span>
|
||||
@endif
|
||||
<span class="text-[11px] text-white/60 italic font-serif">{{ __('web.detail.audience') }}</span>
|
||||
</div>
|
||||
|
||||
<h1 class="font-serif text-[30px] sm:text-[38px] lg:text-[44px] font-semibold m-0 tracking-[-0.8px] leading-[1.1] max-w-[920px] text-white" style="text-wrap:balance;">
|
||||
{{ $release->title }}
|
||||
</h1>
|
||||
|
||||
@if (filled($lead))
|
||||
<p class="font-serif text-[16.5px] sm:text-[19px] leading-[1.45] m-0 mt-5 text-white/85 max-w-[820px] font-normal" style="text-wrap:pretty;">
|
||||
{{ $lead }}
|
||||
</p>
|
||||
@endif
|
||||
|
||||
<div class="flex flex-wrap items-center text-[12.5px] text-white/75 mt-6" style="gap:10px 22px;">
|
||||
@if ($companyName)
|
||||
<span class="inline-flex items-center gap-2">
|
||||
<span class="w-7 h-7 bg-white text-ink inline-flex items-center justify-center text-[13px] font-bold font-serif">{{ $companyInitial }}</span>
|
||||
<span class="font-semibold text-white">{{ $companyName }}</span>
|
||||
</span>
|
||||
<span class="w-px h-[14px] bg-white/25" aria-hidden="true"></span>
|
||||
@endif
|
||||
@if ($publishedAt)
|
||||
<time datetime="{{ $publishedAt->toIso8601String() }}" class="font-mono text-[11.5px] text-white/65">
|
||||
{{ $publishedAt->translatedFormat('j. F Y') }} · {{ __('web.detail.time_at', ['time' => $publishedAt->format('H:i')]) }}
|
||||
</time>
|
||||
@endif
|
||||
<span class="font-mono text-[11.5px] text-white/65">{{ __('web.shared.read_time', ['minutes' => $readTime]) }} · {{ __('web.detail.words', ['count' => number_format($wordCount, 0, ',', '.')]) }}</span>
|
||||
@if ($companyCountry)
|
||||
<span class="inline-flex items-center gap-1.5 font-mono text-[11.5px] text-white/65">
|
||||
<svg width="11" height="11" viewBox="0 0 14 14" fill="none" aria-hidden="true"><path d="M7 1a5 5 0 015 5c0 4-5 7-5 7s-5-3-5-7a5 5 0 015-5z" stroke="currentColor" stroke-width="1.3" fill="none" /><circle cx="7" cy="6" r="1.5" fill="currentColor" /></svg>
|
||||
{{ $companyCountry }}
|
||||
</span>
|
||||
@endif
|
||||
|
||||
@if ($isRecommended)
|
||||
<span class="inline-flex items-center gap-1.5 px-2 py-[3px] text-[9.5px] font-bold tracking-[0.14em] uppercase text-white border border-white/40 font-mono cursor-help"
|
||||
title="{{ __('web.detail.recommended_hint') }}">
|
||||
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
||||
<path d="M12 2l9 4v6c0 5-3.5 9-9 10-5.5-1-9-5-9-10V6z" stroke="currentColor" stroke-width="2" fill="none" />
|
||||
<path d="M8 12l3 3 5-6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
{{ __('web.detail.recommended') }}
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</section>
|
||||
@else
|
||||
{{-- Hero Meta Block --}}
|
||||
<section class="max-w-layout mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="pt-[18px] pb-8 border-b border-bg-rule">
|
||||
|
|
@ -221,15 +303,9 @@
|
|||
|
||||
{{-- Hero Image --}}
|
||||
<section class="max-w-layout mx-auto px-4 sm:px-6 lg:px-8 pt-8">
|
||||
<div class="relative flex items-end p-[18px] bg-bg-dark hatch-dark overflow-hidden" style="aspect-ratio:21/9;">
|
||||
@if ($imageUrl)
|
||||
<img src="{{ $imageUrl }}" alt="{{ $imageCaption ?: $release->title }}"
|
||||
class="absolute inset-0 h-full w-full object-cover" loading="eager">
|
||||
@else
|
||||
<span class="relative text-[10px] font-mono tracking-wider uppercase text-white/50">
|
||||
{{ $companyName ? __('web.detail.image_placeholder_company', ['company' => $companyName]) : __('web.detail.image_placeholder') }} (16:9)
|
||||
</span>
|
||||
@endif
|
||||
<div class="relative flex items-end p-[18px] bg-bg-dark overflow-hidden" style="aspect-ratio:21/9;">
|
||||
<img src="{{ $imageUrl }}" alt="{{ $imageCaption ?: $release->title }}"
|
||||
class="absolute inset-0 h-full w-full object-cover" loading="eager">
|
||||
</div>
|
||||
@if ($imageCaption || $imageCredit)
|
||||
<div class="text-[11.5px] text-ink-3 mt-2.5 italic max-w-[720px]">
|
||||
|
|
@ -237,6 +313,7 @@
|
|||
</div>
|
||||
@endif
|
||||
</section>
|
||||
@endif
|
||||
|
||||
{{-- Body + Sidebar --}}
|
||||
<section class="max-w-layout mx-auto px-4 sm:px-6 lg:px-8 pt-10 grid grid-cols-1 lg:grid-cols-[1fr_280px] gap-10 lg:gap-14">
|
||||
|
|
@ -331,6 +408,20 @@
|
|||
</a>
|
||||
<span class="text-ink-4">{{ __('web.detail.reports_free') }}</span>
|
||||
</div>
|
||||
|
||||
{{-- Magic-Link-Hinweis: hinterlegte Firmen-/Pressekontakte verwalten
|
||||
ihre Mitteilung über den passwortlosen Anmeldelink im pressekonto. --}}
|
||||
@php
|
||||
$portalUrl = rtrim(config('domains.domain_portal_url', config('app.url')), '/');
|
||||
@endphp
|
||||
<div class="mt-3 flex flex-wrap items-center gap-x-4 gap-y-1.5 text-[11.5px] text-ink-3">
|
||||
<span>{{ __('web.detail.manage_question') }}</span>
|
||||
<a href="{{ $portalUrl }}/anmeldelink" class="inline-flex items-center gap-1.5 text-ink-2 underline underline-offset-2 hover:text-ink transition-colors">
|
||||
<svg width="12" height="12" viewBox="0 0 14 14" class="flex-shrink-0" aria-hidden="true"><path d="M1 3h12v8H1zM1 3l6 4 6-4" stroke="currentColor" stroke-width="1.3" fill="none" /></svg>
|
||||
{{ __('web.detail.manage_link') }}
|
||||
</a>
|
||||
<span class="text-ink-4">{{ __('web.detail.manage_hint') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Sidebar --}}
|
||||
|
|
@ -433,10 +524,14 @@
|
|||
</aside>
|
||||
</section>
|
||||
|
||||
{{-- Empfehlungen --}}
|
||||
{{-- Empfehlungen: zweispaltig nur, wenn beide Listen gefüllt sind —
|
||||
eine einzelne Liste nutzt sonst die volle Layout-Breite. --}}
|
||||
@if ($companyReleases->isNotEmpty() || $relatedReleases->isNotEmpty())
|
||||
<section class="max-w-layout mx-auto px-4 sm:px-6 lg:px-8 mt-14">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-10">
|
||||
<div @class([
|
||||
'grid grid-cols-1 gap-10',
|
||||
'md:grid-cols-2' => $companyReleases->isNotEmpty() && $relatedReleases->isNotEmpty(),
|
||||
])>
|
||||
@if ($companyReleases->isNotEmpty())
|
||||
<div>
|
||||
<h3 class="font-serif text-[20px] font-semibold m-0 mb-1 tracking-[-0.2px]">{{ __('web.detail.more_from', ['company' => $companyName]) }}</h3>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue