Skip to content

Commit 38985aa

Browse files
committed
feat: 🚀 添加归档页面
1 parent e9618a8 commit 38985aa

23 files changed

+346
-34
lines changed

docs/.vitepress/config.mts

+1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ export default defineConfig({
7676
{ text: "指南", link: "/01.指南/" },
7777
{ text: "设计", link: "/05.设计/01.设计 - 思路/01.设计 - 思路设计" },
7878
{ text: "API", link: "/07.API/01.登录 API" },
79+
{ text: "归档", link: "/archives" },
7980
],
8081
socialLinks: [{ icon: "github", link: "https://github.com/Kele-Bingtang/hd-security" }],
8182

docs/@pages/archivesPage.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ archivesPage: true
33
title: 归档
44
permalink: /archives/
55
article: false
6-
---
6+
layout: page
7+
---
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<script setup lang="ts" name="ArchivesPage">
2+
import { useDesign } from "../hooks";
3+
import { useData } from "vitepress";
4+
import { postsSymbol } from "../configProvider";
5+
import { inject } from "vue";
6+
import RouteLink from "./RouteLink.vue";
7+
import { KtContentData } from "../data/post";
8+
9+
const { getPrefixClass } = useDesign();
10+
const prefixClass = getPrefixClass("archives");
11+
12+
const { frontmatter } = useData();
13+
14+
const posts = inject(postsSymbol);
15+
16+
const getDate = (item: KtContentData) => {
17+
const {
18+
frontmatter: { date },
19+
} = item;
20+
21+
if (date) return date.slice(5, 10);
22+
};
23+
</script>
24+
25+
<template>
26+
<div :class="`${prefixClass} tk-page`">
27+
<div :class="`${prefixClass}-header flx-justify-between`">
28+
<div class="title">{{ frontmatter.title }}</div>
29+
<div class="count">总共 {{ posts.sortPostsByDate.length }} 篇文章</div>
30+
</div>
31+
32+
<div :class="`${prefixClass}-timeline`">
33+
<template v-for="(monthPosts, year) in posts.groupPostsByYearMonth" :key="year">
34+
<div :class="`${prefixClass}-timeline__year flx-justify-between`">
35+
<div class="year">{{ String(year) === "NaN" ? "未指定" : year }} 年</div>
36+
<div class="count">{{ posts.groupPostsByYear[year].length }}篇</div>
37+
</div>
38+
39+
<div :class="`${prefixClass}-timeline-m`">
40+
<template v-for="(posts, month) in monthPosts" :key="month">
41+
<div :class="`${prefixClass}-timeline-m__month flx-justify-between`">
42+
<div class="month">{{ String(month) === "NaN" ? "未指定" : month }} 月</div>
43+
<div class="count">{{ posts.length }}篇</div>
44+
</div>
45+
46+
<ul>
47+
<li v-for="item in posts" :key="item.title">
48+
<RouteLink :to="item.frontmatter.permalink || item.url">
49+
<span class="date">{{ getDate(item) }}</span>
50+
<span>{{ item.title }}</span>
51+
</RouteLink>
52+
</li>
53+
</ul>
54+
</template>
55+
</div>
56+
</template>
57+
</div>
58+
</div>
59+
</template>
60+
61+
<style lang="scss" scoped>
62+
@use "../styles/components/archivesPage.scss";
63+
</style>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<script setup lang="ts" name="FriendLinkCard">
2+
import { useDesign } from "../hooks";
3+
4+
const { getPrefixClass } = useDesign();
5+
const prefixClass = getPrefixClass("friendLink");
6+
</script>
7+
8+
<template>
9+
<div :class="prefixClass"></div>
10+
</template>
11+
12+
<style lang="scss" scoped>
13+
@use "../styles/components/friendLinkCard.scss";
14+
</style>

vitepress-theme-tk/src/components/HomeMyCard.vue

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
<script setup lang="ts" name="HomeMyCard">
22
import { useDesign } from "../hooks";
3-
import { useData } from "vitepress";
4-
import { unref } from "vue";
3+
import { useThemeConfig } from "../configProvider";
54
65
const { getPrefixClass } = useDesign();
76
const prefixClass = getPrefixClass("my");
87
9-
const { theme } = useData();
10-
11-
const blogger = unref(theme).blogger || {};
8+
const blogger = useThemeConfig().blogger || {};
129
</script>
1310

1411
<template>

vitepress-theme-tk/src/components/HomePostItem.vue

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<script setup lang="ts" name="HomePostItem">
22
import { computed, unref } from "vue";
33
import { useDesign } from "../hooks";
4-
import { useRouter, useData } from "vitepress";
4+
import { useData } from "vitepress";
55
import { KtContentData } from "../data/post";
66
import { createImageViewer } from "./ImageViewer";
77
import { isArray } from "../helper";
@@ -12,7 +12,6 @@ const prefixClass = getPrefixClass("post-item");
1212
1313
const props = defineProps<{ post: KtContentData }>();
1414
15-
const router = useRouter();
1615
const { frontmatter } = useData();
1716
1817
const postFrontmatter = computed(() => props.post.frontmatter);

vitepress-theme-tk/src/components/HomePostList.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script setup lang="ts" name="HomePostList">
2-
import { computed, inject, reactive, ref, toRaw, unref, watch } from "vue";
2+
import { inject, reactive, ref, unref, watch } from "vue";
33
import HomePostItem from "./HomePostItem.vue";
44
import { postsSymbol } from "../configProvider";
55
import Pagination from "./Pagination.vue";

vitepress-theme-tk/src/components/HomeTagCard.vue

+8-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,14 @@ watch(
3232
{ immediate: true }
3333
);
3434
35-
const tagBgColor = ["#11a8cd", "#F8B26A", "#67CC86", "#E15B64", "#F47E60", "#849B87"];
35+
const tagBgColor = unref(frontmatter).tk?.tagBgColor || [
36+
"#11a8cd",
37+
"#F8B26A",
38+
"#67CC86",
39+
"#E15B64",
40+
"#F47E60",
41+
"#849B87",
42+
];
3643
3744
const getTagBgColor = (index: number) => {
3845
return tagBgColor[index % tagBgColor.length];

vitepress-theme-tk/src/components/RouteLink.vue

+3-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ const handleGo = (e: MouseEvent) => {
1818
// 避免重复跳转
1919
const currentPath = `${decodeURIComponent(pathname)}${search}${decodeURIComponent(hash)}`;
2020
21-
if (to !== undefined && to !== currentPath) router.push(to);
21+
if (to !== undefined && to !== currentPath) {
22+
router.push(to);
23+
}
2224
};
2325
</script>
2426

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<script setup lang="ts" name="SiteInfoCard">
2+
import { useDesign } from "../hooks";
3+
4+
const { getPrefixClass } = useDesign();
5+
const prefixClass = getPrefixClass("siteInfo");
6+
</script>
7+
8+
<template>
9+
<div :class="prefixClass"></div>
10+
</template>
11+
12+
<style lang="scss" scoped>
13+
@use "../styles/components/siteInfoCard.scss";
14+
</style>

vitepress-theme-tk/src/configProvider.ts

+4
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,7 @@ export const isTagsPage = () => {
4747
const { frontmatter } = useData();
4848
return unref(frontmatter).tagsPage;
4949
};
50+
export const isArchivesPage = () => {
51+
const { frontmatter } = useData();
52+
return unref(frontmatter).archivesPage;
53+
};

vitepress-theme-tk/src/data/post.ts

+8
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ export interface Post {
2929
* 根据日期排序的文章列表
3030
*/
3131
sortPostsByDate: KtContentData[];
32+
/**
33+
* 根据年份分组,key 为年份,value 为该年份的文章列表,如 { 2025: [{}, {}], 2024: [{}, {}] }
34+
*/
35+
groupPostsByYear: Record<number, KtContentData[]>;
36+
/**
37+
* 根据年份和月份分组,key 为年份,value 为该年份的月份分组,如:{ 2025: { 01: [{}, {}], 02: [{}, {}] }, 2024: { 01: [], 02: [{}, {}] } }
38+
*/
39+
groupPostsByYearMonth: Record<number, Record<number, KtContentData[]>>;
3240
/**
3341
* 分组的文章列表
3442
*/

vitepress-theme-tk/src/data/posts.data.ts

+7
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import {
66
getSortPostsByDate,
77
getGroupPosts,
88
getGroupCards,
9+
groupByYear,
10+
groupByYearMonth,
911
} from "../helper/post";
1012
import { formatDate } from "../helper/date";
1113
import { KtThemeConfig } from "../config/types";
@@ -38,13 +40,18 @@ export default createContentLoader("**/*.md", {
3840
const originPosts = filterPosts(posts);
3941
const sortPostsByDateAndSticky = getSortPostsByDateAndSticky(originPosts);
4042
const sortPostsByDate = getSortPostsByDate(originPosts);
43+
const groupPostsByYear = groupByYear(sortPostsByDate);
44+
const groupPostsByYearMonth = groupByYearMonth(sortPostsByDate);
45+
4146
const groupPosts = getGroupPosts(sortPostsByDateAndSticky);
4247
const groupCards = getGroupCards(groupPosts);
4348

4449
return {
4550
originPosts,
4651
sortPostsByDateAndSticky,
4752
sortPostsByDate,
53+
groupPostsByYear,
54+
groupPostsByYearMonth,
4855
groupPosts,
4956
groupCards,
5057
};

vitepress-theme-tk/src/helper/post.ts

+36
Original file line numberDiff line numberDiff line change
@@ -112,3 +112,39 @@ export const getPostsTime = (post: KtContentData): number => {
112112
export const compareDate = (prev: KtContentData, next: KtContentData) => {
113113
return getPostsTime(next) - getPostsTime(prev);
114114
};
115+
116+
/**
117+
* 根据年份分组,key 为年份,value 为该年份的文章列表,如 { 2025: [{}, {}], 2024: [{}, {}] }
118+
* @param posts 文章列表
119+
*/
120+
export const groupByYear = (posts: KtContentData[]) => {
121+
return posts.reduce(
122+
(pre, cur) => {
123+
const year = new Date(cur.frontmatter.date).getFullYear();
124+
if (!pre[year]) pre[year] = [];
125+
126+
pre[year].push(cur);
127+
return pre;
128+
},
129+
{} as Record<number, KtContentData[]>
130+
);
131+
};
132+
/**
133+
* 根据年份和月份分组,key 为年份,value 为该年份的月份分组,如:{ 2025: { 01: [{}, {}], 02: [{}, {}] }, 2024: { 01: [], 02: [{}, {}] } }
134+
* @param posts 文章列表
135+
*/
136+
export const groupByYearMonth = (posts: KtContentData[]) => {
137+
return posts.reduce(
138+
(pre, cur) => {
139+
const date = new Date(cur.frontmatter.date);
140+
const year = date.getFullYear();
141+
const month = Number(String(date.getMonth() + 1).padStart(2, "0"));
142+
if (!pre[year]) pre[year] = {};
143+
if (!pre[year][month]) pre[year][month] = [];
144+
145+
pre[year][month].push(cur);
146+
return pre;
147+
},
148+
{} as Record<number, Record<number, KtContentData[]>>
149+
);
150+
};

vitepress-theme-tk/src/hooks/usePermalinks.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ export function usePermalinks() {
2828
if (permalink === decodePath) return router.go(href);
2929

3030
if (!permalink) {
31-
// 如果 permalink 不存在,则根据 permalink 找 pathname
32-
const path = permalinks.inv[pathname];
31+
// 如果 permalink 不存在,则根据 decodePath 找 pathname
32+
const path = permalinks.inv[decodePath];
3333

3434
// 如果 path 存在,则进行更新
3535
if (path) {
@@ -68,7 +68,7 @@ export function usePermalinks() {
6868
await nextTick();
6969
history.replaceState(history.state || null, "", `${permalink}${search}${decodeHash}`);
7070
} else {
71-
// 不存在 permalink 则跳转
71+
// 第二点,不存在 permalink 则获取文档地址来跳转
7272
const path = permalinks.inv[`/${decodePath}`];
7373
if (path) return router.push(`${path}${search}${decodeHash}`);
7474
}

vitepress-theme-tk/src/layout/index.vue

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,22 @@
11
<script setup lang="ts">
2-
import { useData } from "vitepress";
32
import DefaultTheme from "vitepress/theme";
4-
import { computed, unref } from "vue";
53
import { useDesign } from "../hooks";
64
import HomeBanner from "../components/HomeBanner.vue";
75
import HomePostList from "../components/HomePostList.vue";
86
import HomeInfo from "../components/HomeInfo.vue";
9-
import { isHomePage, isCategoriesPage, isTagsPage } from "../configProvider.ts";
7+
import ArchivesPage from "../components/ArchivesPage.vue";
8+
import { isHomePage, useThemeConfig, isArchivesPage } from "../configProvider";
109
1110
defineOptions({
1211
name: "TkLayout",
1312
});
1413
15-
const { theme } = useData();
1614
const { Layout } = DefaultTheme;
1715
1816
const { getPrefixClass } = useDesign();
1917
const prefixClass = getPrefixClass("layout");
2018
21-
const useKtTheme = unref(theme).ktTheme ?? true;
19+
const useKtTheme = useThemeConfig().ktTheme ?? true;
2220
</script>
2321

2422
<template>
@@ -80,6 +78,7 @@ const useKtTheme = unref(theme).ktTheme ?? true;
8078
<!-- content -->
8179
<template #page-top>
8280
<slot name="page-top" />
81+
<ArchivesPage v-if="isArchivesPage()" />
8382
</template>
8483
<template #page-bottom>
8584
<slot name="page-bottom" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
@use "../namespace.scss" as *;
2+
3+
$prefix-class: #{$theme-namespace}-archives;
4+
5+
.#{$prefix-class} {
6+
.count {
7+
font-size: 0.85rem;
8+
opacity: 0.8;
9+
font-weight: 300;
10+
font-style: oblique;
11+
}
12+
13+
&-header {
14+
.title {
15+
font-size: 2rem;
16+
font-weight: 600;
17+
}
18+
19+
.count {
20+
font-style: normal;
21+
}
22+
}
23+
24+
&-timeline {
25+
margin-top: 2rem;
26+
&__year {
27+
border-bottom: 1px solid var(--tk-gray-lower);
28+
.year {
29+
padding: 0.5rem 0;
30+
font-size: 1.5rem;
31+
}
32+
}
33+
34+
&-m {
35+
margin-top: 1rem;
36+
&__month {
37+
border-bottom: 1px solid var(--tk-gray-lower);
38+
.month {
39+
padding-bottom: 0.5rem;
40+
font-size: 1.2rem;
41+
}
42+
}
43+
44+
ul {
45+
padding: 0.5rem 1rem;
46+
li {
47+
line-height: 2;
48+
a {
49+
display: block;
50+
transition: padding 0.3s;
51+
&:hover {
52+
padding-left: 1rem;
53+
color: var(--tk-theme-color);
54+
background: var(--tk-lower-hover);
55+
}
56+
57+
.date {
58+
opacity: 0.6;
59+
font-size: 0.85rem;
60+
margin-right: 0.3rem;
61+
}
62+
}
63+
}
64+
}
65+
}
66+
}
67+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@use "../namespace.scss" as *;
2+
3+
$prefix-class: #{$theme-namespace}-friendLink;
4+
5+
.#{$prefix-class} {
6+
}

0 commit comments

Comments
 (0)