@sugarat/theme 0.2.30 → 0.3.0

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 CHANGED
@@ -93,7 +93,8 @@ declare namespace Theme {
93
93
  label: string;
94
94
  type: string;
95
95
  }
96
- interface CommentConfig extends GiscusConfig {
96
+ type CommentConfig = ((GiscusOption & CommentCommonConfig) | GiscusConfig | ArtalkConfig);
97
+ interface CommentCommonConfig {
97
98
  /**
98
99
  * @default '评论'
99
100
  */
@@ -109,7 +110,15 @@ declare namespace Theme {
109
110
  */
110
111
  mobileMinify?: boolean;
111
112
  }
112
- interface GiscusConfig {
113
+ interface GiscusConfig extends CommentCommonConfig {
114
+ type: 'giscus';
115
+ options: GiscusOption;
116
+ }
117
+ interface ArtalkConfig extends CommentCommonConfig {
118
+ type: 'artalk';
119
+ options: ArtalkOption;
120
+ }
121
+ interface GiscusOption {
113
122
  repo: Repo;
114
123
  repoId: string;
115
124
  category: string;
@@ -119,6 +128,10 @@ declare namespace Theme {
119
128
  lang?: string;
120
129
  loading?: 'lazy' | 'eager';
121
130
  }
131
+ interface ArtalkOption {
132
+ site: string;
133
+ server: string;
134
+ }
122
135
  interface HotArticle {
123
136
  title?: string;
124
137
  pageSize?: number;
@@ -319,7 +332,8 @@ declare namespace Theme {
319
332
  search?: SearchConfig;
320
333
  /**
321
334
  * 配置评论
322
- * power by https://giscus.app/zh-CN
335
+ * giscus: https://giscus.app/zh-CN
336
+ * artalk: https://artalk.js.org/
323
337
  */
324
338
  comment?: CommentConfig | false;
325
339
  /**
@@ -391,6 +405,7 @@ declare namespace Theme {
391
405
  */
392
406
  oml2d?: Options;
393
407
  homeTags?: boolean;
408
+ buttonAfterArticle?: ButtonAfterArticleConfig | false;
394
409
  }
395
410
  interface BackToTop {
396
411
  /**
@@ -470,6 +485,22 @@ declare namespace Theme {
470
485
  */
471
486
  handleChangeSlogan?: (oldSlogan: string) => string | Promise<string>;
472
487
  }
488
+ interface ButtonAfterArticleConfig {
489
+ openTitle?: string;
490
+ closeTitle?: string;
491
+ content?: string;
492
+ icon?: 'aliPay' | 'wechatPay' | string;
493
+ /**
494
+ * 按钮尺寸
495
+ * @default 'default'
496
+ */
497
+ size?: 'small' | 'default' | 'large';
498
+ /**
499
+ * 默认展开
500
+ * @default false
501
+ */
502
+ expand?: boolean;
503
+ }
473
504
  }
474
505
 
475
506
  /**
package/node.js CHANGED
@@ -40,7 +40,7 @@ module.exports = __toCommonJS(node_exports);
40
40
  // src/utils/node/mdPlugins.ts
41
41
  var import_module = require("module");
42
42
 
43
- // ../../node_modules/.pnpm/vitepress-plugin-tabs@0.2.0_vitepress@1.0.1_vue@3.4.21/node_modules/vitepress-plugin-tabs/dist/index.js
43
+ // ../../node_modules/.pnpm/vitepress-plugin-tabs@0.2.0_vitepress@1.0.2_vue@3.4.21/node_modules/vitepress-plugin-tabs/dist/index.js
44
44
  var tabsMarker = "=tabs";
45
45
  var tabsMarkerLen = tabsMarker.length;
46
46
  var ruleBlockTabs = (state, startLine, endLine, silent) => {
@@ -453,6 +453,16 @@ function getArticles(cfg) {
453
453
  }).filter((v) => v.meta.layout !== "home");
454
454
  return data;
455
455
  }
456
+ function patchVPConfig(vpConfig, cfg) {
457
+ vpConfig.head = vpConfig.head || [];
458
+ if (cfg?.comment && "type" in cfg.comment && cfg?.comment?.type === "artalk") {
459
+ const server = cfg.comment?.options?.server;
460
+ if (server) {
461
+ vpConfig.head.push(["link", { href: `${server}/dist/Artalk.css`, rel: "stylesheet" }]);
462
+ vpConfig.head.push(["script", { src: `${server}/dist/Artalk.js`, id: "artalk-script" }]);
463
+ }
464
+ }
465
+ }
456
466
  function patchVPThemeConfig(cfg, vpThemeConfig = {}) {
457
467
  vpThemeConfig.sidebar = patchDefaultThemeSideBar(cfg)?.sidebar;
458
468
  return vpThemeConfig;
@@ -574,6 +584,7 @@ function getThemeConfig(cfg) {
574
584
  registerMdPlugins(extraVPConfig, markdownPlugin);
575
585
  patchMermaidPluginCfg(extraVPConfig);
576
586
  patchOptimizeDeps(extraVPConfig);
587
+ patchVPConfig(extraVPConfig, cfg);
577
588
  return {
578
589
  themeConfig: {
579
590
  blog: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sugarat/theme",
3
- "version": "0.2.30",
3
+ "version": "0.3.0",
4
4
  "description": "简约风的 Vitepress 博客主题,sugarat vitepress blog theme",
5
5
  "author": "sugar",
6
6
  "license": "MIT",
@@ -52,12 +52,13 @@
52
52
  },
53
53
  "devDependencies": {
54
54
  "@element-plus/icons-vue": "^2.1.0",
55
+ "artalk": "^2.8.3",
55
56
  "element-plus": "^2.3.4",
56
57
  "javascript-stringify": "^2.1.0",
57
58
  "pagefind": "1.0.3",
58
59
  "sass": "^1.56.1",
59
60
  "typescript": "^4.8.2",
60
- "vitepress": "1.0.1",
61
+ "vitepress": "1.0.2",
61
62
  "vue": "^3.4.21"
62
63
  },
63
64
  "scripts": {
@@ -7,8 +7,6 @@ import { useBlogThemeMode } from '../composables/config/blog'
7
7
  import BlogHomeInfo from './BlogHomeInfo.vue'
8
8
  import BlogHomeBanner from './BlogHomeBanner.vue'
9
9
  import BlogList from './BlogList.vue'
10
- import BlogComment from './BlogComment.vue'
11
-
12
10
  import BlogSidebar from './BlogSidebar.vue'
13
11
  import BlogImagePreview from './BlogImagePreview.vue'
14
12
  import BlogArticleAnalyze from './BlogArticleAnalyze.vue'
@@ -17,6 +15,11 @@ import BlogPopover from './BlogPopover.vue'
17
15
  import BlogFooter from './BlogFooter.vue'
18
16
  import BlogHomeHeaderAvatar from './BlogHomeHeaderAvatar.vue'
19
17
  import BlogBackToTop from './BlogBackToTop.vue'
18
+ import CommentGiscus from './CommentGiscus.vue'
19
+
20
+ import CommentArtalk from './CommentArtalk.vue'
21
+ import BlogButtonAfterArticle from './BlogButtonAfterArticle.vue'
22
+ import BlogCommentWrapper from './BlogCommentWrapper.vue'
20
23
 
21
24
  const { frontmatter } = useData()
22
25
  const layout = computed(() => frontmatter.value.layout)
@@ -74,8 +77,12 @@ useOml2d()
74
77
  <slot name="doc-after" />
75
78
  <!-- 评论 -->
76
79
  <ClientOnly>
80
+ <BlogButtonAfterArticle />
77
81
  <BlogBackToTop />
78
- <BlogComment />
82
+ <BlogCommentWrapper>
83
+ <CommentArtalk />
84
+ <CommentGiscus />
85
+ </BlogCommentWrapper>
79
86
  </ClientOnly>
80
87
  </template>
81
88
  <template #layout-bottom>
@@ -191,6 +198,7 @@ useOml2d()
191
198
  .blog-list-wrapper {
192
199
  width: 100%;
193
200
  }
201
+
194
202
  .blog-info-wrapper {
195
203
  margin-left: 16px;
196
204
  position: sticky;
@@ -0,0 +1,122 @@
1
+ <script lang="ts" setup>
2
+ import { ElButton } from 'element-plus'
3
+ import { computed, ref, watch } from 'vue'
4
+ import { useData } from 'vitepress'
5
+ import { useBlogConfig } from '../composables/config/blog'
6
+ import { aliPaySVG, weChatPaySVG } from '../constants/svg'
7
+
8
+ const { buttonAfterArticle: _buttonAfterArticle } = useBlogConfig()
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
+ })
19
+
20
+ const showContent = ref(false)
21
+
22
+ watch(buttonAfterArticleConfig, () => {
23
+ showContent.value = !!buttonAfterArticleConfig.value?.expand
24
+ }, {
25
+ immediate: true
26
+ })
27
+
28
+ const svg = computed(() => {
29
+ const icon = buttonAfterArticleConfig.value?.icon
30
+ if (icon === 'aliPay') {
31
+ return aliPaySVG
32
+ }
33
+ else if (icon === 'wechatPay') {
34
+ return weChatPaySVG
35
+ }
36
+ else {
37
+ return icon as string
38
+ }
39
+ })
40
+
41
+ function toggleContent() {
42
+ showContent.value = !showContent.value
43
+ }
44
+ </script>
45
+
46
+ <template>
47
+ <div v-if="buttonAfterArticleConfig" class="appreciation-container">
48
+ <ElButton :size="buttonAfterArticleConfig.size || 'default'" class="content-button" :type="showContent ? 'danger' : 'primary'" @click="toggleContent">
49
+ <span class="content-icon" v-html="svg" />
50
+ {{ showContent ? buttonAfterArticleConfig.closeTitle : buttonAfterArticleConfig.openTitle }}
51
+ </ElButton>
52
+ <transition name="content">
53
+ <div v-if="showContent" class="content-container" v-html="buttonAfterArticleConfig.content" />
54
+ </transition>
55
+ </div>
56
+ </template>
57
+
58
+ <style scoped lang="scss">
59
+ .appreciation-container {
60
+ text-align: center;
61
+ padding: 20px;
62
+ font-size: 14px;
63
+ color: #606266;
64
+
65
+ :deep(.el-button.el-button--primary){
66
+ background-color: var(--vp-c-brand-2);
67
+ border-color: var(--vp-c-brand-2);
68
+ }
69
+ }
70
+
71
+ .content-container {
72
+ position: relative;
73
+ display: flex;
74
+ justify-content: center;
75
+ align-items: center;
76
+ margin-top: 20px;
77
+ :deep(img){
78
+ height: 260px;
79
+ }
80
+ }
81
+
82
+ .content-icon {
83
+ font-family: "iconfont" !important;
84
+ font-size: 16px;
85
+ margin-right: 8px;
86
+ font-style: normal;
87
+ -webkit-font-smoothing: antialiased;
88
+ -moz-osx-font-smoothing: grayscale;
89
+ }
90
+
91
+ /* 进入动画 */
92
+ .content-enter-active {
93
+ animation: fadeIn 0.5s ease forwards;
94
+ }
95
+
96
+ /* 离开动画 */
97
+ .content-leave-active {
98
+ animation: fadeOut 0.3s ease forwards;
99
+ }
100
+
101
+ /* 淡入 */
102
+ @keyframes fadeIn {
103
+ from {
104
+ opacity: 0;
105
+ }
106
+
107
+ to {
108
+ opacity: 1;
109
+ }
110
+ }
111
+
112
+ /* 淡出 */
113
+ @keyframes fadeOut {
114
+ from {
115
+ opacity: 1;
116
+ }
117
+
118
+ to {
119
+ opacity: 0;
120
+ }
121
+ }
122
+ </style>
@@ -1,66 +1,33 @@
1
1
  <script setup lang="ts">
2
2
  import { useElementSize, useElementVisibility, useWindowSize } from '@vueuse/core'
3
- import { useData, useRoute } from 'vitepress'
4
- import { computed, h, ref, watch } from 'vue'
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 Giscus from '@giscus/vue'
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('#giscus-comment')?.scrollIntoView({
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 commentConfig = computed<Theme.CommentConfig>(() => {
24
- if (!giscusConfig) {
25
- return {} as any
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
- if (frontmatter.value.comment === false) {
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.mobileMinify ?? true))
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.label ?? '评论'
48
+ return commentConfig.value?.label ?? '评论'
82
49
  })
83
50
  </script>
84
51
 
85
52
  <template>
86
- <div v-if="show && _docWidth" id="giscus-comment" ref="commentEl" class="comment" data-pagefind-ignore="all">
87
- <Giscus
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
  }
@@ -12,7 +12,7 @@ import {
12
12
 
13
13
  const route = useRoute()
14
14
  const docs = useArticles()
15
- const showTags = useConfig()?.config?.blog?.homeTags ?? true
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
  })
@@ -166,7 +166,8 @@ const link = computed(() => withBase(wrapperCleanUrls(!!cleanUrls, props.route))
166
166
  margin-left: 24px;
167
167
  border-radius: 2px;
168
168
  background-repeat: no-repeat;
169
- background-size: 120px 80px;
169
+ background-size: contain;
170
+ background-position: center;
170
171
  }
171
172
 
172
173
  .pc-visible {
@@ -181,7 +182,8 @@ const link = computed(() => withBase(wrapperCleanUrls(!!cleanUrls, props.route))
181
182
  .cover-img {
182
183
  width: 100px;
183
184
  height: 60px;
184
- background-size: 100px 60px;
185
+ background-size: contain;
186
+ background-position: center;
185
187
  }
186
188
 
187
189
  .pc-visible {
@@ -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>
@@ -108,11 +108,6 @@ export function useBlogThemeMode() {
108
108
  return inject(configSymbol)!.value?.blog?.blog ?? true
109
109
  }
110
110
 
111
- export function useGiscusConfig() {
112
- const blogConfig = useConfig()
113
- return blogConfig.config?.blog?.comment
114
- }
115
-
116
111
  export function useArticles() {
117
112
  const blogConfig = useConfig()
118
113
  const articles = computed(() => blogConfig.config?.blog?.pagesData || [])
@@ -100,7 +100,9 @@ export namespace Theme {
100
100
  type: string
101
101
  }
102
102
 
103
- export interface CommentConfig extends GiscusConfig {
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
- * power by https://giscus.app/zh-CN
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,7 @@ export namespace Theme {
424
439
  */
425
440
  oml2d?: Oml2dOptions
426
441
  homeTags?: boolean
442
+ buttonAfterArticle?: ButtonAfterArticleConfig | false
427
443
  }
428
444
 
429
445
  export interface BackToTop {
@@ -509,4 +525,20 @@ export namespace Theme {
509
525
  */
510
526
  handleChangeSlogan?: (oldSlogan: string) => string | Promise<string>
511
527
  }
528
+ export interface ButtonAfterArticleConfig {
529
+ openTitle?: string
530
+ closeTitle?: string
531
+ content?: string
532
+ icon?: 'aliPay' | 'wechatPay' | string
533
+ /**
534
+ * 按钮尺寸
535
+ * @default 'default'
536
+ */
537
+ size?: 'small' | 'default' | 'large'
538
+ /**
539
+ * 默认展开
540
+ * @default false
541
+ */
542
+ expand?: boolean
543
+ }
512
544
  }
@@ -52,3 +52,26 @@ export const themeSVG = `<svg width="128" height="128" viewBox="0 0 24 24" xmlns
52
52
  export const icpSVG = '<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" data-v-2f084f89=""><title data-v-2f084f89="">ICP备案号</title><path d="M778.24 163.84c-76.8-40.96-165.888-61.44-269.312-61.44s-192.512 20.48-269.312 61.44h-133.12l23.552 337.92c8.192 113.664 67.584 217.088 162.816 280.576l215.04 144.384 215.04-144.384c96.256-63.488 155.648-166.912 163.84-280.576l23.552-337.92H778.24z m47.104 333.824c-7.168 94.208-56.32 181.248-135.168 233.472l-181.248 120.832L327.68 731.136c-78.848-53.248-129.024-139.264-135.168-233.472L173.056 225.28h136.192v-26.624c58.368-23.552 124.928-34.816 199.68-34.816s141.312 12.288 199.68 34.816V225.28H844.8l-19.456 272.384z" data-v-2f084f89=""></path><path d="M685.056 328.704v-46.08H455.68c2.048-4.096 6.144-9.216 11.264-15.36 5.12-7.168 9.216-12.288 11.264-15.36L419.84 240.64c-31.744 46.08-75.776 87.04-133.12 123.904 4.096 4.096 10.24 11.264 18.432 21.504l17.408 17.408c23.552-15.36 45.056-31.744 63.488-50.176 26.624 25.6 49.152 43.008 67.584 51.2-46.08 15.36-104.448 27.648-175.104 35.84 2.048 5.12 6.144 13.312 9.216 24.576 4.096 11.264 6.144 19.456 7.168 24.576l39.936-7.168v218.112H389.12V680.96h238.592v19.456h54.272V481.28H348.16c60.416-12.288 114.688-27.648 163.84-46.08 49.152 19.456 118.784 34.816 210.944 46.08 5.12-17.408 10.24-34.816 17.408-51.2-62.464-4.096-116.736-12.288-161.792-24.576 38.912-20.48 74.752-46.08 106.496-76.8z m-150.528 194.56h94.208v41.984h-94.208v-41.984z m0 78.848h94.208v41.984h-94.208v-41.984z m-144.384-78.848h94.208v41.984H390.144v-41.984z m0 78.848h94.208v41.984H390.144v-41.984zM424.96 326.656h182.272c-26.624 22.528-57.344 41.984-94.208 57.344-31.744-15.36-61.44-34.816-88.064-57.344z" data-v-2f084f89=""></path></svg>'
53
53
 
54
54
  export const copyrightSVG = '<svg t="1695543755857" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="89399" width="200" height="200"><path d="M512 16C238.066 16 16 238.066 16 512s222.066 496 496 496 496-222.066 496-496S785.934 16 512 16z m234.268 693.506c-3.184 3.734-79.552 91.462-219.702 91.462-169.384 0-288.968-126.52-288.968-291.134 0-162.606 124.008-286.802 287.524-286.802 133.914 0 203.93 74.63 206.844 77.808a24 24 0 0 1 2.476 29.246l-44.76 69.31c-8.098 12.534-25.548 14.702-36.468 4.59-0.466-0.428-53.058-47.76-123.76-47.76-92.232 0-147.832 67.15-147.832 152.164 0 79.204 51.028 159.384 148.554 159.384 77.394 0 130.56-56.676 131.088-57.25 10.264-11.13 28.118-10.066 37.016 2.106l49.094 67.144a24.002 24.002 0 0 1-1.106 29.732z" p-id="89400"></path></svg>'
55
+
56
+ export const aliPaySVG = `
57
+ <svg
58
+ id="mx_n_1711731519286" t="1711731519285" class="icon" viewBox="0 0 1024 1024" version="1.1"
59
+ xmlns="http://www.w3.org/2000/svg" p-id="9945" width="16" height="16"
60
+ >
61
+ <path
62
+ d="M230.404 576.536c-12.087 9.728-25.043 23.93-28.805 41.984-5.12 24.666-1.069 55.541 22.728 79.761 28.828 29.362 72.637 37.398 91.56 38.779 51.4 3.717 106.184-21.772 147.477-50.844 16.184-11.42 43.899-34.349 70.39-69.721-59.37-30.653-133.477-64.557-212.703-61.24-40.47 1.692-69.454 10.084-90.647 21.281z m752.859 135.545C1009.463 650.574 1024 582.968 1024 512 1024 229.688 794.335 0 512 0 229.665 0 0 229.688 0 512c0 282.335 229.665 512 512 512 170.385 0 321.491-83.723 414.631-212.124-87.997-43.742-233.027-115.734-322.36-159.299-42.63 48.596-105.65 97.303-176.84 118.495-44.722 13.29-85.037 18.365-127.199 9.75-41.739-8.548-72.481-28.093-90.401-47.683-9.127-9.995-19.612-22.706-27.203-37.82a71.25 71.25 0 0 0 1.202 3.049s-4.363-7.524-7.702-19.5a85.994 85.994 0 0 1-3.34-18.143 93.517 93.517 0 0 1-0.2-13.045c-0.378-7.702-0.066-15.783 1.67-24.064 4.185-20.235 12.822-43.81 35.172-65.692 49.063-48.039 114.777-50.621 148.814-50.42 50.421 0.289 138.04 22.35 211.812 48.439 20.436-43.52 33.547-90.068 42.007-121.1H305.308v-33.168h157.518v-66.337H272.139v-33.169h190.687v-66.315c0-9.105 1.803-16.584 16.584-16.584h74.619v82.899h207.293v33.169H554.029v66.337h165.82s-16.65 92.828-68.719 184.32c115.557 41.272 278.128 104.849 332.133 126.086z"
63
+ fill="white" p-id="9946"
64
+ />
65
+ </svg>
66
+ `
67
+ export const weChatPaySVG = `
68
+ <svg
69
+ t="1711730357270" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
70
+ p-id="4392" width="16" height="16"
71
+ >
72
+ <path
73
+ d="M512 1024a512 512 0 1 1 512-512 512 512 0 0 1-512 512z m-112.523636-836.538182c-144.989091 0-262.516364 100.538182-262.516364 224.465455 0 74.007273 42.123636 139.636364 106.705455 180.363636l-19.549091 78.312727 86.807272-47.592727a301.265455 301.265455 0 0 0 88.669091 13.381818h2.210909a178.967273 178.967273 0 0 1-3.607272-34.909091c0-115.083636 109.498182-208.407273 244.363636-208.407272 6.167273 0 11.636364 0 18.152727 0.814545-10.589091-115.665455-123.461818-206.778182-261.469091-206.778182z m246.690909 226.443637c-124.741818 0-225.861818 86.109091-225.861818 192.465454s101.003636 192.349091 225.861818 192.349091a257.047273 257.047273 0 0 0 99.723636-20.014545l77.265455 40.610909L802.909091 744.727273a179.316364 179.316364 0 0 0 69.003636-138.24c0-106.24-101.12-192.465455-225.861818-192.465455z m81.454545 152.087272a31.767273 31.767273 0 1 1 32.349091-31.767272 32 32 0 0 1-32.349091 31.767272z m-164.072727 0a31.767273 31.767273 0 1 1 32.349091-31.767272 32 32 0 0 1-32.349091 31.767272zM502.341818 373.527273a34.909091 34.909091 0 1 1 34.909091-34.909091 34.909091 34.909091 0 0 1-34.909091 34.909091z m-206.196363 0a34.909091 34.909091 0 1 1 34.90909-34.909091 34.909091 34.909091 0 0 1-34.90909 34.909091z m0 0"
74
+ fill="white" p-id="4393"
75
+ />
76
+ </svg>
77
+ `
package/src/node.ts CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  patchOptimizeDeps,
7
7
  registerMdPlugins,
8
8
  } from './utils/node/mdPlugins'
9
- import { checkConfig, getArticles, patchVPThemeConfig } from './utils/node/theme'
9
+ import { checkConfig, getArticles, patchVPConfig, patchVPThemeConfig } from './utils/node/theme'
10
10
  import { getVitePlugins, registerVitePlugins } from './utils/node/vitePlugins'
11
11
 
12
12
  /**
@@ -34,6 +34,8 @@ export function getThemeConfig(cfg?: Partial<Theme.BlogConfig>) {
34
34
  // patch extraVPConfig
35
35
  patchMermaidPluginCfg(extraVPConfig)
36
36
  patchOptimizeDeps(extraVPConfig)
37
+
38
+ patchVPConfig(extraVPConfig, cfg)
37
39
  return {
38
40
  themeConfig: {
39
41
  blog: {
@@ -125,7 +125,15 @@ export function getArticles(cfg?: Partial<Theme.BlogConfig>) {
125
125
  }
126
126
 
127
127
  export function patchVPConfig(vpConfig: any, cfg?: Partial<Theme.BlogConfig>) {
128
- // TODO: 待确定场景
128
+ vpConfig.head = vpConfig.head || []
129
+ // Artalk 资源地址
130
+ if (cfg?.comment && 'type' in cfg.comment && cfg?.comment?.type === 'artalk') {
131
+ const server = cfg.comment?.options?.server
132
+ if (server) {
133
+ vpConfig.head.push(['link', { href: `${server}/dist/Artalk.css`, rel: 'stylesheet' }])
134
+ vpConfig.head.push(['script', { src: `${server}/dist/Artalk.js`, id: 'artalk-script' }])
135
+ }
136
+ }
129
137
  }
130
138
 
131
139
  export function patchVPThemeConfig(
@@ -1,3 +1,13 @@
1
+ import type Artalk, { ArtalkConfig } from 'artalk'
2
+
3
+ declare global {
4
+ interface Window {
5
+ Artalk: {
6
+ init(options: Partial<ArtalkConfig>): Artalk
7
+ }
8
+ }
9
+ }
10
+
1
11
  declare module '*.vue' {
2
12
  import type { ComponentOptions } from 'vue'
3
13