归档统计
661 字
3 分钟
归档统计
获取归档列表
文件路径:src/pages/archive.astro
---import { getSortedPostsList } from "@/utils/content-utils"; // [!code --]const sortedPostsList = await getSortedPostsList(); // [!code --]<ArchivePanel sortedPosts={sortedPostsList} client:only="svelte" /> // [!code --]
import { getArchiveList } from "@/utils/content-utils";
// 获取归档列表(posts + moments + bangumi + life)const archiveList = await getArchiveList();
// 计算各类型数量const postsCount = archiveList.filter(item => item.type === "post").length;const momentsCount = archiveList.filter(item => item.type === "moment").length;const bangumiCount = archiveList.filter(item => item.type === "bangumi").length;const lifeCount = archiveList.filter(item => item.type === "life").length;const totalCount = postsCount + momentsCount + bangumiCount + lifeCount;---
<MainGridLayout title={i18n(I18nKey.archive)}> <!-- 统计信息 --> <div class="card-base px-8 py-6 mb-6"> <div class="flex flex-wrap gap-6 justify-center text-center"> <div class="flex flex-col"> <span class="text-3xl font-bold text-amber-500">{postsCount}</span> <span class="text-sm text-30 mt-1">{i18n(I18nKey.postList)}</span> </div> <div class="w-px bg-neutral-200 dark:bg-neutral-700"></div> <div class="flex flex-col"> <span class="text-3xl font-bold text-(--primary)">{momentsCount}</span> <span class="text-sm text-30 mt-1">{i18n(I18nKey.moments)}</span> </div> <div class="w-px bg-neutral-200 dark:bg-neutral-700"></div> <div class="flex flex-col"> <span class="text-3xl font-bold text-red-500 dark:text-red-400">{bangumiCount}</span> <span class="text-sm text-30 mt-1">{i18n(I18nKey.bangumi)}</span> </div> <div class="w-px bg-neutral-200 dark:bg-neutral-700"></div> <div class="flex flex-col"> <span class="text-3xl font-bold text-emerald-600 dark:text-emerald-400">{lifeCount}</span> <span class="text-sm text-30 mt-1">生活</span> </div> <div class="w-px bg-neutral-200 dark:bg-neutral-700"></div> <div class="flex flex-col"> <span class="text-3xl font-bold text-(--primary)">{totalCount}</span> <span class="text-sm text-30 mt-1">总计</span> </div> </div> </div> <ArchivePanel sortedPosts={archiveList} client:only="svelte" /></MainGridLayout>更新内容工具函数文件
文件路径:src/utils/content-utils.ts
---import { getCategoryUrl, getPostUrlBySlug } from "@utils/url-utils";import { getDiaryList } from "@/data/diary"---
export interface ArchiveItem { id: string; type: "post" | "moment" | "bangumi" | "life"; link?: string; data: { title: string; published: Date; tags: string[]; category?: string | null; };}
export async function getArchiveList(): Promise<ArchiveItem[]> { const posts = await getCollection("posts", ({ data }) => { return import.meta.env.PROD ? data.draft !== true : true; }); const diaryList = getDiaryList();
const postItems: ArchiveItem[] = posts.map((post) => ({ id: post.id, type: "post", link: getPostUrlBySlug(post.id), data: { title: post.data.title, published: post.data.published, tags: post.data.tags, category: post.data.category || null, }, }));
// 将日记数据转换为归档项 const momentItems: ArchiveItem[] = diaryList.map((diary) => { let title = diary.content || ""; title = title.replace(/[#*`]/g, "").trim(); if (title.length > 50) title = `${title.substring(0, 50)}...`; if (!title) title = i18n(I18nKey.moments) || "日常动态";
return { id: String(diary.id), type: "moment", link: "/diary/", data: { title: title, published: new Date(diary.date), tags: diary.tags || [], category: null, }, }; });
// 空数组,用于保持接口兼容性 const bangumiItems: ArchiveItem[] = []; const lifeItems: ArchiveItem[] = [];
return [...postItems, ...momentItems, ...bangumiItems, ...lifeItems].sort((a, b) => { const timeA = a.data.published.getTime(); const timeB = b.data.published.getTime(); return timeB - timeA; });}定义类型
文件路径:src/components/controls/ArchivePanel.svelte
interface Post { id: string; type?: "post" | "moment" | "bangumi" | "life"; link?: string; data: { title: string; tags: string[]; category?: string | null; published: Date; };}
{@const postLink = post.link || getPostUrlBySlug(post.id)}<a href={getPostUrlBySlug(post.id)} // [!code --] href={postLink} // [!code ++] aria-label={post.data.title} class="group btn-plain block! h-10 w-full rounded-lg hover:text-[initial]">
<div class="w-[70%] md:max-w-[65%] md:w-[65%] text-left font-bold group-hover:translate-x-1 transition-all group-hover:text-(--primary) text-75 pr-8 whitespace-nowrap text-ellipsis overflow-hidden flex items-center gap-2" > {#if post.type === 'post'} <span class="px-1.5 py-0.5 text-[10px] bg-amber-500 text-white rounded-md shrink-0 uppercase tracking-wider opacity-80 font-normal"> 文章 </span> {:else if post.type === 'moment'} <span class="px-1.5 py-0.5 text-[10px] bg-(--primary) text-white rounded-md shrink-0 uppercase tracking-wider opacity-80 font-normal"> {i18n(I18nKey.moments) || 'Moment'} </span> {:else if post.type === 'bangumi'} <span class="px-1.5 py-0.5 text-[10px] bg-red-500 text-white rounded-md shrink-0 uppercase tracking-wider opacity-80 font-normal"> {i18n(I18nKey.bangumi) || 'Record'} </span> {:else if post.type === 'life'} <span class="px-1.5 py-0.5 text-[10px] bg-emerald-600 text-white rounded-md shrink-0 uppercase tracking-wider opacity-80 font-normal"> 生活 </span> {/if} <span class="truncate">{post.data.title}</span> </div>语言配置
- 文件路径:
src/i18n/i18nKey.ts
moments = "moments",- 文件路径:
src/i18n/languages/en.ts
[Key.moments]: "Dynamic",- 文件路径:
src/i18n/languages/ja.ts
[Key.moments]: "ダイナミック",- 文件路径:
src/i18n/languages/ru.ts
[Key.moments]: "Динамика",- 文件路径:
src/i18n/languages/zh_CN.ts
[Key.moments]: "动态",- 文件路径:
src/i18n/languages/zh_TW.ts
[Key.moments]: "動態",支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!