Web-Frontend: Aufrufe-Anzeige + Share-Tracking auf der PM-Detailseite

- Meta-Zeile zeigt Aufrufe (hits inkl. aktuellem Aufruf) in beiden
  Hero-Varianten; in der Vorschau ausgeblendet
- Teilen-Buttons melden den Kanal an release.share (fetch keepalive,
  CSRF-Meta); Link-kopieren trackt nur bei erfolgreichem Copy

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-07-10 09:56:55 +00:00
parent 644f860223
commit 34ec14d2a9

View file

@ -213,7 +213,7 @@
{{ $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>
<span class="font-mono text-[11.5px] text-white/65">{{ __('web.shared.read_time', ['minutes' => $readTime]) }} · {{ __('web.detail.words', ['count' => number_format($wordCount, 0, ',', '.')]) }}@unless ($isPreview) · {{ __('web.detail.views', ['count' => number_format((int) $release->hits, 0, ',', '.')]) }}@endunless</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>
@ -279,7 +279,7 @@
{{ $publishedAt->translatedFormat('j. F Y') }} · {{ __('web.detail.time_at', ['time' => $publishedAt->format('H:i')]) }}
</time>
@endif
<span class="font-mono text-[11.5px] text-ink-3">{{ __('web.shared.read_time', ['minutes' => $readTime]) }} · {{ __('web.detail.words', ['count' => number_format($wordCount, 0, ',', '.')]) }}</span>
<span class="font-mono text-[11.5px] text-ink-3">{{ __('web.shared.read_time', ['minutes' => $readTime]) }} · {{ __('web.detail.words', ['count' => number_format($wordCount, 0, ',', '.')]) }}@unless ($isPreview) · {{ __('web.detail.views', ['count' => number_format((int) $release->hits, 0, ',', '.')]) }}@endunless</span>
@if ($companyCountry)
<span class="inline-flex items-center gap-1.5 font-mono text-[11.5px] text-ink-3">
<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>
@ -462,19 +462,30 @@
url: @js($shareUrl),
title: @js($release->title),
copied: false,
copy() { navigator.clipboard?.writeText(this.url).then(() => { this.copied = true; setTimeout(() => this.copied = false, 2000); }); }
{{-- Share-Klicks als Ereignis loggen (ohne Personenbezug); in der Vorschau kein Tracking. --}}
trackUrl: @js($isPreview ? null : route('release.share', ['slug' => $release->slug])),
track(channel) {
if (!this.trackUrl) return;
fetch(this.trackUrl, {
method: 'POST',
keepalive: true,
headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': document.querySelector('meta[name=csrf-token]')?.content ?? '' },
body: JSON.stringify({ channel })
}).catch(() => {});
},
copy() { navigator.clipboard?.writeText(this.url).then(() => { this.copied = true; this.track('copy'); setTimeout(() => this.copied = false, 2000); }); }
}">
<div class="eyebrow muted text-[9.5px] mb-2.5">{{ __('web.detail.share') }}</div>
<div class="grid grid-cols-2 gap-1.5">
<a :href="`https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(url)}`" target="_blank" rel="noopener" class="inline-flex items-center gap-[7px] px-2.5 py-2 text-[11.5px] font-medium bg-white border border-bg-rule-strong text-ink hover:bg-bg-elev transition-colors cursor-pointer">
<a :href="`https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(url)}`" @click="track('linkedin')" target="_blank" rel="noopener" class="inline-flex items-center gap-[7px] px-2.5 py-2 text-[11.5px] font-medium bg-white border border-bg-rule-strong text-ink hover:bg-bg-elev transition-colors cursor-pointer">
<svg width="13" height="13" viewBox="0 0 16 16" aria-hidden="true"><path d="M3 6h2.5v8H3V6zm1.25-3a1.25 1.25 0 110 2.5 1.25 1.25 0 010-2.5zM7 6h2.4v1.1c.4-.7 1.3-1.3 2.6-1.3 2.7 0 3 1.7 3 3.9V14h-2.5v-3.7c0-.9 0-2-1.3-2s-1.5 1-1.5 2V14H7V6z" fill="currentColor" /></svg>
LinkedIn
</a>
<a :href="`https://twitter.com/intent/tweet?url=${encodeURIComponent(url)}&text=${encodeURIComponent(title)}`" target="_blank" rel="noopener" class="inline-flex items-center gap-[7px] px-2.5 py-2 text-[11.5px] font-medium bg-white border border-bg-rule-strong text-ink hover:bg-bg-elev transition-colors cursor-pointer">
<a :href="`https://twitter.com/intent/tweet?url=${encodeURIComponent(url)}&text=${encodeURIComponent(title)}`" @click="track('x')" target="_blank" rel="noopener" class="inline-flex items-center gap-[7px] px-2.5 py-2 text-[11.5px] font-medium bg-white border border-bg-rule-strong text-ink hover:bg-bg-elev transition-colors cursor-pointer">
<svg width="13" height="13" viewBox="0 0 16 16" aria-hidden="true"><path d="M2 2l5.5 7.2L2 14h1.6l4.7-3.7L11.5 14H14L8.2 6.4 13.6 2H12L7.5 5.5 4.5 2H2z" fill="currentColor" /></svg>
X
</a>
<a :href="`mailto:?subject=${encodeURIComponent(title)}&body=${encodeURIComponent(url)}`" class="inline-flex items-center gap-[7px] px-2.5 py-2 text-[11.5px] font-medium bg-white border border-bg-rule-strong text-ink hover:bg-bg-elev transition-colors cursor-pointer">
<a :href="`mailto:?subject=${encodeURIComponent(title)}&body=${encodeURIComponent(url)}`" @click="track('email')" class="inline-flex items-center gap-[7px] px-2.5 py-2 text-[11.5px] font-medium bg-white border border-bg-rule-strong text-ink hover:bg-bg-elev transition-colors cursor-pointer">
<svg width="13" height="13" viewBox="0 0 16 16" aria-hidden="true"><rect x="2" y="3" width="12" height="10" stroke="currentColor" stroke-width="1.3" fill="none" /><path d="M2 4l6 4 6-4" stroke="currentColor" stroke-width="1.3" fill="none" /></svg>
{{ __('web.detail.email') }}
</a>