PM-Vorschau: Workflow oben + farbig, Metadaten, saubere Inhalts-Typografie
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
b7145512a7
commit
5a8da0c1f4
6 changed files with 318 additions and 44 deletions
|
|
@ -5,6 +5,33 @@
|
|||
|
||||
---
|
||||
|
||||
## 2026-06-12 · PM-Vorschau-Umbau + Profil-Feinschliff ✅
|
||||
|
||||
- **Was**: (1) PM-Detailseite (Customer) nach Kevins Review umgebaut:
|
||||
Status-Workflow direkt unter den Header, farblich abgehoben
|
||||
(Soft-Hintergrund + 3px-Border je Status: Entwurf hub, Überarbeiten
|
||||
err, In Prüfung warn, neu: Veröffentlicht ok); danach Pressekontakte +
|
||||
Status & Verlauf, dann erst Titelbild und Inhalt. Metadaten ergänzt:
|
||||
Portal, Kategorie, Sprache als Kacheln, Themen (Keywords) als Badges,
|
||||
Backlink — alles im Verlaufs-Panel. (2) **Inhalts-Typografie**: Die
|
||||
Detailseiten nutzten `prose`-Klassen, aber das Tailwind-Typography-
|
||||
Plugin ist gar nicht installiert → Text erschien unformatiert (Diff
|
||||
Editor vs. Vorschau). Neue Klasse `.pr-content` in hub-components.css
|
||||
bildet die Editor-Typografie nach (Absätze, Listen, H2-H4, Links,
|
||||
Blockquote); Customer- UND Admin-Detailseite umgestellt, Lesebreite
|
||||
max 760px. (3) Profil: Pflicht-Badges an Pflichtfeldern, Fokus-Fix
|
||||
nach dem Speichern (blur statt Autofokus auf „Anzeigename"),
|
||||
Submit-Modal-Bestätigungen von rohen Checkboxen auf Flux-Switches
|
||||
(Alpine-State via change-Event, Button-Freischaltung unverändert).
|
||||
- **Dateien**: `customer/press-releases/show.blade.php` (Umbau),
|
||||
`admin/press-releases/show.blade.php` (.pr-content),
|
||||
`resources/css/shared/hub-components.css` (.pr-content),
|
||||
`customer/profile.blade.php`, `components/press-release-submit-modal.blade.php`.
|
||||
- **Build/Test**: Suite 546 passed / 4 skipped, Pint clean, npm run build ok.
|
||||
- **Offene Fragen**: Web-Detailseiten (`web/release-detail` u. a.) nutzen
|
||||
ebenfalls wirkungslose `prose`-Klassen — beim Web-Relaunch auf
|
||||
`.pr-content` (oder Typography-Plugin) umstellen.
|
||||
|
||||
## 2026-06-12 · User-Panel-Restarbeiten (Kevins Liste) ✅
|
||||
|
||||
- **Was**: Alle Punkte aus `docs/user-admin/User-Panel-Restarbeiten.md`
|
||||
|
|
|
|||
|
|
@ -0,0 +1,120 @@
|
|||
|
||||
|
||||
**Version:** Juni 2026 **Datum:** 11.06.2026 **Status:** Abgestimmt – bereit zur Integration ins Konzept-/Decision-Log **Scope:** Behandlung von Links in Presseartikeln, `rel`-Auszeichnung, Linkangabe und Linktyp-Auswahl im Editor, Abgrenzung zum verkauften Dofollow-Backlink. Präzisiert den entsprechenden Punkt im Decision-Update „Preisstruktur & Veröffentlichungs-Flow".
|
||||
|
||||
---
|
||||
|
||||
## 1. Kontext & Klarstellung
|
||||
|
||||
In der Preis-Abstimmung war der Punkt „verkaufte Dofollow-Backlinks ausgeschlossen" zu pauschal formuliert und konnte als „keine Links" missverstanden werden. Das ist falsch. Links in Presseartikeln gehören selbstverständlich dazu. Die Frage ist nicht _ob_, sondern _wie ausgezeichnet_ und _wie verkauft_.
|
||||
|
||||
Es geht um zwei verschiedene Dinge, die beide „Backlink" heißen:
|
||||
|
||||
1. **Der Link im Presseartikel zur Kundenseite** – normaler, erwarteter Bestandteil jeder PM. Erlaubt, darf hervorgehoben werden. Muss technisch korrekt ausgezeichnet sein.
|
||||
2. **Den „Dofollow-Backlink für SEO-Wert" als bezahltes Upsell verkaufen** – das ist die Falle und bleibt ausgeschlossen.
|
||||
|
||||
---
|
||||
|
||||
## 2. Grundregel (Google-konform)
|
||||
|
||||
**Externe Links in Pressemitteilungen werden systemseitig mit `rel="sponsored"` bzw. `rel="nofollow"` ausgezeichnet.**
|
||||
|
||||
Hintergrund: Google behandelt Links in Pressemitteilungen als Kategorie, die nofollow gehört – der Kunde setzt den Link selbst, es ist keine redaktionelle Empfehlung des Portals. Jeder über Bezahlung oder kommerzielle Vereinbarung entstandene Link muss entsprechend qualifiziert sein; eine fehlende Kennzeichnung von Paid-Placements ist selbst der Richtlinienverstoß. Für kombinierte Fälle (bezahlte Platzierung + kein Endorsement) ist `rel="sponsored nofollow"` zulässig.
|
||||
|
||||
**Konsequenz fürs Produkt:** Die `rel`-Auszeichnung ist **nicht kundenseitig wählbar**. Sie wird vom System anhand der Platzierungs-Kategorie automatisch gesetzt. Damit ist die Domain dauerhaft sauber und es gibt keinen Hebel, über den ein Kunde „dofollow" erzwingen könnte.
|
||||
|
||||
---
|
||||
|
||||
## 3. Wichtig: nofollow ≠ wertlos
|
||||
|
||||
Die alte Logik „nofollow = nutzlos" gilt seit 2019 nicht mehr. Google behandelt `nofollow`/`sponsored`/`ugc` seitdem als **Hinweis**, nicht als absolute Anweisung. Praktischer Wert für den Kunden bleibt:
|
||||
|
||||
- **Referral-Traffic** – direkte Klicks vom Presseartikel auf die Kundenseite
|
||||
- **Marken-Assoziation & Kontext** – die Nennung selbst zählt
|
||||
- **AI-/LLM-Sichtbarkeit** – Markennennungen aus Presseartikeln fließen zunehmend in Google AI Overviews und LLM-Antworten ein, wo Sichtbarkeit von Autorität abhängt, nicht nur von klassischen Backlinks
|
||||
|
||||
**Das ist das ehrliche, zukunftsfeste Verkaufsargument:** Sichtbarkeit, Reichweite und Auffindbarkeit – nicht „PageRank kaufen".
|
||||
|
||||
---
|
||||
|
||||
## 4. Linktypen im Überblick
|
||||
|
||||
|Element|Funktion|`rel` (systemseitig)|
|
||||
|---|---|---|
|
||||
|Firmen-Link im PM-Fließtext|Standard, immer möglich|`sponsored` / `nofollow`|
|
||||
|**Unternehmens-CTA-Box** (Website, Newsroom, Kontakt) am PM-Ende|Hervorhebung, optisch abgesetzt|`sponsored` / `nofollow`|
|
||||
|Link zur **Landingpage / Produktseite** (extern)|vom Kunden gewählt|`sponsored` / `nofollow`|
|
||||
|Link zum **Unternehmensprofil auf dem Portal** (intern)|redaktionelle interne Verlinkung|**follow**|
|
||||
|
||||
**Der unterschätzte Punkt – die interne Verlinkung:** Ein follow-Link auf das **portaleigene** Unternehmensprofil ist regelkonform (interner, redaktioneller Link) und stärkt die **eigene** Domain-Architektur. Der Kunde bekommt eine sichtbare „Über das Unternehmen"-Verlinkung; das Portal baut gleichzeitig seine interne Linkstruktur auf, statt fremde Autorität zu verschenken.
|
||||
|
||||
---
|
||||
|
||||
## 5. Linkangabe & Linktyp-Auswahl im Editor
|
||||
|
||||
**Anforderung:** Beim Erstellen einer PM gibt der Kunde Links an und wählt einen Linktyp.
|
||||
|
||||
**Sauberes Design (Google-konform):** Der Kunde wählt **Ziel und Zweck** des Links – das System leitet daraus die korrekte `rel`-Auszeichnung ab. Die Begriffe „follow/nofollow" tauchen im Kunden-UI **nicht** auf.
|
||||
|
||||
Editor-Flow beim Hinzufügen eines Links:
|
||||
|
||||
1. **Ziel-URL** eingeben
|
||||
2. **Link-Art** wählen (das ist die kundenseitige „Linktyp"-Auswahl):
|
||||
|
||||
|Link-Art (Auswahl im Editor)|Beispiel|Systemseitige Auszeichnung|
|
||||
|---|---|---|
|
||||
|Unternehmens-Website|startseite.de|extern → `sponsored`/`nofollow`|
|
||||
|Spezifische Landingpage / Produktseite|aktion.startseite.de|extern → `sponsored`/`nofollow`|
|
||||
|Newsroom / Unternehmensprofil auf dem Portal|(interner Profil-Link)|intern → `follow`|
|
||||
|Kontakt / Social-Profil|LinkedIn etc.|extern → `sponsored`/`nofollow`|
|
||||
|
||||
3. **Darstellung** (optional, ggf. tarif-/boost-abhängig): Inline-Textlink **oder** hervorgehobene CTA-Box. Das betrifft die _Präsentation_, nicht den Link-Typ.
|
||||
|
||||
**Entscheidung festgehalten:** Die Linktyp-Auswahl steuert **Ziel und Darstellung**, nie das `rel`-Attribut. Das `rel` ist systemgesteuert. Damit hat der Kunde maximale Freiheit bei Ziel und Hervorhebung, ohne dass die Domain-Sicherheit kippt.
|
||||
|
||||
---
|
||||
|
||||
## 6. Was Produkt ist – und was tabu bleibt
|
||||
|
||||
||Status|
|
||||
|---|---|
|
||||
|Links in der PM (extern, korrekt ausgezeichnet)|✅ Standard, kostenlos Teil der Veröffentlichung|
|
||||
|Hervorgehobene CTA-Box / Linkdarstellung|✅ als Hervorhebungs-/Boost-Feature verkaufbar|
|
||||
|follow-Link auf portaleigenes Unternehmensprofil|✅ regelkonform, stärkt eigene Domain|
|
||||
|Sichtbarkeit / Reichweite / Platzierung|✅ das eigentliche Verkaufsargument|
|
||||
|„Dofollow-Backlink" als bezahltes Upsell|❌ Link-Scheme-Verstoß, Domain-Risiko, gegen Anti-Zombie|
|
||||
|Kundenseitiger follow/nofollow-Schalter|❌ nicht im UI, `rel` bleibt systemgesteuert|
|
||||
|
||||
---
|
||||
|
||||
## 7. Anti-Zombie-Check (dieser Stand)
|
||||
|
||||
- ✅ Keine versteckten SEO-Versprechen – verkauft wird Sichtbarkeit, nicht PageRank
|
||||
- ✅ Domain-Glaubwürdigkeit langfristig geschützt (korrekte `rel`-Auszeichnung systemseitig)
|
||||
- ✅ Kunde behält volle Freiheit bei Linkziel und Hervorhebung
|
||||
- ✅ Regelkonform gegenüber Google-Spam-Richtlinien, kein Graubereich
|
||||
- ✅ Interne Verlinkung baut eigenes Asset statt fremde Autorität zu verschenken
|
||||
|
||||
---
|
||||
|
||||
## 8. Offene / spätere Punkte
|
||||
|
||||
- **Darstellungs-Stufung:** Soll die hervorgehobene CTA-Box ein eigenes Boost-/Tarif-Feature sein oder Standard? (Hängt am Boost-Konzept.)
|
||||
- **Anzahl Links pro PM:** Sinnvolle Obergrenze definieren (gegen Link-Spam in der PM selbst, z. B. Profil + Website + 1–2 Kontextlinks).
|
||||
- **Anchor-Text-Regeln:** Optional späterer Hinweis/Soft-Check gegen übermäßige Exact-Match-Anchors (Spam-Signal), eher Phase 2.
|
||||
|
||||
---
|
||||
|
||||
## 9. Korrektur am vorherigen Decision-Update
|
||||
|
||||
Im Dokument „Preisstruktur & Veröffentlichungs-Flow", Abschnitt 4, wird der Eintrag
|
||||
|
||||
> „Bewusst ausgeschlossen: Verkaufte Dofollow-Backlinks."
|
||||
|
||||
ersetzt durch:
|
||||
|
||||
> „Verlinkung: Links zur Kundenseite sind Standard-Bestandteil jeder PM, systemseitig als `sponsored`/`nofollow` ausgezeichnet. Hervorhebung der Linkdarstellung ist als Produkt-Feature möglich. **Tabu:** Verkauf von Dofollow-Backlinks und kundenseitige `rel`-Auswahl. Details siehe Decision-Update „Verlinkung & Backlinks"."
|
||||
|
||||
---
|
||||
|
||||
_SEO-/Richtlinien-Stand: Google-Spam-Policies inkl. Link-Spam-Enforcement 2024–2026; `nofollow`/`sponsored`/`ugc` als Hinweise seit September 2019. Vor produktiver Umsetzung der `rel`-Logik einmal gegen die dann aktuelle Google-Search-Central-Doku gegenprüfen._
|
||||
|
|
@ -81,6 +81,87 @@
|
|||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* PM-Inhalt (gerenderter Editor-HTML in Vorschau/Detail)
|
||||
*
|
||||
* Die Detailseiten nutzten `prose`-Klassen, aber das
|
||||
* Tailwind-Typography-Plugin ist nicht installiert — der Text
|
||||
* erschien deshalb unformatiert. Diese Klasse bildet die
|
||||
* Editor-Typografie nach (Absätze, Listen, Zwischenüberschriften,
|
||||
* Links), ohne eine neue Abhängigkeit einzuführen.
|
||||
* ============================================================ */
|
||||
|
||||
.pr-content {
|
||||
font-size: 14.5px;
|
||||
line-height: 1.7;
|
||||
color: var(--color-ink);
|
||||
}
|
||||
.pr-content p {
|
||||
margin: 0 0 1em;
|
||||
}
|
||||
.pr-content p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.pr-content h2,
|
||||
.pr-content h3,
|
||||
.pr-content h4 {
|
||||
color: var(--color-ink);
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.2px;
|
||||
line-height: 1.3;
|
||||
margin: 1.6em 0 0.6em;
|
||||
}
|
||||
.pr-content h2 {
|
||||
font-size: 19px;
|
||||
}
|
||||
.pr-content h3 {
|
||||
font-size: 16.5px;
|
||||
}
|
||||
.pr-content h4 {
|
||||
font-size: 15px;
|
||||
}
|
||||
.pr-content h2:first-child,
|
||||
.pr-content h3:first-child,
|
||||
.pr-content h4:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.pr-content ul,
|
||||
.pr-content ol {
|
||||
margin: 0 0 1em;
|
||||
padding-inline-start: 1.4em;
|
||||
}
|
||||
.pr-content ul {
|
||||
list-style: disc;
|
||||
}
|
||||
.pr-content ol {
|
||||
list-style: decimal;
|
||||
}
|
||||
.pr-content li {
|
||||
margin: 0.3em 0;
|
||||
}
|
||||
.pr-content a {
|
||||
color: var(--color-hub);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 2px;
|
||||
}
|
||||
.pr-content strong,
|
||||
.pr-content b {
|
||||
font-weight: 700;
|
||||
color: var(--color-ink);
|
||||
}
|
||||
.pr-content blockquote {
|
||||
margin: 1em 0;
|
||||
padding: 0.2em 0 0.2em 1em;
|
||||
border-left: 3px solid var(--color-hub-soft-2);
|
||||
color: var(--color-ink-2);
|
||||
font-style: italic;
|
||||
}
|
||||
.pr-content hr {
|
||||
margin: 1.5em 0;
|
||||
border: 0;
|
||||
border-top: 1px solid var(--color-bg-rule);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* Stat-Cards (KPI-Karten mit farbigem Strip links)
|
||||
* ============================================================ */
|
||||
|
|
|
|||
|
|
@ -467,7 +467,7 @@ new #[Layout('components.layouts.app'), Title('Pressemitteilung')] class extends
|
|||
<span class="section-eyebrow">{{ __('Inhalt') }}</span>
|
||||
</div>
|
||||
<div class="p-5">
|
||||
<div class="prose prose-zinc dark:prose-invert max-w-none text-[color:var(--color-ink)]">
|
||||
<div class="pr-content max-w-[760px]">
|
||||
{!! $pr->renderedText() !!}
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -197,22 +197,6 @@ new #[Layout('components.layouts.app'), Title('Pressemitteilung')] class extends
|
|||
</div>
|
||||
</header>
|
||||
|
||||
{{-- ============== TITELBILD (Hero) ============== --}}
|
||||
{{-- Harte Obergrenze 1280x580 px: Container deckelt Breite und Seitenverhältnis,
|
||||
damit das Bild auf großen Screens nicht über die Detailgröße hinauswächst. --}}
|
||||
<article class="panel overflow-hidden mx-auto w-full max-w-[1280px]">
|
||||
<div class="relative aspect-[1280/580] w-full">
|
||||
<img src="{{ $coverUrl }}" alt="{{ $pr->title }}"
|
||||
class="absolute inset-0 h-full w-full object-cover" loading="lazy" />
|
||||
</div>
|
||||
@if ($coverIsPlaceholder)
|
||||
<div class="flex items-center gap-2 border-t border-[color:var(--color-bg-rule)] px-5 py-2.5 text-[12px] text-[color:var(--color-ink-3)]">
|
||||
<flux:icon.photo variant="micro" class="size-3.5" />
|
||||
<span>{{ __('Platzhalter-Titelbild — laden Sie im Editor ein eigenes Bild hoch.') }}</span>
|
||||
</div>
|
||||
@endif
|
||||
</article>
|
||||
|
||||
{{-- ============== SHARE-LINK ERFOLG ============== --}}
|
||||
@if ($shareUrl)
|
||||
<article class="panel" style="border-color:var(--color-ok);">
|
||||
|
|
@ -253,9 +237,11 @@ new #[Layout('components.layouts.app'), Title('Pressemitteilung')] class extends
|
|||
</article>
|
||||
@endif
|
||||
|
||||
{{-- ============== STATUS-WORKFLOW ============== --}}
|
||||
{{-- ============== STATUS-WORKFLOW (oben, farblich abgehoben) ============== --}}
|
||||
@if ($pr->status === PressReleaseStatus::Draft || $pr->status === PressReleaseStatus::Rejected)
|
||||
<article class="panel">
|
||||
<article class="panel"
|
||||
style="border-color:var(--color-{{ $pr->status === PressReleaseStatus::Rejected ? 'err' : 'hub' }}); border-left-width:3px;
|
||||
background:var(--color-{{ $pr->status === PressReleaseStatus::Rejected ? 'err' : 'hub' }}-soft);">
|
||||
<div class="panel-head">
|
||||
<span class="section-eyebrow">{{ __('Status-Workflow') }}</span>
|
||||
<span @class(['badge', 'dot', $pr->status === PressReleaseStatus::Rejected ? 'err' : 'hub'])>
|
||||
|
|
@ -268,7 +254,7 @@ new #[Layout('components.layouts.app'), Title('Pressemitteilung')] class extends
|
|||
? __('Sie können den Text bearbeiten und erneut zur Prüfung einreichen.')
|
||||
: __('Reichen Sie den Entwurf ein, sobald er vollständig ist.') }}
|
||||
</p>
|
||||
<div class="flex items-center gap-2 flex-shrink-0">
|
||||
<div class="flex items-center gap-2 flex-shrink-0 flex-wrap">
|
||||
@if ($canEdit)
|
||||
<flux:button variant="filled" icon="pencil" href="{{ route('me.press-releases.edit', $pr->id) }}" wire:navigate>
|
||||
{{ __('Bearbeiten') }}
|
||||
|
|
@ -284,10 +270,28 @@ new #[Layout('components.layouts.app'), Title('Pressemitteilung')] class extends
|
|||
</article>
|
||||
@endif
|
||||
|
||||
@if ($pr->status === PressReleaseStatus::Review)
|
||||
<article class="panel" style="border-color:var(--color-warn); border-left-width:3px;">
|
||||
@if ($pr->status === PressReleaseStatus::Published)
|
||||
<article class="panel" style="border-color:var(--color-ok); border-left-width:3px; background:var(--color-ok-soft);">
|
||||
<div class="panel-head">
|
||||
<span class="section-eyebrow">{{ __('In Prüfung') }}</span>
|
||||
<span class="section-eyebrow">{{ __('Status-Workflow') }}</span>
|
||||
<span class="badge ok dot">{{ __('Live') }}</span>
|
||||
</div>
|
||||
<div class="p-5 flex items-start gap-3">
|
||||
<div class="w-9 h-9 rounded-[5px] flex items-center justify-center flex-shrink-0
|
||||
bg-[color:var(--color-ok-soft)] border border-[color:var(--color-ok)]/30 text-[color:var(--color-gain-deep)]">
|
||||
<flux:icon.check-circle class="size-[18px]" />
|
||||
</div>
|
||||
<p class="flex-1 text-[13px] text-[color:var(--color-ink-2)] m-0">
|
||||
{{ __('Diese Pressemitteilung ist veröffentlicht (seit :date).', ['date' => $pr->published_at?->format('d.m.Y H:i') ?? '–']) }}
|
||||
</p>
|
||||
</div>
|
||||
</article>
|
||||
@endif
|
||||
|
||||
@if ($pr->status === PressReleaseStatus::Review)
|
||||
<article class="panel" style="border-color:var(--color-warn); border-left-width:3px; background:var(--color-warn-soft);">
|
||||
<div class="panel-head">
|
||||
<span class="section-eyebrow">{{ __('Status-Workflow') }}</span>
|
||||
<span class="badge warn dot">{{ __('Geduld bitte') }}</span>
|
||||
</div>
|
||||
<div class="p-5 flex items-start gap-3">
|
||||
|
|
@ -400,7 +404,46 @@ new #[Layout('components.layouts.app'), Title('Pressemitteilung')] class extends
|
|||
</div>
|
||||
</div>
|
||||
@endif
|
||||
<div class="rounded-[5px] border border-[color:var(--color-bg-rule)] bg-[color:var(--color-bg-elev)] p-3">
|
||||
<div class="text-[11px] uppercase tracking-[0.6px] text-[color:var(--color-ink-3)] font-semibold">{{ __('Portal') }}</div>
|
||||
<div class="text-[13px] font-semibold text-[color:var(--color-ink)] mt-1">
|
||||
{{ $pr->portal?->label() ?? '–' }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="rounded-[5px] border border-[color:var(--color-bg-rule)] bg-[color:var(--color-bg-elev)] p-3">
|
||||
<div class="text-[11px] uppercase tracking-[0.6px] text-[color:var(--color-ink-3)] font-semibold">{{ __('Kategorie') }}</div>
|
||||
<div class="text-[13px] font-semibold text-[color:var(--color-ink)] mt-1">
|
||||
{{ $categoryName }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="rounded-[5px] border border-[color:var(--color-bg-rule)] bg-[color:var(--color-bg-elev)] p-3">
|
||||
<div class="text-[11px] uppercase tracking-[0.6px] text-[color:var(--color-ink-3)] font-semibold">{{ __('Sprache') }}</div>
|
||||
<div class="text-[13px] font-semibold text-[color:var(--color-ink)] mt-1">
|
||||
{{ strtoupper($pr->language) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (filled($pr->keywords))
|
||||
<div class="mt-3 rounded-[5px] border border-[color:var(--color-bg-rule)] bg-[color:var(--color-bg-elev)] p-3">
|
||||
<div class="text-[11px] uppercase tracking-[0.6px] text-[color:var(--color-ink-3)] font-semibold mb-2">{{ __('Themen') }}</div>
|
||||
<div class="flex flex-wrap gap-1.5">
|
||||
@foreach (array_filter(array_map('trim', explode(',', $pr->keywords))) as $keyword)
|
||||
<span class="badge hub">{{ $keyword }}</span>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if ($pr->backlink_url)
|
||||
<div class="mt-3 rounded-[5px] border border-[color:var(--color-bg-rule)] bg-[color:var(--color-bg-elev)] p-3">
|
||||
<div class="text-[11px] uppercase tracking-[0.6px] text-[color:var(--color-ink-3)] font-semibold mb-1">{{ __('Backlink') }}</div>
|
||||
<a href="{{ $pr->backlink_url }}" target="_blank"
|
||||
class="text-[12.5px] break-all text-[color:var(--color-hub)] underline underline-offset-2 decoration-[color:var(--color-hub)]/40 hover:decoration-[color:var(--color-hub)]">
|
||||
{{ $pr->backlink_url }}
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if ($pr->no_export)
|
||||
<div class="mt-3 flex items-center gap-2 text-[12px] text-[color:var(--color-ink-3)]">
|
||||
|
|
@ -449,35 +492,31 @@ new #[Layout('components.layouts.app'), Title('Pressemitteilung')] class extends
|
|||
</article>
|
||||
</div>
|
||||
|
||||
{{-- ============== TITELBILD (Hero) ============== --}}
|
||||
{{-- Harte Obergrenze 1280x580 px: Container deckelt Breite und Seitenverhältnis,
|
||||
damit das Bild auf großen Screens nicht über die Detailgröße hinauswächst. --}}
|
||||
<article class="panel overflow-hidden mx-auto w-full max-w-[1280px]">
|
||||
<div class="relative aspect-[1280/580] w-full">
|
||||
<img src="{{ $coverUrl }}" alt="{{ $pr->title }}"
|
||||
class="absolute inset-0 h-full w-full object-cover" loading="lazy" />
|
||||
</div>
|
||||
@if ($coverIsPlaceholder)
|
||||
<div class="flex items-center gap-2 border-t border-[color:var(--color-bg-rule)] px-5 py-2.5 text-[12px] text-[color:var(--color-ink-3)]">
|
||||
<flux:icon.photo variant="micro" class="size-3.5" />
|
||||
<span>{{ __('Platzhalter-Titelbild — laden Sie im Editor ein eigenes Bild hoch.') }}</span>
|
||||
</div>
|
||||
@endif
|
||||
</article>
|
||||
|
||||
{{-- ============== INHALT ============== --}}
|
||||
<article class="panel">
|
||||
<div class="panel-head">
|
||||
<span class="section-eyebrow">{{ __('Inhalt') }}</span>
|
||||
</div>
|
||||
<div class="p-5">
|
||||
<div class="prose prose-zinc dark:prose-invert max-w-none text-[color:var(--color-ink)]">
|
||||
<div class="pr-content max-w-[760px]">
|
||||
{!! $pr->renderedText() !!}
|
||||
</div>
|
||||
|
||||
@if ($pr->keywords || $pr->backlink_url)
|
||||
<div class="mt-6 space-y-2 border-t border-[color:var(--color-bg-rule)] pt-4 text-[12.5px] text-[color:var(--color-ink-2)]">
|
||||
@if ($pr->keywords)
|
||||
<p class="m-0">
|
||||
<strong class="text-[color:var(--color-ink)] font-semibold">{{ __('Stichwörter') }}:</strong>
|
||||
{{ $pr->keywords }}
|
||||
</p>
|
||||
@endif
|
||||
@if ($pr->backlink_url)
|
||||
<p class="m-0">
|
||||
<strong class="text-[color:var(--color-ink)] font-semibold">{{ __('Backlink') }}:</strong>
|
||||
<a href="{{ $pr->backlink_url }}" target="_blank"
|
||||
class="text-[color:var(--color-hub)] underline underline-offset-2 decoration-[color:var(--color-hub)]/40 hover:decoration-[color:var(--color-hub)]">
|
||||
{{ $pr->backlink_url }}
|
||||
</a>
|
||||
</p>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</article>
|
||||
|
||||
|
|
|
|||
|
|
@ -264,6 +264,7 @@ test('customer press release detail shows assigned contacts and status history',
|
|||
'title' => 'Alpha Detailmeldung',
|
||||
'status' => PressReleaseStatus::Review->value,
|
||||
'hits' => 1234,
|
||||
'keywords' => 'Energie, Wasserstoff',
|
||||
]);
|
||||
$contact = Contact::factory()->create([
|
||||
'company_id' => $company->id,
|
||||
|
|
@ -288,12 +289,18 @@ test('customer press release detail shows assigned contacts and status history',
|
|||
|
||||
LivewireVolt::test('customer.press-releases.show', ['id' => $pressRelease->id])
|
||||
->assertSee('Alpha Detailmeldung')
|
||||
->assertSee('Status-Workflow')
|
||||
->assertSee('Zugeordnete Pressekontakte')
|
||||
->assertSee('Paula Presse')
|
||||
->assertSee('paula@example.test')
|
||||
->assertSee('Status & Verlauf')
|
||||
->assertSee('In Pruefung')
|
||||
->assertSee('1.234')
|
||||
->assertSee('Portal')
|
||||
->assertSee('Kategorie')
|
||||
->assertSee('Themen')
|
||||
->assertSee('Energie')
|
||||
->assertSee('Wasserstoff')
|
||||
->assertSee('Zur Prüfung eingereicht')
|
||||
->assertSee('durch Kunden Nutzer');
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue