From 2d89e4d53fd3cd47490f0370a3a51c85eb930d09 Mon Sep 17 00:00:00 2001 From: "saica.go" Date: Fri, 30 May 2025 00:21:07 +0800 Subject: [PATCH] feat: make archive page dynamic (#469) --- src/components/ArchivePanel.svelte | 149 ++++++++++++++++++ src/components/PostMeta.astro | 6 +- src/components/widget/Categories.astro | 2 +- src/components/widget/Tags.astro | 2 +- src/content/posts/cjk-test.md | 12 -- src/pages/archive.astro | 14 ++ src/pages/archive/category/[category].astro | 45 ------ .../archive/category/uncategorized.astro | 11 -- src/pages/archive/index.astro | 11 -- src/pages/archive/tag/[tag].astro | 64 -------- src/utils/encoding-utils.ts | 32 ---- src/utils/url-utils.ts | 25 +-- 12 files changed, 172 insertions(+), 201 deletions(-) create mode 100644 src/components/ArchivePanel.svelte delete mode 100644 src/content/posts/cjk-test.md create mode 100644 src/pages/archive.astro delete mode 100644 src/pages/archive/category/[category].astro delete mode 100644 src/pages/archive/category/uncategorized.astro delete mode 100644 src/pages/archive/index.astro delete mode 100644 src/pages/archive/tag/[tag].astro delete mode 100644 src/utils/encoding-utils.ts diff --git a/src/components/ArchivePanel.svelte b/src/components/ArchivePanel.svelte new file mode 100644 index 00000000..dca69f94 --- /dev/null +++ b/src/components/ArchivePanel.svelte @@ -0,0 +1,149 @@ + + +
+ {#each groups as group} +
+
+
+ {group.year} +
+
+
+
+
+ {group.posts.length} {i18n(I18nKey.postsCount)} +
+
+ + {#each group.posts as post} + +
+ +
+ {formatDate(post.data.published)} +
+ + +
+
+
+ + +
+ {post.data.title} +
+ + + +
+
+ {/each} +
+ {/each} +
diff --git a/src/components/PostMeta.astro b/src/components/PostMeta.astro index 0a67979b..4832d4d7 100644 --- a/src/components/PostMeta.astro +++ b/src/components/PostMeta.astro @@ -3,7 +3,7 @@ import { Icon } from "astro-icon/components"; import I18nKey from "../i18n/i18nKey"; import { i18n } from "../i18n/translation"; import { formatDateToYYYYMMDD } from "../utils/date-utils"; -import { url, getTagUrl } from "../utils/url-utils"; +import { getCategoryUrl, getTagUrl } from "../utils/url-utils"; interface Props { class: string; @@ -53,7 +53,7 @@ const className = Astro.props.class;
- {category || i18n(I18nKey.uncategorized)} @@ -70,7 +70,7 @@ const className = Astro.props.class;
{(tags && tags.length > 0) && tags.map((tag, i) => (
/
-
{tag.trim()} diff --git a/src/components/widget/Categories.astro b/src/components/widget/Categories.astro index db67c0e1..739d975a 100644 --- a/src/components/widget/Categories.astro +++ b/src/components/widget/Categories.astro @@ -27,7 +27,7 @@ const style = Astro.props.style; > {categories.map((c) => diff --git a/src/components/widget/Tags.astro b/src/components/widget/Tags.astro index 3ead19db..5ed0b62b 100644 --- a/src/components/widget/Tags.astro +++ b/src/components/widget/Tags.astro @@ -23,7 +23,7 @@ const style = Astro.props.style;
{tags.map(t => ( - + {t.name.trim()} ))} diff --git a/src/content/posts/cjk-test.md b/src/content/posts/cjk-test.md deleted file mode 100644 index 53d3bb51..00000000 --- a/src/content/posts/cjk-test.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: CJK edge case for test -published: 2025-05-04 -updated: 2025-05-04 -description: 'CJK Test' -image: '' -tags: [C#, テスト, 技术, Fuwari] -category: '技术' -draft: true ---- - -CJK Test \ No newline at end of file diff --git a/src/pages/archive.astro b/src/pages/archive.astro new file mode 100644 index 00000000..52ced049 --- /dev/null +++ b/src/pages/archive.astro @@ -0,0 +1,14 @@ +--- +import ArchivePanel from "@components/ArchivePanel.svelte"; +import I18nKey from "@i18n/i18nKey"; +import { i18n } from "@i18n/translation"; +import MainGridLayout from "@layouts/MainGridLayout.astro"; +import { getSortedPosts } from "../utils/content-utils"; + +const sortedPosts = await getSortedPosts(); +--- + + + + + diff --git a/src/pages/archive/category/[category].astro b/src/pages/archive/category/[category].astro deleted file mode 100644 index c31673dd..00000000 --- a/src/pages/archive/category/[category].astro +++ /dev/null @@ -1,45 +0,0 @@ ---- -import ArchivePanel from "@components/ArchivePanel.astro"; -import I18nKey from "@i18n/i18nKey"; -import { i18n } from "@i18n/translation"; -import MainGridLayout from "@layouts/MainGridLayout.astro"; -import { getCategoryList } from "@utils/content-utils"; - -export async function getStaticPaths() { - const categories = await getCategoryList(); - - const standardPaths = categories.map((category) => { - return { - params: { - category: encodeURIComponent(category.name.trim()), - }, - props: { - decodedCategory: category.name.trim(), - }, - }; - }); - - const nonEncodedCJKPaths = categories - .filter((category) => - /[\u3000-\u9fff\uac00-\ud7af\u4e00-\u9faf]/.test(category.name), - ) - .map((category) => ({ - params: { - category: category.name.trim(), // Do not encode CJK characters - }, - props: { - decodedCategory: category.name.trim(), - }, - })); - - return [...standardPaths, ...nonEncodedCJKPaths]; -} - -const { decodedCategory } = Astro.props; -const category = - decodedCategory || decodeURIComponent(Astro.params.category as string); ---- - - - - diff --git a/src/pages/archive/category/uncategorized.astro b/src/pages/archive/category/uncategorized.astro deleted file mode 100644 index 2ba29aae..00000000 --- a/src/pages/archive/category/uncategorized.astro +++ /dev/null @@ -1,11 +0,0 @@ ---- -import ArchivePanel from "@components/ArchivePanel.astro"; -import { UNCATEGORIZED } from "@constants/constants"; -import I18nKey from "@i18n/i18nKey"; -import { i18n } from "@i18n/translation"; -import MainGridLayout from "@layouts/MainGridLayout.astro"; ---- - - - - diff --git a/src/pages/archive/index.astro b/src/pages/archive/index.astro deleted file mode 100644 index 20760598..00000000 --- a/src/pages/archive/index.astro +++ /dev/null @@ -1,11 +0,0 @@ ---- -import ArchivePanel from "@components/ArchivePanel.astro"; -import I18nKey from "@i18n/i18nKey"; -import { i18n } from "@i18n/translation"; -import MainGridLayout from "@layouts/MainGridLayout.astro"; ---- - - - - - diff --git a/src/pages/archive/tag/[tag].astro b/src/pages/archive/tag/[tag].astro deleted file mode 100644 index 34eedd13..00000000 --- a/src/pages/archive/tag/[tag].astro +++ /dev/null @@ -1,64 +0,0 @@ ---- -import ArchivePanel from "@components/ArchivePanel.astro"; -import I18nKey from "@i18n/i18nKey"; -import { i18n } from "@i18n/translation"; -import MainGridLayout from "@layouts/MainGridLayout.astro"; -import { getSortedPosts } from "@utils/content-utils"; -import { decodePathSegment, encodePathSegment } from "@utils/encoding-utils"; - -export async function getStaticPaths() { - const posts = await getSortedPosts(); - - const allTags = posts.reduce>((acc, post) => { - if (Array.isArray(post.data.tags)) { - // biome-ignore lint/complexity/noForEach: - post.data.tags.forEach((tag) => { - if (typeof tag === "string") { - acc.add(tag.trim()); - } else { - acc.add(String(tag).trim()); - } - }); - } else if (post.data.tags && typeof post.data.tags === "string") { - // biome-ignore lint/complexity/noForEach: - (post.data.tags as string) - .split(",") - .forEach((tag) => acc.add(tag.trim())); - } - return acc; - }, new Set()); - - const allTagsArray = Array.from(allTags); - - // judge if the string is CJK - const isCJK = (str: string) => - /[\u3000-\u9fff\uac00-\ud7af\u4e00-\u9faf]/.test(str); - - const standardPaths = allTagsArray.map((tag) => ({ - params: { - tag: encodePathSegment(tag), - }, - props: { - decodedTag: tag, - }, - })); - - const nonEncodedCJKPaths = allTagsArray.filter(isCJK).map((tag) => ({ - params: { - tag: tag, // keep CJK characters unencoded - }, - props: { - decodedTag: tag, - }, - })); - - return [...standardPaths, ...nonEncodedCJKPaths]; -} - -const { decodedTag } = Astro.props; -const tag = decodedTag || decodePathSegment(Astro.params.tag as string); ---- - - - - diff --git a/src/utils/encoding-utils.ts b/src/utils/encoding-utils.ts deleted file mode 100644 index 1e3a1599..00000000 --- a/src/utils/encoding-utils.ts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Utility functions for ensuring consistent URL encoding - */ - -/** - * Ensure consistent URL encoding across all tags and categories - * - * @param value The string to encode - * @returns The encoded string - */ -export function encodePathSegment(value: string): string { - if (!value) return ""; - - return encodeURIComponent(value.trim()); -} - -/** - * Decode from the URL path - * - * @param value String to decode - * @returns Decoded string - */ -export function decodePathSegment(value: string): string { - if (!value) return ""; - - try { - return decodeURIComponent(value); - } catch (e) { - console.error(`Failed to decode path segment: ${value}`, e); - return value; - } -} diff --git a/src/utils/url-utils.ts b/src/utils/url-utils.ts index 583c5cb8..a7512900 100644 --- a/src/utils/url-utils.ts +++ b/src/utils/url-utils.ts @@ -1,7 +1,3 @@ -import i18nKey from "@i18n/i18nKey"; -import { i18n } from "@i18n/translation"; -import { encodePathSegment } from "./encoding-utils"; - export function pathsEqual(path1: string, path2: string) { const normalizedPath1 = path1.replace(/^\/|\/$/g, "").toLowerCase(); const normalizedPath2 = path2.replace(/^\/|\/$/g, "").toLowerCase(); @@ -18,26 +14,13 @@ export function getPostUrlBySlug(slug: string): string { } export function getTagUrl(tag: string): string { - if (!tag) return url("/archive/tag/"); - - // use common encoding function - const encodedTag = encodePathSegment(tag); - const tagUrl = `/archive/tag/${encodedTag}/`; - console.log(`Generating URL for tag "${tag.trim()}" => "${tagUrl}"`); - return url(tagUrl); + if (!tag) return url("/archive/"); + return url(`/archive/?tag=${encodeURIComponent(tag.trim())}`); } export function getCategoryUrl(category: string): string { - console.log(`category: ${category}`); - if (!category) return url("/archive/category/"); - - const trimmedCategory = category.trim(); - if (trimmedCategory === i18n(i18nKey.uncategorized)) - return url("/archive/category/uncategorized/"); - - return url( - `/archive/category/${encodeURIComponent(trimmedCategory).replace(/%20/g, "+")}/`, - ); + if (!category) return url("/archive/"); + return url(`/archive/?category=${encodeURIComponent(category.trim())}`); } export function getDir(path: string): string {