Skip to content

Commit da0687c

Browse files
committed
feat: 🚀 新增 Banner 3 个风格切换,优化部分代码和样式,修复部分问题
1 parent 65a1af8 commit da0687c

34 files changed

+389
-135
lines changed

docs/.vitepress/config.mts

+4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ const tkConfig = themeConfig({
2020
siteIteration: 2500,
2121
pageIteration: 2500,
2222
},
23+
banner: {
24+
bgStyle: "bigImg",
25+
bigImgSrc: "/img/girl.png",
26+
},
2327
});
2428

2529
// https://vitepress.dev/reference/site-config

docs/index.md

+13
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,19 @@
33
layout: home
44

55
tk:
6+
features:
7+
- title: 指南
8+
description: Hd Security 使用指南说明
9+
link: /01.指南/
10+
imgUrl: /img/web.png
11+
- title: 设计
12+
description: Hd Security 设计思路说明
13+
link: /design/
14+
imgUrl: /img/ui.png
15+
- title: API
16+
description: Hd Security 所有的 API 介绍
17+
link: /07.API/01.登录 API/
18+
imgUrl: /img/other.png
619
description:
720
- 故事由我书写,旅程由你见证,传奇由她聆听 —— 来自 Young Kbt
821
- 积跬步以至千里,致敬每个爱学习的你 —— 来自 Evan Xu

docs/public/img/girl.png

7.08 MB
Loading

docs/public/img/logo.png

5.36 KB
Loading

docs/public/img/more.png

40.4 KB
Loading

docs/public/img/other.png

32.2 KB
Loading

docs/public/img/ui.png

23.6 KB
Loading

docs/public/img/web.png

37.9 KB
Loading

plugins/vitepress-plugin-doc-analysis/src/helper.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export const log = (message: string, type = "yellow") => {
88
};
99

1010
// 默认忽略的文件夹列表
11-
export const DEFAULT_IGNORE_DIR = [".vitepress", "node_modules"];
11+
export const DEFAULT_IGNORE_DIR = [".vitepress", "node_modules", "public"];
1212

1313
export default (option: SiteInfoOption = {}) => {
1414
const { base = process.cwd() } = option;

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import matter from "gray-matter";
44
import type { PermalinkOption } from "./types";
55

66
// 默认忽略的文件夹列表
7-
export const DEFAULT_IGNORE_DIR = ["scripts", "components", "assets", ".vitepress", "node_modules", "package.json"];
7+
export const DEFAULT_IGNORE_DIR = ["scripts", "components", "assets", ".vitepress", "node_modules", "package.json", "public"];
88

99
// key 为文件路径,value 为永久链接
1010
let permalinks: Record<string, string> = {};

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export const log = (message: string, type = "yellow") => {
1111
};
1212

1313
// 默认忽略的文件夹列表
14-
export const DEFAULT_IGNORE_DIR = ["scripts", "components", "assets", ".vitepress", "node_modules", "package.json"];
14+
export const DEFAULT_IGNORE_DIR = ["scripts", "components", "assets", ".vitepress", "node_modules", "package.json", "public"];
1515

1616
/**
1717
* 生成侧边栏数据

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

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
<script setup lang="ts" name="ArchivesPage">
22
import { useDesign } from "../hooks";
3-
import { useData } from "vitepress";
4-
import { postsSymbol } from "../configProvider";
3+
import { postsSymbol, useUnrefData } from "../configProvider";
54
import { inject } from "vue";
65
import { KtContentData } from "../data/types";
76
87
const { getPrefixClass } = useDesign();
98
const prefixClass = getPrefixClass("archives");
109
11-
const { frontmatter } = useData();
10+
const { frontmatter } = useUnrefData();
1211
1312
const posts = inject(postsSymbol);
1413

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

+12-13
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,25 @@
11
<script setup lang="ts" name="ArticleAnalyze">
2-
import { useData, useRoute } from "vitepress";
2+
import { useRoute } from "vitepress";
33
import { useDesign, useBuSunZi } from "../hooks";
44
import { ElBreadcrumb, ElBreadcrumbItem, ElIcon } from "element-plus";
55
import { computed, ref, unref } from "vue";
66
import { formatDate } from "../helper";
77
import { House, User, Calendar, FolderOpened, CollectionTag, Reading, Clock, View } from "@element-plus/icons-vue";
8-
import { useThemeConfig } from "../configProvider";
8+
import { useUnrefData } from "../configProvider";
99
import { FileWords } from "vitepress-plugin-doc-analysis";
1010
1111
const { getPrefixClass } = useDesign();
1212
const prefixClass = getPrefixClass("articleAnalyze");
1313
14-
const { page, frontmatter } = useData();
15-
const themeConfig = useThemeConfig();
14+
const { theme, frontmatter, page } = useUnrefData();
1615
17-
const author = unref(frontmatter).author || themeConfig.author;
18-
const date = formatDate(unref(frontmatter).date || new Date(), "yyyy-MM-dd");
19-
const categories = unref(frontmatter).categories || [];
20-
const tags = unref(frontmatter).tags || [];
16+
const author = frontmatter.author || theme.author;
17+
const date = formatDate(frontmatter.date || new Date(), "yyyy-MM-dd");
18+
const categories = frontmatter.categories || [];
19+
const tags = frontmatter.tags || [];
2120
// 文章阅读量
22-
const { eachFileWords } = themeConfig.docAnalysisInfo || {};
23-
const { pageView = true, wordsCount = true, readingTime = true, pageIteration } = themeConfig.docAnalysis || {};
21+
const { eachFileWords } = theme.docAnalysisInfo || {};
22+
const { pageView = true, wordsCount = true, readingTime = true, pageIteration } = theme.docAnalysis || {};
2423
2524
const pageViewInfo = computed(() => {
2625
let pageViewInfo: Partial<FileWords> = {};
@@ -32,8 +31,8 @@ const pageViewInfo = computed(() => {
3231
});
3332
3433
// 面包屑
35-
const breadcrumb = unref(frontmatter).breadcrumb || themeConfig.breadcrumb || { enabled: true, showCurrentName: false };
36-
const relativePathArr = unref(page).relativePath.split("/") as string[];
34+
const breadcrumb = frontmatter.breadcrumb || theme.breadcrumb || { enabled: true, showCurrentName: false };
35+
const relativePathArr = page.relativePath.split("/") as string[];
3736
const classifyList = ref<string[]>([]);
3837
3938
relativePathArr.forEach((item, index) => {
@@ -46,7 +45,7 @@ relativePathArr.forEach((item, index) => {
4645
});
4746
4847
const getFilePath = (index: number) => {
49-
return themeConfig.catalogues?.inv[relativePathArr[index]];
48+
return theme.catalogues?.inv[relativePathArr[index]];
5049
};
5150
5251
const { pagePv, isGet } = useBuSunZi(pageIteration);

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ defineProps<{ item: DefaultTheme.SidebarMulti; index: number | string }>();
2020
<span>{{ `${index}. ${item.text}` }}</span>
2121
</div>
2222

23-
<ul v-if="item.items" :class="`${prefixClass}__inline`">
23+
<ul v-if="item.items" :class="`${prefixClass}__inline flx-wrap-between`">
2424
<!-- 递归 -->
2525
<CatalogueItem v-for="(item, i) in item.items" :key="i" :item :index="`${index}-${i + 1}`" />
2626
</ul>

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

+4-7
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
11
<script setup lang="ts" name="Catalogue">
22
import { useDesign } from "../hooks";
3-
import { useThemeConfig } from "../configProvider";
4-
import { unref } from "vue";
5-
import { useData } from "vitepress";
3+
import { useUnrefData } from "../configProvider";
64
import CatalogueItem from "./CatalogueItem.vue";
75
86
const { getPrefixClass } = useDesign();
97
const prefixClass = getPrefixClass("catalogue");
108
11-
const themeConfig = useThemeConfig();
12-
const { frontmatter } = useData();
9+
const { theme, frontmatter } = useUnrefData();
1310
1411
const getPath = () => {
15-
const { path } = unref(frontmatter);
12+
const { path } = frontmatter;
1613
1714
if (!path) return "";
1815
if (path.startsWith("/") && path.endsWith("/")) return path;
@@ -21,7 +18,7 @@ const getPath = () => {
2118
return `/${path}/`;
2219
};
2320
24-
const catalogueList = themeConfig.sidebar[getPath()];
21+
const catalogueList = theme.sidebar[getPath()];
2522
</script>
2623

2724
<template>

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

+84-20
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,141 @@
11
<script setup lang="ts" name="HomeBanner">
22
import { useDesign } from "../hooks";
3-
import { useData } from "vitepress";
4-
import { onMounted, onUnmounted, unref } from "vue";
3+
import { withBase } from "vitepress";
4+
import { onMounted, onUnmounted, unref, ref, nextTick } from "vue";
55
import { useTypes } from "../hooks";
6+
import { useUnrefData } from "../configProvider";
7+
import { isNumber } from "../helper";
8+
import HomeBannerWaves from "./HomeBannerWaves.vue";
69
710
const { getPrefixClass } = useDesign();
811
const prefixClass = getPrefixClass("banner");
912
10-
const { site, frontmatter } = useData();
11-
12-
const title = unref(frontmatter).name || unref(site).title || "";
13-
const descArray = [...new Set(unref(frontmatter).tk?.description?.filter((v: string) => !!v))] as string[];
14-
15-
const { text, shouldAnimate, startTypes, stopTypes } = useTypes(descArray, {
16-
typesInTime: unref(frontmatter).tk?.typesInTime,
17-
typesOutTime: unref(frontmatter).tk?.typesOutTime,
18-
typesNextTime: unref(frontmatter).tk?.typesNextTime,
19-
});
13+
const { site, theme, frontmatter } = useUnrefData();
14+
15+
const title = frontmatter.name || site.title || "";
16+
const descArray = [...new Set(frontmatter.tk?.description?.filter((v: string) => !!v))] as string[];
17+
const {
18+
bgStyle = "default",
19+
bigImgSrc,
20+
maskBg = "rgba(0,0,0,0.4)",
21+
defaultBgColor = "#e5e5e5",
22+
defaultTextColor = "#000000",
23+
features = [],
24+
typesInTime = 200,
25+
typesOutTime = 100,
26+
typesNextTime = 800,
27+
titleFontSize = "3.2rem",
28+
descFontSize = "1.4rem",
29+
} = { ...theme.banner, ...frontmatter.tk };
30+
31+
const isDefaultStyle = bgStyle === "default";
32+
const isBigImgStyle = bgStyle === "bigImg";
33+
const isGridStyle = bgStyle === "grid";
34+
35+
const getStyle = () => {
36+
let baseStyle = { "--banner-title-text": titleFontSize, "--banner-desc-text": descFontSize };
37+
38+
if (isDefaultStyle) return { ...baseStyle, backgroundColor: defaultBgColor, "--banner-text-color": defaultTextColor };
39+
if (isGridStyle) {
40+
return {
41+
...baseStyle,
42+
background:
43+
"rgb(40,40,45) url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACMAAAAjCAYAAAAe2bNZAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABOSURBVFhH7c6xCQAgDAVRR9A6E4hLu4uLiWJ7tSnuQcIvr2TRYsw3/zOGGEOMIcYQY4gxxBhiDDGGGEOMIcYQY4gxxBhiDLkx52W4Gn1tuslCtHJvL54AAAAASUVORK5CYII=)",
44+
"--banner-text-color": "#ffffff",
45+
};
46+
}
47+
if (isBigImgStyle) {
48+
return {
49+
...baseStyle,
50+
backgroundImage: bigImgSrc ? `url(${bigImgSrc})` : "",
51+
"--banner-text-color": "#ffffff",
52+
"--banner-mask-bg-color": isNumber(maskBg) ? `rgba(0, 0, 0, ${maskBg})` : maskBg,
53+
};
54+
}
55+
};
2056
2157
const bannerRef = ref<HTMLElement | null>(null);
2258
2359
const watchScroll = () => {
2460
const vPNavDom = document.querySelector(".VPNavBar");
2561
// 获取窗口高度
2662
const windowH = unref(bannerRef)?.clientHeight;
63+
2764
if (!vPNavDom || !windowH) return;
2865
const toggleClass = () => {
29-
if (document.documentElement.scrollTop < windowH) vPNavDom.classList.add("big-img-nav-bar");
30-
else vPNavDom.classList.remove("big-img-nav-bar");
66+
if (unref(bannerRef) && document.documentElement.scrollTop + 100 < windowH) {
67+
vPNavDom.classList.add("big-img-nav-bar");
68+
} else vPNavDom.classList.remove("big-img-nav-bar");
3169
};
3270
3371
toggleClass();
34-
3572
window.onscroll = () => {
3673
toggleClass();
3774
};
3875
};
3976
77+
// 打字效果
78+
const { text, shouldAnimate, startTypes, stopTypes } = useTypes(descArray, {
79+
typesInTime,
80+
typesOutTime,
81+
typesNextTime,
82+
});
83+
4084
onMounted(() => {
4185
startTypes();
86+
if (isBigImgStyle) nextTick(() => watchScroll());
4287
});
4388
4489
onUnmounted(() => {
4590
stopTypes();
91+
window.onscroll = null;
4692
});
4793
</script>
4894

4995
<template>
50-
<div ref="bannerRef" :class="`${prefixClass} big-img`" :style="{ backgroundImage: bigImg ? `url(${bigImg})` : '' }">
51-
<div class="mask" />
52-
53-
<div :class="`${prefixClass}-content`">
96+
<div
97+
ref="bannerRef"
98+
:class="[prefixClass, { default: isDefaultStyle, 'big-img': isBigImgStyle, grid: isGridStyle }]"
99+
:style="getStyle()"
100+
>
101+
<div v-if="isBigImgStyle" class="mask" />
102+
103+
<div :class="[`${prefixClass}-content`, { center: isBigImgStyle || !features.length }]">
54104
<h1 :class="`${prefixClass}-content__title`">{{ title }}</h1>
55105
<p v-if="descArray.length" :class="`${prefixClass}-content__desc`">
56106
<span>{{ text }}</span>
57107
<span :class="['typed', { 'is-animation': shouldAnimate }]">|</span>
58108
</p>
59109
</div>
110+
111+
<div v-if="features.length && !isBigImgStyle" :class="`${prefixClass}-feature flx-wrap-between`">
112+
<div :class="`${prefixClass}-feature__item`" v-for="(feature, index) in features" :key="index">
113+
<a v-if="feature.link" :href="feature.link" class="flx-column-center">
114+
<img v-if="feature.imgUrl" class="feature-img" :src="withBase(feature.imgUrl)" :alt="feature.title" />
115+
<p class="feature-title">{{ feature.title }}</p>
116+
<p class="feature-description">{{ feature.description }}</p>
117+
</a>
118+
</div>
119+
</div>
60120
</div>
121+
<HomeBannerWaves v-if="isBigImgStyle" />
61122
</template>
62123

63124
<style lang="scss" scoped>
64125
@use "../styles/components/homeBanner.scss";
65126
</style>
66127

67128
<style lang="scss">
129+
// 大图风格时,指定顶部导航栏样式
68130
.VPNavBar.home.big-img-nav-bar {
69131
background-color: transparent !important;
70132
71133
.VPNavBarTitle .title,
72134
.VPNavBarMenuLink,
73-
.VPNavBarMenuGroup .text {
135+
.VPNavBarMenuGroup .text,
136+
.VPSocialLink {
74137
color: #ffffff;
138+
75139
&.active,
76140
&:hover {
77141
color: var(--tk-theme-color);

0 commit comments

Comments
 (0)