diff --git a/docs/ops-runbook.md b/docs/ops-runbook.md index 423542d..2fa2538 100644 --- a/docs/ops-runbook.md +++ b/docs/ops-runbook.md @@ -32,6 +32,14 @@ Markdown (src/content/posts) → Astro build (dist/) → Gitea Actions → act_r ## Build pitfalls (from prior Astro work — check these first) +- **Pagefind is an ES module and exposes no window global.** `dist/pagefind/pagefind.js` + ends with `export { search, debouncedSearch, … }`. Load it with a dynamic `import()`, never + a classic ` diff --git a/src/components/PostList.astro b/src/components/PostList.astro index 17312ca..737d4c6 100644 --- a/src/components/PostList.astro +++ b/src/components/PostList.astro @@ -1,5 +1,8 @@ --- import type { CollectionEntry } from 'astro:content'; +import { getCollection } from 'astro:content'; +import { postLang } from '../lib/lang'; +import { tagCounts, tagLink } from '../lib/tags'; interface Props { posts: CollectionEntry<'posts'>[]; @@ -24,6 +27,10 @@ const catHref = (cat: string) => `/${isZh ? 'zh/categories' : 'categories'}/${ca const og = (post: CollectionEntry<'posts'>) => post.data.ogImage || '/og-default.png'; +// Tag pills only link when the tag has its own page (>= TAG_MIN_POSTS in this language). +const counts = tagCounts((await getCollection('posts', ({ data }) => !data.draft)) + .filter((p) => postLang(p.slug) === lang)); + // The row thumbnail is displayed at ~398 CSS px wide, so the list used to pull a // 1200x630 PNG (~45 KB) per row for a 398px slot. Serve 400w/800w WebP derived from // the same art instead (5.8 KB / 16.1 KB — see scripts/optimize-images.py). @@ -64,7 +71,10 @@ const thumb = (post: CollectionEntry<'posts'>, w: 400 | 800) => )} · {post.data.category} - {post.data.tags.map((t) => {t})} + {post.data.tags.map((t) => { + const href = tagLink(t, counts, lang); + return href ? {t} : {t}; + })}

{post.data.description}

diff --git a/src/components/Search.astro b/src/components/Search.astro index 5cb45d8..9994bf0 100644 --- a/src/components/Search.astro +++ b/src/components/Search.astro @@ -11,6 +11,13 @@ const placeholder = lang === 'zh' ? '搜索文章…' : 'Search posts…'; const noResults = lang === 'zh' ? '没有匹配的结果。' : 'No results.'; +// Empty-search state: a dead end helps nobody. Offer the topic entry points that +// actually exist (tag pages are generated for tags with >= 3 posts). +const popular = ['docker', 'self-hosting', 'nginx', 'monitoring', 'automation']; +const popularHref = (t: string) => (lang === 'zh' ? `/zh/tags/${t}/` : `/tags/${t}/`); +const tryLabel = lang === 'zh' ? '试试这些主题:' : 'Try a topic:'; +const archiveLabel = lang === 'zh' ? '浏览全部文章' : 'Browse all posts'; +const archiveHref = lang === 'zh' ? '/zh/posts/' : '/posts/'; ---
+ + +