presseportale/resources/views/components/web/site-header.blade.php
Kevin Adametz 0a3e52d603 19-05-2026 Rebrand Pressekonto, Hub-Flux UI und Legacy-Media-Migration
Umbenennung presseportale → pressekonto in Domains, Themes und Dokumentation.
Design-Tokens, Portal-Shell, Customer-Dashboard, Auth- und Admin-PM-Views.
Artisan-Befehl migrate:legacy-media mit Tests und Hub-Flux-Entwicklungsdocs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-19 16:36:13 +00:00

312 lines
19 KiB
PHP

@props([
'activeRegion' => 'DE',
'language' => 'Deutsch',
'languageShort' => 'DE',
'navigation' => null,
'ticker' => [],
'marketIndex' => null,
'asideSlides' => null,
'brand' => null,
])
@php
$themeKey = config('app.theme');
$brand = $brand ?? config('domains.domains.'.$themeKey.'.brand', [
'name' => 'businessportal',
'accent' => '24',
'tagline_short' => 'Pressemitteilungen · DACH',
]);
$brandName = $brand['name'] ?? 'businessportal';
$brandAccent = $brand['accent'] ?? '';
$brandTagline = $brand['tagline_short'] ?? 'Pressemitteilungen · DACH';
@endphp
@php
\Carbon\Carbon::setLocale('de');
$today = now();
$regions = [
['code' => 'DE', 'flag' => '🇩🇪'],
['code' => 'AT', 'flag' => '🇦🇹'],
['code' => 'CH', 'flag' => '🇨🇭'],
['code' => 'EN', 'flag' => '🌐'],
];
$navigation ??= [
['label' => 'Startseite', 'href' => route('home'), 'active' => true],
['label' => 'Wirtschaft', 'href' => route('kategorien')],
['label' => 'Technologie', 'href' => route('kategorien')],
['label' => 'Finanzen', 'href' => route('kategorien')],
['label' => 'Industrie', 'href' => route('kategorien')],
['label' => 'Energie', 'href' => route('kategorien')],
['label' => 'Gesundheit', 'href' => route('kategorien')],
['label' => 'Handel', 'href' => route('kategorien')],
['label' => 'Immobilien', 'href' => route('kategorien')],
['label' => 'Mobilität', 'href' => route('kategorien')],
['label' => 'Alle Rubriken', 'href' => route('kategorien')],
];
$activeLabel = collect($navigation)->firstWhere('active', true)['label'] ?? 'Menü';
@endphp
<header>
{{-- Top Utility Bar (dunkel) --}}
<div id="topbar" class="bg-topbar-grad text-ink-on-dark-2 border-b border-black">
<div class="max-w-layout mx-auto px-4 sm:px-6 lg:px-8 flex items-stretch text-[11.5px] tracking-wide">
<span class="flex items-center pr-3 sm:pr-4 py-2 whitespace-nowrap border-r border-ink-on-dark-rule text-[10.5px] sm:text-[11.5px]">
<span class="hidden sm:inline">{{ ucfirst($today->isoFormat('dd, D. MMMM YYYY')) }}</span>
<span class="sm:hidden">{{ ucfirst($today->isoFormat('dd, D. MMM')) }}</span>
</span>
<span class="hidden md:flex items-center px-3.5 text-[9.5px] uppercase font-semibold tracking-[0.16em] text-ink-3 whitespace-nowrap">
Ausgabe
</span>
@foreach ($regions as $region)
<button type="button"
class="flex items-center gap-1 sm:gap-1.5 px-1.5 sm:px-2.5 py-2 text-[11px] sm:text-[11.5px] whitespace-nowrap -mb-px border-b-2 cursor-pointer transition-colors
@if ($region['code'] === $activeRegion) font-semibold text-ink-on-dark bg-white/[0.06] border-brand
@else font-medium text-ink-on-dark-2 border-transparent hover:text-ink-on-dark hover:bg-white/[0.04] @endif"
aria-label="Region {{ $region['code'] }}"
aria-pressed="{{ $region['code'] === $activeRegion ? 'true' : 'false' }}">
<span class="text-[11px] sm:text-[12px] leading-none">{{ $region['flag'] }}</span>
<span>{{ $region['code'] }}</span>
</button>
@endforeach
<span class="flex-1"></span>
{{-- Sprache: mobil verkürzt; ab lg mit Newsletter/RSS/API --}}
<span class="flex items-center gap-3 sm:gap-4 py-2 whitespace-nowrap">
<span class="inline-flex items-center gap-1.5">
<svg width="11" height="11" viewBox="0 0 12 12" fill="none" class="opacity-60" aria-hidden="true">
<circle cx="6" cy="6" r="5" stroke="currentColor" stroke-width="1" />
<path d="M1 6h10M6 1c2 1.5 2 8.5 0 10M6 1c-2 1.5-2 8.5 0 10" stroke="currentColor" stroke-width="1" fill="none" />
</svg>
<strong class="text-ink-on-dark font-semibold">
<span class="hidden lg:inline">{{ $language }}</span>
<span class="lg:hidden">{{ $languageShort }}</span>
</strong>
</span>
<span class="hidden lg:inline-block w-px h-[14px] bg-ink-on-dark-rule"></span>
<a href="#newsletter" class="hidden lg:inline cursor-pointer hover:text-ink-on-dark transition-colors">Newsletter</a>
<a href="#rss" class="hidden lg:inline cursor-pointer hover:text-ink-on-dark transition-colors">RSS</a>
<a href="{{ route('api') }}" class="hidden lg:inline cursor-pointer hover:text-ink-on-dark transition-colors">API</a>
</span>
</div>
</div>
{{-- Header (Logo + Suche + Buttons + Burger) --}}
<div id="header" class="header-normal bg-bg border-b border-bg-rule"
x-data="{ searchOpen: false }"
@keydown.escape.window="searchOpen = false">
<div class="max-w-layout mx-auto px-4 sm:px-6 lg:px-8 py-3 lg:py-[18px] flex items-center gap-3 sm:gap-4 lg:gap-6">
<a href="{{ route('home') }}" class="block cursor-pointer group flex-shrink-0" aria-label="{{ $brandName }}{{ $brandAccent }} Startseite">
<div class="text-[22px] sm:text-[24px] lg:text-[28px] font-semibold leading-none tracking-[-0.5px]">
<x-web.brand-mark :brand="$themeKey" />
</div>
<div class="eyebrow muted mt-1 text-[9.5px] tracking-[0.18em] hidden sm:block">
{{ $brandTagline }}
</div>
</a>
{{-- Suchfeld nur ab md sichtbar --}}
<form action="{{ route('suche') }}" method="get" class="hidden md:block flex-1 max-w-[460px]">
<label class="sr-only" for="site-search">Pressemitteilungen, Unternehmen, Branchen, ISIN durchsuchen</label>
<div class="flex items-center gap-2.5 px-3.5 py-2.5 border border-bg-rule bg-bg-elev text-[13px] text-ink-3 rounded-[2px] focus-within:border-brand transition-colors">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true">
<circle cx="7" cy="7" r="5" stroke="currentColor" stroke-width="1.5" />
<path d="M11 11l3 3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" />
</svg>
<input id="site-search" type="search" name="q"
placeholder="Pressemitteilungen, Unternehmen, Branchen, ISIN…"
class="flex-1 bg-transparent border-0 p-0 text-[13px] text-ink placeholder:text-ink-3 focus:outline-none focus:ring-0 min-w-0">
<span class="hidden xl:inline-block text-[10.5px] text-ink-4 border border-bg-rule px-1.5 py-0.5 rounded-[2px] font-mono">⌘K</span>
</div>
<div class="hidden lg:flex justify-end mt-1.5">
<a href="{{ route('suche') }}" class="inline-flex items-center gap-1.5 text-[11.5px] text-ink-3 underline underline-offset-2 decoration-[#1C1A17]/40 cursor-pointer hover:text-ink hover:decoration-brand transition-colors">
<svg width="10" height="10" viewBox="0 0 12 12" fill="none" aria-hidden="true">
<path d="M2 3h8M3.5 6h5M5 9h2" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" />
</svg>
Erweiterte Suche
</a>
</div>
</form>
<span class="flex-1 md:hidden"></span>
{{-- Such-Icon nur auf mobile --}}
<button type="button"
@click="searchOpen = true"
class="md:hidden inline-flex items-center justify-center w-10 h-10 text-ink rounded-[2px] cursor-pointer hover:bg-bg-elev transition-colors"
aria-label="Suche öffnen">
<svg width="20" height="20" viewBox="0 0 16 16" fill="none" aria-hidden="true">
<circle cx="7" cy="7" r="5" stroke="currentColor" stroke-width="1.5" />
<path d="M11 11l3 3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" />
</svg>
</button>
{{-- Anmelden --}}
<a href="#anmelden"
class="inline-flex items-center gap-2 px-2 sm:px-3 lg:px-4 py-2 lg:py-2.5 text-[13px] font-semibold text-ink rounded-[2px] cursor-pointer hover:text-brand transition-colors"
aria-label="Anmelden">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" class="sm:hidden" aria-hidden="true">
<circle cx="12" cy="8" r="4" stroke="currentColor" stroke-width="1.8" />
<path d="M4 21c0-4 4-7 8-7s8 3 8 7" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" />
</svg>
<span class="hidden sm:inline">Anmelden</span>
</a>
{{-- Veröffentlichen --}}
<a href="{{ route('veroeffentlichen') }}"
class="inline-flex items-center gap-1.5 sm:gap-2 px-3 sm:px-4 lg:px-[18px] py-2 lg:py-2.5 text-[12.5px] sm:text-[13px] font-semibold text-white bg-brand cursor-pointer hover:bg-brand-deep rounded-[2px] transition-colors whitespace-nowrap"
aria-label="Pressemitteilung veröffentlichen">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" class="sm:hidden" aria-hidden="true">
<path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" />
</svg>
<span class="sm:hidden">PM</span>
<span class="hidden sm:inline">Veröffentlichen</span>
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" class="hidden sm:inline" aria-hidden="true">
<path d="M3 6h6M6 3l3 3-3 3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</a>
</div>
{{-- Such-Overlay --}}
<div x-show="searchOpen"
x-transition.opacity.duration.150ms
class="fixed inset-0 z-50 bg-ink/70 backdrop-blur-sm"
@click.self="searchOpen = false"
style="display: none;">
<div x-show="searchOpen"
x-transition.duration.200ms
class="bg-bg border-b border-bg-rule shadow-xl">
<div class="max-w-layout mx-auto px-4 sm:px-6 py-6">
<div class="flex items-start justify-between mb-4">
<div>
<div class="eyebrow mb-1">Suche</div>
<h2 class="font-serif text-[22px] font-semibold text-ink">Pressemitteilungen durchsuchen</h2>
</div>
<button type="button"
@click="searchOpen = false"
class="inline-flex items-center justify-center w-10 h-10 text-ink rounded-[2px] cursor-pointer hover:bg-bg-elev transition-colors"
aria-label="Suche schließen">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M6 6l12 12M6 18L18 6" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" />
</svg>
</button>
</div>
<form action="{{ route('suche') }}" method="get">
<label class="sr-only" for="site-search-mobile">Pressemitteilungen durchsuchen</label>
<div class="flex items-center gap-2.5 px-4 py-3.5 border border-bg-rule-strong bg-bg-elev text-[15px] text-ink-3 rounded-[2px]">
<svg width="20" height="20" viewBox="0 0 16 16" fill="none" aria-hidden="true">
<circle cx="7" cy="7" r="5" stroke="currentColor" stroke-width="1.5" />
<path d="M11 11l3 3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" />
</svg>
<input id="site-search-mobile" type="search" name="q"
placeholder="Pressemitteilungen, Unternehmen, Branchen, ISIN…"
x-ref="searchInput"
x-init="$watch('searchOpen', value => value && setTimeout(() => $refs.searchInput.focus(), 50))"
class="flex-1 bg-transparent border-0 p-0 text-[15px] text-ink placeholder:text-ink-3 focus:outline-none focus:ring-0 min-w-0">
<button type="submit"
class="px-3 py-1.5 text-[12px] font-semibold bg-brand text-white rounded-[2px] cursor-pointer hover:bg-brand-deep transition-colors">
Suchen
</button>
</div>
<div class="mt-3 flex justify-between text-[11.5px] text-ink-3">
<a href="{{ route('suche') }}" class="inline-flex items-center gap-1.5 cursor-pointer hover:text-ink transition-colors underline underline-offset-2 decoration-[#1C1A17]/40">
<svg width="10" height="10" viewBox="0 0 12 12" fill="none" aria-hidden="true">
<path d="M2 3h8M3.5 6h5M5 9h2" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" />
</svg>
Erweiterte Suche
</a>
<span class="hidden sm:inline-flex items-center gap-1.5">
Drücken Sie
<kbd class="font-mono text-[10.5px] text-ink-4 border border-bg-rule px-1.5 py-0.5 rounded-[2px]">Esc</kbd>
zum Schließen
</span>
</div>
</form>
</div>
</div>
</div>
</div>
{{-- Main Navigation (Underline-Tabs Desktop, Burger Mobile) --}}
<nav class="bg-bg border-b border-bg-rule relative"
x-data="{ menuOpen: false }"
@keydown.escape.window="menuOpen = false"
@click.outside="menuOpen = false"
aria-label="Hauptnavigation">
{{-- Desktop: horizontale Tabs --}}
<div class="hidden lg:flex max-w-layout mx-auto px-8 items-stretch">
@foreach ($navigation as $item)
<a href="{{ $item['href'] }}"
class="px-4 py-3.5 text-[13.5px] whitespace-nowrap border-b-2 -mb-px cursor-pointer transition-colors
@if ($item['active'] ?? false) font-semibold text-ink border-brand
@else font-medium text-ink-2 border-transparent hover:text-ink hover:border-bg-rule-strong/30 @endif">
{{ $item['label'] }}
</a>
@endforeach
</div>
{{-- Mobile: aktive Kategorie + Burger --}}
<div class="lg:hidden max-w-layout mx-auto px-4 sm:px-6">
<button type="button"
@click="menuOpen = !menuOpen"
class="flex items-center justify-between w-full py-3 cursor-pointer group"
:aria-expanded="menuOpen.toString()"
aria-controls="mobile-nav-menu"
aria-label="Hauptmenü öffnen">
<span class="flex items-center gap-3">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" class="text-ink"
:class="{ 'hidden': menuOpen }" aria-hidden="true">
<path d="M3 6h18M3 12h18M3 18h18" stroke="currentColor" stroke-width="2" stroke-linecap="round" />
</svg>
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" class="text-ink hidden"
:class="{ 'hidden': !menuOpen, '!block': menuOpen }" aria-hidden="true">
<path d="M6 6l12 12M6 18L18 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" />
</svg>
<span class="text-[10px] font-bold tracking-[0.18em] uppercase text-ink-3 group-hover:text-ink transition-colors">Rubrik</span>
<span class="font-serif text-[15px] font-semibold text-ink leading-none">{{ $activeLabel }}</span>
</span>
<svg width="14" height="14" viewBox="0 0 12 12" fill="none" class="text-ink-3 transition-transform"
:class="{ 'rotate-180': menuOpen }" aria-hidden="true">
<path d="M2 4l4 4 4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</button>
</div>
{{-- Mobile Dropdown --}}
<div id="mobile-nav-menu"
x-show="menuOpen"
x-transition.origin.top
x-cloak
class="lg:hidden border-t border-bg-rule bg-bg-elev absolute left-0 right-0 z-40 shadow-lg"
style="display: none;">
<div class="max-w-layout mx-auto px-4 sm:px-6 py-2">
@foreach ($navigation as $item)
<a href="{{ $item['href'] }}"
class="flex items-center justify-between px-3 py-3 text-[14px] border-b border-bg-rule last:border-b-0 cursor-pointer transition-colors
@if ($item['active'] ?? false) font-semibold text-brand bg-brand/[0.04]
@else font-medium text-ink-2 hover:text-ink hover:bg-bg @endif">
<span>{{ $item['label'] }}</span>
@if ($item['active'] ?? false)
<svg width="14" height="14" viewBox="0 0 12 12" fill="none" aria-hidden="true">
<path d="M2 6l3 3 5-6" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />
</svg>
@else
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" class="text-ink-3" aria-hidden="true">
<path d="M4 2l4 4-4 4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
</svg>
@endif
</a>
@endforeach
</div>
</div>
</nav>
<x-web.live-ticker :items="$ticker" :market-index="$marketIndex" :aside-slides="$asideSlides" />
</header>