3d343822e9
- 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>
50 lines
1.7 KiB
TypeScript
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 {};
|
|
}
|
|
}
|