@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
package/src/constants/svg.ts
CHANGED
|
@@ -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
|
+
`
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { useData } from 'vitepress'
|
|
2
|
+
import { nextTick, provide } from 'vue'
|
|
3
|
+
import { useDarkTransitionConfig } from '../composables/config/blog'
|
|
4
|
+
|
|
5
|
+
export function useDarkTransition() {
|
|
6
|
+
const { isDark } = useData()
|
|
7
|
+
|
|
8
|
+
const isOpenDarkTransition = useDarkTransitionConfig()
|
|
9
|
+
|
|
10
|
+
if (!isOpenDarkTransition) {
|
|
11
|
+
return
|
|
12
|
+
}
|
|
13
|
+
const enableTransitions = () =>
|
|
14
|
+
'startViewTransition' in document
|
|
15
|
+
&& window.matchMedia('(prefers-reduced-motion: no-preference)').matches
|
|
16
|
+
|
|
17
|
+
provide('toggle-appearance', async ({ clientX: x, clientY: y }: MouseEvent) => {
|
|
18
|
+
if (!enableTransitions()) {
|
|
19
|
+
isDark.value = !isDark.value
|
|
20
|
+
return
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const clipPath = [
|
|
24
|
+
`circle(0px at ${x}px ${y}px)`,
|
|
25
|
+
`circle(${Math.hypot(
|
|
26
|
+
Math.max(x, innerWidth - x),
|
|
27
|
+
Math.max(y, innerHeight - y)
|
|
28
|
+
)}px at ${x}px ${y}px)`
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
// @ts-expect-error
|
|
32
|
+
await document.startViewTransition(async () => {
|
|
33
|
+
isDark.value = !isDark.value
|
|
34
|
+
await nextTick()
|
|
35
|
+
}).ready
|
|
36
|
+
|
|
37
|
+
document.documentElement.animate(
|
|
38
|
+
{ clipPath: isDark.value ? clipPath.reverse() : clipPath },
|
|
39
|
+
{
|
|
40
|
+
duration: 300,
|
|
41
|
+
easing: 'ease-in',
|
|
42
|
+
pseudoElement: `::view-transition-${isDark.value ? 'old' : 'new'}(root)`
|
|
43
|
+
}
|
|
44
|
+
)
|
|
45
|
+
})
|
|
46
|
+
}
|
package/src/hooks/useOml2d.ts
CHANGED
|
@@ -59,15 +59,21 @@ export function useOml2d() {
|
|
|
59
59
|
...defaultOptions.tips,
|
|
60
60
|
...oml2dOptions.tips,
|
|
61
61
|
style: {
|
|
62
|
+
// @ts-expect-error
|
|
62
63
|
...defaultOptions?.tips?.style,
|
|
64
|
+
// @ts-expect-error
|
|
63
65
|
...oml2dOptions?.tips?.style
|
|
64
66
|
},
|
|
65
67
|
mobileStyle: {
|
|
68
|
+
// @ts-expect-error
|
|
66
69
|
...defaultOptions?.tips?.mobileStyle,
|
|
70
|
+
// @ts-expect-error
|
|
67
71
|
...oml2dOptions?.tips?.mobileStyle
|
|
68
72
|
},
|
|
69
73
|
copyTips: {
|
|
74
|
+
// @ts-expect-error
|
|
70
75
|
...defaultOptions?.tips?.copyTips,
|
|
76
|
+
// @ts-expect-error
|
|
71
77
|
...oml2dOptions?.tips?.copyTips
|
|
72
78
|
}
|
|
73
79
|
}
|
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: {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
::view-transition-old(root),
|
|
2
|
+
::view-transition-new(root) {
|
|
3
|
+
animation: none;
|
|
4
|
+
mix-blend-mode: normal;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
::view-transition-old(root),
|
|
8
|
+
.dark::view-transition-new(root) {
|
|
9
|
+
z-index: 1;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
::view-transition-new(root),
|
|
13
|
+
.dark::view-transition-old(root) {
|
|
14
|
+
z-index: 9999;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.blog-theme-layout .VPSwitchAppearance {
|
|
18
|
+
width: 22px !important;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.blog-theme-layout .VPSwitchAppearance .check {
|
|
22
|
+
transform: none !important;
|
|
23
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { PluginOption } from 'vite'
|
|
2
|
+
import type { SiteConfig } from 'vitepress'
|
|
3
|
+
import type { Theme } from '../../composables/config/index'
|
|
4
|
+
import { getArticleMeta } from './theme'
|
|
5
|
+
import { debounce, isEqual } from './index'
|
|
6
|
+
|
|
7
|
+
export function themeReloadPlugin() {
|
|
8
|
+
let blogConfig: Theme.BlogConfig
|
|
9
|
+
let vitepressConfig: SiteConfig
|
|
10
|
+
let docsDir: string
|
|
11
|
+
|
|
12
|
+
const generateRoute = (filepath: string) => {
|
|
13
|
+
return filepath.replace(docsDir, '').replace('.md', '')
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
name: '@sugarat/theme-reload',
|
|
18
|
+
apply: 'serve',
|
|
19
|
+
configureServer(server) {
|
|
20
|
+
const restart = debounce(() => {
|
|
21
|
+
server.restart()
|
|
22
|
+
}, 500)
|
|
23
|
+
server.watcher.on('add', (path) => {
|
|
24
|
+
const route = generateRoute(path)
|
|
25
|
+
const meta = getArticleMeta(path, route, blogConfig?.timeZone)
|
|
26
|
+
blogConfig.pagesData.push({
|
|
27
|
+
route,
|
|
28
|
+
meta
|
|
29
|
+
})
|
|
30
|
+
restart()
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
server.watcher.on('change', (path: string) => {
|
|
34
|
+
const route = generateRoute(path)
|
|
35
|
+
const meta = getArticleMeta(path, route, blogConfig?.timeZone)
|
|
36
|
+
const matched = blogConfig.pagesData.find(v => v.route === route)
|
|
37
|
+
|
|
38
|
+
if (matched && !isEqual(matched.meta, meta, ['date', 'description'])) {
|
|
39
|
+
matched.meta = meta
|
|
40
|
+
restart()
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
server.watcher.on('unlink', (path) => {
|
|
45
|
+
const route = generateRoute(path)
|
|
46
|
+
const idx = blogConfig.pagesData.findIndex(v => v.route === route)
|
|
47
|
+
if (idx >= 0) {
|
|
48
|
+
blogConfig.pagesData.splice(idx, 1)
|
|
49
|
+
restart()
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
},
|
|
53
|
+
configResolved(config: any) {
|
|
54
|
+
vitepressConfig = config.vitepress
|
|
55
|
+
docsDir = vitepressConfig.srcDir
|
|
56
|
+
blogConfig = config.vitepress.site.themeConfig.blog
|
|
57
|
+
},
|
|
58
|
+
} as PluginOption
|
|
59
|
+
}
|
package/src/utils/node/index.ts
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
/* eslint-disable prefer-rest-params */
|
|
3
3
|
import { spawn, spawnSync } from 'node:child_process'
|
|
4
4
|
import path from 'node:path'
|
|
5
|
-
import { formatDate } from '../client'
|
|
6
5
|
|
|
7
6
|
export function clearMatterContent(content: string) {
|
|
8
7
|
let first___: unknown
|
|
@@ -31,16 +30,10 @@ export function clearMatterContent(content: string) {
|
|
|
31
30
|
.join('\n')
|
|
32
31
|
)
|
|
33
32
|
}
|
|
33
|
+
|
|
34
34
|
export function getDefaultTitle(content: string) {
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
.split('\n')
|
|
38
|
-
?.find((str) => {
|
|
39
|
-
return str.startsWith('# ')
|
|
40
|
-
})
|
|
41
|
-
?.slice(2)
|
|
42
|
-
.replace(/^\s+|\s+$/g, '') || ''
|
|
43
|
-
return title
|
|
35
|
+
const match = content.match(/^(#+)\s+(.+)/m)
|
|
36
|
+
return match?.[2] || ''
|
|
44
37
|
}
|
|
45
38
|
|
|
46
39
|
export function getFileBirthTime(url: string) {
|
|
@@ -57,10 +50,10 @@ export function getFileBirthTime(url: string) {
|
|
|
57
50
|
}
|
|
58
51
|
}
|
|
59
52
|
catch (error) {
|
|
60
|
-
return
|
|
53
|
+
return date
|
|
61
54
|
}
|
|
62
55
|
|
|
63
|
-
return
|
|
56
|
+
return date
|
|
64
57
|
}
|
|
65
58
|
|
|
66
59
|
export function getGitTimestamp(file: string) {
|
|
@@ -79,8 +72,9 @@ export function getGitTimestamp(file: string) {
|
|
|
79
72
|
|
|
80
73
|
export function getTextSummary(text: string, count = 100) {
|
|
81
74
|
return (
|
|
82
|
-
|
|
83
|
-
|
|
75
|
+
text
|
|
76
|
+
// 首个标题
|
|
77
|
+
?.replace(/^#+\s+.*/, '')
|
|
84
78
|
// 除去标题
|
|
85
79
|
?.replace(/#/g, '')
|
|
86
80
|
// 除去图片
|
|
@@ -91,9 +85,9 @@ export function getTextSummary(text: string, count = 100) {
|
|
|
91
85
|
?.replace(/\*\*(.*?)\*\*/g, '$1')
|
|
92
86
|
?.split('\n')
|
|
93
87
|
?.filter(v => !!v)
|
|
94
|
-
?.slice(1)
|
|
95
88
|
?.join('\n')
|
|
96
89
|
?.replace(/>(.*)/, '')
|
|
90
|
+
?.trim()
|
|
97
91
|
?.slice(0, count)
|
|
98
92
|
)
|
|
99
93
|
}
|
|
@@ -151,3 +145,43 @@ export function getFirstImagURLFromMD(content: string, route: string) {
|
|
|
151
145
|
|
|
152
146
|
return joinPath('/', relativePath)
|
|
153
147
|
}
|
|
148
|
+
|
|
149
|
+
export function debounce(func: any, delay = 1000) {
|
|
150
|
+
let timeoutId: any
|
|
151
|
+
return (...rest: any[]) => {
|
|
152
|
+
clearTimeout(timeoutId)
|
|
153
|
+
timeoutId = setTimeout(() => {
|
|
154
|
+
func(...rest)
|
|
155
|
+
}, delay)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function isEqual(obj1: any, obj2: any, excludeKeys: string[] = []) {
|
|
160
|
+
const keys1 = Object.keys(obj1).filter(key => !excludeKeys.includes(key))
|
|
161
|
+
const keys2 = Object.keys(obj2).filter(key => !excludeKeys.includes(key))
|
|
162
|
+
|
|
163
|
+
if (keys1.length !== keys2.length) {
|
|
164
|
+
return false
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
for (const key of keys1) {
|
|
168
|
+
if (!keys2.includes(key)) {
|
|
169
|
+
return false
|
|
170
|
+
}
|
|
171
|
+
const val1 = obj1[key]
|
|
172
|
+
const val2 = obj2[key]
|
|
173
|
+
const areObjects = isObject(val1) && isObject(val2)
|
|
174
|
+
if (
|
|
175
|
+
(areObjects && !isEqual(val1, val2, excludeKeys))
|
|
176
|
+
|| (!areObjects && val1 !== val2)
|
|
177
|
+
) {
|
|
178
|
+
return false
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return true
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export function isObject(obj: any) {
|
|
186
|
+
return obj != null && typeof obj === 'object'
|
|
187
|
+
}
|
package/src/utils/node/theme.ts
CHANGED
|
@@ -21,111 +21,114 @@ export function patchDefaultThemeSideBar(cfg?: Partial<Theme.BlogConfig>) {
|
|
|
21
21
|
: undefined
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
export function getPageRoute(filepath: string, srcDir: string) {
|
|
25
|
+
let route = filepath.replace('.md', '')
|
|
26
|
+
// 去除 srcDir 处理目录名
|
|
27
|
+
// TODO:优化 路径处理,同VitePress 内部一致
|
|
28
|
+
if (route.startsWith('./')) {
|
|
29
|
+
route = route.replace(
|
|
30
|
+
new RegExp(
|
|
31
|
+
`^\\.\\/${path
|
|
32
|
+
.join(srcDir, '/')
|
|
33
|
+
.replace(new RegExp(`\\${path.sep}`, 'g'), '/')}`
|
|
34
|
+
),
|
|
35
|
+
''
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
route = route.replace(
|
|
40
|
+
new RegExp(
|
|
41
|
+
`^${path
|
|
42
|
+
.join(srcDir, '/')
|
|
43
|
+
.replace(new RegExp(`\\${path.sep}`, 'g'), '/')}`
|
|
44
|
+
),
|
|
45
|
+
''
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
return `/${route}`
|
|
49
|
+
}
|
|
26
50
|
|
|
51
|
+
const defaultTimeZoneOffset = new Date().getTimezoneOffset() / -60
|
|
52
|
+
export function getArticleMeta(filepath: string, route: string, timeZone = defaultTimeZoneOffset) {
|
|
53
|
+
const fileContent = fs.readFileSync(filepath, 'utf-8')
|
|
54
|
+
|
|
55
|
+
const { data: frontmatter, excerpt, content } = matter(fileContent, {
|
|
56
|
+
excerpt: true,
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
const meta: Partial<Theme.PageMeta> = {
|
|
60
|
+
...frontmatter
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (!meta.title) {
|
|
64
|
+
meta.title = getDefaultTitle(content)
|
|
65
|
+
}
|
|
66
|
+
if (!meta.date) {
|
|
67
|
+
meta.date = formatDate(getFileBirthTime(filepath))
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
meta.date = formatDate(
|
|
71
|
+
new Date(`${new Date(meta.date).toUTCString()}+${timeZone}`)
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// 处理tags和categories,兼容历史文章
|
|
76
|
+
meta.categories
|
|
77
|
+
= typeof meta.categories === 'string'
|
|
78
|
+
? [meta.categories]
|
|
79
|
+
: meta.categories
|
|
80
|
+
meta.tags = typeof meta.tags === 'string' ? [meta.tags] : meta.tags
|
|
81
|
+
meta.tag = [meta.tag || []]
|
|
82
|
+
.flat()
|
|
83
|
+
.concat([
|
|
84
|
+
...new Set([...(meta.categories || []), ...(meta.tags || [])])
|
|
85
|
+
])
|
|
86
|
+
|
|
87
|
+
// 获取摘要信息
|
|
88
|
+
// TODO:摘要生成优化
|
|
89
|
+
meta.description
|
|
90
|
+
= meta.description || getTextSummary(content, 100) || excerpt
|
|
91
|
+
|
|
92
|
+
// 获取封面图
|
|
93
|
+
meta.cover
|
|
94
|
+
= meta.cover
|
|
95
|
+
?? (getFirstImagURLFromMD(fileContent, route))
|
|
96
|
+
|
|
97
|
+
// 是否发布 默认发布
|
|
98
|
+
if (meta.publish === false) {
|
|
99
|
+
meta.hidden = true
|
|
100
|
+
meta.recommend = false
|
|
101
|
+
}
|
|
102
|
+
return meta as Theme.PageMeta
|
|
103
|
+
}
|
|
27
104
|
export function getArticles(cfg?: Partial<Theme.BlogConfig>) {
|
|
28
105
|
const srcDir = cfg?.srcDir || process.argv.slice(2)?.[1] || '.'
|
|
29
106
|
const files = glob.sync(`${srcDir}/**/*.md`, { ignore: ['node_modules'] })
|
|
30
107
|
|
|
31
108
|
// 文章数据
|
|
32
|
-
const
|
|
33
|
-
.map((
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
.replace('.md', '')
|
|
37
|
-
|
|
38
|
-
// 去除 srcDir 处理目录名
|
|
39
|
-
if (route.startsWith('./')) {
|
|
40
|
-
route = route.replace(
|
|
41
|
-
new RegExp(
|
|
42
|
-
`^\\.\\/${path
|
|
43
|
-
.join(srcDir, '/')
|
|
44
|
-
.replace(new RegExp(`\\${path.sep}`, 'g'), '/')}`
|
|
45
|
-
),
|
|
46
|
-
''
|
|
47
|
-
)
|
|
48
|
-
}
|
|
49
|
-
else {
|
|
50
|
-
route = route.replace(
|
|
51
|
-
new RegExp(
|
|
52
|
-
`^${path
|
|
53
|
-
.join(srcDir, '/')
|
|
54
|
-
.replace(new RegExp(`\\${path.sep}`, 'g'), '/')}`
|
|
55
|
-
),
|
|
56
|
-
''
|
|
57
|
-
)
|
|
58
|
-
}
|
|
59
|
-
// hack:RSS使用
|
|
60
|
-
pageMap.set(`/${route}`, v)
|
|
61
|
-
|
|
62
|
-
const fileContent = fs.readFileSync(v, 'utf-8')
|
|
63
|
-
// TODO:摘要生成优化
|
|
64
|
-
// TODO: 用上内容content
|
|
65
|
-
const { data: frontmatter, excerpt } = matter(fileContent, {
|
|
66
|
-
excerpt: true
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
const meta: Partial<Theme.PageMeta> = {
|
|
70
|
-
...frontmatter
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (!meta.title) {
|
|
74
|
-
// TODO:优化标题的采集
|
|
75
|
-
meta.title = getDefaultTitle(fileContent)
|
|
76
|
-
}
|
|
77
|
-
if (!meta.date) {
|
|
78
|
-
// getGitTimestamp(v).then((v) => {
|
|
79
|
-
// meta.date = formatDate(v)
|
|
80
|
-
// })
|
|
81
|
-
meta.date = getFileBirthTime(v)
|
|
82
|
-
}
|
|
83
|
-
else {
|
|
84
|
-
const timeZone = cfg?.timeZone ?? 8
|
|
85
|
-
meta.date = formatDate(
|
|
86
|
-
new Date(`${new Date(meta.date).toUTCString()}+${timeZone}`)
|
|
87
|
-
)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// 处理tags和categories,兼容历史文章
|
|
91
|
-
meta.categories
|
|
92
|
-
= typeof meta.categories === 'string'
|
|
93
|
-
? [meta.categories]
|
|
94
|
-
: meta.categories
|
|
95
|
-
meta.tags = typeof meta.tags === 'string' ? [meta.tags] : meta.tags
|
|
96
|
-
meta.tag = [meta.tag || []]
|
|
97
|
-
.flat()
|
|
98
|
-
.concat([
|
|
99
|
-
...new Set([...(meta.categories || []), ...(meta.tags || [])])
|
|
100
|
-
])
|
|
101
|
-
|
|
102
|
-
// 获取摘要信息
|
|
103
|
-
const wordCount = 100
|
|
104
|
-
meta.description
|
|
105
|
-
= meta.description || getTextSummary(fileContent, wordCount)
|
|
106
|
-
|
|
107
|
-
// 获取封面图
|
|
108
|
-
meta.cover
|
|
109
|
-
= meta.cover
|
|
110
|
-
?? (getFirstImagURLFromMD(fileContent, `/${route}`))
|
|
111
|
-
|
|
112
|
-
// 是否发布 默认发布
|
|
113
|
-
if (meta.publish === false) {
|
|
114
|
-
meta.hidden = true
|
|
115
|
-
meta.recommend = false
|
|
116
|
-
}
|
|
117
|
-
|
|
109
|
+
const pageData = files
|
|
110
|
+
.map((filepath) => {
|
|
111
|
+
const route = getPageRoute(filepath, srcDir)
|
|
112
|
+
const meta = getArticleMeta(filepath, route, cfg?.timeZone)
|
|
118
113
|
return {
|
|
119
|
-
route
|
|
114
|
+
route,
|
|
120
115
|
meta
|
|
121
116
|
}
|
|
122
117
|
})
|
|
123
118
|
.filter(v => v.meta.layout !== 'home')
|
|
124
|
-
return
|
|
119
|
+
return pageData as Theme.PageData[]
|
|
125
120
|
}
|
|
126
121
|
|
|
127
122
|
export function patchVPConfig(vpConfig: any, cfg?: Partial<Theme.BlogConfig>) {
|
|
128
|
-
|
|
123
|
+
vpConfig.head = vpConfig.head || []
|
|
124
|
+
// Artalk 资源地址
|
|
125
|
+
if (cfg?.comment && 'type' in cfg.comment && cfg?.comment?.type === 'artalk') {
|
|
126
|
+
const server = cfg.comment?.options?.server
|
|
127
|
+
if (server) {
|
|
128
|
+
vpConfig.head.push(['link', { href: `${server}/dist/Artalk.css`, rel: 'stylesheet' }])
|
|
129
|
+
vpConfig.head.push(['script', { src: `${server}/dist/Artalk.js`, id: 'artalk-script' }])
|
|
130
|
+
}
|
|
131
|
+
}
|
|
129
132
|
}
|
|
130
133
|
|
|
131
134
|
export function patchVPThemeConfig(
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
import { RssPlugin } from 'vitepress-plugin-rss'
|
|
13
13
|
import type { Theme } from '../../composables/config/index'
|
|
14
14
|
import { _require } from './mdPlugins'
|
|
15
|
+
import { themeReloadPlugin } from './hot-reload-plugin'
|
|
15
16
|
import { joinPath } from './index'
|
|
16
17
|
|
|
17
18
|
export function getVitePlugins(cfg?: Partial<Theme.BlogConfig>) {
|
|
@@ -19,10 +20,16 @@ export function getVitePlugins(cfg?: Partial<Theme.BlogConfig>) {
|
|
|
19
20
|
|
|
20
21
|
// Build完后运行的一系列列方法
|
|
21
22
|
const buildEndFn: any[] = []
|
|
23
|
+
|
|
22
24
|
// 执行自定义的 buildEnd 钩子
|
|
23
25
|
plugins.push(inlineBuildEndPlugin(buildEndFn))
|
|
26
|
+
|
|
24
27
|
// 处理cover image的路径(暂只支持自动识别的文章首图)
|
|
25
28
|
plugins.push(coverImgTransform())
|
|
29
|
+
|
|
30
|
+
// 自动重载首页
|
|
31
|
+
plugins.push(themeReloadPlugin())
|
|
32
|
+
|
|
26
33
|
// 内置简化版的pagefind
|
|
27
34
|
if (cfg && cfg.search !== false) {
|
|
28
35
|
const ops = cfg.search instanceof Object ? cfg.search : {}
|
|
@@ -47,13 +54,6 @@ export function getVitePlugins(cfg?: Partial<Theme.BlogConfig>) {
|
|
|
47
54
|
if (cfg?.RSS) {
|
|
48
55
|
plugins.push(RssPlugin(cfg.RSS))
|
|
49
56
|
}
|
|
50
|
-
// 未来移除使用
|
|
51
|
-
// if (cfg && cfg.search !== undefined) {
|
|
52
|
-
// console.log(
|
|
53
|
-
// '已从内部移除 pagefind 支持,请单独安装 vitepress-plugin-pagefind 插件使用'
|
|
54
|
-
// )
|
|
55
|
-
// }
|
|
56
|
-
|
|
57
57
|
return plugins
|
|
58
58
|
}
|
|
59
59
|
|
package/types/vue-shim.d.ts
CHANGED