presseportale/resources/views/livewire/customer/press-releases/index.blade.php
Kevin Adametz e8c47b7553
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
22-05-2026 Optimierung der User und Admin Panels
2026-05-22 11:18:59 +02:00

682 lines
35 KiB
PHP

<?php
use App\Enums\Portal;
use App\Enums\PressReleaseStatus;
use App\Models\PressRelease;
use App\Services\Customer\CustomerCompanyContext;
use App\Services\PressRelease\BlacklistViolationException;
use App\Services\PressRelease\PressReleaseService;
use Flux\Flux;
use Illuminate\Support\Facades\DB;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Attributes\Url;
use Livewire\Volt\Component;
use Livewire\WithPagination;
new #[Layout('components.layouts.app'), Title('Meine Pressemitteilungen')] class extends Component {
use WithPagination;
public string $search = '';
public string $statusFilter = 'all';
#[Url(as: 'company', except: 'all')]
public string $companyFilter = 'all';
public string $portalFilter = 'all';
public string $sortBy = 'created_at';
public string $sortDir = 'desc';
public function sort(string $column): void
{
if ($this->sortBy === $column) {
$this->sortDir = $this->sortDir === 'asc' ? 'desc' : 'asc';
} else {
$this->sortBy = $column;
$this->sortDir = 'asc';
}
$this->resetPage();
}
public function setView(string $view): void
{
$this->statusFilter = $view;
$this->resetPage();
}
public function resetFilters(): void
{
$this->search = '';
$this->statusFilter = 'all';
$this->portalFilter = 'all';
if ($this->companyFilter !== 'all') {
$this->companyFilter = 'all';
}
$this->resetPage();
}
public function updatedSearch(): void
{
$this->resetPage();
}
public function updatedStatusFilter(): void
{
$this->resetPage();
}
public function updatedCompanyFilter(): void
{
$this->resetPage();
}
public function updatedPortalFilter(): void
{
$this->resetPage();
}
public function submitForReview(int $id): void
{
$pr = $this->findMyPR($id);
if (!$pr) {
return;
}
try {
app(PressReleaseService::class)->submitForReview($pr);
Flux::toast(
heading: __('Eingereicht'),
text: __('Pressemitteilung zur Prüfung eingereicht.'),
variant: 'success',
);
} catch (BlacklistViolationException $e) {
Flux::toast(
heading: __('Automatisch abgelehnt'),
text: __('Unzulässiges Wort gefunden: ":word".', ['word' => $e->word]),
variant: 'danger',
duration: 8000,
);
} catch (\LogicException $e) {
Flux::toast(text: $e->getMessage(), variant: 'danger');
}
}
public function with(): array
{
$userId = auth()->id();
$context = app(CustomerCompanyContext::class);
$selectedCompanyId = $context->selectedCompanyId(auth()->user());
$base = PressRelease::withoutGlobalScopes()
->where('user_id', $userId)
->when($selectedCompanyId !== null, fn($q) => $q->where('company_id', $selectedCompanyId))
->when($selectedCompanyId === null && $this->companyFilter === 'assigned', fn($q) => $q->whereNotNull('company_id'))
->when($selectedCompanyId === null && $this->companyFilter === 'unassigned', fn($q) => $q->whereNull('company_id'));
$statusCountsRaw = (clone $base)->toBase()->selectRaw('status, COUNT(*) as aggregate')->groupBy('status')->pluck('aggregate', 'status');
$statusCounts = [
'all' => (int) $statusCountsRaw->sum(),
PressReleaseStatus::Published->value => (int) ($statusCountsRaw[PressReleaseStatus::Published->value] ?? 0),
PressReleaseStatus::Draft->value => (int) ($statusCountsRaw[PressReleaseStatus::Draft->value] ?? 0),
PressReleaseStatus::Review->value => (int) ($statusCountsRaw[PressReleaseStatus::Review->value] ?? 0),
PressReleaseStatus::Rejected->value => (int) ($statusCountsRaw[PressReleaseStatus::Rejected->value] ?? 0),
PressReleaseStatus::Archived->value => (int) ($statusCountsRaw[PressReleaseStatus::Archived->value] ?? 0),
];
$prs = (clone $base)
->with('company:id,name')
->when(filled($this->search), function ($q): void {
$term = $this->search;
$q->where('title', 'like', '%' . $term . '%');
})
->when($this->statusFilter !== 'all', fn($q) => $q->where('status', $this->statusFilter))
->when($this->portalFilter !== 'all', fn($q) => $q->where('portal', $this->portalFilter))
->orderBy(in_array($this->sortBy, ['title', 'status', 'created_at']) ? $this->sortBy : 'created_at', $this->sortDir)
->paginate(25);
return [
'pressReleases' => $prs,
'statusOptions' => PressReleaseStatus::cases(),
'portalOptions' => Portal::cases(),
'selectedCompany' => $context->selectedCompany(auth()->user()),
'hasGlobalCompanyContext' => $selectedCompanyId === null,
'statusCounts' => $statusCounts,
];
}
private function findMyPR(int $id): ?PressRelease
{
return PressRelease::withoutGlobalScopes()
->where('id', $id)
->where('user_id', auth()->id())
->first();
}
}; ?>
@php
$hasAnyFilter =
$search !== '' ||
$statusFilter !== 'all' ||
$portalFilter !== 'all' ||
($hasGlobalCompanyContext && $companyFilter !== 'all');
$hasAnyPR = $statusCounts['all'] > 0;
@endphp
<div class="space-y-8">
{{-- Flash-Banner ersetzt durch <flux:toast /> im Layout. --}}
{{-- ============== PAGE HEADER ============== --}}
<header class="grid items-end gap-8" style="grid-template-columns:1fr auto;">
<div class="min-w-0">
<div class="flex items-center gap-3 mb-3 flex-nowrap whitespace-nowrap">
<span class="badge hub dot">{{ __('User Backend') }}</span>
<span class="eyebrow muted">{{ __('Mein Bereich · Pressemitteilungen') }}</span>
</div>
<h1 class="text-[34px] font-bold tracking-[-0.7px] leading-[1.1] m-0 text-[color:var(--color-ink)]">
{{ __('Meine Pressemitteilungen') }}
</h1>
{{-- Counter-Strip + Kontext-Hinweis --}}
@if ($hasAnyPR)
<div class="counter-strip mt-3">
<span class="seg"><b>{{ $statusCounts['all'] }}</b> {{ __('Mitteilungen') }}</span>
@if ($statusCounts[\App\Enums\PressReleaseStatus::Published->value] > 0)
<span class="sep"></span>
<span
class="seg is-ok"><b>{{ $statusCounts[\App\Enums\PressReleaseStatus::Published->value] }}</b>
{{ __('veröffentlicht') }}</span>
@endif
@if ($statusCounts[\App\Enums\PressReleaseStatus::Review->value] > 0)
<span class="sep"></span>
<span
class="seg is-warn"><b>{{ $statusCounts[\App\Enums\PressReleaseStatus::Review->value] }}</b>
{{ __('in Prüfung') }}</span>
@endif
@if ($statusCounts[\App\Enums\PressReleaseStatus::Draft->value] > 0)
<span class="sep"></span>
<span
class="seg is-muted"><b>{{ $statusCounts[\App\Enums\PressReleaseStatus::Draft->value] }}</b>
{{ __('Entwürfe') }}</span>
@endif
@if ($statusCounts[\App\Enums\PressReleaseStatus::Rejected->value] > 0)
<span class="sep"></span>
<span
class="seg is-err"><b>{{ $statusCounts[\App\Enums\PressReleaseStatus::Rejected->value] }}</b>
{{ __('abgelehnt') }}</span>
@endif
</div>
@endif
@if ($selectedCompany)
<p class="text-[12.5px] leading-[1.55] mt-2 m-0 text-[color:var(--color-ink-3)]">
{{ __('Gefiltert auf :company', ['company' => $selectedCompany->name]) }}
</p>
@elseif (!$hasAnyPR)
<p class="text-[13.5px] leading-[1.55] mt-2 m-0 max-w-[640px] text-[color:var(--color-ink-2)]">
{{ __('Übersicht aller PMs Ihres Kundenkontos, mit Filter und Schnellaktionen.') }}
</p>
@endif
</div>
<div class="flex items-center gap-2 flex-shrink-0">
<flux:button variant="primary" icon="plus" href="{{ route('me.press-releases.create') }}" wire:navigate>
{{ __('Neue Pressemitteilung') }}
</flux:button>
</div>
</header>
{{-- ============== SAVED-VIEWS-TABS ============== --}}
@if ($hasAnyPR)
<nav class="view-tabs" aria-label="{{ __('Gespeicherte Ansichten') }}">
<button type="button" wire:click="setView('all')" @class(['view-tab', 'is-active' => $statusFilter === 'all'])>
{{ __('Alle') }} <span class="cnt">{{ $statusCounts['all'] }}</span>
</button>
<button type="button" wire:click="setView('{{ \App\Enums\PressReleaseStatus::Published->value }}')"
@class([
'view-tab',
'is-active' =>
$statusFilter === \App\Enums\PressReleaseStatus::Published->value,
])>
{{ __('Veröffentlicht') }} <span
class="cnt">{{ $statusCounts[\App\Enums\PressReleaseStatus::Published->value] }}</span>
</button>
<button type="button" wire:click="setView('{{ \App\Enums\PressReleaseStatus::Draft->value }}')"
@class([
'view-tab',
'is-active' =>
$statusFilter === \App\Enums\PressReleaseStatus::Draft->value,
])>
{{ __('Entwürfe') }} <span
class="cnt">{{ $statusCounts[\App\Enums\PressReleaseStatus::Draft->value] }}</span>
</button>
<button type="button" wire:click="setView('{{ \App\Enums\PressReleaseStatus::Review->value }}')"
@class([
'view-tab',
'is-active' =>
$statusFilter === \App\Enums\PressReleaseStatus::Review->value,
])>
{{ __('In Prüfung') }} <span
class="cnt">{{ $statusCounts[\App\Enums\PressReleaseStatus::Review->value] }}</span>
</button>
<button type="button" wire:click="setView('{{ \App\Enums\PressReleaseStatus::Rejected->value }}')"
@class([
'view-tab',
'is-active' =>
$statusFilter === \App\Enums\PressReleaseStatus::Rejected->value,
])>
{{ __('Abgelehnt') }} <span
class="cnt">{{ $statusCounts[\App\Enums\PressReleaseStatus::Rejected->value] }}</span>
</button>
<button type="button" wire:click="setView('{{ \App\Enums\PressReleaseStatus::Archived->value }}')"
@class([
'view-tab',
'is-active' =>
$statusFilter === \App\Enums\PressReleaseStatus::Archived->value,
])>
{{ __('Archiv') }} <span
class="cnt">{{ $statusCounts[\App\Enums\PressReleaseStatus::Archived->value] }}</span>
</button>
</nav>
@endif
{{-- ============== FILTER + SUCHE ============== --}}
@if ($hasAnyPR)
<section class="space-y-3">
<div class="flex items-center gap-2 flex-wrap">
<flux:input wire:model.live.debounce.300ms="search" placeholder="{{ __('Titel suchen…') }}"
icon="magnifying-glass" class="max-w-[340px]" />
<span class="w-px h-6 bg-[color:var(--color-bg-rule)] mx-1"></span>
<flux:select wire:model.live="portalFilter" class="sm:w-44">
<option value="all">{{ __('Portal: Alle') }}</option>
@foreach ($portalOptions as $p)
<option value="{{ $p->value }}">{{ __('Portal:') }} {{ $p->label() }}</option>
@endforeach
</flux:select>
@if ($hasGlobalCompanyContext)
<flux:select wire:model.live="companyFilter" class="sm:w-56">
<option value="all">{{ __('Firma: Alle') }}</option>
<option value="assigned">{{ __('Firma: Mit Firma') }}</option>
<option value="unassigned">{{ __('Firma: Ohne Firma') }}</option>
</flux:select>
@endif
</div>
{{-- Active-Chips --}}
@if ($hasAnyFilter)
<div class="flex items-center gap-2 flex-wrap text-[11.5px]">
<span class="eyebrow muted" style="margin-right:2px;">{{ __('Aktiv') }}</span>
@if ($statusFilter !== 'all')
@php $statusEnum = \App\Enums\PressReleaseStatus::tryFrom($statusFilter); @endphp
<span class="active-chip">
<span>{{ __('Status') }}:
<strong>{{ $statusEnum?->label() ?? $statusFilter }}</strong></span>
<button type="button" class="x" wire:click="setView('all')"
aria-label="{{ __('Filter entfernen') }}">
<svg width="8" height="8" viewBox="0 0 12 12" fill="none">
<path d="M3 3l6 6M9 3l-6 6" stroke="currentColor" stroke-width="1.6"
stroke-linecap="round" />
</svg>
</button>
</span>
@endif
@if ($portalFilter !== 'all')
@php $portalEnum = \App\Enums\Portal::tryFrom($portalFilter); @endphp
<span class="active-chip">
<span>{{ __('Portal') }}:
<strong>{{ $portalEnum?->label() ?? $portalFilter }}</strong></span>
<button type="button" class="x" wire:click="$set('portalFilter', 'all')"
aria-label="{{ __('Filter entfernen') }}">
<svg width="8" height="8" viewBox="0 0 12 12" fill="none">
<path d="M3 3l6 6M9 3l-6 6" stroke="currentColor" stroke-width="1.6"
stroke-linecap="round" />
</svg>
</button>
</span>
@endif
@if ($hasGlobalCompanyContext && $companyFilter !== 'all')
<span class="active-chip">
<span>{{ __('Firma') }}:
<strong>{{ $companyFilter === 'assigned' ? __('Mit Firma') : __('Ohne Firma') }}</strong></span>
<button type="button" class="x" wire:click="$set('companyFilter', 'all')"
aria-label="{{ __('Filter entfernen') }}">
<svg width="8" height="8" viewBox="0 0 12 12" fill="none">
<path d="M3 3l6 6M9 3l-6 6" stroke="currentColor" stroke-width="1.6"
stroke-linecap="round" />
</svg>
</button>
</span>
@endif
@if ($search !== '')
<span class="active-chip">
<span>{{ __('Suche') }}:
<strong>„{{ \Illuminate\Support\Str::limit($search, 40) }}"</strong></span>
<button type="button" class="x" wire:click="$set('search', '')"
aria-label="{{ __('Filter entfernen') }}">
<svg width="8" height="8" viewBox="0 0 12 12" fill="none">
<path d="M3 3l6 6M9 3l-6 6" stroke="currentColor" stroke-width="1.6"
stroke-linecap="round" />
</svg>
</button>
</span>
@endif
<button type="button" wire:click="resetFilters"
class="text-[11.5px] font-semibold text-[color:var(--color-ink-3)] hover:text-[color:var(--color-hub)] underline-offset-[3px] hover:underline">
{{ __('Alle zurücksetzen') }}
</button>
</div>
@endif
</section>
@endif
{{-- ============== TABELLE / EMPTY ============== --}}
<article class="panel overflow-hidden">
@if ($pressReleases->isNotEmpty())
<div class="panel-head">
<span class="section-eyebrow">
@if ($statusFilter !== 'all')
@php $sEnum = \App\Enums\PressReleaseStatus::tryFrom($statusFilter); @endphp
{{ $sEnum?->label() ?? __('Pressemitteilungen') }}
@else
{{ __('Alle Pressemitteilungen') }}
@endif
</span>
<span class="text-[11.5px] text-[color:var(--color-ink-3)]">
{{ __(':count Einträge', ['count' => $pressReleases->total()]) }}
</span>
</div>
<flux:table>
<flux:table.columns>
<flux:table.column class="w-[140px]">{{ __('Status') }}</flux:table.column>
<flux:table.column sortable :sorted="$sortBy === 'title'" :direction="$sortDir"
wire:click="sort('title')">
{{ __('Titel') }}
</flux:table.column>
<flux:table.column class="w-[180px]">{{ __('Portal') }}</flux:table.column>
<flux:table.column class="w-[180px]">{{ __('Firma') }}</flux:table.column>
<flux:table.column class="w-[140px]" sortable :sorted="$sortBy === 'created_at'"
:direction="$sortDir" wire:click="sort('created_at')">
{{ __('Datum') }}
</flux:table.column>
<flux:table.column class="w-[80px]">{{ __('Aktionen') }}</flux:table.column>
</flux:table.columns>
@foreach ($pressReleases as $pr)
@php
$status = $pr->status->value;
$rowClass = match ($status) {
'review' => 'is-row-warn',
'rejected' => 'is-row-err',
default => '',
};
$badgeClass = match ($status) {
'published' => 'ok',
'review' => 'warn',
'rejected' => 'err',
'archived', 'draft' => 'muted',
default => 'hub',
};
$portal = $pr->portal?->value ?? 'both';
$showPe = in_array($portal, ['presseecho', 'both'], true);
$showBp = in_array($portal, ['businessportal24', 'both'], true);
$dateSubLabel = match ($status) {
'published' => __('veröffentlicht'),
'review' => __('eingereicht'),
'rejected' => __('abgelehnt'),
'draft' => __('erstellt'),
'archived' => __('archiviert'),
default => __('erstellt'),
};
$primaryDate = match (true) {
$status === 'published' && $pr->published_at => $pr->published_at,
default => $pr->created_at,
};
@endphp
<flux:table.row wire:key="{{ $pr->id }}" class="{{ $rowClass }}">
<flux:table.cell>
<div class="flex items-center gap-1 flex-wrap">
<span class="badge {{ $badgeClass }} dot">{{ $pr->status->label() }}</span>
@if ($status === 'draft')
<button type="button" class="inline-action"
wire:click="submitForReview({{ $pr->id }})"
wire:confirm="{{ __('Pressemitteilung zur Prüfung einreichen?') }}"
title="{{ __('Zur redaktionellen Prüfung senden') }}">
{{ __('Zur Prüfung →') }}
</button>
@endif
</div>
</flux:table.cell>
<flux:table.cell>
<a href="{{ route('me.press-releases.show', $pr->id) }}" wire:navigate
class="block font-semibold text-[13.5px] leading-[1.35] text-[color:var(--color-ink)] hover:text-[color:var(--color-hub)] hover:underline underline-offset-[3px] decoration-[color:var(--color-hub)]/40 hover:decoration-[color:var(--color-hub)]">
{{ $pr->title }}
</a>
<div class="text-[11.5px] text-[color:var(--color-ink-3)] mt-0.5 leading-[1.4]">
PM-{{ $pr->id }}
</div>
</flux:table.cell>
<flux:table.cell>
<div class="flex flex-wrap gap-1">
@if ($showPe)
<span class="portal-pill pe"><span class="pdot"></span>presseecho</span>
@endif
@if ($showBp)
<span class="portal-pill bp"><span
class="pdot"></span>businessportal24</span>
@endif
</div>
</flux:table.cell>
<flux:table.cell>
@if ($pr->company)
<span class="text-[12.5px] text-[color:var(--color-ink-2)] font-medium">
{{ $pr->company->name }}
</span>
@else
<span
class="text-[11.5px] text-[color:var(--color-ink-4)] italic">{{ __('— keine —') }}</span>
@endif
</flux:table.cell>
<flux:table.cell>
<div class="font-mono text-[12px] text-[color:var(--color-ink-2)] tabular-nums">
{{ $primaryDate?->format('d.m.Y') }}
</div>
<div class="text-[10.5px] text-[color:var(--color-ink-4)] mt-0.5">
{{ $dateSubLabel }} · {{ $primaryDate?->format('H:i') }}
</div>
@if ($status === 'review' && $pr->scheduled_at && $pr->scheduled_at->isFuture())
<div class="mt-1 inline-flex items-center gap-1 text-[10.5px] font-mono tabular-nums text-[color:var(--color-accent-deep)]">
<flux:icon.calendar variant="micro" class="size-3" />
<span>{{ __('geplant') }} · {{ $pr->scheduled_at->format('d.m. H:i') }}</span>
</div>
@endif
@if ($pr->embargo_at && $pr->embargo_at->isFuture())
<div class="mt-1 inline-flex items-center gap-1 text-[10.5px] font-mono tabular-nums text-[color:var(--color-accent-deep)]">
<flux:icon.lock-closed variant="micro" class="size-3" />
<span>{{ __('Embargo bis') }} {{ $pr->embargo_at->format('d.m.') }}</span>
</div>
@endif
</flux:table.cell>
<flux:table.cell>
<div class="flex items-center gap-1">
<flux:button size="sm" variant="ghost" icon="eye"
href="{{ route('me.press-releases.show', $pr->id) }}" wire:navigate />
@if (in_array($status, ['draft', 'rejected']))
<flux:button size="sm" variant="ghost" icon="pencil"
href="{{ route('me.press-releases.edit', $pr->id) }}" wire:navigate />
@endif
</div>
</flux:table.cell>
</flux:table.row>
@endforeach
</flux:table>
<div class="border-t border-[color:var(--color-bg-rule)] p-4">
{{ $pressReleases->links('components.portal.pagination') }}
</div>
@elseif ($hasAnyPR && $search !== '')
{{-- Empty: Suche ohne Treffer --}}
<div class="empty-stage">
<div class="empty-ico">
<svg width="28" height="28" viewBox="0 0 24 24" fill="none">
<circle cx="10.5" cy="10.5" r="6" stroke="currentColor" stroke-width="1.6" />
<path d="M15.5 15.5L20 20" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" />
</svg>
</div>
<h3 class="empty-title">{{ __('Keine Treffer für „:term"', ['term' => $search]) }}</h3>
<p class="empty-sub">
{{ __('Wir konnten zu Ihrer Suche nichts finden. Prüfen Sie die Schreibweise oder schränken Sie den Suchbegriff ein.') }}
</p>
<div class="flex items-center gap-2.5 mt-6">
<flux:button variant="primary" wire:click="$set('search', '')">
{{ __('Suche zurücksetzen') }}
</flux:button>
</div>
</div>
@elseif ($hasAnyPR && $hasAnyFilter)
{{-- Empty: Filter ohne Treffer --}}
<div class="empty-stage">
<div class="empty-ico warm">
<svg width="28" height="28" viewBox="0 0 24 24" fill="none">
<path d="M4 6h16M7 12h10M10 18h4" stroke="currentColor" stroke-width="1.8"
stroke-linecap="round" />
</svg>
</div>
<h3 class="empty-title">{{ __('Keine Mitteilungen mit diesen Filtern') }}</h3>
<p class="empty-sub">
{{ __('Aktive Filter passen auf keine Einträge. Setzen Sie einen Filter zurück oder probieren Sie eine breitere Auswahl.') }}
</p>
<div class="flex items-center gap-2.5 mt-6">
<flux:button variant="primary" wire:click="resetFilters">{{ __('Alle Filter zurücksetzen') }}
</flux:button>
</div>
</div>
@else
{{-- Empty: gar keine PMs überhaupt --}}
<div class="empty-stage">
<div class="empty-ico">
<svg width="28" height="28" viewBox="0 0 24 24" fill="none">
<rect x="3" y="4" width="14" height="16" stroke="currentColor" stroke-width="1.5" />
<path d="M17 7h4v13H6" stroke="currentColor" stroke-width="1.5" />
<path d="M6 8h8M6 11h8M6 14h5" stroke="currentColor" stroke-width="1.3"
stroke-linecap="round" />
</svg>
</div>
<h3 class="empty-title">{{ __('Noch keine Pressemitteilungen') }}</h3>
<p class="empty-sub">
{{ __('Starten Sie mit Ihrer ersten Mitteilung. Nach redaktioneller Prüfung erscheint sie i. d. R. binnen 4 Stunden werktags auf beiden Portalen.') }}
</p>
<div class="flex items-center gap-2.5 mt-6">
<flux:button variant="primary" icon="plus" href="{{ route('me.press-releases.create') }}"
wire:navigate>
{{ __('Erste Pressemitteilung erstellen') }}
</flux:button>
</div>
<div class="mt-9 grid gap-3 w-full max-w-[560px]" style="grid-template-columns:repeat(3,1fr);">
<div
class="text-left px-3 py-2.5 bg-[color:var(--color-bg-elev)] border border-[color:var(--color-bg-rule)] rounded-[3px]">
<div
class="font-mono text-[9.5px] tracking-[0.16em] text-[color:var(--color-accent-deep)] font-bold mb-1">
01</div>
<div class="text-[11.5px] font-semibold text-[color:var(--color-ink)] leading-tight">
{{ __('Firma zuordnen') }}</div>
</div>
<div
class="text-left px-3 py-2.5 bg-[color:var(--color-bg-elev)] border border-[color:var(--color-bg-rule)] rounded-[3px]">
<div
class="font-mono text-[9.5px] tracking-[0.16em] text-[color:var(--color-accent-deep)] font-bold mb-1">
02</div>
<div class="text-[11.5px] font-semibold text-[color:var(--color-ink)] leading-tight">
{{ __('Mitteilung verfassen') }}</div>
</div>
<div
class="text-left px-3 py-2.5 bg-[color:var(--color-bg-elev)] border border-[color:var(--color-bg-rule)] rounded-[3px]">
<div
class="font-mono text-[9.5px] tracking-[0.16em] text-[color:var(--color-accent-deep)] font-bold mb-1">
03</div>
<div class="text-[11.5px] font-semibold text-[color:var(--color-ink)] leading-tight">
{{ __('Zur Prüfung senden') }}</div>
</div>
</div>
</div>
@endif
</article>
{{-- ============== STATUS-AKTIONEN-LEGENDE ============== --}}
@if ($hasAnyPR)
<article class="panel-warm p-5">
<div class="grid items-start gap-6" style="grid-template-columns:auto 1fr;">
<div class="min-w-[180px]">
<div class="section-eyebrow">{{ __('Aktionen je Status') }}</div>
<p class="text-[12px] text-[color:var(--color-ink-3)] leading-[1.55] mt-3 m-0 max-w-[200px]">
{{ __('Welche Aktionen pro Status verfügbar sind.') }}
</p>
</div>
<div class="grid gap-4" style="grid-template-columns:repeat(5,minmax(0,1fr));">
<div>
<span class="badge muted dot" style="margin-bottom:8px;">{{ __('Entwurf') }}</span>
<ul
class="text-[11.5px] text-[color:var(--color-ink-2)] leading-[1.7] mt-2 list-none p-0 m-0 space-y-0.5">
<li>{{ __('Bearbeiten') }}</li>
<li>{{ __('Vorschau') }}</li>
<li class="text-[color:var(--color-accent-deep)] font-semibold">
{{ __('→ Zur Prüfung senden') }}</li>
</ul>
</div>
<div>
<span class="badge warn dot" style="margin-bottom:8px;">{{ __('In Prüfung') }}</span>
<ul
class="text-[11.5px] text-[color:var(--color-ink-2)] leading-[1.7] mt-2 list-none p-0 m-0 space-y-0.5">
<li>{{ __('Vorschau') }}</li>
<li class="text-[color:var(--color-ink-3)] italic">{{ __('Warten auf Redaktion') }}</li>
</ul>
</div>
<div>
<span class="badge ok dot" style="margin-bottom:8px;">{{ __('Veröffentlicht') }}</span>
<ul
class="text-[11.5px] text-[color:var(--color-ink-2)] leading-[1.7] mt-2 list-none p-0 m-0 space-y-0.5">
<li>{{ __('Vorschau') }}</li>
<li class="text-[color:var(--color-ink-3)] italic">{{ __('Statistik (bald)') }}</li>
</ul>
</div>
<div>
<span class="badge err dot" style="margin-bottom:8px;">{{ __('Abgelehnt') }}</span>
<ul
class="text-[11.5px] text-[color:var(--color-ink-2)] leading-[1.7] mt-2 list-none p-0 m-0 space-y-0.5">
<li>{{ __('Bearbeiten') }}</li>
<li class="text-[color:var(--color-accent-deep)] font-semibold">
{{ __('→ Erneut einreichen') }}</li>
</ul>
</div>
<div>
<span class="badge muted dot" style="margin-bottom:8px;">{{ __('Archiviert') }}</span>
<ul
class="text-[11.5px] text-[color:var(--color-ink-2)] leading-[1.7] mt-2 list-none p-0 m-0 space-y-0.5">
<li>{{ __('Vorschau') }}</li>
</ul>
</div>
</div>
</div>
</article>
@endif
</div>