@sugarat/theme 0.4.13 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/node.d.ts +13 -1
- package/node.js +147 -52
- package/node.mjs +755 -0
- package/package.json +13 -10
- package/src/components/BlogAlert.vue +10 -9
- package/src/components/BlogArticleAnalyze.vue +8 -9
- package/src/components/BlogAuthor.vue +6 -5
- package/src/components/BlogBackToTop.vue +8 -10
- package/src/components/BlogButtonAfterArticle.vue +5 -14
- package/src/components/BlogCommentWrapper.vue +11 -28
- package/src/components/BlogDocCover.vue +3 -3
- package/src/components/BlogFooter.vue +3 -1
- package/src/components/BlogFriendLink.vue +4 -3
- package/src/components/BlogHomeBanner.vue +7 -6
- package/src/components/BlogHomeHeaderAvatar.vue +3 -3
- package/src/components/BlogHomeOverview.vue +4 -4
- package/src/components/BlogHomeTags.vue +5 -5
- package/src/components/BlogHotArticle.vue +4 -7
- package/src/components/BlogItem.vue +4 -3
- package/src/components/BlogList.vue +7 -6
- package/src/components/BlogRecommendArticle.vue +11 -14
- package/src/components/BlogSidebar.vue +9 -15
- package/src/components/CommentArtalk.vue +7 -5
- package/src/components/CommentGiscus.vue +7 -8
- package/src/components/Icon.vue +33 -0
- package/src/composables/config/blog.ts +207 -89
- package/src/composables/config/index.ts +9 -0
- package/src/hooks/useOml2d.ts +15 -8
- package/src/index.ts +3 -0
- package/src/node.ts +5 -1
- package/src/styles/index.scss +6 -6
- package/src/utils/node/hot-reload-plugin.ts +31 -1
- package/src/utils/node/index.ts +0 -2
- package/src/utils/node/mdPlugins.ts +4 -0
- package/src/utils/node/theme.ts +15 -18
- package/src/utils/node/vitePlugins.ts +120 -34
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sugarat/theme",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "简约风的 Vitepress 博客主题,sugarat vitepress blog theme",
|
|
5
5
|
"author": "sugar",
|
|
6
6
|
"license": "MIT",
|
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
"exports": {
|
|
21
21
|
"./node": {
|
|
22
22
|
"types": "./node.d.ts",
|
|
23
|
+
"import": "./node.mjs",
|
|
24
|
+
"require": "./node.js",
|
|
23
25
|
"default": "./node.js"
|
|
24
26
|
},
|
|
25
27
|
"./package.json": "./package.json",
|
|
@@ -29,6 +31,7 @@
|
|
|
29
31
|
"files": [
|
|
30
32
|
"node.d.ts",
|
|
31
33
|
"node.js",
|
|
34
|
+
"node.mjs",
|
|
32
35
|
"src",
|
|
33
36
|
"types"
|
|
34
37
|
],
|
|
@@ -42,29 +45,29 @@
|
|
|
42
45
|
"@mermaid-js/mermaid-mindmap": "^9.3.0",
|
|
43
46
|
"@vue/shared": "^3.4.26",
|
|
44
47
|
"@vueuse/core": "^9.13.0",
|
|
45
|
-
"fast-glob": "^3.3.2",
|
|
46
48
|
"markdown-it-task-checkbox": "^1.0.6",
|
|
47
49
|
"mermaid": "^10.9.0",
|
|
48
50
|
"oh-my-live2d": "^0.19.3",
|
|
49
51
|
"swiper": "^11.1.1",
|
|
50
52
|
"vitepress-markdown-timeline": "^1.2.1",
|
|
53
|
+
"vitepress-plugin-group-icons": "^1.2.4",
|
|
51
54
|
"vitepress-plugin-mermaid": "2.0.13",
|
|
52
55
|
"vitepress-plugin-tabs": "0.2.0",
|
|
53
|
-
"@sugarat/theme-shared": "0.0.
|
|
54
|
-
"vitepress-plugin-
|
|
55
|
-
"vitepress-plugin-announcement": "0.1.
|
|
56
|
-
"vitepress-plugin-
|
|
56
|
+
"@sugarat/theme-shared": "0.0.3",
|
|
57
|
+
"vitepress-plugin-pagefind": "0.4.10",
|
|
58
|
+
"vitepress-plugin-announcement": "0.1.3",
|
|
59
|
+
"vitepress-plugin-rss": "0.3.0"
|
|
57
60
|
},
|
|
58
61
|
"devDependencies": {
|
|
59
62
|
"@element-plus/icons-vue": "^2.3.1",
|
|
60
63
|
"artalk": "^2.8.5",
|
|
61
64
|
"element-plus": "^2.7.2",
|
|
62
|
-
"pagefind": "^1.1.
|
|
65
|
+
"pagefind": "^1.1.1",
|
|
63
66
|
"sass": "^1.77.8",
|
|
64
67
|
"typescript": "^5.4.5",
|
|
65
|
-
"vite": "^5.
|
|
66
|
-
"vitepress": "1.
|
|
67
|
-
"vue": "^3.
|
|
68
|
+
"vite": "^5.4.9",
|
|
69
|
+
"vitepress": "1.4.1",
|
|
70
|
+
"vue": "^3.5.12",
|
|
68
71
|
"vitepress-plugin-51la": "0.1.0"
|
|
69
72
|
},
|
|
70
73
|
"scripts": {
|
|
@@ -1,30 +1,31 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import { ElAlert } from 'element-plus'
|
|
3
3
|
import { onMounted, ref } from 'vue'
|
|
4
|
-
import {
|
|
4
|
+
import { useAlertConfig } from '../composables/config/blog'
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
// TODO:拆分插件,对标公告插件
|
|
7
|
+
const alertProps = useAlertConfig()
|
|
7
8
|
const show = ref(false)
|
|
8
9
|
const storageKey = 'theme-blog-alert'
|
|
9
10
|
const closeFlag = `${storageKey}-close`
|
|
10
11
|
onMounted(() => {
|
|
11
12
|
// 取旧值
|
|
12
13
|
const oldValue = localStorage.getItem(storageKey)
|
|
13
|
-
const newValue = JSON.stringify(alertProps)
|
|
14
|
+
const newValue = JSON.stringify(alertProps.value)
|
|
14
15
|
localStorage.setItem(storageKey, newValue)
|
|
15
16
|
|
|
16
17
|
// >= 0 每次都展示,区别是否自动消失
|
|
17
|
-
if (Number(alertProps?.duration) >= 0) {
|
|
18
|
+
if (Number(alertProps?.value?.duration) >= 0) {
|
|
18
19
|
show.value = true
|
|
19
|
-
if (alertProps?.duration) {
|
|
20
|
+
if (alertProps?.value?.duration) {
|
|
20
21
|
setTimeout(() => {
|
|
21
22
|
show.value = false
|
|
22
|
-
}, alertProps?.duration)
|
|
23
|
+
}, alertProps?.value?.duration)
|
|
23
24
|
}
|
|
24
25
|
return
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
if (oldValue !== newValue && alertProps?.duration === -1) {
|
|
28
|
+
if (oldValue !== newValue && alertProps?.value?.duration === -1) {
|
|
28
29
|
// 当做新值处理
|
|
29
30
|
show.value = true
|
|
30
31
|
localStorage.removeItem(closeFlag)
|
|
@@ -32,14 +33,14 @@ onMounted(() => {
|
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
// 新旧相等,判断是否点击过close,没点击关闭依然展示
|
|
35
|
-
if (oldValue === newValue && alertProps?.duration === -1 && !localStorage.getItem(closeFlag)) {
|
|
36
|
+
if (oldValue === newValue && alertProps?.value?.duration === -1 && !localStorage.getItem(closeFlag)) {
|
|
36
37
|
show.value = true
|
|
37
38
|
}
|
|
38
39
|
})
|
|
39
40
|
|
|
40
41
|
function handleClose() {
|
|
41
42
|
show.value = false
|
|
42
|
-
if (alertProps?.duration === -1) {
|
|
43
|
+
if (alertProps?.value?.duration === -1) {
|
|
43
44
|
localStorage.setItem(closeFlag, `${+new Date()}`)
|
|
44
45
|
}
|
|
45
46
|
}
|
|
@@ -11,14 +11,14 @@ import {
|
|
|
11
11
|
EditPen,
|
|
12
12
|
UserFilled
|
|
13
13
|
} from '@element-plus/icons-vue'
|
|
14
|
-
import { useAnalyzeTitles,
|
|
14
|
+
import { useAnalyzeTitles, useArticleConfig, useAuthorList, useCurrentArticle, useDocMetaInsertPosition, useDocMetaInsertSelector, useFormatShowDate, useGlobalAuthor } from '../composables/config/blog'
|
|
15
15
|
import countWord, { formatDate } from '../utils/client'
|
|
16
|
-
import type { Theme } from '../composables/config'
|
|
17
16
|
import BlogDocCover from './BlogDocCover.vue'
|
|
18
17
|
|
|
19
18
|
const formatShowDate = useFormatShowDate()
|
|
20
|
-
const
|
|
21
|
-
const
|
|
19
|
+
const article = useArticleConfig()
|
|
20
|
+
const authorList = useAuthorList()
|
|
21
|
+
const readingTimePosition = computed(() => article?.value?.readingTimePosition || 'inline')
|
|
22
22
|
|
|
23
23
|
const { frontmatter } = useData()
|
|
24
24
|
const tags = computed(() => {
|
|
@@ -33,7 +33,7 @@ const tags = computed(() => {
|
|
|
33
33
|
]
|
|
34
34
|
})
|
|
35
35
|
const showAnalyze = computed(
|
|
36
|
-
() => frontmatter.value?.readingTime ?? article?.readingTime ?? true
|
|
36
|
+
() => frontmatter.value?.readingTime ?? article?.value?.readingTime ?? true
|
|
37
37
|
)
|
|
38
38
|
|
|
39
39
|
const wordCount = ref(0)
|
|
@@ -102,7 +102,7 @@ onMounted(() => {
|
|
|
102
102
|
|
|
103
103
|
const currentArticle = useCurrentArticle()
|
|
104
104
|
const publishDate = computed(() => {
|
|
105
|
-
return formatShowDate(currentArticle.value?.meta?.date || '')
|
|
105
|
+
return formatShowDate.value(currentArticle.value?.meta?.date || '')
|
|
106
106
|
})
|
|
107
107
|
|
|
108
108
|
const hoverDate = computed(() => {
|
|
@@ -111,15 +111,14 @@ const hoverDate = computed(() => {
|
|
|
111
111
|
|
|
112
112
|
const hiddenTime = computed(() => frontmatter.value.date === false)
|
|
113
113
|
|
|
114
|
-
const
|
|
115
|
-
const globalAuthor = computed(() => theme.value.blog?.author || '')
|
|
114
|
+
const globalAuthor = useGlobalAuthor()
|
|
116
115
|
const author = computed(
|
|
117
116
|
() =>
|
|
118
117
|
(frontmatter.value.author || currentArticle.value?.meta.author)
|
|
119
118
|
?? globalAuthor.value
|
|
120
119
|
)
|
|
121
120
|
const currentAuthorInfo = computed(() =>
|
|
122
|
-
authorList?.find(v => author.value === v.nickname)
|
|
121
|
+
authorList?.value?.find(v => author.value === v.nickname)
|
|
123
122
|
)
|
|
124
123
|
const hiddenAuthor = computed(() => frontmatter.value.author === false)
|
|
125
124
|
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { useData, withBase } from 'vitepress'
|
|
3
3
|
import { computed } from 'vue'
|
|
4
|
-
import { useBlogConfig } from '../composables/config/blog'
|
|
4
|
+
import { useBlogConfig, useGlobalAuthor, useHomeConfig } from '../composables/config/blog'
|
|
5
5
|
|
|
6
|
-
const
|
|
6
|
+
const home = useHomeConfig()
|
|
7
7
|
const { frontmatter, site } = useData()
|
|
8
|
+
const globalAuthor = useGlobalAuthor()
|
|
8
9
|
const author = computed(() =>
|
|
9
10
|
frontmatter.value.author
|
|
10
11
|
?? frontmatter.value?.blog?.author
|
|
11
|
-
?? home?.author
|
|
12
|
-
??
|
|
12
|
+
?? home?.value?.author
|
|
13
|
+
?? globalAuthor?.value
|
|
13
14
|
)
|
|
14
15
|
const logo = computed(() =>
|
|
15
16
|
frontmatter.value?.logo
|
|
16
17
|
?? frontmatter.value?.blog?.logo
|
|
17
|
-
?? home?.logo
|
|
18
|
+
?? home?.value?.logo
|
|
18
19
|
?? site.value?.themeConfig?.logo
|
|
19
20
|
?? '/logo.png'
|
|
20
21
|
)
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import { useElementSize, useScroll } from '@vueuse/core'
|
|
3
|
-
import { ElIcon } from 'element-plus'
|
|
4
3
|
import { computed, ref } from 'vue'
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
4
|
+
import { useBackToTopConfig, useOpenBackToTop } from '../composables/config/blog'
|
|
5
|
+
import Icon from './Icon.vue'
|
|
7
6
|
|
|
8
7
|
function handleBackRoTop() {
|
|
9
8
|
window.scrollTo({ top: 0, behavior: 'smooth' })
|
|
@@ -15,29 +14,28 @@ const { width } = useElementSize(el)
|
|
|
15
14
|
const docWidth = computed(() => `${width.value}px`)
|
|
16
15
|
|
|
17
16
|
const backToTopConfig = useBackToTopConfig()
|
|
18
|
-
const open =
|
|
17
|
+
const open = useOpenBackToTop()
|
|
19
18
|
|
|
20
19
|
const { y } = useScroll(window)
|
|
21
20
|
const defaultTriggerHeight = 450
|
|
22
|
-
const triggerTop = computed(() =>
|
|
21
|
+
const triggerTop = computed(() => backToTopConfig.value?.top ?? defaultTriggerHeight)
|
|
23
22
|
|
|
24
23
|
const show = computed(() => width && y.value > triggerTop.value)
|
|
25
24
|
|
|
26
|
-
const iconSVGStr = computed(() =>
|
|
25
|
+
const iconSVGStr = computed(() => backToTopConfig?.value?.icon)
|
|
27
26
|
</script>
|
|
28
27
|
|
|
29
28
|
<template>
|
|
30
29
|
<div v-if="open" v-show="show" class="back-to-top">
|
|
31
30
|
<span class="icon-wrapper" @click="handleBackRoTop">
|
|
32
|
-
<
|
|
33
|
-
<
|
|
34
|
-
<svg v-else width="512" height="512" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
|
31
|
+
<Icon :size="20" :icon="iconSVGStr">
|
|
32
|
+
<svg width="512" height="512" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
|
35
33
|
<path
|
|
36
34
|
fill="currentColor"
|
|
37
35
|
d="m20 22l-3.86-1.55c.7-1.53 1.2-3.11 1.51-4.72zM7.86 20.45L4 22l2.35-6.27c.31 1.61.81 3.19 1.51 4.72M12 2s5 2 5 10c0 3.1-.75 5.75-1.67 7.83A2 2 0 0 1 13.5 21h-3a2 2 0 0 1-1.83-1.17C7.76 17.75 7 15.1 7 12c0-8 5-10 5-10m0 10c1.1 0 2-.9 2-2s-.9-2-2-2s-2 .9-2 2s.9 2 2 2"
|
|
38
36
|
/>
|
|
39
37
|
</svg>
|
|
40
|
-
</
|
|
38
|
+
</Icon>
|
|
41
39
|
</span>
|
|
42
40
|
</div>
|
|
43
41
|
</template>
|
|
@@ -1,31 +1,22 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import { ElButton } from 'element-plus'
|
|
3
3
|
import { computed, ref, watch } from 'vue'
|
|
4
|
-
import {
|
|
5
|
-
import { useBlogConfig } from '../composables/config/blog'
|
|
4
|
+
import { useButtonAfterConfig } from '../composables/config/blog'
|
|
6
5
|
import { aliPaySVG, weChatPaySVG } from '../constants/svg'
|
|
7
6
|
|
|
8
|
-
const
|
|
9
|
-
const { frontmatter } = useData()
|
|
10
|
-
const frontmatterConfig = computed(() => frontmatter.value.buttonAfterArticle)
|
|
11
|
-
|
|
12
|
-
const buttonAfterArticleConfig = computed(() => {
|
|
13
|
-
if (frontmatterConfig.value === false || (!frontmatterConfig.value && !_buttonAfterArticle)) {
|
|
14
|
-
return false
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return { ..._buttonAfterArticle, ...frontmatterConfig.value }
|
|
18
|
-
})
|
|
7
|
+
const buttonAfterArticleConfig = useButtonAfterConfig()
|
|
19
8
|
|
|
20
9
|
const showContent = ref(false)
|
|
21
10
|
|
|
22
11
|
watch(buttonAfterArticleConfig, () => {
|
|
23
|
-
showContent.value = !!buttonAfterArticleConfig.value?.expand
|
|
12
|
+
showContent.value = buttonAfterArticleConfig.value !== false && !!buttonAfterArticleConfig.value?.expand
|
|
24
13
|
}, {
|
|
25
14
|
immediate: true
|
|
26
15
|
})
|
|
27
16
|
|
|
28
17
|
const svg = computed(() => {
|
|
18
|
+
if (buttonAfterArticleConfig.value === false)
|
|
19
|
+
return ''
|
|
29
20
|
const icon = buttonAfterArticleConfig.value?.icon
|
|
30
21
|
if (icon === 'aliPay') {
|
|
31
22
|
return aliPaySVG
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { useElementSize, useElementVisibility, useWindowSize } from '@vueuse/core'
|
|
3
|
-
import {
|
|
4
|
-
import { computed, h, ref } from 'vue'
|
|
5
|
-
import { ElIcon } from 'element-plus'
|
|
3
|
+
import { computed, ref } from 'vue'
|
|
6
4
|
import { Comment } from '@element-plus/icons-vue'
|
|
7
|
-
import {
|
|
5
|
+
import { useCommentConfig, useOpenCommentConfig } from '../composables/config/blog'
|
|
6
|
+
import Icon from './Icon.vue'
|
|
8
7
|
|
|
9
|
-
const { frontmatter } = useData()
|
|
10
8
|
const commentEl = ref(null)
|
|
11
9
|
const commentIsVisible = useElementVisibility(commentEl)
|
|
12
10
|
|
|
@@ -17,28 +15,13 @@ function handleScrollToComment() {
|
|
|
17
15
|
})
|
|
18
16
|
}
|
|
19
17
|
|
|
20
|
-
const
|
|
21
|
-
const commentConfig = computed(() =>
|
|
22
|
-
_comment === false ? undefined : _comment
|
|
23
|
-
)
|
|
18
|
+
const commentConfig = useCommentConfig()
|
|
24
19
|
|
|
25
|
-
const show =
|
|
26
|
-
return _comment && frontmatter.value.comment !== false
|
|
27
|
-
})
|
|
20
|
+
const show = useOpenCommentConfig()
|
|
28
21
|
|
|
29
22
|
const { width } = useWindowSize()
|
|
30
23
|
const mobileMinify = computed(() => width.value < 768 && (commentConfig.value?.mobileMinify ?? true))
|
|
31
24
|
|
|
32
|
-
const CommentIcon = commentConfig.value?.icon
|
|
33
|
-
? h('i', {
|
|
34
|
-
onVnodeMounted(vnode) {
|
|
35
|
-
if (vnode.el) {
|
|
36
|
-
vnode.el.outerHTML = commentConfig.value?.icon
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
})
|
|
40
|
-
: h(Comment)
|
|
41
|
-
|
|
42
25
|
const $vpDoc = document.querySelector('.vp-doc')
|
|
43
26
|
const el = ref<any>($vpDoc)
|
|
44
27
|
const { width: _docWidth } = useElementSize(el)
|
|
@@ -54,17 +37,17 @@ const labelText = computed(() => {
|
|
|
54
37
|
<slot />
|
|
55
38
|
<div v-show="!commentIsVisible" class="comment-btn-wrapper">
|
|
56
39
|
<span v-if="!mobileMinify && labelText" class="icon-wrapper-text" @click="handleScrollToComment">
|
|
57
|
-
<
|
|
58
|
-
<
|
|
59
|
-
</
|
|
40
|
+
<Icon :size="20" :icon="commentConfig?.icon">
|
|
41
|
+
<Comment />
|
|
42
|
+
</Icon>
|
|
60
43
|
<span class="text">
|
|
61
44
|
{{ labelText }}
|
|
62
45
|
</span>
|
|
63
46
|
</span>
|
|
64
47
|
<span v-else class="icon-wrapper" @click="handleScrollToComment">
|
|
65
|
-
<
|
|
66
|
-
<
|
|
67
|
-
</
|
|
48
|
+
<Icon :size="20" :icon="commentConfig?.icon">
|
|
49
|
+
<Comment />
|
|
50
|
+
</Icon>
|
|
68
51
|
</span>
|
|
69
52
|
</div>
|
|
70
53
|
</div>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import { useData } from 'vitepress'
|
|
3
3
|
import { computed } from 'vue'
|
|
4
|
-
import {
|
|
4
|
+
import { useArticleConfig, useCurrentArticle } from '../composables/config/blog'
|
|
5
5
|
|
|
6
6
|
const { frontmatter } = useData()
|
|
7
7
|
const cover = computed(() => frontmatter.value.cover)
|
|
@@ -9,9 +9,9 @@ const cover = computed(() => frontmatter.value.cover)
|
|
|
9
9
|
const currentArticle = useCurrentArticle()
|
|
10
10
|
const realCover = computed<string>(() => import.meta.env.DEV ? cover.value : currentArticle.value?.meta?.cover)
|
|
11
11
|
|
|
12
|
-
const
|
|
12
|
+
const article = useArticleConfig()
|
|
13
13
|
const hiddenCover = computed(
|
|
14
|
-
() => frontmatter.value?.hiddenCover ?? article?.hiddenCover ?? false
|
|
14
|
+
() => frontmatter.value?.hiddenCover ?? article?.value?.hiddenCover ?? false
|
|
15
15
|
)
|
|
16
16
|
</script>
|
|
17
17
|
|
|
@@ -5,9 +5,10 @@ import packageJSON from '../../package.json'
|
|
|
5
5
|
import { copyrightSVG, icpSVG, themeSVG } from '../constants/svg'
|
|
6
6
|
import { vOuterHtml } from '../directives'
|
|
7
7
|
|
|
8
|
-
const
|
|
8
|
+
const footerConfig = useHomeFooterConfig()
|
|
9
9
|
|
|
10
10
|
const renderData = computed(() => {
|
|
11
|
+
const footerData = footerConfig.value
|
|
11
12
|
if (!footerData) {
|
|
12
13
|
return []
|
|
13
14
|
}
|
|
@@ -104,6 +105,7 @@ const renderData = computed(() => {
|
|
|
104
105
|
</a>
|
|
105
106
|
<span v-else>{{ item.name }}</span>
|
|
106
107
|
</span>
|
|
108
|
+
<!-- TODO: 理论上存在问题,待优化 -->
|
|
107
109
|
<span v-else v-outer-html="item" />
|
|
108
110
|
</template>
|
|
109
111
|
</p>
|
|
@@ -3,7 +3,7 @@ import { ElAvatar } from 'element-plus'
|
|
|
3
3
|
import { useDark, useIntervalFn } from '@vueuse/core'
|
|
4
4
|
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
|
5
5
|
import Swiper from 'swiper'
|
|
6
|
-
import {
|
|
6
|
+
import { useFriendData } from '../composables/config/blog'
|
|
7
7
|
import { getImageUrl, shuffleArray } from '../utils/client'
|
|
8
8
|
import type { Theme } from '../'
|
|
9
9
|
import { friendLinkSvgStr } from '../constants/svg'
|
|
@@ -12,13 +12,13 @@ const isDark = useDark({
|
|
|
12
12
|
storageKey: 'vitepress-theme-appearance'
|
|
13
13
|
})
|
|
14
14
|
|
|
15
|
-
const
|
|
15
|
+
const friendData = useFriendData()
|
|
16
16
|
const friendConfig = computed<Theme.FriendConfig>(() => ({
|
|
17
17
|
list: [],
|
|
18
18
|
random: false,
|
|
19
19
|
limit: Number.MAX_SAFE_INTEGER,
|
|
20
20
|
title: `${friendLinkSvgStr}友情链接`,
|
|
21
|
-
...(Array.isArray(
|
|
21
|
+
...(Array.isArray(friendData.value) ? { list: friendData.value } : friendData.value)
|
|
22
22
|
}))
|
|
23
23
|
|
|
24
24
|
const limit = computed(() => {
|
|
@@ -89,6 +89,7 @@ onMounted(() => {
|
|
|
89
89
|
}
|
|
90
90
|
})
|
|
91
91
|
|
|
92
|
+
// TODO: SSR渲染支持
|
|
92
93
|
onUnmounted(() => {
|
|
93
94
|
pause()
|
|
94
95
|
})
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
|
3
3
|
import { useData } from 'vitepress'
|
|
4
|
-
import {
|
|
4
|
+
import { useHomeConfig } from '../composables/config/blog'
|
|
5
5
|
|
|
6
6
|
const { site, frontmatter } = useData()
|
|
7
|
-
const
|
|
7
|
+
const home = useHomeConfig()
|
|
8
8
|
|
|
9
9
|
const name = computed(
|
|
10
|
-
() => (frontmatter.value.blog?.name ?? site.value.title) || home?.name || ''
|
|
10
|
+
() => (frontmatter.value.blog?.name ?? site.value.title) || home?.value?.name || ''
|
|
11
11
|
)
|
|
12
|
-
const motto = computed(() => frontmatter.value.blog?.motto || home?.motto || '')
|
|
12
|
+
const motto = computed(() => frontmatter.value.blog?.motto || home?.value?.motto || '')
|
|
13
13
|
|
|
14
14
|
const inspiring = ref('')
|
|
15
15
|
const inspiringList = computed<string[]>(() => {
|
|
16
16
|
return [
|
|
17
17
|
...new Set(
|
|
18
|
-
[frontmatter.value.blog?.inspiring, home?.inspiring]
|
|
18
|
+
[frontmatter.value.blog?.inspiring, home?.value?.inspiring]
|
|
19
19
|
.flat()
|
|
20
20
|
.filter(v => !!v)
|
|
21
21
|
)
|
|
@@ -23,7 +23,7 @@ const inspiringList = computed<string[]>(() => {
|
|
|
23
23
|
})
|
|
24
24
|
const inspiringIndex = ref<number>(-1)
|
|
25
25
|
const inspiringTimeout = computed<number>(
|
|
26
|
-
() => frontmatter.value.blog?.inspiringTimeout || home?.inspiringTimeout || 0
|
|
26
|
+
() => frontmatter.value.blog?.inspiringTimeout || home?.value?.inspiringTimeout || 0
|
|
27
27
|
)
|
|
28
28
|
|
|
29
29
|
watch(inspiringTimeout, () => {
|
|
@@ -50,6 +50,7 @@ onUnmounted(() => {
|
|
|
50
50
|
}
|
|
51
51
|
})
|
|
52
52
|
|
|
53
|
+
// TODO:SSR 支持
|
|
53
54
|
async function changeSlogan() {
|
|
54
55
|
// 顺手启动定时器
|
|
55
56
|
startTimer()
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { useData, withBase } from 'vitepress'
|
|
3
3
|
import { computed } from 'vue'
|
|
4
|
-
import {
|
|
4
|
+
import { useHomeConfig } from '../composables/config/blog'
|
|
5
5
|
|
|
6
|
-
const
|
|
6
|
+
const home = useHomeConfig()
|
|
7
7
|
const { frontmatter, site } = useData()
|
|
8
8
|
const logo = computed(() =>
|
|
9
9
|
frontmatter.value.logo
|
|
10
10
|
?? frontmatter.value?.blog?.logo
|
|
11
|
-
?? home?.logo
|
|
11
|
+
?? home?.value?.logo
|
|
12
12
|
?? site.value.themeConfig?.logo
|
|
13
13
|
?? '/logo.png'
|
|
14
14
|
)
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
import { computed } from 'vue'
|
|
3
3
|
import { useData } from 'vitepress'
|
|
4
4
|
import { isCurrentWeek } from '../utils/client'
|
|
5
|
-
import { useArticles,
|
|
5
|
+
import { useArticles, useHomeAnalysis, useHomeConfig } from '../composables/config/blog'
|
|
6
6
|
import BlogAuthor from './BlogAuthor.vue'
|
|
7
7
|
|
|
8
|
-
const
|
|
8
|
+
const home = useHomeConfig()
|
|
9
9
|
const { frontmatter } = useData()
|
|
10
|
-
const avatarMode = computed(() => frontmatter.value?.blog?.avatarMode || home?.avatarMode || 'card')
|
|
10
|
+
const avatarMode = computed(() => frontmatter.value?.blog?.avatarMode || home?.value?.avatarMode || 'card')
|
|
11
11
|
|
|
12
12
|
const showCardAvatar = computed(() => avatarMode.value === 'card')
|
|
13
13
|
const showSplitCard = computed(() => avatarMode.value === 'split')
|
|
@@ -33,7 +33,7 @@ const currentWeek = computed(() => {
|
|
|
33
33
|
})
|
|
34
34
|
|
|
35
35
|
const analysis = useHomeAnalysis()
|
|
36
|
-
const titles = computed(() => (frontmatter.value?.blog?.analysis?.articles?.title || analysis?.articles?.title || []))
|
|
36
|
+
const titles = computed(() => (frontmatter.value?.blog?.analysis?.articles?.title || analysis?.value?.articles?.title || []))
|
|
37
37
|
</script>
|
|
38
38
|
|
|
39
39
|
<template>
|
|
@@ -6,18 +6,18 @@ import { useRoute, useRouter } from 'vitepress'
|
|
|
6
6
|
import {
|
|
7
7
|
useActiveTag,
|
|
8
8
|
useArticles,
|
|
9
|
-
useConfig,
|
|
10
9
|
useCurrentPageNum,
|
|
10
|
+
useHomeTagsConfig,
|
|
11
11
|
} from '../composables/config/blog'
|
|
12
12
|
import { tagsSvgStr } from '../constants/svg'
|
|
13
13
|
|
|
14
14
|
const route = useRoute()
|
|
15
15
|
const docs = useArticles()
|
|
16
|
-
const homeTagsConfig =
|
|
17
|
-
const showTags = computed(() => !!(homeTagsConfig ?? true))
|
|
18
|
-
const title = computed(() => (typeof homeTagsConfig === 'boolean' || !homeTagsConfig?.title)
|
|
16
|
+
const homeTagsConfig = useHomeTagsConfig()
|
|
17
|
+
const showTags = computed(() => !!(homeTagsConfig.value ?? true))
|
|
18
|
+
const title = computed(() => (typeof homeTagsConfig.value === 'boolean' || !homeTagsConfig.value?.title)
|
|
19
19
|
? `${tagsSvgStr}标签`
|
|
20
|
-
: homeTagsConfig?.title
|
|
20
|
+
: homeTagsConfig.value?.title
|
|
21
21
|
)
|
|
22
22
|
const tags = computed(() => {
|
|
23
23
|
return [...new Set(docs.value.map(v => v.meta.tag || []).flat(3))]
|
|
@@ -2,17 +2,14 @@
|
|
|
2
2
|
import { computed, ref } from 'vue'
|
|
3
3
|
import { ElButton } from 'element-plus'
|
|
4
4
|
import { useRouter, withBase } from 'vitepress'
|
|
5
|
-
import { useArticles,
|
|
5
|
+
import { useArticles, useCleanUrls, useFormatShowDate, useHotArticleConfig, useShowHotArticle } from '../composables/config/blog'
|
|
6
6
|
import { wrapperCleanUrls } from '../utils/client'
|
|
7
7
|
import { fireSVG } from '../constants/svg'
|
|
8
8
|
|
|
9
9
|
const formatShowDate = useFormatShowDate()
|
|
10
10
|
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
const hotArticle = computed(() =>
|
|
14
|
-
_hotArticle === false ? undefined : _hotArticle
|
|
15
|
-
)
|
|
11
|
+
const hotArticle = useHotArticleConfig()
|
|
12
|
+
const show = useShowHotArticle()
|
|
16
13
|
|
|
17
14
|
const title = computed(() => hotArticle.value?.title || `${fireSVG}精选文章`)
|
|
18
15
|
const nextText = computed(() => hotArticle.value?.nextText || '换一组')
|
|
@@ -56,7 +53,7 @@ const showChangeBtn = computed(() => {
|
|
|
56
53
|
|
|
57
54
|
<template>
|
|
58
55
|
<div
|
|
59
|
-
v-if="
|
|
56
|
+
v-if="show && (recommendList.length || empty)" class="card recommend"
|
|
60
57
|
data-pagefind-ignore="all"
|
|
61
58
|
>
|
|
62
59
|
<!-- 头部 -->
|
|
@@ -20,7 +20,7 @@ const props = defineProps<{
|
|
|
20
20
|
const formatShowDate = useFormatShowDate()
|
|
21
21
|
|
|
22
22
|
const showTime = computed(() => {
|
|
23
|
-
return formatShowDate(props.date)
|
|
23
|
+
return formatShowDate.value(props.date)
|
|
24
24
|
})
|
|
25
25
|
const cleanUrls = useCleanUrls()
|
|
26
26
|
const link = computed(() => withBase(wrapperCleanUrls(!!cleanUrls, props.route)))
|
|
@@ -30,14 +30,15 @@ function handleSkipDoc() {
|
|
|
30
30
|
router.go(link.value)
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
const
|
|
33
|
+
const imageStyle = useImageStyle()
|
|
34
|
+
const coverPreview = computed(() => imageStyle.value.coverPreview)
|
|
34
35
|
|
|
35
36
|
const resultCover = computed(() => {
|
|
36
37
|
if (!props.cover) {
|
|
37
38
|
return ''
|
|
38
39
|
}
|
|
39
40
|
const baseCover = withBase(props.cover)
|
|
40
|
-
const coverRule = [coverPreview]
|
|
41
|
+
const coverRule = [coverPreview.value]
|
|
41
42
|
.flat()
|
|
42
43
|
.filter(v => !!v)
|
|
43
44
|
.find((coverRule) => {
|
|
@@ -5,14 +5,15 @@ import { useData, useRoute, useRouter } from 'vitepress'
|
|
|
5
5
|
import {
|
|
6
6
|
useActiveTag,
|
|
7
7
|
useArticles,
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
useCurrentPageNum,
|
|
9
|
+
useGlobalAuthor,
|
|
10
|
+
useHomeConfig
|
|
10
11
|
} from '../composables/config/blog'
|
|
11
12
|
import type { Theme } from '../composables/config'
|
|
12
13
|
import BlogItem from './BlogItem.vue'
|
|
13
14
|
|
|
14
|
-
const {
|
|
15
|
-
const globalAuthor =
|
|
15
|
+
const { frontmatter } = useData<Theme.Config>()
|
|
16
|
+
const globalAuthor = useGlobalAuthor()
|
|
16
17
|
const docs = useArticles()
|
|
17
18
|
|
|
18
19
|
const activeTag = useActiveTag()
|
|
@@ -41,9 +42,9 @@ const filterData = computed(() => {
|
|
|
41
42
|
)
|
|
42
43
|
})
|
|
43
44
|
|
|
44
|
-
const
|
|
45
|
+
const home = useHomeConfig()
|
|
45
46
|
const pageSize = computed(
|
|
46
|
-
() => frontmatter.value.blog?.pageSize || home?.pageSize || 6
|
|
47
|
+
() => frontmatter.value.blog?.pageSize || home?.value?.pageSize || 6
|
|
47
48
|
)
|
|
48
49
|
const currentPage = useCurrentPageNum()
|
|
49
50
|
const currentWikiData = computed(() => {
|