Files
windwiderstand/src/lib/comment-counts.ts
T
Peter Meier 3d343822e9
Deploy / verify (push) Successful in 42s
Deploy / deploy (push) Successful in 1m4s
feat: print-friendly layout + comment count on every post overview
- Hides Header / HeaderOverlay / Footer / TopBanner / Breadcrumbs and
  the comment accordion when printing. Action toolbar already had
  `print:hidden`.
- Adds @media print rules in app.css: 1.5cm page margins, 11pt body,
  forced black-on-white, expand link URLs after anchor text inside
  articles, keep images and headings together at page breaks.
- PostCard now renders the count pill whenever a value is known (incl.
  zero); previously hidden for `count === 0`, so posts whose comments
  are still pending always looked empty.
- Extracts the bulk-fetch helper to `lib/comment-counts.ts`
  (`fetchCommentCounts` + `postSlugForComments`) and uses it from both
  `BlogOverview` and `PostOverviewBlock`. Homepage / any page with a
  post_overview block now shows the badges too — previously only the
  paginated /posts/* routes did.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-28 15:29:15 +02:00

50 lines
1.7 KiB
TypeScript

/**
* Helper for fetching comment counts in bulk and keying them by post slug.
* Used by overview components (BlogOverview, PostOverviewBlock) so each
* render fires a single `/api/comments/counts?ids=…` request instead of
* one request per card.
*/
import { env } from "$env/dynamic/public";
import type { PostEntry } from "$lib/cms";
export type CommentCountsMap = Record<string, number>;
/** Strip the leading slash so it matches `params.slug` (= comment page_id). */
export function postSlugForComments(p: PostEntry): string {
const raw = (p as { slug?: string; _slug?: string }).slug ?? p._slug ?? "";
return raw.replace(/^\//, "").trim();
}
/**
* Bulk-fetch approved comment counts for many posts. Returns a map
* `{ slug: count }` (slug as in `postSlugForComments`). Missing or failed
* responses resolve to an empty object — callers can then `?? null` per slug.
*/
export async function fetchCommentCounts(
slugs: string[],
options?: { environment?: string; signal?: AbortSignal },
): Promise<CommentCountsMap> {
const cleaned = slugs.filter(Boolean);
if (cleaned.length === 0) return {};
const cmsBase = (
env.PUBLIC_CMS_URL ||
import.meta.env.PUBLIC_CMS_URL ||
""
).replace(/\/$/, "");
if (!cmsBase) return {};
const url = new URL(`${cmsBase}/api/comments/counts`);
url.searchParams.set("ids", cleaned.join(","));
if (options?.environment) {
url.searchParams.set("_environment", options.environment);
}
try {
const r = await fetch(url.toString(), { signal: options?.signal });
if (!r.ok) return {};
const d = (await r.json()) as { counts?: CommentCountsMap };
return d?.counts ?? {};
} catch {
return {};
}
}