@sugarat/theme 0.1.49 → 0.1.50
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 +1 -1
- package/node.js +23 -19
- package/package.json +23 -23
- package/src/components/BlogAlert.vue +17 -17
- package/src/components/BlogApp.vue +81 -49
- package/src/components/BlogArticleAnalyze.vue +56 -57
- package/src/components/BlogComment.vue +53 -50
- package/src/components/BlogDocCover.vue +4 -4
- package/src/components/BlogFriendLink.vue +40 -31
- package/src/components/BlogHomeBanner.vue +22 -16
- package/src/components/BlogHomeOverview.vue +20 -20
- package/src/components/BlogHomeTags.vue +49 -40
- package/src/components/BlogHotArticle.vue +43 -36
- package/src/components/BlogImagePreview.vue +7 -5
- package/src/components/BlogItem.vue +42 -43
- package/src/components/BlogList.vue +46 -42
- package/src/components/BlogPopover.vue +41 -39
- package/src/components/BlogRecommendArticle.vue +58 -48
- package/src/components/BlogSearch.vue +143 -145
- package/src/components/UserWorks.vue +214 -210
- package/src/composables/config/blog.ts +7 -5
- package/src/composables/config/index.ts +33 -31
- package/src/constants/svg.ts +2 -2
- package/src/index.ts +1 -2
- package/src/node.ts +2 -2
- package/src/styles/scss/global.scss +0 -5
- package/src/utils/client/index.ts +9 -8
- package/src/utils/node/genFeed.ts +8 -7
- package/src/utils/node/index.ts +8 -6
- package/src/utils/node/mdPlugins.ts +29 -22
- package/src/utils/node/theme.ts +16 -13
- package/src/utils/node/vitePlugins.ts +7 -6
- package/types/vue-shim.d.ts +1 -1
|
@@ -1,12 +1,186 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { ElCarousel, ElCarouselItem, ElImage, ElMessage } from 'element-plus'
|
|
3
|
+
import VPDocAsideOutline from 'vitepress/dist/client/theme-default/components/VPDocAsideOutline.vue'
|
|
4
|
+
import { computed, reactive, ref, watch, watchEffect } from 'vue'
|
|
5
|
+
import { slugify } from '@mdit-vue/shared'
|
|
6
|
+
import { useWindowSize } from '@vueuse/core'
|
|
7
|
+
import {
|
|
8
|
+
formatDate,
|
|
9
|
+
getGithubDirUpdateTime,
|
|
10
|
+
getGithubUpdateTime
|
|
11
|
+
} from '../utils/client'
|
|
12
|
+
import {
|
|
13
|
+
useActiveAnchor,
|
|
14
|
+
useAutoUpdateAnchor,
|
|
15
|
+
useUserWorks
|
|
16
|
+
} from '../composables/config/blog'
|
|
17
|
+
import type { Theme } from '../composables/config'
|
|
18
|
+
|
|
19
|
+
const currentAnchor = useAutoUpdateAnchor()
|
|
20
|
+
// 更新锚点的时候更新 url 中的 hash
|
|
21
|
+
watch(
|
|
22
|
+
() => currentAnchor.id,
|
|
23
|
+
(val) => {
|
|
24
|
+
if (val) {
|
|
25
|
+
window.history.replaceState(null, '', `#${val}`)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
)
|
|
29
|
+
const mountActiveAnchorEl = useActiveAnchor()
|
|
30
|
+
watch(mountActiveAnchorEl, () => {
|
|
31
|
+
const { value } = mountActiveAnchorEl
|
|
32
|
+
if (value) {
|
|
33
|
+
value.scroll({
|
|
34
|
+
behavior: 'smooth'
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
const works = useUserWorks()
|
|
40
|
+
const workList = reactive<
|
|
41
|
+
(Theme.UserWork & {
|
|
42
|
+
year?: string | undefined
|
|
43
|
+
startTime: string
|
|
44
|
+
lastUpdate?: string
|
|
45
|
+
endTime?: string
|
|
46
|
+
covers?: string[]
|
|
47
|
+
coverLayout?: string
|
|
48
|
+
})[]
|
|
49
|
+
>([])
|
|
50
|
+
|
|
51
|
+
// 格式化数据
|
|
52
|
+
watch(
|
|
53
|
+
works,
|
|
54
|
+
(val) => {
|
|
55
|
+
const sortDate = [...val.list].map((v) => {
|
|
56
|
+
const { time } = v
|
|
57
|
+
|
|
58
|
+
// 格式化时间
|
|
59
|
+
const metaInfo
|
|
60
|
+
= typeof time === 'string'
|
|
61
|
+
? {
|
|
62
|
+
startTime: time,
|
|
63
|
+
endTime: '',
|
|
64
|
+
lastUpdate: ''
|
|
65
|
+
}
|
|
66
|
+
: {
|
|
67
|
+
startTime: time.start,
|
|
68
|
+
endTime: time.end,
|
|
69
|
+
lastUpdate: time.lastupdate
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// 格式化封面信息
|
|
73
|
+
const covers: string[] = []
|
|
74
|
+
let coverLayout = 'swiper'
|
|
75
|
+
|
|
76
|
+
if (typeof v.cover === 'string') {
|
|
77
|
+
covers.push(v.cover)
|
|
78
|
+
}
|
|
79
|
+
else if (Array.isArray(v.cover)) {
|
|
80
|
+
covers.push(...v.cover)
|
|
81
|
+
}
|
|
82
|
+
else if (typeof v.cover === 'object') {
|
|
83
|
+
covers.push(...v.cover.urls)
|
|
84
|
+
coverLayout = v.cover.layout ?? coverLayout
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
...v,
|
|
88
|
+
...metaInfo,
|
|
89
|
+
covers,
|
|
90
|
+
coverLayout
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
// 过滤出置顶数据
|
|
94
|
+
const topDate = sortDate.filter(v => v.top !== undefined)
|
|
95
|
+
const normalDate = sortDate.filter(v => v.top === undefined)
|
|
96
|
+
// 数据排序
|
|
97
|
+
topDate.sort((a, b) => a.top! - b.top!)
|
|
98
|
+
normalDate.sort((a, b) => +new Date(b.startTime) - +new Date(a.startTime))
|
|
99
|
+
if (topDate.length) {
|
|
100
|
+
// @ts-expect-error
|
|
101
|
+
topDate[0].year = works.value.topTitle ?? '置顶'
|
|
102
|
+
}
|
|
103
|
+
// 数据分组
|
|
104
|
+
const groupDate = normalDate.reduce((prev, cur) => {
|
|
105
|
+
const { startTime } = cur
|
|
106
|
+
const year = new Date(startTime).getFullYear()
|
|
107
|
+
const data = { ...cur }
|
|
108
|
+
if (!prev[year]) {
|
|
109
|
+
prev[year] = []
|
|
110
|
+
// 第一项数据加上year属性
|
|
111
|
+
// @ts-expect-error
|
|
112
|
+
data.year = year
|
|
113
|
+
}
|
|
114
|
+
prev[year].push(data)
|
|
115
|
+
return prev
|
|
116
|
+
}, {} as Record<string, (Theme.UserWork & { year?: string; startTime: string })[]>)
|
|
117
|
+
workList.push(...topDate, ...Object.values(groupDate).reverse().flat())
|
|
118
|
+
},
|
|
119
|
+
{ immediate: true }
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
const init = ref(true)
|
|
123
|
+
// 更新时间信息
|
|
124
|
+
watchEffect(() => {
|
|
125
|
+
if (workList.length && init.value) {
|
|
126
|
+
init.value = false
|
|
127
|
+
workList.forEach((data) => {
|
|
128
|
+
// 接口获取最后更新时间
|
|
129
|
+
if (!data.lastUpdate && data.github) {
|
|
130
|
+
data.lastUpdate = '获取中...'
|
|
131
|
+
const { github } = data
|
|
132
|
+
if (typeof github === 'string') {
|
|
133
|
+
getGithubUpdateTime(github)
|
|
134
|
+
.then((time) => {
|
|
135
|
+
data.lastUpdate = formatDate(time, 'yyyy-MM-dd')
|
|
136
|
+
})
|
|
137
|
+
.catch(() => {
|
|
138
|
+
data.lastUpdate = '地址解析失败'
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
const { owner, repo, path, branch } = github
|
|
143
|
+
// 拼接Github链接
|
|
144
|
+
let githubUrl = `https://github.com/${owner}/${repo}`
|
|
145
|
+
if (path) {
|
|
146
|
+
githubUrl += `/tree/${branch || 'master'}/${path}`
|
|
147
|
+
}
|
|
148
|
+
else if (branch) {
|
|
149
|
+
githubUrl += `/tree/${branch}`
|
|
150
|
+
}
|
|
151
|
+
data.github = githubUrl
|
|
152
|
+
getGithubDirUpdateTime(owner, repo, path ?? '', branch)
|
|
153
|
+
.then((time) => {
|
|
154
|
+
data.lastUpdate = formatDate(time, 'yyyy-MM-dd')
|
|
155
|
+
})
|
|
156
|
+
.catch(() => {
|
|
157
|
+
data.lastUpdate = '地址解析失败'
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
})
|
|
162
|
+
}
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
const { width } = useWindowSize()
|
|
166
|
+
const isCardMode = computed(() => width.value > 768)
|
|
167
|
+
function handleChooseTag(tag: string) {
|
|
168
|
+
ElMessage({
|
|
169
|
+
message: `点击了${tag}标签,标签过滤功能开发中ing...`,
|
|
170
|
+
type: 'warning'
|
|
171
|
+
})
|
|
172
|
+
}
|
|
173
|
+
</script>
|
|
174
|
+
|
|
1
175
|
<template>
|
|
2
176
|
<div class="user-works-page VPDoc">
|
|
3
177
|
<div class="aside-container">
|
|
4
178
|
<!-- TODO:过滤,可吸顶 -->
|
|
5
179
|
<div class="filter">
|
|
6
180
|
<!-- 时间: -->
|
|
7
|
-
<div
|
|
181
|
+
<div />
|
|
8
182
|
<!-- TODO: tags -->
|
|
9
|
-
<div
|
|
183
|
+
<div />
|
|
10
184
|
</div>
|
|
11
185
|
</div>
|
|
12
186
|
<!-- 作品列表 -->
|
|
@@ -16,21 +190,23 @@
|
|
|
16
190
|
{{ works.description }}
|
|
17
191
|
</p>
|
|
18
192
|
<!-- 标题,描述信息,时间,线上链接,代码仓库,示例图片(几张,多种展示样式支持) -->
|
|
19
|
-
<div
|
|
193
|
+
<div v-for="(work, idx) in workList" :key="idx" class="work">
|
|
20
194
|
<!-- 大日期标题 -->
|
|
21
|
-
<h2 :id="`work_${work.year}`"
|
|
195
|
+
<h2 v-if="work.year" :id="`work_${work.year}`">
|
|
22
196
|
<a :href="`#work_${work.year}`">{{ work.year }}</a>
|
|
23
197
|
</h2>
|
|
24
198
|
<!-- 作品标题 -->
|
|
25
|
-
<h3
|
|
26
|
-
<a class="pin" :href="
|
|
199
|
+
<h3 :id="slugify(work.title)" class="title">
|
|
200
|
+
<a class="pin" :href="`#${slugify(work.title)}`" />
|
|
27
201
|
<a v-if="work.url" rel="noopener" target="_blank" :href="work.url">{{
|
|
28
202
|
work.title
|
|
29
203
|
}}</a>
|
|
30
204
|
<span v-else>{{ work.title }}</span>
|
|
31
|
-
<Badge v-if="work.status" :type="work.status?.type || 'tip'">
|
|
32
|
-
|
|
33
|
-
|
|
205
|
+
<Badge v-if="work.status" :type="work.status?.type || 'tip'">
|
|
206
|
+
{{
|
|
207
|
+
work.status.text
|
|
208
|
+
}}
|
|
209
|
+
</Badge>
|
|
34
210
|
</h3>
|
|
35
211
|
<!-- 补充信息 -->
|
|
36
212
|
<div class="info">
|
|
@@ -46,18 +222,18 @@
|
|
|
46
222
|
<path
|
|
47
223
|
d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8s8 3.58 8 8s-3.58 8-8 8zm-.22-13h-.06c-.4 0-.72.32-.72.72v4.72c0 .35.18.68.49.86l4.15 2.49c.34.2.78.1.98-.24a.71.71 0 0 0-.25-.99l-3.87-2.3V7.72c0-.4-.32-.72-.72-.72z"
|
|
48
224
|
fill="currentColor"
|
|
49
|
-
|
|
225
|
+
/>
|
|
50
226
|
</svg>
|
|
51
227
|
</span>
|
|
52
228
|
<span>{{ work.startTime }}</span>
|
|
53
229
|
<span v-if="work.endTime"> - {{ work.endTime }}</span>
|
|
54
230
|
</div>
|
|
55
|
-
<!-- GitHub links-->
|
|
56
|
-
<div
|
|
231
|
+
<!-- GitHub links -->
|
|
232
|
+
<div v-if="work.github" class="links">
|
|
57
233
|
<a
|
|
58
|
-
class="github-link"
|
|
59
234
|
v-if="work.github"
|
|
60
|
-
|
|
235
|
+
class="github-link"
|
|
236
|
+
:href="work.github as string"
|
|
61
237
|
target="_blank"
|
|
62
238
|
rel="noopener"
|
|
63
239
|
>
|
|
@@ -70,17 +246,15 @@
|
|
|
70
246
|
<path
|
|
71
247
|
d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6c-3.3.3-5.6-1.3-5.6-3.6c0-2 2.3-3.6 5.2-3.6c3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9c2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9c.3 2 2.9 3.3 5.9 2.6c2.9-.7 4.9-2.6 4.6-4.6c-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2c12.8 2.3 17.3-5.6 17.3-12.1c0-6.2-.3-40.4-.3-61.4c0 0-70 15-84.7-29.8c0 0-11.4-29.1-27.8-36.6c0 0-22.9-15.7 1.6-15.4c0 0 24.9 2 38.6 25.8c21.9 38.6 58.6 27.5 72.9 20.9c2.3-16 8.8-27.1 16-33.7c-55.9-6.2-112.3-14.3-112.3-110.5c0-27.5 7.6-41.3 23.6-58.9c-2.6-6.5-11.1-33.3 2.6-67.9c20.9-6.5 69 27 69 27c20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27c13.7 34.7 5.2 61.4 2.6 67.9c16 17.7 25.8 31.5 25.8 58.9c0 96.5-58.9 104.2-114.8 110.5c9.2 7.9 17 22.9 17 46.4c0 33.7-.3 75.4-.3 83.6c0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252C496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2c1.6 1.6 3.9 2.3 5.2 1c1.3-1 1-3.3-.7-5.2c-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9c1.6 1 3.6.7 4.3-.7c.7-1.3-.3-2.9-2.3-3.9c-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2c2.3 2.3 5.2 2.6 6.5 1c1.3-1.3.7-4.3-1.3-6.2c-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9c1.6 2.3 4.3 3.3 5.6 2.3c1.6-1.3 1.6-3.9 0-6.2c-1.4-2.3-4-3.3-5.6-2z"
|
|
72
248
|
fill="currentColor"
|
|
73
|
-
|
|
249
|
+
/>
|
|
74
250
|
</svg>
|
|
75
251
|
</i>
|
|
76
|
-
<span class="lastupdate"
|
|
77
|
-
>最后更新时间:{{ work.lastUpdate }}</span
|
|
78
|
-
>
|
|
252
|
+
<span v-if="work.lastUpdate" class="lastupdate">最后更新时间:{{ work.lastUpdate }}</span>
|
|
79
253
|
</a>
|
|
80
254
|
</div>
|
|
81
255
|
<!-- 其它自定义链接 -->
|
|
82
|
-
<div
|
|
83
|
-
<i
|
|
256
|
+
<div v-if="work.links?.length" class="links">
|
|
257
|
+
<i v-if="work.links?.length" class="icon">
|
|
84
258
|
<svg
|
|
85
259
|
xmlns="http://www.w3.org/2000/svg"
|
|
86
260
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
@@ -95,18 +269,18 @@
|
|
|
95
269
|
>
|
|
96
270
|
<path
|
|
97
271
|
d="M10 14a3.5 3.5 0 0 0 5 0l4-4a3.5 3.5 0 0 0-5-5l-.5.5"
|
|
98
|
-
|
|
272
|
+
/>
|
|
99
273
|
<path
|
|
100
274
|
d="M14 10a3.5 3.5 0 0 0-5 0l-4 4a3.5 3.5 0 0 0 5 5l.5-.5"
|
|
101
|
-
|
|
275
|
+
/>
|
|
102
276
|
</g>
|
|
103
277
|
</svg>
|
|
104
278
|
</i>
|
|
105
279
|
<a
|
|
106
|
-
class="link"
|
|
107
280
|
v-for="link in work.links || []"
|
|
108
|
-
:href="link.url"
|
|
109
281
|
:key="link.url"
|
|
282
|
+
class="link"
|
|
283
|
+
:href="link.url"
|
|
110
284
|
:title="link.title"
|
|
111
285
|
target="_blank"
|
|
112
286
|
rel="noopener"
|
|
@@ -115,7 +289,7 @@
|
|
|
115
289
|
</a>
|
|
116
290
|
</div>
|
|
117
291
|
<!-- tags -->
|
|
118
|
-
<div
|
|
292
|
+
<div v-if="work.tags?.length" class="tags">
|
|
119
293
|
<i class="icon">
|
|
120
294
|
<svg
|
|
121
295
|
xmlns="http://www.w3.org/2000/svg"
|
|
@@ -125,48 +299,48 @@
|
|
|
125
299
|
<path
|
|
126
300
|
fill="currentColor"
|
|
127
301
|
d="M256 128v698.88l196.032-156.864a96 96 0 0 1 119.936 0L768 826.816V128H256zm-32-64h576a32 32 0 0 1 32 32v797.44a32 32 0 0 1-51.968 24.96L531.968 720a32 32 0 0 0-39.936 0L243.968 918.4A32 32 0 0 1 192 893.44V96a32 32 0 0 1 32-32z"
|
|
128
|
-
|
|
302
|
+
/>
|
|
129
303
|
</svg>
|
|
130
304
|
</i>
|
|
131
305
|
<span
|
|
132
|
-
@click="handleChooseTag(tag)"
|
|
133
|
-
class="tag"
|
|
134
306
|
v-for="tag in work.tags"
|
|
135
307
|
:key="tag"
|
|
136
|
-
|
|
308
|
+
class="tag"
|
|
309
|
+
@click="handleChooseTag(tag)"
|
|
310
|
+
>{{ tag }}
|
|
137
311
|
</span>
|
|
138
312
|
</div>
|
|
139
313
|
</div>
|
|
140
314
|
<!-- 封面图 -->
|
|
141
|
-
<div
|
|
315
|
+
<div v-if="work.covers?.length" class="images">
|
|
142
316
|
<!-- swiper -->
|
|
143
317
|
<div v-if="work.coverLayout === 'swiper'" class="swiper-mode">
|
|
144
|
-
<
|
|
318
|
+
<ElCarousel
|
|
145
319
|
autoplay
|
|
146
320
|
height="260px"
|
|
147
321
|
:type="isCardMode && work.covers.length >= 3 ? 'card' : ''"
|
|
148
322
|
>
|
|
149
|
-
<
|
|
150
|
-
style="text-align: center"
|
|
323
|
+
<ElCarouselItem
|
|
151
324
|
v-for="(url, idx) in work.covers"
|
|
152
325
|
:key="url"
|
|
326
|
+
style="text-align: center"
|
|
153
327
|
>
|
|
154
|
-
<
|
|
155
|
-
preview-teleported
|
|
328
|
+
<ElImage
|
|
156
329
|
:key="url"
|
|
330
|
+
preview-teleported
|
|
157
331
|
:src="url"
|
|
158
332
|
loading="lazy"
|
|
159
333
|
:preview-src-list="work.covers"
|
|
160
334
|
:initial-index="idx"
|
|
161
335
|
hide-on-click-modal
|
|
162
|
-
:alt="work.title
|
|
336
|
+
:alt="`${work.title}-${idx}`"
|
|
163
337
|
/>
|
|
164
|
-
</
|
|
165
|
-
</
|
|
338
|
+
</ElCarouselItem>
|
|
339
|
+
</ElCarousel>
|
|
166
340
|
</div>
|
|
167
341
|
<!-- list -->
|
|
168
342
|
<div v-if="work.coverLayout === 'list'" class="list-mode">
|
|
169
|
-
<
|
|
343
|
+
<ElImage
|
|
170
344
|
v-for="(url, idx) in work.covers"
|
|
171
345
|
:key="url"
|
|
172
346
|
:src="url"
|
|
@@ -177,7 +351,7 @@
|
|
|
177
351
|
/>
|
|
178
352
|
</div>
|
|
179
353
|
</div>
|
|
180
|
-
<div class="description" v-html="work.description"
|
|
354
|
+
<div class="description" v-html="work.description" />
|
|
181
355
|
</div>
|
|
182
356
|
</div>
|
|
183
357
|
<div class="aside-container">
|
|
@@ -188,176 +362,6 @@
|
|
|
188
362
|
</div>
|
|
189
363
|
</template>
|
|
190
364
|
|
|
191
|
-
<script lang="ts" setup>
|
|
192
|
-
import { ElImage, ElCarousel, ElCarouselItem, ElMessage } from 'element-plus'
|
|
193
|
-
import VPDocAsideOutline from 'vitepress/dist/client/theme-default/components/VPDocAsideOutline.vue'
|
|
194
|
-
import { computed, reactive, ref, watch, watchEffect } from 'vue'
|
|
195
|
-
import { slugify } from '@mdit-vue/shared'
|
|
196
|
-
import { useWindowSize } from '@vueuse/core'
|
|
197
|
-
import {
|
|
198
|
-
getGithubUpdateTime,
|
|
199
|
-
formatDate,
|
|
200
|
-
getGithubDirUpdateTime
|
|
201
|
-
} from '../utils/client'
|
|
202
|
-
import {
|
|
203
|
-
useUserWorks,
|
|
204
|
-
useActiveAnchor,
|
|
205
|
-
useAutoUpdateAnchor
|
|
206
|
-
} from '../composables/config/blog'
|
|
207
|
-
import { Theme } from '../composables/config'
|
|
208
|
-
|
|
209
|
-
const currentAnchor = useAutoUpdateAnchor()
|
|
210
|
-
// 更新锚点的时候更新 url 中的 hash
|
|
211
|
-
watch(
|
|
212
|
-
() => currentAnchor.id,
|
|
213
|
-
(val) => {
|
|
214
|
-
if (val) {
|
|
215
|
-
window.history.replaceState(null, '', `#${val}`)
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
)
|
|
219
|
-
const mountActiveAnchorEl = useActiveAnchor()
|
|
220
|
-
watch(mountActiveAnchorEl, () => {
|
|
221
|
-
const { value } = mountActiveAnchorEl
|
|
222
|
-
if (value) {
|
|
223
|
-
value.scroll({
|
|
224
|
-
behavior: 'smooth'
|
|
225
|
-
})
|
|
226
|
-
}
|
|
227
|
-
})
|
|
228
|
-
|
|
229
|
-
const works = useUserWorks()
|
|
230
|
-
const workList = reactive<
|
|
231
|
-
(Theme.UserWork & {
|
|
232
|
-
year?: string | undefined
|
|
233
|
-
startTime: string
|
|
234
|
-
lastUpdate?: string
|
|
235
|
-
endTime?: string
|
|
236
|
-
covers?: string[]
|
|
237
|
-
coverLayout?: string
|
|
238
|
-
})[]
|
|
239
|
-
>([])
|
|
240
|
-
|
|
241
|
-
// 格式化数据
|
|
242
|
-
watch(
|
|
243
|
-
works,
|
|
244
|
-
(val) => {
|
|
245
|
-
const sortDate = [...val.list].map((v) => {
|
|
246
|
-
const { time } = v
|
|
247
|
-
|
|
248
|
-
// 格式化时间
|
|
249
|
-
const metaInfo =
|
|
250
|
-
typeof time === 'string'
|
|
251
|
-
? {
|
|
252
|
-
startTime: time,
|
|
253
|
-
endTime: '',
|
|
254
|
-
lastUpdate: ''
|
|
255
|
-
}
|
|
256
|
-
: {
|
|
257
|
-
startTime: time.start,
|
|
258
|
-
endTime: time.end,
|
|
259
|
-
lastUpdate: time.lastupdate
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// 格式化封面信息
|
|
263
|
-
const covers: string[] = []
|
|
264
|
-
let coverLayout = 'swiper'
|
|
265
|
-
|
|
266
|
-
if (typeof v.cover === 'string') {
|
|
267
|
-
covers.push(v.cover)
|
|
268
|
-
} else if (Array.isArray(v.cover)) {
|
|
269
|
-
covers.push(...v.cover)
|
|
270
|
-
} else if (typeof v.cover === 'object') {
|
|
271
|
-
covers.push(...v.cover.urls)
|
|
272
|
-
coverLayout = v.cover.layout ?? coverLayout
|
|
273
|
-
}
|
|
274
|
-
return {
|
|
275
|
-
...v,
|
|
276
|
-
...metaInfo,
|
|
277
|
-
covers,
|
|
278
|
-
coverLayout
|
|
279
|
-
}
|
|
280
|
-
})
|
|
281
|
-
// 过滤出置顶数据
|
|
282
|
-
const topDate = sortDate.filter((v) => v.top !== undefined)
|
|
283
|
-
const normalDate = sortDate.filter((v) => v.top === undefined)
|
|
284
|
-
// 数据排序
|
|
285
|
-
topDate.sort((a, b) => a.top! - b.top!)
|
|
286
|
-
normalDate.sort((a, b) => +new Date(b.startTime) - +new Date(a.startTime))
|
|
287
|
-
if (topDate.length) {
|
|
288
|
-
// @ts-ignore
|
|
289
|
-
topDate[0].year = works.value.topTitle ?? '置顶'
|
|
290
|
-
}
|
|
291
|
-
// 数据分组
|
|
292
|
-
const groupDate = normalDate.reduce((prev, cur) => {
|
|
293
|
-
const { startTime } = cur
|
|
294
|
-
const year = new Date(startTime).getFullYear()
|
|
295
|
-
const data = { ...cur }
|
|
296
|
-
if (!prev[year]) {
|
|
297
|
-
prev[year] = []
|
|
298
|
-
// 第一项数据加上year属性
|
|
299
|
-
// @ts-ignore
|
|
300
|
-
data.year = year
|
|
301
|
-
}
|
|
302
|
-
prev[year].push(data)
|
|
303
|
-
return prev
|
|
304
|
-
}, {} as Record<string, (Theme.UserWork & { year?: string; startTime: string })[]>)
|
|
305
|
-
workList.push(...topDate, ...Object.values(groupDate).reverse().flat())
|
|
306
|
-
},
|
|
307
|
-
{ immediate: true }
|
|
308
|
-
)
|
|
309
|
-
|
|
310
|
-
const init = ref(true)
|
|
311
|
-
// 更新时间信息
|
|
312
|
-
watchEffect(() => {
|
|
313
|
-
if (workList.length && init.value) {
|
|
314
|
-
init.value = false
|
|
315
|
-
workList.forEach((data) => {
|
|
316
|
-
// 接口获取最后更新时间
|
|
317
|
-
if (!data.lastUpdate && data.github) {
|
|
318
|
-
data.lastUpdate = '获取中...'
|
|
319
|
-
const { github } = data
|
|
320
|
-
if (typeof github === 'string') {
|
|
321
|
-
getGithubUpdateTime(github)
|
|
322
|
-
.then((time) => {
|
|
323
|
-
data.lastUpdate = formatDate(time, 'yyyy-MM-dd')
|
|
324
|
-
})
|
|
325
|
-
.catch(() => {
|
|
326
|
-
data.lastUpdate = '地址解析失败'
|
|
327
|
-
})
|
|
328
|
-
} else {
|
|
329
|
-
const { owner, repo, path, branch } = github
|
|
330
|
-
// 拼接Github链接
|
|
331
|
-
let githubUrl = `https://github.com/${owner}/${repo}`
|
|
332
|
-
if (path) {
|
|
333
|
-
githubUrl += `/tree/${branch || 'master'}/${path}`
|
|
334
|
-
} else if (branch) {
|
|
335
|
-
githubUrl += `/tree/${branch}`
|
|
336
|
-
}
|
|
337
|
-
data.github = githubUrl
|
|
338
|
-
getGithubDirUpdateTime(owner, repo, path ?? '', branch)
|
|
339
|
-
.then((time) => {
|
|
340
|
-
data.lastUpdate = formatDate(time, 'yyyy-MM-dd')
|
|
341
|
-
})
|
|
342
|
-
.catch(() => {
|
|
343
|
-
data.lastUpdate = '地址解析失败'
|
|
344
|
-
})
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
})
|
|
348
|
-
}
|
|
349
|
-
})
|
|
350
|
-
|
|
351
|
-
const { width } = useWindowSize()
|
|
352
|
-
const isCardMode = computed(() => width.value > 768)
|
|
353
|
-
const handleChooseTag = (tag: string) => {
|
|
354
|
-
ElMessage({
|
|
355
|
-
message: `点击了${tag}标签,标签过滤功能开发中ing...`,
|
|
356
|
-
type: 'warning'
|
|
357
|
-
})
|
|
358
|
-
}
|
|
359
|
-
</script>
|
|
360
|
-
|
|
361
365
|
<style lang="scss" scoped>
|
|
362
366
|
.user-works-page {
|
|
363
367
|
display: flex;
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { useData, useRoute, withBase } from 'vitepress'
|
|
2
|
-
import {
|
|
2
|
+
import type {
|
|
3
3
|
Component,
|
|
4
|
+
InjectionKey,
|
|
5
|
+
Ref
|
|
6
|
+
} from 'vue'
|
|
7
|
+
import {
|
|
4
8
|
computed,
|
|
5
9
|
defineComponent,
|
|
6
10
|
h,
|
|
7
11
|
inject,
|
|
8
|
-
InjectionKey,
|
|
9
|
-
provide,
|
|
10
|
-
Ref,
|
|
11
12
|
onMounted,
|
|
12
13
|
onUnmounted,
|
|
14
|
+
provide,
|
|
13
15
|
reactive,
|
|
14
16
|
ref
|
|
15
17
|
} from 'vue'
|
|
@@ -119,7 +121,7 @@ export function useCurrentArticle() {
|
|
|
119
121
|
...[`${currentPath}index`, `${decodeURIComponent(currentPath)}index`]
|
|
120
122
|
)
|
|
121
123
|
}
|
|
122
|
-
return docs.value?.find(
|
|
124
|
+
return docs.value?.find(v => okPaths.includes(withBase(v.route)))
|
|
123
125
|
})
|
|
124
126
|
|
|
125
127
|
return currentArticle
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
/* eslint-disable ts/no-namespace */
|
|
1
2
|
import type { ElButton } from 'element-plus'
|
|
2
3
|
import type { DefaultTheme } from 'vitepress'
|
|
3
4
|
import type { FeedOptions } from 'feed'
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
// TODO: 重构 lint 问题
|
|
7
|
+
export declare namespace BlogPopover {
|
|
6
8
|
export interface Title {
|
|
7
9
|
type: 'title'
|
|
8
10
|
content: string
|
|
@@ -174,32 +176,32 @@ export namespace Theme {
|
|
|
174
176
|
title: string
|
|
175
177
|
description: string
|
|
176
178
|
time:
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
179
|
+
| string
|
|
180
|
+
| {
|
|
181
|
+
start: string
|
|
182
|
+
end?: string
|
|
183
|
+
lastupdate?: string
|
|
184
|
+
}
|
|
183
185
|
status?: {
|
|
184
186
|
text: string
|
|
185
187
|
type?: 'tip' | 'warning' | 'danger'
|
|
186
188
|
}
|
|
187
189
|
url?: string
|
|
188
190
|
github?:
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
191
|
+
| string
|
|
192
|
+
| {
|
|
193
|
+
owner: string
|
|
194
|
+
repo: string
|
|
195
|
+
branch?: string
|
|
196
|
+
path?: string
|
|
197
|
+
}
|
|
196
198
|
cover?:
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
199
|
+
| string
|
|
200
|
+
| string[]
|
|
201
|
+
| {
|
|
202
|
+
urls: string[]
|
|
203
|
+
layout?: 'swiper' | 'list'
|
|
204
|
+
}
|
|
203
205
|
links?: {
|
|
204
206
|
title: string
|
|
205
207
|
url: string
|
|
@@ -211,16 +213,16 @@ export namespace Theme {
|
|
|
211
213
|
| boolean
|
|
212
214
|
| 'pagefind'
|
|
213
215
|
| {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
216
|
+
btnPlaceholder?: string
|
|
217
|
+
placeholder?: string
|
|
218
|
+
emptyText?: string
|
|
219
|
+
/**
|
|
220
|
+
* @example
|
|
221
|
+
* 'Total: {{searchResult}} search results.'
|
|
222
|
+
*/
|
|
223
|
+
heading?: string
|
|
224
|
+
mode?: boolean | 'pagefind'
|
|
225
|
+
}
|
|
224
226
|
|
|
225
227
|
export interface UserWorks {
|
|
226
228
|
title: string
|
|
@@ -288,7 +290,7 @@ export namespace Theme {
|
|
|
288
290
|
/**
|
|
289
291
|
* 设置解析 frontmatter 里 date 的时区
|
|
290
292
|
* @default 8 => 'UTC+8'
|
|
291
|
-
|
|
293
|
+
*/
|
|
292
294
|
timeZone?: number
|
|
293
295
|
/**
|
|
294
296
|
* 启用RSS配置
|
package/src/constants/svg.ts
CHANGED
|
@@ -19,7 +19,7 @@ export const fireSVG = `<svg viewBox="0 0 128 128" xmlns="http://www.w3.org/2000
|
|
|
19
19
|
<path fill="url(#notoFire1)" d="M76.11 77.42c-9.09-11.7-5.02-25.05-2.79-30.37c.3-.7-.5-1.36-1.13-.93c-3.91 2.66-11.92 8.92-15.65 17.73c-5.05 11.91-4.69 17.74-1.7 24.86c1.8 4.29-.29 5.2-1.34 5.36c-1.02.16-1.96-.52-2.71-1.23a16.09 16.09 0 0 1-4.44-7.6c-.16-.62-.97-.79-1.34-.28c-2.8 3.87-4.25 10.08-4.32 14.47C40.47 113 51.68 124 65.24 124c17.09 0 29.54-18.9 19.72-34.7c-2.85-4.6-5.53-7.61-8.85-11.88z"/>
|
|
20
20
|
</svg>`
|
|
21
21
|
|
|
22
|
-
export const recommendSVG
|
|
22
|
+
export const recommendSVG = `<svg width="512" height="512" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg">
|
|
23
23
|
<radialGradient id="notoFaceWithMonocle0" cx="63.6" cy="-2088.9" r="56.96" gradientTransform="matrix(1 0 0 -1 0 -2026)" gradientUnits="userSpaceOnUse">
|
|
24
24
|
<stop offset=".5" stop-color="#FDE030"/>
|
|
25
25
|
<stop offset=".919" stop-color="#F7C02B"/>
|
|
@@ -42,4 +42,4 @@ export const recommendSVG =`<svg width="512" height="512" viewBox="0 0 128 128"
|
|
|
42
42
|
<circle cx="79.6" cy="53.7" r="20.6" fill="#CCC" fill-opacity=".5" stroke="#404040" stroke-miterlimit="10" stroke-width="3.5"/>
|
|
43
43
|
<path fill="#FFF" d="M94.8 52.5c-.4-3.8-2.1-7.3-4.9-9.7s-6.4-3.7-10-3.7c-3.7 0-7.3 1.2-10.1 3.5s-4.6 5.8-4.9 9.6c0 .3-.3.5-.5.4c-.2 0-.4-.2-.4-.5c-.1-2 .3-4.1 1.1-6c.8-1.9 2-3.6 3.5-5.1c3-2.9 7.3-4.3 11.4-4.3c4.2 0 8.3 1.6 11.3 4.5c1.5 1.5 2.7 3.2 3.5 5.1c.8 1.9 1.1 4 1 6c0 .3-.2.5-.5.5c-.3.1-.5-.1-.5-.3z"/>
|
|
44
44
|
<path fill="#896024" d="M37.01 49.35c-1.03-.72-2.58-.49-3.58.95s-.67 2.97.36 3.69c1.03.72 2.58.49 3.58-.95c1.01-1.45.68-2.98-.36-3.69z"/>
|
|
45
|
-
</svg>`
|
|
45
|
+
</svg>`
|