feat(structure): compact archive + tag pages + hero/featured, and fix site search
Deploy / build (push) Failing after 13m52s
Deploy / build (push) Failing after 13m52s
Found a real bug while verifying the nav search: /pagefind/pagefind.js is an ES
module that defines no window.Pagefind, but Search.astro loaded it with a classic
<script src> and read window.Pagefind — so every query answered "Search is
unavailable." (confirmed live before the fix). Now a dynamic import; the specifier
must be a variable or Rollup resolves it at build time and the build fails.
Measured before/after in a real browser:
- archive /posts/ + /zh/posts/: 18,220px -> 3,788px (71 rows at 44px, grouped by
year) with a client-side filter (title/tags/description text, category chips,
14 tag chips, zero requests). Tested: "nginx" -> 6 rows, chip devops -> 28.
- tag pages for tags with >= 3 posts. Measured 235 distinct tags (an earlier brief
claimed 74), 156 used exactly once — pages only where a topic exists: 40 tags ->
80 pages, build 165 -> 245 pages. Pills link only when a page exists.
- homepage + ZH homepage: hero (288px) with the real scale claim, three CTAs, a
fixed Featured 4 (scale -> automation -> observability -> a delivered result),
Latest 10 -> 6. ZH hero had linked "关于我" to the English /about/.
- long code blocks collapse above 420px with an Expand button + gradient, copy
button still copies the whole block (verified on the 1010px block).
- search is visible ("⌕ Search /" pill, "/" plus the existing Ctrl/Cmd+K) and the
zero-result screen offers topic chips instead of a dead end.
Docs: project-state B3 entry, ops-runbook Pagefind gotcha.
This commit is contained in:
1 parent
8619e48271
commit
f4008d9e8b
15 files changed
+669
-60
No files matched your search
@@ -0,0 +1,43 @@
|
||||
import type { CollectionEntry } from 'astro:content';
|
||||
|
||||
type Post = CollectionEntry<'posts'>;
|
||||
|
||||
/**
|
||||
* Tag pages are generated only for tags that actually carry a topic.
|
||||
*
|
||||
* Measured 2026-10-16: 235 distinct tags across the posts, of which **156 appear
|
||||
* exactly once** and 40 appear >= 3 times. Generating a page per tag would create
|
||||
* 156 near-empty pages (thin content) and no navigation value; the threshold below
|
||||
* is the line between "a topic" and "a word that appeared in one post".
|
||||
*/
|
||||
export const TAG_MIN_POSTS = 3;
|
||||
|
||||
/** Count how many posts carry each tag. */
|
||||
export function tagCounts(posts: Post[]): Map<string, number> {
|
||||
const counts = new Map<string, number>();
|
||||
for (const p of posts) {
|
||||
for (const t of p.data.tags) counts.set(t, (counts.get(t) ?? 0) + 1);
|
||||
}
|
||||
return counts;
|
||||
}
|
||||
|
||||
/** Tags that get their own page, most-used first (stable, no locale drift). */
|
||||
export function tagPageNames(posts: Post[]): string[] {
|
||||
return [...tagCounts(posts).entries()]
|
||||
.filter(([, n]) => n >= TAG_MIN_POSTS)
|
||||
.sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))
|
||||
.map(([t]) => t);
|
||||
}
|
||||
|
||||
/** Where a tag links to in a given language. */
|
||||
export function tagHref(tag: string, lang: 'en' | 'zh'): string {
|
||||
return lang === 'zh' ? `/zh/tags/${tag}/` : `/tags/${tag}/`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag pills: a tag with a page becomes a link, a one-off tag stays plain text.
|
||||
* Without this split the pills look identical whether or not they go anywhere.
|
||||
*/
|
||||
export function tagLink(tag: string, counts: Map<string, number>, lang: 'en' | 'zh'): string | null {
|
||||
return (counts.get(tag) ?? 0) >= TAG_MIN_POSTS ? tagHref(tag, lang) : null;
|
||||
}
|
||||
Reference in new issue
Block a user