Skip to content

Commit 91aeedc

Browse files
committed
feat: 🚀 首页完成分类和标签功能
1 parent 2d64377 commit 91aeedc

25 files changed

+254
-95
lines changed

.vscode/settings.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
"Iconify",
6767
"xlink",
6868
"qrcode",
69-
"cascader"
69+
"cascader",
70+
"vitepress"
7071
]
7172
}

docs/@pages/archivesPage.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
archivesPage: true
3+
title: 归档
4+
permalink: /archives/
5+
article: false
6+
---

docs/@pages/categoriesPage.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
categoriesPage: true
3+
title: 分类
4+
permalink: /categories/
5+
article: false
6+
layout: home
7+
---

docs/@pages/tagsPage.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
tagsPage: true
3+
title: 标签
4+
permalink: /tags/
5+
article: false
6+
layout: home
7+
---

plugins/vitepress-plugin-permalink/src/helper.ts

-3
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,7 @@ export const DEFAULT_IGNORE_DIR = [
99
"components",
1010
"assets",
1111
".vitepress",
12-
"@pages",
1312
"node_modules",
14-
".vitepress",
15-
"_posts",
1613
"package.json",
1714
];
1815

plugins/vitepress-plugin-sidebar-resolve/src/helper.ts

-3
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,7 @@ export const DEFAULT_IGNORE_DIR = [
1616
"components",
1717
"assets",
1818
".vitepress",
19-
"@pages",
2019
"node_modules",
21-
".vitepress",
22-
"_posts",
2320
"package.json",
2421
];
2522

plugins/vitepress-plugin-sidebar-resolve/src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ export default function VitePluginVitePressSidebarResolve(option: SidebarOption
3434
const { themeConfig, srcDir } = config.vitepress.site;
3535
option.base = option.base || srcDir || ".";
3636

37+
console.log(option);
38+
3739
// 自动生成结构化侧边栏
3840
const sidebar = createSidebar(option);
3941

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
<script setup lang="ts" name="HomeBanner">
22
import { useDesign } from "../hooks";
33
import { useData } from "vitepress";
4-
import { computed, onMounted, onUnmounted, unref } from "vue";
4+
import { onMounted, onUnmounted, unref } from "vue";
55
import { useTypes } from "../hooks";
66
77
const { getPrefixClass } = useDesign();
88
const prefixClass = getPrefixClass("banner");
99
1010
const { site, frontmatter } = useData();
1111
12-
const title = computed(() => unref(frontmatter).name || unref(site).title || "");
13-
const descArray = computed(() => [...new Set(unref(frontmatter).tk?.description?.filter((v: string) => !!v))]);
12+
const title = unref(frontmatter).name || unref(site).title || "";
13+
const descArray = [...new Set(unref(frontmatter).tk?.description?.filter((v: string) => !!v))];
1414
1515
const { text, shouldAnimate, startTypes, stopTypes } = useTypes(descArray, {
1616
typesInTime: unref(frontmatter).tk?.typesInTime,

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

+35-7
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,53 @@
11
<script setup lang="ts" name="HomeCategoryCard">
22
import { useDesign } from "../hooks";
33
import { postsSymbol } from "../configProvider";
4-
import { inject } from "vue";
4+
import { computed, inject, unref, ref, onMounted, watch } from "vue";
5+
import { isCategoriesPages } from "../configProvider.ts";
6+
import RouteLink from "./RouteLink.vue";
7+
import { useRoute, useData } from "vitepress";
58
69
const { getPrefixClass } = useDesign();
710
const prefixClass = getPrefixClass("category");
811
9-
const posts = inject(postsSymbol);
12+
const { frontmatter } = useData();
13+
const {
14+
groupCards: { categories },
15+
} = inject(postsSymbol);
16+
17+
const categorySize = unref(frontmatter).tk?.categorySize || 5;
18+
const currentCategories = computed(() => (isCategoriesPages() ? categories : categories.slice(0, categorySize)));
19+
20+
const route = useRoute();
21+
const category = ref("");
22+
23+
watch(
24+
route,
25+
() => {
26+
const c = new URL(window.location.href).searchParams.get("category");
27+
if (c != unref(category)) category.value = c;
28+
},
29+
{ immediate: true }
30+
);
1031
</script>
1132

1233
<template>
1334
<div :class="`${prefixClass} card`">
14-
<a title="全部分类" class="title">文章分类</a>
35+
<RouteLink to="/categories" :title="isCategoriesPages() ? '全部分类' : '文章分类'" class="title">
36+
{{ isCategoriesPages() ? "全部分类" : "文章分类" }}
37+
</RouteLink>
1538

1639
<div :class="`${prefixClass}-list`">
17-
<a v-for="(item, index) in posts.groupCards.categories" :key="index" :class="{ active: item.key === category }">
18-
{{ item.name }}
40+
<RouteLink
41+
v-for="(item, index) in currentCategories"
42+
:key="index"
43+
:to="`/categories?category=${encodeURIComponent(item.name)}`"
44+
:class="{ active: item.name === category }"
45+
>
46+
<span>{{ item.name }}</span>
1947
<span>{{ item.length }}</span>
20-
</a>
48+
</RouteLink>
2149

22-
<!-- <a v-if="length !== 'all' && length < posts.groupCards.categories.length" class="more">更多 ...</a> -->
50+
<RouteLink v-if="!isCategoriesPages() && categorySize < categories.length" to="/categories">更多 ...</RouteLink>
2351
</div>
2452
</div>
2553
</template>

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

+4-5
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,17 @@ import { useDesign } from "../hooks";
33
import HomeMyCard from "./HomeMyCard.vue";
44
import HomeCategoryCard from "./HomeCategoryCard.vue";
55
import HomeTagCard from "./HomeTagCard.vue";
6+
import { isHomePages, isCategoriesPages, isTagsPages } from "../configProvider.ts";
67
78
const { getPrefixClass } = useDesign();
89
const prefixClass = getPrefixClass("info");
910
</script>
1011

1112
<template>
1213
<div :class="prefixClass">
13-
<HomeMyCard />
14-
15-
<HomeCategoryCard />
16-
17-
<HomeTagCard />
14+
<HomeMyCard v-if="isHomePages()" />
15+
<HomeCategoryCard v-if="isHomePages() || isCategoriesPages()" />
16+
<HomeTagCard v-if="isHomePages() || isTagsPages()" />
1817
</div>
1918
</template>
2019

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

+1-12
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,14 @@ const prefixClass = getPrefixClass("my");
88
99
const { theme } = useData();
1010
11-
const blogger = computed(() => unref(theme).blogger || {});
11+
const blogger = unref(theme).blogger || {};
1212
</script>
1313

1414
<template>
1515
<div :class="`${prefixClass} card`">
1616
<div :class="`${prefixClass}-avatar`">
1717
<img :src="blogger.avatar" alt="头像" title="我好看吗" />
1818
</div>
19-
<!-- <div :class="`${prefixClass}-icons`" v-if="social && social.icons && social.icons.length">
20-
<a
21-
v-for="(item, index) in social.icons"
22-
:key="index"
23-
:href="item.link"
24-
:title="item.title"
25-
:class="['iconfont', item.iconClass]"
26-
:style="{ width: 100 / social.icons.length + '%' }"
27-
target="_blank"
28-
/>
29-
</div> -->
3019
<div :class="`${prefixClass}-blogger`">
3120
<span class="name">{{ blogger.name }}</span>
3221
<span class="slogan">{{ blogger.slogan }}</span>

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

+14-19
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,18 @@ import { KtContentData } from "../data/post";
66
import { createImageViewer } from "./ImageViewer";
77
import { isArray } from "../helper";
88
import { useData } from "vitepress";
9+
import RouteLink from "./RouteLink.vue";
910
1011
const { getPrefixClass } = useDesign();
1112
const prefixClass = getPrefixClass("post-item");
1213
13-
const props = defineProps<{
14-
post: KtContentData;
15-
}>();
14+
const props = defineProps<{ post: KtContentData }>();
1615
1716
const router = useRouter();
1817
const { frontmatter } = useData();
1918
2019
const postFrontmatter = computed(() => props.post.frontmatter);
21-
22-
const handleGo = () => {
23-
router.push(postFrontmatter.permalink || props.post.url);
24-
};
25-
20+
const postUrl = computed(() => props.post.frontmatter.permalink || props.post.url);
2621
const getImgUrl = (imgUrl: string | string[]) => {
2722
if (isArray(imgUrl)) return imgUrl[0];
2823
return imgUrl;
@@ -42,9 +37,9 @@ const handleViewImg = (imgUrl: string | string[]) => {
4237
<div :class="`${prefixClass}-info`">
4338
<div :class="`${prefixClass}-info__left`">
4439
<!-- 标题 -->
45-
<a class="title" href="javascript:void(0)" @click="handleGo">
40+
<RouteLink class="title" :to="postUrl">
4641
{{ post.title }}
47-
</a>
42+
</RouteLink>
4843

4944
<!-- 描述 -->
5045
<p v-if="postFrontmatter.description" class="description">
@@ -53,35 +48,35 @@ const handleViewImg = (imgUrl: string | string[]) => {
5348

5449
<!-- 文章信息 -->
5550
<div :class="`${prefixClass}-info__left-footer`">
56-
<a
51+
<RouteLink
5752
v-if="post.author?.name"
5853
title="作者"
59-
:href="post.author.link ? post.author.link : 'javaScript:void(0)'"
54+
:to="post.author.link ? post.author.link : 'javaScript:void(0)'"
6055
:target="post.author.link ? '_blank' : '_self'"
6156
class="split"
6257
>
6358
{{ post.author.name }}
64-
</a>
59+
</RouteLink>
6560

66-
<a v-if="post.date" title="创建时间" class="split">{{ post.date }}</a>
61+
<RouteLink v-if="post.date" title="创建时间" class="split">{{ post.date }}</RouteLink>
6762

6863
<span v-if="postFrontmatter.categories?.length" title="分类" class="split">
69-
<a v-for="(category, index) in postFrontmatter.categories" :key="index" class="or">
64+
<RouteLink v-for="(category, index) in postFrontmatter.categories" :key="index" class="or">
7065
{{ category }}
71-
</a>
66+
</RouteLink>
7267
</span>
7368

7469
<span v-if="postFrontmatter.tags?.length" title="标签" class="split">
75-
<a v-for="(tag, index) in postFrontmatter.tags" :key="index" class="or">
70+
<RouteLink v-for="(tag, index) in postFrontmatter.tags" :key="index" class="or">
7671
{{ tag }}
77-
</a>
72+
</RouteLink>
7873
</span>
7974
</div>
8075

8176
<!-- 摘要 -->
8277
<div :class="`${prefixClass}-info__left-excerpt`" v-if="post.excerpt">
8378
<div class="excerpt" v-html="post.excerpt"></div>
84-
<a class="more" :href="post.url" @click="handleGo">阅读全文 ></a>
79+
<RouteLink class="more" :to="postUrl">阅读全文 ></RouteLink>
8580
</div>
8681
</div>
8782

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

+52-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
<script setup lang="ts" name="HomePostList">
2-
import { computed, inject, reactive, unref } from "vue";
2+
import { computed, inject, reactive, unref, ref, watch } from "vue";
33
import HomePostItem from "./HomePostItem.vue";
44
import { postsSymbol } from "../configProvider";
55
import Pagination from "./Pagination.vue";
6-
import { useData } from "vitepress";
6+
import { useData, useRoute } from "vitepress";
77
import { useDesign } from "../hooks";
8+
import { isHomePages, isCategoriesPages, isTagsPages } from "../configProvider.ts";
89
910
const { getPrefixClass } = useDesign();
1011
const prefixClass = getPrefixClass("post-list");
@@ -16,15 +17,60 @@ const pageInfo = reactive({
1617
pageNum: 1,
1718
pageSizes: [10, 20, 50, 100, 200],
1819
pageSize: unref(frontmatter).tk?.page?.pageSize || 10,
19-
total: posts.sortPostsByDateAndSticky?.length || 0,
20+
total: 0,
2021
});
2122
22-
const pageOptions = computed(() => ({ size: "small", ...unref(frontmatter).tk?.page }));
23+
const pageOptions = { size: "small", ...unref(frontmatter).tk?.page };
24+
25+
const route = useRoute();
26+
const category = ref("");
27+
const tag = ref("");
28+
29+
watch(
30+
route,
31+
() => {
32+
const { searchParams } = new URL(window.location.href);
33+
34+
const pageNum = searchParams.get("pageNum") || 1;
35+
if (pageNum !== pageInfo.pageNum) pageInfo.pageNum = pageNum;
36+
37+
const {
38+
data: { frontmatter },
39+
} = route;
40+
41+
if (frontmatter.categoriesPage || frontmatter.layout === "home") {
42+
const c = searchParams.get("category") || "";
43+
if (c !== unref(category)) category.value = c;
44+
}
45+
46+
if (frontmatter.tagsPages || frontmatter.layout === "home") {
47+
const t = searchParams.get("tag") || "";
48+
if (t !== unref(tag)) tag.value = t;
49+
}
50+
},
51+
{ immediate: true }
52+
);
2353
2454
const currentPosts = computed(() => {
2555
const { pageNum, pageSize } = pageInfo;
26-
return posts.sortPostsByDateAndSticky.slice((pageNum - 1) * pageSize, pageNum * pageSize);
56+
57+
let post = posts.sortPostsByDateAndSticky;
58+
if (unref(category)) post = posts.groupPosts.categories[unref(category)];
59+
else if (unref(tag)) post = posts.groupPosts.tags[unref(tag)];
60+
61+
pageInfo.total = post.length;
62+
63+
return post.slice((pageNum - 1) * pageSize, pageNum * pageSize);
2764
});
65+
66+
const pageNumKey = "pageNum";
67+
const handlePagination = () => {
68+
const { searchParams } = new URL(window.location.href!);
69+
searchParams.delete(pageNumKey);
70+
searchParams.append(pageNumKey, String(pageInfo.pageNum));
71+
72+
window.history.pushState({}, "", `${window.location.pathname}?${searchParams.toString()}`);
73+
};
2874
</script>
2975

3076
<template>
@@ -40,6 +86,7 @@ const currentPosts = computed(() => {
4086
v-if="posts.sortPostsByDateAndSticky?.length >= pageInfo.pageSize"
4187
v-model="pageInfo"
4288
v-bind="pageOptions"
89+
@pagination="handlePagination"
4390
/>
4491
</div>
4592
</ClientOnly>

0 commit comments

Comments
 (0)