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:
@@ -1,65 +0,0 @@
|
||||
<script lang="ts">
|
||||
import Icon from "@iconify/svelte";
|
||||
import "$lib/iconify-offline";
|
||||
import { env } from "$env/dynamic/public";
|
||||
import { useTranslate, T } from "$lib/translations";
|
||||
|
||||
const t = useTranslate();
|
||||
|
||||
let {
|
||||
pageId,
|
||||
environment,
|
||||
targetId = "comments-section",
|
||||
class: cls = "",
|
||||
}: {
|
||||
pageId: string;
|
||||
environment?: string;
|
||||
targetId?: string;
|
||||
class?: string;
|
||||
} = $props();
|
||||
|
||||
let count = $state<number | null>(null);
|
||||
|
||||
const cmsBase = (
|
||||
env.PUBLIC_CMS_URL ||
|
||||
import.meta.env.PUBLIC_CMS_URL ||
|
||||
"http://localhost:3000"
|
||||
).replace(/\/$/, "");
|
||||
|
||||
$effect(() => {
|
||||
const url = `${cmsBase}/api/comments/${encodeURIComponent(pageId)}/count${
|
||||
environment ? `?_environment=${encodeURIComponent(environment)}` : ""
|
||||
}`;
|
||||
let cancelled = false;
|
||||
fetch(url)
|
||||
.then((r) => r.json())
|
||||
.then((d) => {
|
||||
if (cancelled) return;
|
||||
count = typeof d?.count === "number" ? d.count : 0;
|
||||
})
|
||||
.catch(() => {
|
||||
if (!cancelled) count = 0;
|
||||
});
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
});
|
||||
|
||||
function onClick(e: MouseEvent) {
|
||||
const el = document.getElementById(targetId) as HTMLDetailsElement | null;
|
||||
if (!el) return;
|
||||
e.preventDefault();
|
||||
el.open = true;
|
||||
el.scrollIntoView({ behavior: "smooth", block: "start" });
|
||||
}
|
||||
</script>
|
||||
|
||||
<a
|
||||
href="#{targetId}"
|
||||
onclick={onClick}
|
||||
aria-label={t(T.comments_jump_to)}
|
||||
class="no-underline! inline-flex items-center gap-1 text-xs font-medium transition-colors {cls}"
|
||||
>
|
||||
<Icon icon="mdi:comment-outline" class="size-4" />
|
||||
<span class="tabular-nums">{count ?? "…"}</span>
|
||||
</a>
|
||||
@@ -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}
|
||||
|
||||
@@ -133,7 +133,7 @@ const TRANSLATION_KEYS = [
|
||||
"post_map_activate",
|
||||
"post_map_open_osm",
|
||||
"post_comments",
|
||||
// Comment plugin (Comments.svelte / PostCard count pill / CommentCountBadge).
|
||||
// Comment plugin (Comments.svelte / PostCard count pill / PostActions toolbar).
|
||||
"comments_loading",
|
||||
"comments_load_error_title",
|
||||
"comments_retry",
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
import EventBadges from "$lib/components/EventBadges.svelte";
|
||||
import EventMap from "$lib/components/EventMap.svelte";
|
||||
import Accordion from "$lib/components/Accordion.svelte";
|
||||
import CommentCountBadge from "$lib/components/CommentCountBadge.svelte";
|
||||
import Comments from "$lib/components/Comments.svelte";
|
||||
import PostActions from "$lib/components/PostActions.svelte";
|
||||
import RustyImage from "$lib/components/RustyImage.svelte";
|
||||
@@ -78,16 +77,12 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap items-center gap-x-4 gap-y-2 text-sm text-zinc-600">
|
||||
{#if data.commentPageId}
|
||||
<CommentCountBadge
|
||||
pageId={data.commentPageId}
|
||||
targetId="comments-section"
|
||||
/>
|
||||
{/if}
|
||||
<PostActions
|
||||
url={data.canonicalUrl}
|
||||
title={data.seoTitle}
|
||||
readingTimeMinutes={data.readingTimeMinutes}
|
||||
commentPageId={data.commentPageId}
|
||||
commentTargetId="comments-section"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user