@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 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.1_@algolia+client-search@4.19.1_@types+node@20.6.3__tymgq2io4kjnp3wlifsw2g5vnu/node_modules/vitepress-plugin-tabs/dist/index.js
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.9",
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.9"
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.1",
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, useRoute } from 'vitepress'
5
- import { computed, onMounted, ref, watch } from 'vue'
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, formatShowDate } from '../utils/client'
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
- watch(
133
- () => route.path,
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
- 字数:{{ wordCount }} 个字
136
+ {{ topWordCount }}
149
137
  </span>
150
138
  <span>
151
139
  <ElIcon><AlarmClock /></ElIcon>
152
- 预计:{{ readTime }} 分钟
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
- {{ wordCount }} 个字
171
+ {{ inlineWordCount }}
184
172
  </span>
185
- <span title="预计阅读时间">
173
+ <span :title="readTimeTitle">
186
174
  <ElIcon><AlarmClock /></ElIcon>
187
- {{ readTime }} 分钟
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
- {{ wordCount }} 个字
182
+ {{ inlineWordCount }}
195
183
  </span>
196
- <span title="预计阅读时间">
184
+ <span :title="readTimeTitle">
197
185
  <ElIcon><AlarmClock /></ElIcon>
198
- {{ readTime }} 分钟
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 { formatShowDate, wrapperCleanUrls } from '../utils/client'
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 { formatShowDate, wrapperCleanUrls } from '../utils/client'
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 { formatShowDate, wrapperCleanUrls } from '../utils/client'
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 v-if="currentWikiData.length" class="recommend-container">
171
- <li v-for="(v, idx) in currentWikiData" :key="v.route">
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
- content: "";
272
- position: absolute;
273
- left: 0;
274
- right: 0;
275
- height: 0;
276
- bottom: -3px;
277
- border-bottom: 1px solid #b1b3b8;
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
+ }