@sugarat/theme 0.2.30 → 0.3.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 +40 -3
- package/node.js +196 -117
- package/package.json +4 -2
- package/src/components/BlogApp.vue +26 -7
- package/src/components/BlogButtonAfterArticle.vue +122 -0
- package/src/components/{BlogComment.vue → BlogCommentWrapper.vue} +14 -54
- package/src/components/BlogHomeBanner.vue +1 -1
- package/src/components/BlogHomeHeaderAvatar.vue +7 -5
- package/src/components/BlogHomeInfo.vue +1 -1
- package/src/components/BlogHomeTags.vue +1 -1
- package/src/components/BlogHotArticle.vue +37 -8
- package/src/components/BlogItem.vue +29 -15
- package/src/components/BlogPopover.vue +4 -0
- package/src/components/BlogRecommendArticle.vue +30 -7
- package/src/components/CommentArtalk.vue +74 -0
- package/src/components/CommentGiscus.vue +49 -0
- package/src/composables/config/blog.ts +4 -5
- package/src/composables/config/index.ts +41 -3
- package/src/constants/svg.ts +23 -0
- package/src/hooks/useDarkTransition.ts +46 -0
- package/src/hooks/useOml2d.ts +6 -0
- package/src/node.ts +3 -1
- package/src/styles/dark-transition.css +23 -0
- package/src/utils/node/hot-reload-plugin.ts +59 -0
- package/src/utils/node/index.ts +49 -15
- package/src/utils/node/theme.ts +94 -91
- package/src/utils/node/vitePlugins.ts +7 -7
- package/types/vue-shim.d.ts +10 -0
|
@@ -1,66 +1,33 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { useElementSize, useElementVisibility, useWindowSize } from '@vueuse/core'
|
|
3
|
-
import { useData
|
|
4
|
-
import { computed, h, ref
|
|
3
|
+
import { useData } from 'vitepress'
|
|
4
|
+
import { computed, h, ref } from 'vue'
|
|
5
5
|
import { ElIcon } from 'element-plus'
|
|
6
6
|
import { Comment } from '@element-plus/icons-vue'
|
|
7
|
-
import
|
|
8
|
-
import { useGiscusConfig } from '../composables/config/blog'
|
|
9
|
-
import type { Theme } from '../composables/config/index'
|
|
7
|
+
import { useBlogConfig } from '../composables/config/blog'
|
|
10
8
|
|
|
11
9
|
const { frontmatter } = useData()
|
|
12
10
|
const commentEl = ref(null)
|
|
13
11
|
const commentIsVisible = useElementVisibility(commentEl)
|
|
14
12
|
|
|
15
13
|
function handleScrollToComment() {
|
|
16
|
-
document.querySelector('#
|
|
14
|
+
document.querySelector('#blog-comment-wrapper')?.scrollIntoView({
|
|
17
15
|
behavior: 'smooth',
|
|
18
16
|
block: 'start'
|
|
19
17
|
})
|
|
20
18
|
}
|
|
21
|
-
const giscusConfig = useGiscusConfig()
|
|
22
19
|
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return giscusConfig
|
|
28
|
-
})
|
|
20
|
+
const { comment: _comment } = useBlogConfig()
|
|
21
|
+
const commentConfig = computed(() =>
|
|
22
|
+
_comment === false ? undefined : _comment
|
|
23
|
+
)
|
|
29
24
|
|
|
30
25
|
const show = computed(() => {
|
|
31
|
-
|
|
32
|
-
return frontmatter.value.comment
|
|
33
|
-
}
|
|
34
|
-
if (!giscusConfig) {
|
|
35
|
-
return giscusConfig
|
|
36
|
-
}
|
|
37
|
-
return (
|
|
38
|
-
giscusConfig.repo
|
|
39
|
-
&& giscusConfig.repoId
|
|
40
|
-
&& giscusConfig.category
|
|
41
|
-
&& giscusConfig.categoryId
|
|
42
|
-
)
|
|
26
|
+
return _comment && frontmatter.value.comment !== false
|
|
43
27
|
})
|
|
44
28
|
|
|
45
|
-
const { isDark } = useData()
|
|
46
|
-
|
|
47
|
-
const route = useRoute()
|
|
48
|
-
const showComment = ref(true)
|
|
49
|
-
watch(
|
|
50
|
-
() => route.path,
|
|
51
|
-
() => {
|
|
52
|
-
showComment.value = false
|
|
53
|
-
setTimeout(() => {
|
|
54
|
-
showComment.value = true
|
|
55
|
-
}, 200)
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
immediate: true
|
|
59
|
-
}
|
|
60
|
-
)
|
|
61
|
-
|
|
62
29
|
const { width } = useWindowSize()
|
|
63
|
-
const mobileMinify = computed(() => width.value < 768 && (commentConfig.value
|
|
30
|
+
const mobileMinify = computed(() => width.value < 768 && (commentConfig.value?.mobileMinify ?? true))
|
|
64
31
|
|
|
65
32
|
const CommentIcon = commentConfig.value?.icon
|
|
66
33
|
? h('i', {
|
|
@@ -78,20 +45,13 @@ const { width: _docWidth } = useElementSize(el)
|
|
|
78
45
|
const docWidth = computed(() => `${_docWidth.value}px`)
|
|
79
46
|
|
|
80
47
|
const labelText = computed(() => {
|
|
81
|
-
return commentConfig.value
|
|
48
|
+
return commentConfig.value?.label ?? '评论'
|
|
82
49
|
})
|
|
83
50
|
</script>
|
|
84
51
|
|
|
85
52
|
<template>
|
|
86
|
-
<div v-if="show && _docWidth" id="
|
|
87
|
-
<
|
|
88
|
-
v-if="showComment" :repo="commentConfig.repo" :repo-id="commentConfig.repoId"
|
|
89
|
-
:category="commentConfig.category" :category-id="commentConfig.categoryId"
|
|
90
|
-
:mapping="commentConfig.mapping || 'pathname'" reactions-enabled="1" emit-metadata="0"
|
|
91
|
-
:input-position="commentConfig.inputPosition || 'top'" :theme="isDark ? 'dark' : 'light'"
|
|
92
|
-
:lang="commentConfig.lang || 'zh-CN'" :loading="commentConfig.loading || 'eager'"
|
|
93
|
-
/>
|
|
94
|
-
|
|
53
|
+
<div v-if="show && _docWidth" id="blog-comment-wrapper" ref="commentEl" class="blog-comment-wrapper" data-pagefind-ignore="all">
|
|
54
|
+
<slot />
|
|
95
55
|
<div v-show="!commentIsVisible" class="comment-btn-wrapper">
|
|
96
56
|
<span v-if="!mobileMinify && labelText" class="icon-wrapper-text" @click="handleScrollToComment">
|
|
97
57
|
<ElIcon :size="20">
|
|
@@ -151,7 +111,7 @@ const labelText = computed(() => {
|
|
|
151
111
|
border-radius: 2px;
|
|
152
112
|
padding: 2px 6px;
|
|
153
113
|
|
|
154
|
-
span.text{
|
|
114
|
+
span.text {
|
|
155
115
|
font-size: 12px;
|
|
156
116
|
margin-left: 4px;
|
|
157
117
|
}
|
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { useData, withBase } from 'vitepress'
|
|
3
3
|
import { computed } from 'vue'
|
|
4
|
-
import { useWindowSize } from '@vueuse/core'
|
|
5
4
|
import { useBlogConfig } from '../composables/config/blog'
|
|
6
5
|
|
|
7
|
-
const { width } = useWindowSize()
|
|
8
|
-
const inMiniScreen = computed(() => width.value <= 767)
|
|
9
|
-
|
|
10
6
|
const { home } = useBlogConfig()
|
|
11
7
|
const { frontmatter, site } = useData()
|
|
12
8
|
const logo = computed(() =>
|
|
@@ -19,7 +15,7 @@ const alwaysHide = computed(() => frontmatter.value.blog?.minScreenAvatar === fa
|
|
|
19
15
|
</script>
|
|
20
16
|
|
|
21
17
|
<template>
|
|
22
|
-
<div v-show="
|
|
18
|
+
<div v-show="!alwaysHide" class="blog-home-header-avatar">
|
|
23
19
|
<img :src="withBase(logo)" alt="avatar">
|
|
24
20
|
</div>
|
|
25
21
|
</template>
|
|
@@ -47,4 +43,10 @@ const alwaysHide = computed(() => frontmatter.value.blog?.minScreenAvatar === fa
|
|
|
47
43
|
transition-timing-function: cubic-bezier(.34, 0, .84, 1)
|
|
48
44
|
}
|
|
49
45
|
}
|
|
46
|
+
|
|
47
|
+
@media screen and (min-width: 768px) {
|
|
48
|
+
.blog-home-header-avatar{
|
|
49
|
+
display: none;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
50
52
|
</style>
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
|
|
13
13
|
const route = useRoute()
|
|
14
14
|
const docs = useArticles()
|
|
15
|
-
const showTags = useConfig()?.config?.blog?.homeTags ??
|
|
15
|
+
const showTags = useConfig()?.config?.blog?.homeTags ?? true
|
|
16
16
|
const tags = computed(() => {
|
|
17
17
|
return [...new Set(docs.value.map(v => v.meta.tag || []).flat(3))]
|
|
18
18
|
})
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import { computed, ref } from 'vue'
|
|
3
|
-
import { ElButton
|
|
4
|
-
import { withBase } from 'vitepress'
|
|
3
|
+
import { ElButton } from 'element-plus'
|
|
4
|
+
import { useRouter, withBase } from 'vitepress'
|
|
5
5
|
import { useArticles, useBlogConfig, useCleanUrls } from '../composables/config/blog'
|
|
6
6
|
import { formatShowDate, wrapperCleanUrls } from '../utils/client'
|
|
7
7
|
import { fireSVG } from '../constants/svg'
|
|
@@ -26,6 +26,11 @@ const recommendList = computed(() => {
|
|
|
26
26
|
})
|
|
27
27
|
|
|
28
28
|
const currentPage = ref(1)
|
|
29
|
+
|
|
30
|
+
const router = useRouter()
|
|
31
|
+
function handleLinkClick(link: string) {
|
|
32
|
+
router.go(link)
|
|
33
|
+
}
|
|
29
34
|
function changePage() {
|
|
30
35
|
const newIdx
|
|
31
36
|
= currentPage.value % Math.ceil(recommendList.value.length / pageSize.value)
|
|
@@ -48,7 +53,10 @@ const showChangeBtn = computed(() => {
|
|
|
48
53
|
</script>
|
|
49
54
|
|
|
50
55
|
<template>
|
|
51
|
-
<div
|
|
56
|
+
<div
|
|
57
|
+
v-if="_hotArticle !== false && (recommendList.length || empty)" class="card recommend"
|
|
58
|
+
data-pagefind-ignore="all"
|
|
59
|
+
>
|
|
52
60
|
<!-- 头部 -->
|
|
53
61
|
<div class="card-header">
|
|
54
62
|
<span class="title" v-html="title" />
|
|
@@ -64,11 +72,19 @@ const showChangeBtn = computed(() => {
|
|
|
64
72
|
<!-- 简介 -->
|
|
65
73
|
<div class="des">
|
|
66
74
|
<!-- title -->
|
|
67
|
-
<
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
75
|
+
<a
|
|
76
|
+
:href="withBase(v.route)"
|
|
77
|
+
class="title" @click="(e) => {
|
|
78
|
+
e.preventDefault()
|
|
79
|
+
handleLinkClick(withBase(v.route))
|
|
80
|
+
}"
|
|
81
|
+
>
|
|
82
|
+
<span>
|
|
83
|
+
{{
|
|
84
|
+
v.meta.title
|
|
85
|
+
}}
|
|
86
|
+
</span>
|
|
87
|
+
</a>
|
|
72
88
|
<!-- 描述信息 -->
|
|
73
89
|
<div class="suffix">
|
|
74
90
|
<!-- 日期 -->
|
|
@@ -172,6 +188,19 @@ const showChangeBtn = computed(() => {
|
|
|
172
188
|
.title {
|
|
173
189
|
font-size: 14px;
|
|
174
190
|
color: var(--vp-c-text-1);
|
|
191
|
+
font-weight: 500;
|
|
192
|
+
position: relative;
|
|
193
|
+
cursor: pointer;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.title:hover::after {
|
|
197
|
+
content: "";
|
|
198
|
+
position: absolute;
|
|
199
|
+
left: 0;
|
|
200
|
+
right: 0;
|
|
201
|
+
height: 0;
|
|
202
|
+
bottom: -3px;
|
|
203
|
+
border-bottom: 1px solid #b1b3b8;
|
|
175
204
|
}
|
|
176
205
|
|
|
177
206
|
.suffix {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
import { withBase } from 'vitepress'
|
|
2
|
+
import { useRouter, withBase } from 'vitepress'
|
|
3
3
|
import { computed } from 'vue'
|
|
4
4
|
import { formatShowDate, wrapperCleanUrls } from '../utils/client'
|
|
5
5
|
import { useCleanUrls } from '../composables/config/blog'
|
|
@@ -19,24 +19,36 @@ const props = defineProps<{
|
|
|
19
19
|
const showTime = computed(() => {
|
|
20
20
|
return formatShowDate(props.date)
|
|
21
21
|
})
|
|
22
|
-
|
|
23
22
|
const cleanUrls = useCleanUrls()
|
|
24
23
|
const link = computed(() => withBase(wrapperCleanUrls(!!cleanUrls, props.route)))
|
|
24
|
+
|
|
25
|
+
const router = useRouter()
|
|
26
|
+
function handleSkipDoc() {
|
|
27
|
+
router.go(link.value)
|
|
28
|
+
}
|
|
25
29
|
</script>
|
|
26
30
|
|
|
27
31
|
<template>
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
<a
|
|
33
|
+
class="blog-item" :href="link" @click="(e) => {
|
|
34
|
+
e.preventDefault()
|
|
35
|
+
handleSkipDoc()
|
|
36
|
+
}"
|
|
37
|
+
>
|
|
38
|
+
<i v-show="!!pin" class="pin" />
|
|
31
39
|
<!-- 标题 -->
|
|
32
|
-
<p class="title mobile-visible">
|
|
40
|
+
<p class="title mobile-visible">
|
|
41
|
+
{{ title }}
|
|
42
|
+
</p>
|
|
33
43
|
<div class="info-container">
|
|
34
44
|
<!-- 左侧信息 -->
|
|
35
45
|
<div class="info-part">
|
|
36
46
|
<!-- 标题 -->
|
|
37
|
-
<p class="title pc-visible">
|
|
47
|
+
<p class="title pc-visible">
|
|
48
|
+
{{ title }}
|
|
49
|
+
</p>
|
|
38
50
|
<!-- 简短描述 -->
|
|
39
|
-
<p v-
|
|
51
|
+
<p v-show="!descriptionHTML && !!description" class="description">
|
|
40
52
|
{{ description }}
|
|
41
53
|
</p>
|
|
42
54
|
<template v-if="descriptionHTML">
|
|
@@ -44,19 +56,19 @@ const link = computed(() => withBase(wrapperCleanUrls(!!cleanUrls, props.route))
|
|
|
44
56
|
</template>
|
|
45
57
|
<!-- 底部补充描述 -->
|
|
46
58
|
<div class="badge-list pc-visible">
|
|
47
|
-
<span v-
|
|
59
|
+
<span v-show="author" class="split">{{ author }}</span>
|
|
48
60
|
<span class="split">{{ showTime }}</span>
|
|
49
|
-
<span v-
|
|
61
|
+
<span v-show="tag?.length" class="split">{{ tag?.join(' · ') }}</span>
|
|
50
62
|
</div>
|
|
51
63
|
</div>
|
|
52
64
|
<!-- 右侧封面图 -->
|
|
53
|
-
<div v-
|
|
65
|
+
<div v-show="cover" class="cover-img" :style="`background-image: url(${withBase(`${cover}`)});`" />
|
|
54
66
|
</div>
|
|
55
67
|
<!-- 底部补充描述 -->
|
|
56
68
|
<div class="badge-list mobile-visible">
|
|
57
|
-
<span v-
|
|
69
|
+
<span v-show="author" class="split">{{ author }}</span>
|
|
58
70
|
<span class="split">{{ showTime }}</span>
|
|
59
|
-
<span v-
|
|
71
|
+
<span v-show="tag?.length" class="split">{{ tag?.join(' · ') }}</span>
|
|
60
72
|
</div>
|
|
61
73
|
</a>
|
|
62
74
|
</template>
|
|
@@ -166,7 +178,8 @@ const link = computed(() => withBase(wrapperCleanUrls(!!cleanUrls, props.route))
|
|
|
166
178
|
margin-left: 24px;
|
|
167
179
|
border-radius: 2px;
|
|
168
180
|
background-repeat: no-repeat;
|
|
169
|
-
background-size:
|
|
181
|
+
background-size: contain;
|
|
182
|
+
background-position: center;
|
|
170
183
|
}
|
|
171
184
|
|
|
172
185
|
.pc-visible {
|
|
@@ -181,7 +194,8 @@ const link = computed(() => withBase(wrapperCleanUrls(!!cleanUrls, props.route))
|
|
|
181
194
|
.cover-img {
|
|
182
195
|
width: 100px;
|
|
183
196
|
height: 60px;
|
|
184
|
-
background-size:
|
|
197
|
+
background-size: contain;
|
|
198
|
+
background-position: center;
|
|
185
199
|
}
|
|
186
200
|
|
|
187
201
|
.pc-visible {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import { computed, onMounted, ref } from 'vue'
|
|
3
|
-
import { useRoute, withBase } from 'vitepress'
|
|
4
|
-
import { ElButton
|
|
3
|
+
import { useRoute, useRouter, withBase } from 'vitepress'
|
|
4
|
+
import { ElButton } from 'element-plus'
|
|
5
5
|
import { formatShowDate, wrapperCleanUrls } from '../utils/client'
|
|
6
6
|
import { useArticles, useBlogConfig, useCleanUrls } from '../composables/config/blog'
|
|
7
7
|
import { recommendSVG } from '../constants/svg'
|
|
@@ -147,6 +147,11 @@ onMounted(() => {
|
|
|
147
147
|
})
|
|
148
148
|
|
|
149
149
|
const cleanUrls = useCleanUrls()
|
|
150
|
+
|
|
151
|
+
const router = useRouter()
|
|
152
|
+
function handleLinkClick(link: string) {
|
|
153
|
+
router.go(link)
|
|
154
|
+
}
|
|
150
155
|
</script>
|
|
151
156
|
|
|
152
157
|
<template>
|
|
@@ -169,13 +174,18 @@ const cleanUrls = useCleanUrls()
|
|
|
169
174
|
<!-- 简介 -->
|
|
170
175
|
<div class="des">
|
|
171
176
|
<!-- title -->
|
|
172
|
-
<
|
|
173
|
-
|
|
177
|
+
<a
|
|
178
|
+
class="title" :class="{
|
|
174
179
|
current: isCurrentDoc(v.route),
|
|
175
|
-
}"
|
|
180
|
+
}"
|
|
181
|
+
:href="wrapperCleanUrls(cleanUrls, v.route)"
|
|
182
|
+
@click="(e) => {
|
|
183
|
+
e.preventDefault()
|
|
184
|
+
handleLinkClick(wrapperCleanUrls(cleanUrls, v.route))
|
|
185
|
+
}"
|
|
176
186
|
>
|
|
177
|
-
{{ v.meta.title }}
|
|
178
|
-
</
|
|
187
|
+
<span>{{ v.meta.title }}</span>
|
|
188
|
+
</a>
|
|
179
189
|
<!-- 描述信息 -->
|
|
180
190
|
<div class="suffix">
|
|
181
191
|
<!-- 日期 -->
|
|
@@ -248,12 +258,25 @@ const cleanUrls = useCleanUrls()
|
|
|
248
258
|
color: var(--vp-c-text-1);
|
|
249
259
|
word-break: break-all;
|
|
250
260
|
white-space: break-spaces;
|
|
261
|
+
font-weight: 500;
|
|
262
|
+
position: relative;
|
|
263
|
+
cursor: pointer;
|
|
251
264
|
|
|
252
265
|
&.current {
|
|
253
266
|
color: var(--vp-c-brand-1);
|
|
254
267
|
}
|
|
255
268
|
}
|
|
256
269
|
|
|
270
|
+
.title:hover::after {
|
|
271
|
+
content: "";
|
|
272
|
+
position: absolute;
|
|
273
|
+
left: 0;
|
|
274
|
+
right: 0;
|
|
275
|
+
height: 0;
|
|
276
|
+
bottom: -3px;
|
|
277
|
+
border-bottom: 1px solid #b1b3b8;
|
|
278
|
+
}
|
|
279
|
+
|
|
257
280
|
.suffix {
|
|
258
281
|
font-size: 12px;
|
|
259
282
|
color: var(--vp-c-text-2);
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
|
3
|
+
import { useData, useRoute } from 'vitepress'
|
|
4
|
+
import type Artalk from 'artalk'
|
|
5
|
+
|
|
6
|
+
import { useBlogConfig } from '../composables/config/blog'
|
|
7
|
+
|
|
8
|
+
const { isDark, page } = useData()
|
|
9
|
+
const el = ref<HTMLDivElement>()
|
|
10
|
+
|
|
11
|
+
const route = useRoute()
|
|
12
|
+
|
|
13
|
+
const artalk = ref<Artalk>()
|
|
14
|
+
|
|
15
|
+
const { comment } = useBlogConfig()
|
|
16
|
+
const commentConfig = computed(() => {
|
|
17
|
+
if (comment && 'type' in comment && comment.type === 'artalk') {
|
|
18
|
+
return comment.options
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return false
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
onMounted(() => {
|
|
25
|
+
// CDN 异步加载,有优化空间
|
|
26
|
+
const observer = new MutationObserver((mutationsList, observer) => {
|
|
27
|
+
if (window.Artalk && commentConfig.value && el.value) {
|
|
28
|
+
artalk.value = window.Artalk.init({
|
|
29
|
+
el: el.value,
|
|
30
|
+
darkMode: isDark.value,
|
|
31
|
+
pageKey: route.path,
|
|
32
|
+
pageTitle: page.value.title,
|
|
33
|
+
server: commentConfig.value?.server,
|
|
34
|
+
site: commentConfig.value?.site,
|
|
35
|
+
})
|
|
36
|
+
observer.disconnect()
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
observer.observe(document.head, { subtree: true, childList: true, attributes: true, attributeFilter: ['id'] })
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
watch(() => route.path, () => {
|
|
44
|
+
if (artalk.value) {
|
|
45
|
+
artalk.value.update({
|
|
46
|
+
pageKey: route.path,
|
|
47
|
+
pageTitle: page.value.title,
|
|
48
|
+
})
|
|
49
|
+
artalk.value.reload()
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
onUnmounted(() => {
|
|
54
|
+
if (artalk.value) {
|
|
55
|
+
artalk.value.destroy()
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
watch(isDark, () => {
|
|
60
|
+
if (artalk.value) {
|
|
61
|
+
artalk.value.setDarkMode(isDark.value)
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
</script>
|
|
65
|
+
|
|
66
|
+
<template>
|
|
67
|
+
<div v-if="commentConfig" ref="el" class="artalk-container" />
|
|
68
|
+
</template>
|
|
69
|
+
|
|
70
|
+
<style lang="scss" scoped>
|
|
71
|
+
.artalk-container {
|
|
72
|
+
--at-color-main: var(--vp-c-brand-2);
|
|
73
|
+
}
|
|
74
|
+
</style>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useData, useRoute } from 'vitepress'
|
|
3
|
+
import { computed, ref, watch } from 'vue'
|
|
4
|
+
import Giscus from '@giscus/vue'
|
|
5
|
+
import { useBlogConfig } from '../composables/config/blog'
|
|
6
|
+
|
|
7
|
+
// 读取配制
|
|
8
|
+
const { comment } = useBlogConfig()
|
|
9
|
+
const commentConfig = computed(() => {
|
|
10
|
+
if (!comment) {
|
|
11
|
+
return false
|
|
12
|
+
}
|
|
13
|
+
if ('type' in comment && comment.type === 'giscus') {
|
|
14
|
+
return comment.options
|
|
15
|
+
}
|
|
16
|
+
else if (!('type' in comment)) {
|
|
17
|
+
return comment
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return false
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const { isDark } = useData()
|
|
24
|
+
|
|
25
|
+
const route = useRoute()
|
|
26
|
+
const showComment = ref(true)
|
|
27
|
+
watch(
|
|
28
|
+
() => route.path,
|
|
29
|
+
() => {
|
|
30
|
+
showComment.value = false
|
|
31
|
+
setTimeout(() => {
|
|
32
|
+
showComment.value = true
|
|
33
|
+
}, 200)
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
immediate: true
|
|
37
|
+
}
|
|
38
|
+
)
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<template>
|
|
42
|
+
<Giscus
|
|
43
|
+
v-if="commentConfig" :repo="commentConfig.repo" :repo-id="commentConfig.repoId"
|
|
44
|
+
:category="commentConfig.category" :category-id="commentConfig.categoryId"
|
|
45
|
+
:mapping="commentConfig.mapping || 'pathname'" reactions-enabled="1" emit-metadata="0"
|
|
46
|
+
:input-position="commentConfig.inputPosition || 'top'" :theme="isDark ? 'dark' : 'light'"
|
|
47
|
+
:lang="commentConfig.lang || 'zh-CN'" :loading="commentConfig.loading || 'eager'"
|
|
48
|
+
/>
|
|
49
|
+
</template>
|
|
@@ -104,13 +104,12 @@ export function useOml2dOptions() {
|
|
|
104
104
|
return inject(configSymbol)!.value.blog?.oml2d
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
export function
|
|
108
|
-
return inject(configSymbol)!.value
|
|
107
|
+
export function useDarkTransitionConfig() {
|
|
108
|
+
return inject(configSymbol)!.value.blog?.darkTransition ?? true
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
export function
|
|
112
|
-
|
|
113
|
-
return blogConfig.config?.blog?.comment
|
|
111
|
+
export function useBlogThemeMode() {
|
|
112
|
+
return inject(configSymbol)!.value?.blog?.blog ?? true
|
|
114
113
|
}
|
|
115
114
|
|
|
116
115
|
export function useArticles() {
|
|
@@ -100,7 +100,9 @@ export namespace Theme {
|
|
|
100
100
|
type: string
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
export
|
|
103
|
+
export type CommentConfig = ((GiscusOption & CommentCommonConfig) | GiscusConfig | ArtalkConfig)
|
|
104
|
+
|
|
105
|
+
export interface CommentCommonConfig {
|
|
104
106
|
/**
|
|
105
107
|
* @default '评论'
|
|
106
108
|
*/
|
|
@@ -116,7 +118,15 @@ export namespace Theme {
|
|
|
116
118
|
*/
|
|
117
119
|
mobileMinify?: boolean
|
|
118
120
|
}
|
|
119
|
-
export interface GiscusConfig {
|
|
121
|
+
export interface GiscusConfig extends CommentCommonConfig {
|
|
122
|
+
type: 'giscus'
|
|
123
|
+
options: GiscusOption
|
|
124
|
+
}
|
|
125
|
+
export interface ArtalkConfig extends CommentCommonConfig {
|
|
126
|
+
type: 'artalk'
|
|
127
|
+
options: ArtalkOption
|
|
128
|
+
}
|
|
129
|
+
export interface GiscusOption {
|
|
120
130
|
repo: Repo
|
|
121
131
|
repoId: string
|
|
122
132
|
category: string
|
|
@@ -126,6 +136,10 @@ export namespace Theme {
|
|
|
126
136
|
lang?: string
|
|
127
137
|
loading?: 'lazy' | 'eager'
|
|
128
138
|
}
|
|
139
|
+
export interface ArtalkOption {
|
|
140
|
+
site: string
|
|
141
|
+
server: string
|
|
142
|
+
}
|
|
129
143
|
|
|
130
144
|
export interface HotArticle {
|
|
131
145
|
title?: string
|
|
@@ -351,7 +365,8 @@ export namespace Theme {
|
|
|
351
365
|
search?: SearchConfig
|
|
352
366
|
/**
|
|
353
367
|
* 配置评论
|
|
354
|
-
*
|
|
368
|
+
* giscus: https://giscus.app/zh-CN
|
|
369
|
+
* artalk: https://artalk.js.org/
|
|
355
370
|
*/
|
|
356
371
|
comment?: CommentConfig | false
|
|
357
372
|
/**
|
|
@@ -424,6 +439,13 @@ export namespace Theme {
|
|
|
424
439
|
*/
|
|
425
440
|
oml2d?: Oml2dOptions
|
|
426
441
|
homeTags?: boolean
|
|
442
|
+
buttonAfterArticle?: ButtonAfterArticleConfig | false
|
|
443
|
+
/**
|
|
444
|
+
* 是否开启深色模式过渡动画
|
|
445
|
+
* @reference https://vitepress.dev/zh/guide/extending-default-theme#on-appearance-toggle
|
|
446
|
+
* @default true
|
|
447
|
+
*/
|
|
448
|
+
darkTransition?: boolean
|
|
427
449
|
}
|
|
428
450
|
|
|
429
451
|
export interface BackToTop {
|
|
@@ -509,4 +531,20 @@ export namespace Theme {
|
|
|
509
531
|
*/
|
|
510
532
|
handleChangeSlogan?: (oldSlogan: string) => string | Promise<string>
|
|
511
533
|
}
|
|
534
|
+
export interface ButtonAfterArticleConfig {
|
|
535
|
+
openTitle?: string
|
|
536
|
+
closeTitle?: string
|
|
537
|
+
content?: string
|
|
538
|
+
icon?: 'aliPay' | 'wechatPay' | string
|
|
539
|
+
/**
|
|
540
|
+
* 按钮尺寸
|
|
541
|
+
* @default 'default'
|
|
542
|
+
*/
|
|
543
|
+
size?: 'small' | 'default' | 'large'
|
|
544
|
+
/**
|
|
545
|
+
* 默认展开
|
|
546
|
+
* @default false
|
|
547
|
+
*/
|
|
548
|
+
expand?: boolean
|
|
549
|
+
}
|
|
512
550
|
}
|