refactor: fold comment count into PostActions toolbar

CommentCountBadge was a separate component rendered next to PostActions
— two adjacent strips of buttons that should have been one toolbar.
Merges the count fetch + click-to-scroll behaviour into PostActions
behind `commentPageId` / `commentTargetId` props. The standalone
CommentCountBadge.svelte is now redundant; deleted.

Layout under the post hero is now a single row:
[💬 3]  [↗ Teilen]  [📋 Link]  [🖨️]  [⏱ 4 min]

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Peter Meier
2026-04-28 14:52:30 +02:00
parent 3318fe9e17
commit 6b2b7245f4
4 changed files with 67 additions and 74 deletions
+64 -1
View File
@@ -1,12 +1,16 @@
<script lang="ts">
import Icon from "@iconify/svelte";
import "$lib/iconify-offline";
import { env } from "$env/dynamic/public";
import { useTranslate, T } from "$lib/translations";
let {
url,
title,
readingTimeMinutes = null,
commentPageId = null,
commentEnvironment,
commentTargetId = "comments-section",
class: cls = "",
}: {
/** Absolute URL of the page being shared. */
@@ -15,11 +19,58 @@
title: string;
/** Estimated reading time. `null` hides the badge. */
readingTimeMinutes?: number | null;
/** Page id for the comment plugin. `null` hides the count badge. */
commentPageId?: string | null;
/** Optional space override for the comment count fetch. */
commentEnvironment?: string;
/** DOM id of the comment accordion (used by the count-badge click). */
commentTargetId?: string;
class?: string;
} = $props();
const t = useTranslate();
// ── Comment count fetch (only when commentPageId is set) ────────────────
let commentCount = $state<number | null>(null);
const cmsBase = (
env.PUBLIC_CMS_URL ||
import.meta.env.PUBLIC_CMS_URL ||
"http://localhost:3000"
).replace(/\/$/, "");
$effect(() => {
if (!commentPageId) {
commentCount = null;
return;
}
const fetchUrl = `${cmsBase}/api/comments/${encodeURIComponent(commentPageId)}/count${
commentEnvironment
? `?_environment=${encodeURIComponent(commentEnvironment)}`
: ""
}`;
let cancelled = false;
fetch(fetchUrl)
.then((r) => r.json())
.then((d) => {
if (cancelled) return;
commentCount = typeof d?.count === "number" ? d.count : 0;
})
.catch(() => {
if (!cancelled) commentCount = 0;
});
return () => {
cancelled = true;
};
});
function onCommentClick(e: MouseEvent) {
const el = document.getElementById(commentTargetId) as HTMLDetailsElement | null;
if (!el) return;
e.preventDefault();
el.open = true;
el.scrollIntoView({ behavior: "smooth", block: "start" });
}
let copied = $state(false);
let shared = $state(false);
let copyTimer: ReturnType<typeof setTimeout> | null = null;
@@ -77,7 +128,19 @@
}
</script>
<div class="inline-flex flex-wrap items-center gap-x-2 gap-y-1 {cls}">
<div class="inline-flex flex-wrap items-center gap-x-3 gap-y-1 {cls}">
{#if commentPageId}
<a
href="#{commentTargetId}"
onclick={onCommentClick}
aria-label={t(T.comments_jump_to)}
class="no-underline! inline-flex items-center gap-1 text-xs font-medium text-zinc-600 hover:text-zinc-900 transition-colors"
>
<Icon icon="mdi:comment-outline" class="size-4" />
<span class="tabular-nums">{commentCount ?? "…"}</span>
</a>
{/if}
<button
type="button"
onclick={share}