();
for (const post of allPosts) {
if (!post.tags) continue;
for (const tag of post.tags) {
- tags.add(tag);
+ slugs.add(getTagSlug(tag));
}
}
- return Array.from(tags).map((tag) => ({
- tag
+ return Array.from(slugs).map((slug) => ({
+ tag: slug
}));
}
@@ -20,23 +21,31 @@ interface Props {
}
export function generateMetadata({ params }: Props): Metadata {
- const tag = params.tag;
+ const slug = params.tag;
+ // Find original tag label by slug
+ const tag = allPosts
+ .flatMap((post) => post.tags ?? [])
+ .find((t) => getTagSlug(t) === slug);
+
return {
- title: `標籤:${tag}`
+ title: tag ? `標籤:${tag}` : '標籤'
};
}
export default function TagPage({ params }: Props) {
- const tag = params.tag;
+ const slug = params.tag;
const posts = allPosts.filter(
- (post) => post.tags && post.tags.includes(tag)
+ (post) => post.tags && post.tags.some((t) => getTagSlug(t) === slug)
);
+ const tagLabel =
+ posts[0]?.tags?.find((t) => getTagSlug(t) === slug) ?? params.tag;
+
return (
- 標籤:{tag}
+ 標籤:{tagLabel}
{posts.map((post) => (
@@ -46,4 +55,3 @@ export default function TagPage({ params }: Props) {
);
}
-
diff --git a/components/post-list-item.tsx b/components/post-list-item.tsx
index 937804f..99382fb 100644
--- a/components/post-list-item.tsx
+++ b/components/post-list-item.tsx
@@ -45,7 +45,9 @@ export function PostListItem({ post }: Props) {
{post.tags.slice(0, 4).map((t) => (
#{t}
diff --git a/components/right-sidebar.tsx b/components/right-sidebar.tsx
index 71a1f4d..e75f1d3 100644
--- a/components/right-sidebar.tsx
+++ b/components/right-sidebar.tsx
@@ -41,7 +41,7 @@ export function RightSidebar() {
標籤雲
- {tags.map(({ tag, count }) => {
+ {tags.map(({ tag, slug, count }) => {
let sizeClass = 'text-[11px]';
if (count >= 5) sizeClass = 'text-sm font-semibold';
else if (count >= 3) sizeClass = 'text-xs font-medium';
@@ -49,7 +49,7 @@ export function RightSidebar() {
return (
{tag}
diff --git a/lib/posts.ts b/lib/posts.ts
index 1c76a05..d9c26db 100644
--- a/lib/posts.ts
+++ b/lib/posts.ts
@@ -26,7 +26,11 @@ export function getPageBySlug(slug: string): Page | undefined {
);
}
-export function getAllTagsWithCount(): { tag: string; count: number }[] {
+export function getTagSlug(tag: string): string {
+ return encodeURIComponent(tag.toLowerCase().replace(/\s+/g, '-'));
+}
+
+export function getAllTagsWithCount(): { tag: string; slug: string; count: number }[] {
const map = new Map();
for (const post of allPosts) {
@@ -37,7 +41,7 @@ export function getAllTagsWithCount(): { tag: string; count: number }[] {
}
return Array.from(map.entries())
- .map(([tag, count]) => ({ tag, count }))
+ .map(([tag, count]) => ({ tag, slug: getTagSlug(tag), count }))
.sort((a, b) => {
if (b.count === a.count) return a.tag.localeCompare(b.tag);
return b.count - a.count;