feat(blog): build per-post searchText, wire to PostRow and featured

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Josh Bairstow 2026-06-02 00:21:34 +10:00
parent 44d4d327a1
commit 5ac622e576
2 changed files with 32 additions and 1 deletions

View file

@ -0,0 +1,3 @@
---
// Stub — real implementation lands in Task 4.
---

View file

@ -5,6 +5,7 @@ import Mark from "~/components/atoms/Mark.astro";
import PostRow from "~/components/molecules/PostRow.astro"; import PostRow from "~/components/molecules/PostRow.astro";
import YearHead from "~/components/molecules/YearHead.astro"; import YearHead from "~/components/molecules/YearHead.astro";
import InkArrow from "~/components/atoms/InkArrow.astro"; import InkArrow from "~/components/atoms/InkArrow.astro";
import BlogSearch from "~/components/molecules/BlogSearch.astro";
import { blog } from "~/lib/urls"; import { blog } from "~/lib/urls";
import { getCollection } from "astro:content"; import { getCollection } from "astro:content";
@ -25,6 +26,32 @@ for (const post of rest) {
byYear.set(year, bucket); byYear.set(year, bucket);
} }
const yearGroups = Array.from(byYear.entries()).sort(([a], [b]) => b - a); const yearGroups = Array.from(byYear.entries()).sort(([a], [b]) => b - a);
// Build the per-post `data-search` string at build time. We concatenate the
// searchable fields, lowercase, strip a small set of markdown punctuation, and
// collapse whitespace. Body text is the raw markdown from the content
// collection entry's `.body` property — MDX expressions that survive end up as
// literal text, which is harmless for substring matching.
function buildSearchText(post: (typeof posts)[number]): string {
const parts = [
post.data.title,
post.data.tag,
post.data.standfirst,
post.data.description,
post.body ?? "",
].filter(Boolean) as string[];
return parts
.join(" ")
.toLowerCase()
.replace(/[#*_>`\[\]()]/g, " ")
.replace(/\s+/g, " ")
.trim();
}
const searchTextById = new Map<string, string>();
for (const post of posts) {
searchTextById.set(post.id, buildSearchText(post));
}
--- ---
<BaseLayout <BaseLayout
@ -53,7 +80,7 @@ const yearGroups = Array.from(byYear.entries()).sort(([a], [b]) => b - a);
{ {
featured && ( featured && (
<article class="feature"> <article class="feature" data-featured data-search={searchTextById.get(featured.id) ?? ""}>
<div class="cutframe img"> <div class="cutframe img">
<div class="grain" /> <div class="grain" />
<img class="wm" src="/assets/mark-rings.svg" alt="" /> <img class="wm" src="/assets/mark-rings.svg" alt="" />
@ -91,6 +118,7 @@ const yearGroups = Array.from(byYear.entries()).sort(([a], [b]) => b - a);
href={blog(`/posts/${post.id}/`)} href={blog(`/posts/${post.id}/`)}
deck={post.data.standfirst} deck={post.data.standfirst}
tag={post.data.tag} tag={post.data.tag}
searchText={searchTextById.get(post.id) ?? ""}
/> />
))} ))}
</> </>