Categories page: descriptions, per-category terminal illustrations, full ZH version
Deploy / build (push) Successful in 17s
Deploy / build (push) Successful in 17s
- 7 categories now listed with name, blurb, post count and a per-category terminal-style SVG illustration (CategoryArt) - empty categories show '0 posts · coming soon' (non-link, no soft-404) - new zh pages: /zh/categories/ index + /zh/categories/[category]/ detail - PostList is locale-aware (zh-CN dates, zh category links) - zh nav '分类' now points to /zh/categories/ - category detail pages get art + description header - language switch wired both ways (EN <-> ZH)
This commit is contained in:
1 parent
730a936137
commit
4cf52e04c1
11 files changed
+577
-25
No files matched your search
@@ -1,9 +1,11 @@
|
||||
---
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import PostList from '../../components/PostList.astro';
|
||||
import CategoryArt from '../../components/CategoryArt.astro';
|
||||
import { getCollection } from 'astro:content';
|
||||
import { isEn } from '../../lib/lang';
|
||||
import { sortByUpdated } from '../../lib/sort';
|
||||
import { categoryMeta } from '../../lib/categories';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const posts = await getCollection('posts', isEn);
|
||||
@@ -12,13 +14,31 @@ export async function getStaticPaths() {
|
||||
}
|
||||
|
||||
const { category } = Astro.params;
|
||||
const meta = categoryMeta(category as string);
|
||||
|
||||
const posts = sortByUpdated(
|
||||
(await getCollection('posts', isEn)).filter((p) => p.data.category === category),
|
||||
);
|
||||
|
||||
const name = meta?.name.en ?? category;
|
||||
const blurb = meta?.blurb.en;
|
||||
---
|
||||
|
||||
<BaseLayout title={`${category} — Mr Hoelee`} description={`Posts in the ${category} category.`}>
|
||||
<h1>Category: {category}</h1>
|
||||
<PostList posts={posts} />
|
||||
</BaseLayout>
|
||||
<BaseLayout
|
||||
title={`${name} — Mr Hoelee`}
|
||||
description={blurb ?? `Posts in the ${category} category.`}
|
||||
switchHref={`/zh/categories/${category}/`}
|
||||
>
|
||||
<h1>{name}</h1>
|
||||
{blurb && <p class="lede">{blurb}</p>}
|
||||
|
||||
<div class="cat-art-wrap">
|
||||
<CategoryArt slug={category} />
|
||||
</div>
|
||||
|
||||
<p class="cat-count">
|
||||
{posts.length} post{posts.length === 1 ? '' : 's'} in this category
|
||||
</p>
|
||||
|
||||
<PostList posts={posts} lang="en" />
|
||||
</BaseLayout>
|
||||
@@ -1,23 +1,31 @@
|
||||
---
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import CategoryGrid from '../../components/CategoryGrid.astro';
|
||||
import { getCollection } from 'astro:content';
|
||||
import { isEn } from '../../lib/lang';
|
||||
|
||||
const posts = await getCollection('posts', isEn);
|
||||
|
||||
const categories = [...new Set(posts.map((p) => p.data.category))].sort();
|
||||
|
||||
const count = (cat: string) => posts.filter((p) => p.data.category === cat).length;
|
||||
const counts: Record<string, number> = {};
|
||||
for (const p of posts) {
|
||||
const cat = p.data.category as string;
|
||||
counts[cat] = (counts[cat] ?? 0) + 1;
|
||||
}
|
||||
---
|
||||
|
||||
<BaseLayout title="Categories — Mr Hoelee" description="Browse posts by category.">
|
||||
<h1>Categories</h1>
|
||||
<ul class="post-list">
|
||||
{categories.map((cat) => (
|
||||
<li>
|
||||
<a href={`/categories/${cat}/`}><h2>{cat}</h2></a>
|
||||
<p>{count(cat)} post{count(cat) === 1 ? '' : 's'}</p>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</BaseLayout>
|
||||
<BaseLayout
|
||||
title="Categories — Mr Hoelee"
|
||||
description={`Browse ${posts.length} technical posts by category: case studies, DevOps, AI, engineering, tutorials and quick notes.`}
|
||||
switchHref="/zh/categories/"
|
||||
>
|
||||
<div class="page-head">
|
||||
<h1>Categories</h1>
|
||||
<p class="lede">
|
||||
Every post belongs to one of seven themes. The <strong>Case Studies</strong> are my
|
||||
working portfolio — end-to-end build logs with the debugging included. The{' '}
|
||||
<strong>Notes</strong> are the quick fixes. Start wherever matches what you're building.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<CategoryGrid counts={counts} lang="en" />
|
||||
</BaseLayout>
|
||||
@@ -0,0 +1,43 @@
|
||||
---
|
||||
import BaseLayout from '../../../layouts/BaseLayout.astro';
|
||||
import PostList from '../../../components/PostList.astro';
|
||||
import CategoryArt from '../../../components/CategoryArt.astro';
|
||||
import { getCollection } from 'astro:content';
|
||||
import { isZh } from '../../../lib/lang';
|
||||
import { sortByUpdated } from '../../../lib/sort';
|
||||
import { categoryMeta } from '../../../lib/categories';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const posts = await getCollection('posts', isZh);
|
||||
const cats = [...new Set(posts.map((p) => p.data.category))];
|
||||
return cats.map((cat) => ({ params: { category: cat } }));
|
||||
}
|
||||
|
||||
const { category } = Astro.params;
|
||||
const meta = categoryMeta(category as string);
|
||||
|
||||
const posts = sortByUpdated(
|
||||
(await getCollection('posts', isZh)).filter((p) => p.data.category === category),
|
||||
);
|
||||
|
||||
const name = meta?.name.zh ?? category;
|
||||
const blurb = meta?.blurb.zh;
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title={`${name} — Mr Hoelee`}
|
||||
description={blurb ?? `「${category}」分类下的文章。`}
|
||||
lang="zh"
|
||||
switchHref={`/categories/${category}/`}
|
||||
>
|
||||
<h1>{name}</h1>
|
||||
{blurb && <p class="lede">{blurb}</p>}
|
||||
|
||||
<div class="cat-art-wrap">
|
||||
<CategoryArt slug={category} />
|
||||
</div>
|
||||
|
||||
<p class="cat-count">本分类共 {posts.length} 篇文章</p>
|
||||
|
||||
<PostList posts={posts} lang="zh" />
|
||||
</BaseLayout>
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
import BaseLayout from '../../../layouts/BaseLayout.astro';
|
||||
import CategoryGrid from '../../../components/CategoryGrid.astro';
|
||||
import { getCollection } from 'astro:content';
|
||||
import { isZh } from '../../../lib/lang';
|
||||
|
||||
const posts = await getCollection('posts', isZh);
|
||||
|
||||
const counts: Record<string, number> = {};
|
||||
for (const p of posts) {
|
||||
const cat = p.data.category as string;
|
||||
counts[cat] = (counts[cat] ?? 0) + 1;
|
||||
}
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title="分类 — Mr Hoelee"
|
||||
description={`按分类浏览 ${posts.length} 篇中文技术文章:案例研究、DevOps、AI、工程开发、教程与随记。`}
|
||||
lang="zh"
|
||||
switchHref="/categories/"
|
||||
>
|
||||
<div class="page-head">
|
||||
<h1>分类</h1>
|
||||
<p class="lede">
|
||||
每篇文章都属于七大主题之一。<strong>案例研究</strong>是我的实战作品集——包含完整踩坑过程的
|
||||
端到端构建实录;<strong>随记</strong>则是简短速记。从你正在做的事情开始看吧。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<CategoryGrid counts={counts} lang="zh" />
|
||||
</BaseLayout>
|
||||
@@ -34,7 +34,7 @@ const posts = sortByUpdated(await getCollection('posts', isZh));
|
||||
{posts.length === 0 ? (
|
||||
<p><em>中文文章即将发布,敬请期待。</em></p>
|
||||
) : (
|
||||
<PostList posts={posts} />
|
||||
<PostList posts={posts} lang="zh" />
|
||||
)}
|
||||
</section>
|
||||
</BaseLayout>
|
||||
Reference in new issue
Block a user