@sugarat/theme 0.4.9 → 0.4.11
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 +86 -0
- package/node.js +1 -1
- package/package.json +5 -4
- package/src/components/BlogArticleAnalyze.vue +20 -32
- package/src/components/BlogHotArticle.vue +4 -2
- package/src/components/BlogItem.vue +6 -3
- package/src/components/BlogRecommendArticle.vue +35 -17
- package/src/composables/config/blog.ts +103 -0
- package/src/composables/config/index.ts +87 -0
- package/src/utils/client/index.ts +4 -0
package/node.d.ts
CHANGED
|
@@ -175,6 +175,16 @@ declare namespace Theme {
|
|
|
175
175
|
* @default 'sidebar'
|
|
176
176
|
*/
|
|
177
177
|
style?: 'card' | 'sidebar';
|
|
178
|
+
/**
|
|
179
|
+
* 是否在左侧显示日期
|
|
180
|
+
* @default true
|
|
181
|
+
*/
|
|
182
|
+
showDate?: boolean;
|
|
183
|
+
/**
|
|
184
|
+
* 是否在左侧展示序号
|
|
185
|
+
* @default true
|
|
186
|
+
*/
|
|
187
|
+
showNum?: boolean;
|
|
178
188
|
}
|
|
179
189
|
interface HomeAnalysis {
|
|
180
190
|
articles?: {
|
|
@@ -199,6 +209,10 @@ declare namespace Theme {
|
|
|
199
209
|
analysis?: HomeAnalysis;
|
|
200
210
|
}
|
|
201
211
|
interface ArticleConfig {
|
|
212
|
+
/**
|
|
213
|
+
* 文章分析数据展示标题
|
|
214
|
+
*/
|
|
215
|
+
analyzeTitles?: ArticleAnalyzeTitles;
|
|
202
216
|
readingTime?: boolean;
|
|
203
217
|
/**
|
|
204
218
|
* 阅读时间分析展示位置
|
|
@@ -207,6 +221,48 @@ declare namespace Theme {
|
|
|
207
221
|
readingTimePosition?: 'inline' | 'newLine' | 'top';
|
|
208
222
|
hiddenCover?: boolean;
|
|
209
223
|
}
|
|
224
|
+
interface ArticleAnalyzeTitles {
|
|
225
|
+
/**
|
|
226
|
+
* 字数:{{value}} 个字
|
|
227
|
+
*/
|
|
228
|
+
topWordCount?: string;
|
|
229
|
+
/**
|
|
230
|
+
* 预计:{{value}} 分钟
|
|
231
|
+
*/
|
|
232
|
+
topReadTime?: string;
|
|
233
|
+
/**
|
|
234
|
+
* {{value}} 个字
|
|
235
|
+
*/
|
|
236
|
+
inlineWordCount?: string;
|
|
237
|
+
/**
|
|
238
|
+
* {{value}} 分钟
|
|
239
|
+
*/
|
|
240
|
+
inlineReadTime?: string;
|
|
241
|
+
/**
|
|
242
|
+
* 文章字数
|
|
243
|
+
*/
|
|
244
|
+
wordCount?: string;
|
|
245
|
+
/**
|
|
246
|
+
* 预计阅读时间
|
|
247
|
+
*/
|
|
248
|
+
readTime?: string;
|
|
249
|
+
/**
|
|
250
|
+
* 本文作者
|
|
251
|
+
*/
|
|
252
|
+
author?: string;
|
|
253
|
+
/**
|
|
254
|
+
* 发布时间
|
|
255
|
+
*/
|
|
256
|
+
publishDate?: string;
|
|
257
|
+
/**
|
|
258
|
+
* 最近修改时间
|
|
259
|
+
*/
|
|
260
|
+
lastUpdated?: string;
|
|
261
|
+
/**
|
|
262
|
+
* 标签
|
|
263
|
+
*/
|
|
264
|
+
tag?: string;
|
|
265
|
+
}
|
|
210
266
|
interface Alert {
|
|
211
267
|
type: 'success' | 'warning' | 'info' | 'error';
|
|
212
268
|
/**
|
|
@@ -335,6 +391,10 @@ declare namespace Theme {
|
|
|
335
391
|
type ThemeColor = 'vp-default' | 'vp-green' | 'vp-yellow' | 'vp-red' | 'el-blue' | 'el-yellow' | 'el-green' | 'el-red';
|
|
336
392
|
interface BlogConfig {
|
|
337
393
|
blog?: false;
|
|
394
|
+
/**
|
|
395
|
+
* 展示日期格式化
|
|
396
|
+
*/
|
|
397
|
+
formatShowDate?: FormatShowDate;
|
|
338
398
|
/**
|
|
339
399
|
* 内置一些主题色
|
|
340
400
|
* @default 'vp-default'
|
|
@@ -441,6 +501,32 @@ declare namespace Theme {
|
|
|
441
501
|
*/
|
|
442
502
|
imageStyle?: ImageStyleConfig;
|
|
443
503
|
}
|
|
504
|
+
type FormatShowDate = {
|
|
505
|
+
/**
|
|
506
|
+
* 刚刚
|
|
507
|
+
*/
|
|
508
|
+
justNow?: string;
|
|
509
|
+
/**
|
|
510
|
+
* 秒前
|
|
511
|
+
*/
|
|
512
|
+
secondsAgo?: string;
|
|
513
|
+
/**
|
|
514
|
+
* 分钟前
|
|
515
|
+
*/
|
|
516
|
+
minutesAgo?: string;
|
|
517
|
+
/**
|
|
518
|
+
* 小时前
|
|
519
|
+
*/
|
|
520
|
+
hoursAgo?: string;
|
|
521
|
+
/**
|
|
522
|
+
* 天前
|
|
523
|
+
*/
|
|
524
|
+
daysAgo?: string;
|
|
525
|
+
/**
|
|
526
|
+
* 周前
|
|
527
|
+
*/
|
|
528
|
+
weeksAgo?: string;
|
|
529
|
+
} | ((date: Date | string) => string);
|
|
444
530
|
interface BackToTop {
|
|
445
531
|
/**
|
|
446
532
|
* 距离顶部多少距离出现
|
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.3.
|
|
43
|
+
// ../../node_modules/.pnpm/vitepress-plugin-tabs@0.2.0_vitepress@1.3.4_@algolia+client-search@4.19.1_@types+node@20.6.3__ovjzvjgjmyeesvgttjdmi2b3dm/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) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sugarat/theme",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.11",
|
|
4
4
|
"description": "简约风的 Vitepress 博客主题,sugarat vitepress blog theme",
|
|
5
5
|
"author": "sugar",
|
|
6
6
|
"license": "MIT",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"vitepress-plugin-tabs": "0.2.0",
|
|
53
53
|
"@sugarat/theme-shared": "0.0.2",
|
|
54
54
|
"vitepress-plugin-pagefind": "0.4.10",
|
|
55
|
-
"vitepress-plugin-rss": "0.2.
|
|
55
|
+
"vitepress-plugin-rss": "0.2.10"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@element-plus/icons-vue": "^2.3.1",
|
|
@@ -62,8 +62,9 @@
|
|
|
62
62
|
"sass": "^1.77.8",
|
|
63
63
|
"typescript": "^5.4.5",
|
|
64
64
|
"vite": "^5.2.11",
|
|
65
|
-
"vitepress": "1.3.
|
|
66
|
-
"vue": "^3.4.26"
|
|
65
|
+
"vitepress": "1.3.4",
|
|
66
|
+
"vue": "^3.4.26",
|
|
67
|
+
"vitepress-plugin-51la": "0.1.0"
|
|
67
68
|
},
|
|
68
69
|
"scripts": {
|
|
69
70
|
"dev": "npm run build:node && npm run dev:docs",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
// 阅读时间计算方式参考
|
|
3
3
|
// https://zhuanlan.zhihu.com/p/36375802
|
|
4
|
-
import { useData
|
|
5
|
-
import { computed, onMounted, ref
|
|
4
|
+
import { useData } from 'vitepress'
|
|
5
|
+
import { computed, onMounted, ref } from 'vue'
|
|
6
6
|
import { ElIcon } from 'element-plus'
|
|
7
7
|
import {
|
|
8
8
|
AlarmClock,
|
|
@@ -11,11 +11,12 @@ import {
|
|
|
11
11
|
EditPen,
|
|
12
12
|
UserFilled
|
|
13
13
|
} from '@element-plus/icons-vue'
|
|
14
|
-
import { useBlogConfig, useCurrentArticle, useDocMetaInsertPosition, useDocMetaInsertSelector } from '../composables/config/blog'
|
|
15
|
-
import countWord, { formatDate
|
|
14
|
+
import { useAnalyzeTitles, useBlogConfig, useCurrentArticle, useDocMetaInsertPosition, useDocMetaInsertSelector, useFormatShowDate } from '../composables/config/blog'
|
|
15
|
+
import countWord, { formatDate } from '../utils/client'
|
|
16
16
|
import type { Theme } from '../composables/config'
|
|
17
17
|
import BlogDocCover from './BlogDocCover.vue'
|
|
18
18
|
|
|
19
|
+
const formatShowDate = useFormatShowDate()
|
|
19
20
|
const { article, authorList } = useBlogConfig()
|
|
20
21
|
const readingTimePosition = article?.readingTimePosition || 'inline'
|
|
21
22
|
|
|
@@ -57,7 +58,6 @@ const readTime = computed(() => {
|
|
|
57
58
|
const docMetaInsertSelector = useDocMetaInsertSelector()
|
|
58
59
|
const docMetaInsertPosition = useDocMetaInsertPosition()
|
|
59
60
|
|
|
60
|
-
const route = useRoute()
|
|
61
61
|
const $des = ref<HTMLDivElement>()
|
|
62
62
|
|
|
63
63
|
function analyze() {
|
|
@@ -100,9 +100,6 @@ onMounted(() => {
|
|
|
100
100
|
analyze()
|
|
101
101
|
})
|
|
102
102
|
|
|
103
|
-
// 阅读量
|
|
104
|
-
const pv = ref(6666)
|
|
105
|
-
|
|
106
103
|
const currentArticle = useCurrentArticle()
|
|
107
104
|
const publishDate = computed(() => {
|
|
108
105
|
return formatShowDate(currentArticle.value?.meta?.date || '')
|
|
@@ -112,9 +109,6 @@ const hoverDate = computed(() => {
|
|
|
112
109
|
return currentArticle.value?.meta?.date ? `: ${formatDate(currentArticle.value?.meta?.date)}` : ''
|
|
113
110
|
})
|
|
114
111
|
|
|
115
|
-
const timeTitle = computed(() =>
|
|
116
|
-
frontmatter.value.date ? '发布时间' : '最近修改时间'
|
|
117
|
-
)
|
|
118
112
|
const hiddenTime = computed(() => frontmatter.value.date === false)
|
|
119
113
|
|
|
120
114
|
const { theme } = useData<Theme.Config>()
|
|
@@ -129,15 +123,9 @@ const currentAuthorInfo = computed(() =>
|
|
|
129
123
|
)
|
|
130
124
|
const hiddenAuthor = computed(() => frontmatter.value.author === false)
|
|
131
125
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
// TODO: 调用接口取数据
|
|
136
|
-
pv.value = 123
|
|
137
|
-
},
|
|
138
|
-
{
|
|
139
|
-
immediate: true
|
|
140
|
-
}
|
|
126
|
+
const { topWordCount, topReadTime, inlineWordCount, inlineReadTime, authorTitle, readTimeTitle, wordCountTitle, publishDateTitle, lastUpdatedTitle, tagTitle } = useAnalyzeTitles(wordCount, readTime)
|
|
127
|
+
const timeTitle = computed(() =>
|
|
128
|
+
frontmatter.value.date ? publishDateTitle.value : lastUpdatedTitle.value
|
|
141
129
|
)
|
|
142
130
|
</script>
|
|
143
131
|
|
|
@@ -145,16 +133,16 @@ watch(
|
|
|
145
133
|
<div v-if="showAnalyze && readingTimePosition === 'top'" class="doc-analyze" data-pagefind-ignore="all">
|
|
146
134
|
<span>
|
|
147
135
|
<ElIcon><EditPen /></ElIcon>
|
|
148
|
-
|
|
136
|
+
{{ topWordCount }}
|
|
149
137
|
</span>
|
|
150
138
|
<span>
|
|
151
139
|
<ElIcon><AlarmClock /></ElIcon>
|
|
152
|
-
|
|
140
|
+
{{ topReadTime }}
|
|
153
141
|
</span>
|
|
154
142
|
</div>
|
|
155
143
|
<div id="hack-article-des" ref="$des" class="meta-des">
|
|
156
144
|
<!-- TODO:是否需要原创?转载等标签,理论上可以添加标签解决,可以参考 charles7c -->
|
|
157
|
-
<span v-if="author && !hiddenAuthor" class="author" title="
|
|
145
|
+
<span v-if="author && !hiddenAuthor" class="author" :title="authorTitle">
|
|
158
146
|
<ElIcon><UserFilled /></ElIcon>
|
|
159
147
|
<a
|
|
160
148
|
v-if="currentAuthorInfo"
|
|
@@ -172,30 +160,30 @@ watch(
|
|
|
172
160
|
<ElIcon><Clock /></ElIcon>
|
|
173
161
|
{{ publishDate }}
|
|
174
162
|
</span>
|
|
175
|
-
<span v-if="tags.length" class="tags" title="
|
|
163
|
+
<span v-if="tags.length" class="tags" :title="tagTitle">
|
|
176
164
|
<ElIcon><CollectionTag /></ElIcon>
|
|
177
165
|
<a v-for="tag in tags" :key="tag" class="link" :href="`/?tag=${tag}`">{{ tag }}
|
|
178
166
|
</a>
|
|
179
167
|
</span>
|
|
180
168
|
<template v-if="readingTimePosition === 'inline' && showAnalyze">
|
|
181
|
-
<span title="
|
|
169
|
+
<span :title="wordCountTitle">
|
|
182
170
|
<ElIcon><EditPen /></ElIcon>
|
|
183
|
-
{{
|
|
171
|
+
{{ inlineWordCount }}
|
|
184
172
|
</span>
|
|
185
|
-
<span title="
|
|
173
|
+
<span :title="readTimeTitle">
|
|
186
174
|
<ElIcon><AlarmClock /></ElIcon>
|
|
187
|
-
{{
|
|
175
|
+
{{ inlineReadTime }}
|
|
188
176
|
</span>
|
|
189
177
|
</template>
|
|
190
178
|
<template v-if="readingTimePosition === 'newLine' && showAnalyze">
|
|
191
179
|
<div style="width: 100%;" class="new-line-meta-des">
|
|
192
|
-
<span title="
|
|
180
|
+
<span :title="wordCountTitle">
|
|
193
181
|
<ElIcon><EditPen /></ElIcon>
|
|
194
|
-
{{
|
|
182
|
+
{{ inlineWordCount }}
|
|
195
183
|
</span>
|
|
196
|
-
<span title="
|
|
184
|
+
<span :title="readTimeTitle">
|
|
197
185
|
<ElIcon><AlarmClock /></ElIcon>
|
|
198
|
-
{{
|
|
186
|
+
{{ inlineReadTime }}
|
|
199
187
|
</span>
|
|
200
188
|
</div>
|
|
201
189
|
</template>
|
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
import { computed, ref } from 'vue'
|
|
3
3
|
import { ElButton } from 'element-plus'
|
|
4
4
|
import { useRouter, withBase } from 'vitepress'
|
|
5
|
-
import { useArticles, useBlogConfig, useCleanUrls } from '../composables/config/blog'
|
|
6
|
-
import {
|
|
5
|
+
import { useArticles, useBlogConfig, useCleanUrls, useFormatShowDate } from '../composables/config/blog'
|
|
6
|
+
import { wrapperCleanUrls } from '../utils/client'
|
|
7
7
|
import { fireSVG } from '../constants/svg'
|
|
8
8
|
|
|
9
|
+
const formatShowDate = useFormatShowDate()
|
|
10
|
+
|
|
9
11
|
const { hotArticle: _hotArticle } = useBlogConfig()
|
|
10
12
|
|
|
11
13
|
const hotArticle = computed(() =>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import { useRouter, withBase } from 'vitepress'
|
|
3
3
|
import { computed } from 'vue'
|
|
4
|
-
import {
|
|
5
|
-
import { useCleanUrls, useImageStyle } from '../composables/config/blog'
|
|
4
|
+
import { wrapperCleanUrls } from '../utils/client'
|
|
5
|
+
import { useCleanUrls, useFormatShowDate, useImageStyle } from '../composables/config/blog'
|
|
6
6
|
|
|
7
7
|
const props = defineProps<{
|
|
8
8
|
route: string
|
|
@@ -16,6 +16,9 @@ const props = defineProps<{
|
|
|
16
16
|
cover?: string | false
|
|
17
17
|
pin?: number
|
|
18
18
|
}>()
|
|
19
|
+
|
|
20
|
+
const formatShowDate = useFormatShowDate()
|
|
21
|
+
|
|
19
22
|
const showTime = computed(() => {
|
|
20
23
|
return formatShowDate(props.date)
|
|
21
24
|
})
|
|
@@ -79,7 +82,7 @@ const resultCover = computed(() => {
|
|
|
79
82
|
<div class="info-part">
|
|
80
83
|
<!-- 标题 -->
|
|
81
84
|
<p class="title pc-visible">
|
|
82
|
-
{{ title }}
|
|
85
|
+
<span>{{ title }}</span>
|
|
83
86
|
</p>
|
|
84
87
|
<!-- 简短描述 -->
|
|
85
88
|
<p v-show="!descriptionHTML && !!description" class="description">
|
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
import { computed, onMounted, ref } from 'vue'
|
|
3
3
|
import { useRoute, useRouter, withBase } from 'vitepress'
|
|
4
4
|
import { ElButton } from 'element-plus'
|
|
5
|
-
import {
|
|
6
|
-
import { useArticles, useBlogConfig, useCleanUrls } from '../composables/config/blog'
|
|
5
|
+
import { wrapperCleanUrls } from '../utils/client'
|
|
6
|
+
import { useArticles, useBlogConfig, useCleanUrls, useFormatShowDate } from '../composables/config/blog'
|
|
7
7
|
import { recommendSVG } from '../constants/svg'
|
|
8
8
|
import type { Theme } from '../composables/config/index'
|
|
9
9
|
|
|
10
|
+
const formatShowDate = useFormatShowDate()
|
|
11
|
+
|
|
10
12
|
const { recommend: _recommend } = useBlogConfig()
|
|
11
13
|
|
|
12
14
|
const sidebarStyle = computed(() =>
|
|
@@ -19,6 +21,10 @@ const recommendPadding = computed(() =>
|
|
|
19
21
|
const recommend = computed(() =>
|
|
20
22
|
_recommend === false ? undefined : _recommend
|
|
21
23
|
)
|
|
24
|
+
|
|
25
|
+
const showDate = computed(() => (_recommend && _recommend?.showDate) ?? true)
|
|
26
|
+
const showNum = computed(() => (_recommend && _recommend?.showNum) ?? true)
|
|
27
|
+
|
|
22
28
|
const title = computed(() => recommend.value?.title ?? (`<span class="svg-icon">${recommendSVG}</span>` + '相关文章'))
|
|
23
29
|
const pageSize = computed(() => recommend.value?.pageSize || 9)
|
|
24
30
|
const nextText = computed(() => recommend.value?.nextText || '换一组')
|
|
@@ -167,10 +173,16 @@ function handleLinkClick(link: string) {
|
|
|
167
173
|
</ElButton>
|
|
168
174
|
</div>
|
|
169
175
|
<!-- 文章列表 -->
|
|
170
|
-
<ol
|
|
171
|
-
|
|
176
|
+
<ol
|
|
177
|
+
v-if="currentWikiData.length" :class="{
|
|
178
|
+
'hide-num': !showNum,
|
|
179
|
+
}" class="recommend-container"
|
|
180
|
+
>
|
|
181
|
+
<li
|
|
182
|
+
v-for="(v, idx) in currentWikiData" :key="v.route"
|
|
183
|
+
>
|
|
172
184
|
<!-- 序号 -->
|
|
173
|
-
<i class="num">{{ startIdx + idx + 1 }}</i>
|
|
185
|
+
<i v-if="showNum" class="num">{{ startIdx + idx + 1 }}</i>
|
|
174
186
|
<!-- 简介 -->
|
|
175
187
|
<div class="des">
|
|
176
188
|
<!-- title -->
|
|
@@ -187,7 +199,7 @@ function handleLinkClick(link: string) {
|
|
|
187
199
|
<span>{{ v.meta.title }}</span>
|
|
188
200
|
</a>
|
|
189
201
|
<!-- 描述信息 -->
|
|
190
|
-
<div class="suffix">
|
|
202
|
+
<div v-if="showDate" class="suffix">
|
|
191
203
|
<!-- 日期 -->
|
|
192
204
|
<span class="tag">{{ formatShowDate(v.meta.date) }}</span>
|
|
193
205
|
</div>
|
|
@@ -232,6 +244,9 @@ function handleLinkClick(link: string) {
|
|
|
232
244
|
padding: 0 10px 0 0px;
|
|
233
245
|
width: 100%;
|
|
234
246
|
|
|
247
|
+
&.hide-num>li{
|
|
248
|
+
padding: 5px 0;
|
|
249
|
+
}
|
|
235
250
|
li {
|
|
236
251
|
display: flex;
|
|
237
252
|
|
|
@@ -251,6 +266,9 @@ function handleLinkClick(link: string) {
|
|
|
251
266
|
overflow: hidden;
|
|
252
267
|
text-overflow: ellipsis;
|
|
253
268
|
white-space: nowrap;
|
|
269
|
+
display: flex;
|
|
270
|
+
flex-direction: column;
|
|
271
|
+
justify-content: center;
|
|
254
272
|
}
|
|
255
273
|
|
|
256
274
|
.title {
|
|
@@ -261,21 +279,21 @@ function handleLinkClick(link: string) {
|
|
|
261
279
|
font-weight: 500;
|
|
262
280
|
position: relative;
|
|
263
281
|
cursor: pointer;
|
|
264
|
-
|
|
265
|
-
&.current {
|
|
282
|
+
transition: color .25s;
|
|
283
|
+
&.current,&:hover {
|
|
266
284
|
color: var(--vp-c-brand-1);
|
|
267
285
|
}
|
|
268
286
|
}
|
|
269
287
|
|
|
270
|
-
.title:hover::after {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
}
|
|
288
|
+
// .title:hover::after {
|
|
289
|
+
// content: "";
|
|
290
|
+
// position: absolute;
|
|
291
|
+
// left: 0;
|
|
292
|
+
// right: 0;
|
|
293
|
+
// height: 0;
|
|
294
|
+
// bottom: -3px;
|
|
295
|
+
// border-bottom: 1px solid #b1b3b8;
|
|
296
|
+
// }
|
|
279
297
|
|
|
280
298
|
.suffix {
|
|
281
299
|
font-size: 12px;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useData, useRoute, withBase } from 'vitepress'
|
|
2
2
|
import type {
|
|
3
3
|
Component,
|
|
4
|
+
ComputedRef,
|
|
4
5
|
InjectionKey,
|
|
5
6
|
Ref
|
|
6
7
|
} from 'vue'
|
|
@@ -17,6 +18,7 @@ import {
|
|
|
17
18
|
} from 'vue'
|
|
18
19
|
import { useColorMode } from '@vueuse/core'
|
|
19
20
|
|
|
21
|
+
import { formatDate, replaceValue } from '../../utils/client'
|
|
20
22
|
import type { Theme } from './index'
|
|
21
23
|
|
|
22
24
|
const configSymbol: InjectionKey<Ref<Theme.Config>> = Symbol('theme-config')
|
|
@@ -237,3 +239,104 @@ export function useImageStyle() {
|
|
|
237
239
|
export function useHomeAnalysis() {
|
|
238
240
|
return inject(configSymbol)?.value?.blog?.home?.analysis
|
|
239
241
|
}
|
|
242
|
+
|
|
243
|
+
export function useAnalyzeTitles(wordCount: Ref<number>, readTime: ComputedRef<number>) {
|
|
244
|
+
const { article } = useBlogConfig()
|
|
245
|
+
|
|
246
|
+
const topWordCount = computed(() =>
|
|
247
|
+
replaceValue(article?.analyzeTitles?.topWordCount || '字数:{{value}} 个字', wordCount.value)
|
|
248
|
+
)
|
|
249
|
+
const topReadTime = computed(() =>
|
|
250
|
+
replaceValue(article?.analyzeTitles?.topReadTime || '预计:{{value}} 分钟', readTime.value)
|
|
251
|
+
)
|
|
252
|
+
const inlineWordCount = computed(() =>
|
|
253
|
+
replaceValue(article?.analyzeTitles?.inlineWordCount || '{{value}} 个字', wordCount.value)
|
|
254
|
+
)
|
|
255
|
+
const inlineReadTime = computed(() =>
|
|
256
|
+
replaceValue(article?.analyzeTitles?.inlineReadTime || '{{value}} 分钟', readTime.value)
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
const wordCountTitle = computed(() =>
|
|
260
|
+
article?.analyzeTitles?.wordCount || '文章字数'
|
|
261
|
+
)
|
|
262
|
+
const readTimeTitle = computed(() =>
|
|
263
|
+
article?.analyzeTitles?.readTime || '预计阅读时间'
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
const authorTitle = computed(() =>
|
|
267
|
+
article?.analyzeTitles?.author || '本文作者'
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
const publishDateTitle = computed(() =>
|
|
271
|
+
article?.analyzeTitles?.publishDate || '发布时间'
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
const lastUpdatedTitle = computed(() =>
|
|
275
|
+
article?.analyzeTitles?.lastUpdated || '最近修改时间'
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
const tagTitle = computed(() =>
|
|
279
|
+
article?.analyzeTitles?.tag || '标签'
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
return {
|
|
283
|
+
topWordCount,
|
|
284
|
+
topReadTime,
|
|
285
|
+
inlineWordCount,
|
|
286
|
+
inlineReadTime,
|
|
287
|
+
wordCountTitle,
|
|
288
|
+
readTimeTitle,
|
|
289
|
+
authorTitle,
|
|
290
|
+
publishDateTitle,
|
|
291
|
+
lastUpdatedTitle,
|
|
292
|
+
tagTitle
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export function useFormatShowDate() {
|
|
297
|
+
const blog = useBlogConfig()
|
|
298
|
+
if (typeof blog.formatShowDate === 'function') {
|
|
299
|
+
return blog.formatShowDate
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function formatShowDate(date: any) {
|
|
303
|
+
const source = +new Date(date)
|
|
304
|
+
const now = +new Date()
|
|
305
|
+
const diff = now - source
|
|
306
|
+
const oneSeconds = 1000
|
|
307
|
+
const oneMinute = oneSeconds * 60
|
|
308
|
+
const oneHour = oneMinute * 60
|
|
309
|
+
const oneDay = oneHour * 24
|
|
310
|
+
const oneWeek = oneDay * 7
|
|
311
|
+
|
|
312
|
+
const langMap = {
|
|
313
|
+
justNow: '刚刚',
|
|
314
|
+
secondsAgo: '秒前',
|
|
315
|
+
minutesAgo: '分钟前',
|
|
316
|
+
hoursAgo: '小时前',
|
|
317
|
+
daysAgo: '天前',
|
|
318
|
+
weeksAgo: '周前',
|
|
319
|
+
...blog.formatShowDate
|
|
320
|
+
}
|
|
321
|
+
const mapValue = langMap
|
|
322
|
+
|
|
323
|
+
if (diff < 10) {
|
|
324
|
+
return mapValue.justNow
|
|
325
|
+
}
|
|
326
|
+
if (diff < oneMinute) {
|
|
327
|
+
return `${Math.floor(diff / oneSeconds)}${mapValue.secondsAgo}`
|
|
328
|
+
}
|
|
329
|
+
if (diff < oneHour) {
|
|
330
|
+
return `${Math.floor(diff / oneMinute)}${mapValue.minutesAgo}`
|
|
331
|
+
}
|
|
332
|
+
if (diff < oneDay) {
|
|
333
|
+
return `${Math.floor(diff / oneHour)}${mapValue.hoursAgo}`
|
|
334
|
+
}
|
|
335
|
+
if (diff < oneWeek) {
|
|
336
|
+
return `${Math.floor(diff / oneDay)}${mapValue.daysAgo}`
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return formatDate(new Date(date), 'yyyy-MM-dd')
|
|
340
|
+
}
|
|
341
|
+
return formatShowDate
|
|
342
|
+
}
|
|
@@ -184,6 +184,16 @@ export namespace Theme {
|
|
|
184
184
|
* @default 'sidebar'
|
|
185
185
|
*/
|
|
186
186
|
style?: 'card' | 'sidebar'
|
|
187
|
+
/**
|
|
188
|
+
* 是否在左侧显示日期
|
|
189
|
+
* @default true
|
|
190
|
+
*/
|
|
191
|
+
showDate?: boolean
|
|
192
|
+
/**
|
|
193
|
+
* 是否在左侧展示序号
|
|
194
|
+
* @default true
|
|
195
|
+
*/
|
|
196
|
+
showNum?: boolean
|
|
187
197
|
}
|
|
188
198
|
|
|
189
199
|
export interface HomeAnalysis {
|
|
@@ -211,6 +221,10 @@ export namespace Theme {
|
|
|
211
221
|
}
|
|
212
222
|
|
|
213
223
|
export interface ArticleConfig {
|
|
224
|
+
/**
|
|
225
|
+
* 文章分析数据展示标题
|
|
226
|
+
*/
|
|
227
|
+
analyzeTitles?: ArticleAnalyzeTitles
|
|
214
228
|
readingTime?: boolean
|
|
215
229
|
/**
|
|
216
230
|
* 阅读时间分析展示位置
|
|
@@ -219,6 +233,49 @@ export namespace Theme {
|
|
|
219
233
|
readingTimePosition?: 'inline' | 'newLine' | 'top'
|
|
220
234
|
hiddenCover?: boolean
|
|
221
235
|
}
|
|
236
|
+
|
|
237
|
+
export interface ArticleAnalyzeTitles {
|
|
238
|
+
/**
|
|
239
|
+
* 字数:{{value}} 个字
|
|
240
|
+
*/
|
|
241
|
+
topWordCount?: string
|
|
242
|
+
/**
|
|
243
|
+
* 预计:{{value}} 分钟
|
|
244
|
+
*/
|
|
245
|
+
topReadTime?: string
|
|
246
|
+
/**
|
|
247
|
+
* {{value}} 个字
|
|
248
|
+
*/
|
|
249
|
+
inlineWordCount?: string
|
|
250
|
+
/**
|
|
251
|
+
* {{value}} 分钟
|
|
252
|
+
*/
|
|
253
|
+
inlineReadTime?: string
|
|
254
|
+
/**
|
|
255
|
+
* 文章字数
|
|
256
|
+
*/
|
|
257
|
+
wordCount?: string
|
|
258
|
+
/**
|
|
259
|
+
* 预计阅读时间
|
|
260
|
+
*/
|
|
261
|
+
readTime?: string
|
|
262
|
+
/**
|
|
263
|
+
* 本文作者
|
|
264
|
+
*/
|
|
265
|
+
author?: string
|
|
266
|
+
/**
|
|
267
|
+
* 发布时间
|
|
268
|
+
*/
|
|
269
|
+
publishDate?: string
|
|
270
|
+
/**
|
|
271
|
+
* 最近修改时间
|
|
272
|
+
*/
|
|
273
|
+
lastUpdated?: string
|
|
274
|
+
/**
|
|
275
|
+
* 标签
|
|
276
|
+
*/
|
|
277
|
+
tag?: string
|
|
278
|
+
}
|
|
222
279
|
export interface Alert {
|
|
223
280
|
type: 'success' | 'warning' | 'info' | 'error'
|
|
224
281
|
/**
|
|
@@ -368,6 +425,10 @@ export namespace Theme {
|
|
|
368
425
|
| 'el-red'
|
|
369
426
|
export interface BlogConfig {
|
|
370
427
|
blog?: false
|
|
428
|
+
/**
|
|
429
|
+
* 展示日期格式化
|
|
430
|
+
*/
|
|
431
|
+
formatShowDate?: FormatShowDate
|
|
371
432
|
/**
|
|
372
433
|
* 内置一些主题色
|
|
373
434
|
* @default 'vp-default'
|
|
@@ -476,6 +537,32 @@ export namespace Theme {
|
|
|
476
537
|
imageStyle?: ImageStyleConfig
|
|
477
538
|
}
|
|
478
539
|
|
|
540
|
+
export type FormatShowDate = {
|
|
541
|
+
/**
|
|
542
|
+
* 刚刚
|
|
543
|
+
*/
|
|
544
|
+
justNow?: string
|
|
545
|
+
/**
|
|
546
|
+
* 秒前
|
|
547
|
+
*/
|
|
548
|
+
secondsAgo?: string
|
|
549
|
+
/**
|
|
550
|
+
* 分钟前
|
|
551
|
+
*/
|
|
552
|
+
minutesAgo?: string
|
|
553
|
+
/**
|
|
554
|
+
* 小时前
|
|
555
|
+
*/
|
|
556
|
+
hoursAgo?: string
|
|
557
|
+
/**
|
|
558
|
+
* 天前
|
|
559
|
+
*/
|
|
560
|
+
daysAgo?: string
|
|
561
|
+
/**
|
|
562
|
+
* 周前
|
|
563
|
+
*/
|
|
564
|
+
weeksAgo?: string
|
|
565
|
+
} | ((date: Date | string) => string)
|
|
479
566
|
export interface BackToTop {
|
|
480
567
|
/**
|
|
481
568
|
* 距离顶部多少距离出现
|
|
@@ -177,3 +177,7 @@ export function wrapperCleanUrls(cleanUrls: boolean, route: string) {
|
|
|
177
177
|
const tempUrl = route.replace(/\.html$/, '')
|
|
178
178
|
return cleanUrls ? tempUrl : `${tempUrl}.html`
|
|
179
179
|
}
|
|
180
|
+
|
|
181
|
+
export function replaceValue(str: string, value: any) {
|
|
182
|
+
return str.replace(/\{\{value\}\}/, value)
|
|
183
|
+
}
|