@sugarat/theme 0.4.11 → 0.4.13
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 +3 -73
- package/node.js +8 -3
- package/package.json +4 -3
- package/src/components/BlogApp.vue +0 -2
- package/src/composables/config/index.ts +3 -79
- package/src/utils/node/theme.ts +12 -11
- package/src/utils/node/vitePlugins.ts +5 -0
- package/src/components/BlogPopover.vue +0 -290
package/node.d.ts
CHANGED
|
@@ -1,38 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ElButton } from 'element-plus';
|
|
1
|
+
import { DefaultTheme, UserConfig } from 'vitepress';
|
|
3
2
|
import { RSSOptions } from 'vitepress-plugin-rss';
|
|
4
3
|
import { Repo, Mapping } from '@giscus/vue';
|
|
5
4
|
import { Options } from 'oh-my-live2d';
|
|
6
|
-
import { Ref } from 'vue';
|
|
7
5
|
import { PagefindConfig } from 'vitepress-plugin-pagefind';
|
|
6
|
+
import { AnnouncementOptions } from 'vitepress-plugin-announcement';
|
|
8
7
|
export { tabsMarkdownPlugin } from 'vitepress-plugin-tabs';
|
|
9
8
|
|
|
10
9
|
type RSSPluginOptions = RSSOptions;
|
|
11
|
-
declare namespace BlogPopover {
|
|
12
|
-
interface Title {
|
|
13
|
-
type: 'title';
|
|
14
|
-
content: string;
|
|
15
|
-
style?: string;
|
|
16
|
-
}
|
|
17
|
-
interface Text {
|
|
18
|
-
type: 'text';
|
|
19
|
-
content: string;
|
|
20
|
-
style?: string;
|
|
21
|
-
}
|
|
22
|
-
interface Image {
|
|
23
|
-
type: 'image';
|
|
24
|
-
src: string;
|
|
25
|
-
style?: string;
|
|
26
|
-
}
|
|
27
|
-
interface Button {
|
|
28
|
-
type: 'button';
|
|
29
|
-
link: string;
|
|
30
|
-
content: string;
|
|
31
|
-
style?: string;
|
|
32
|
-
props?: InstanceType<typeof ElButton>['$props'];
|
|
33
|
-
}
|
|
34
|
-
type Value = Title | Text | Image | Button;
|
|
35
|
-
}
|
|
36
10
|
type ThemeableImage = string | {
|
|
37
11
|
src: string;
|
|
38
12
|
alt?: string;
|
|
@@ -279,50 +253,6 @@ declare namespace Theme {
|
|
|
279
253
|
showIcon?: boolean;
|
|
280
254
|
html?: string;
|
|
281
255
|
}
|
|
282
|
-
/**
|
|
283
|
-
* 公告
|
|
284
|
-
*/
|
|
285
|
-
interface Popover {
|
|
286
|
-
title: string;
|
|
287
|
-
/**
|
|
288
|
-
* 细粒度的时间控制
|
|
289
|
-
* 默认展示时间,-1 只展示1次,其它数字为每次都展示,一定时间后自动消失,0为不自动消失
|
|
290
|
-
* 配置改变时,会重新触发展示
|
|
291
|
-
*/
|
|
292
|
-
duration: number;
|
|
293
|
-
/**
|
|
294
|
-
* 移动端自动最小化
|
|
295
|
-
* @default false
|
|
296
|
-
*/
|
|
297
|
-
mobileMinify?: boolean;
|
|
298
|
-
body?: BlogPopover.Value[];
|
|
299
|
-
footer?: BlogPopover.Value[];
|
|
300
|
-
/**
|
|
301
|
-
* 手动重新打开
|
|
302
|
-
* @default true
|
|
303
|
-
*/
|
|
304
|
-
reopen?: boolean;
|
|
305
|
-
/**
|
|
306
|
-
* 是否打开闪烁提示,通常需要和 reopen 搭配使用
|
|
307
|
-
* @default true
|
|
308
|
-
*/
|
|
309
|
-
twinkle?: boolean;
|
|
310
|
-
/**
|
|
311
|
-
* 设置展示图标,svg
|
|
312
|
-
* @recommend https://iconbuddy.app/search?q=fire
|
|
313
|
-
*/
|
|
314
|
-
icon?: string;
|
|
315
|
-
/**
|
|
316
|
-
* 设置关闭图标,svg
|
|
317
|
-
* @recommend https://iconbuddy.app/search?q=fire
|
|
318
|
-
*/
|
|
319
|
-
closeIcon?: string;
|
|
320
|
-
/**
|
|
321
|
-
* 自定义展示策略
|
|
322
|
-
* @param to 切换到的目标路由
|
|
323
|
-
*/
|
|
324
|
-
onRouteChanged?: (to: Route, show: Ref<boolean>) => void;
|
|
325
|
-
}
|
|
326
256
|
interface FriendLink {
|
|
327
257
|
nickname: string;
|
|
328
258
|
des: string;
|
|
@@ -428,7 +358,7 @@ declare namespace Theme {
|
|
|
428
358
|
* el-alert
|
|
429
359
|
*/
|
|
430
360
|
alert?: Alert;
|
|
431
|
-
popover?:
|
|
361
|
+
popover?: AnnouncementOptions;
|
|
432
362
|
friend?: FriendLink[] | FriendConfig;
|
|
433
363
|
authorList?: Omit<FriendLink, 'avatar'>[];
|
|
434
364
|
/**
|
package/node.js
CHANGED
|
@@ -398,7 +398,8 @@ async function getArticleMeta(filepath, route, timeZone = defaultTimeZoneOffset)
|
|
|
398
398
|
if (!meta.title) {
|
|
399
399
|
meta.title = (0, import_theme_shared2.getDefaultTitle)(content);
|
|
400
400
|
}
|
|
401
|
-
const
|
|
401
|
+
const utcValue = timeZone >= 0 ? `+${timeZone}` : `${timeZone}`;
|
|
402
|
+
const date = await (meta.date && /* @__PURE__ */ new Date(`${new Date(meta.date).toUTCString()}${utcValue}`) || (0, import_theme_shared2.getFileLastModifyTime)(filepath));
|
|
402
403
|
meta.date = formatDate(date || /* @__PURE__ */ new Date());
|
|
403
404
|
meta.categories = typeof meta.categories === "string" ? [meta.categories] : meta.categories;
|
|
404
405
|
meta.tags = typeof meta.tags === "string" ? [meta.tags] : meta.tags;
|
|
@@ -444,8 +445,8 @@ function patchVPConfig(vpConfig, cfg) {
|
|
|
444
445
|
if (cfg?.comment && "type" in cfg.comment && cfg?.comment?.type === "artalk") {
|
|
445
446
|
const server = cfg.comment?.options?.server;
|
|
446
447
|
if (server) {
|
|
447
|
-
vpConfig.head.push(["link", { href: `${server}/dist/Artalk.css`, rel: "stylesheet" }]);
|
|
448
|
-
vpConfig.head.push(["script", { src: `${server}/dist/Artalk.js`, id: "artalk-script" }]);
|
|
448
|
+
vpConfig.head.push(["link", { href: `${server} /dist/Artalk.css`, rel: "stylesheet" }]);
|
|
449
|
+
vpConfig.head.push(["script", { src: `${server} /dist/Artalk.js`, id: "artalk-script" }]);
|
|
449
450
|
}
|
|
450
451
|
}
|
|
451
452
|
}
|
|
@@ -463,6 +464,7 @@ var import_node_buffer = require("buffer");
|
|
|
463
464
|
var import_vitepress_plugin_pagefind = require("vitepress-plugin-pagefind");
|
|
464
465
|
var import_vitepress_plugin_rss = require("vitepress-plugin-rss");
|
|
465
466
|
var import_theme_shared3 = require("@sugarat/theme-shared");
|
|
467
|
+
var import_vitepress_plugin_announcement = require("vitepress-plugin-announcement");
|
|
466
468
|
|
|
467
469
|
// src/utils/node/hot-reload-plugin.ts
|
|
468
470
|
function themeReloadPlugin() {
|
|
@@ -540,6 +542,9 @@ function getVitePlugins(cfg = {}) {
|
|
|
540
542
|
;
|
|
541
543
|
[cfg?.RSS].flat().forEach((rssConfig) => plugins.push((0, import_vitepress_plugin_rss.RssPlugin)(rssConfig)));
|
|
542
544
|
}
|
|
545
|
+
if (cfg?.popover) {
|
|
546
|
+
plugins.push((0, import_vitepress_plugin_announcement.AnnouncementPlugin)(cfg.popover));
|
|
547
|
+
}
|
|
543
548
|
return plugins;
|
|
544
549
|
}
|
|
545
550
|
function registerVitePlugins(vpCfg, plugins) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sugarat/theme",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.13",
|
|
4
4
|
"description": "简约风的 Vitepress 博客主题,sugarat vitepress blog theme",
|
|
5
5
|
"author": "sugar",
|
|
6
6
|
"license": "MIT",
|
|
@@ -51,8 +51,9 @@
|
|
|
51
51
|
"vitepress-plugin-mermaid": "2.0.13",
|
|
52
52
|
"vitepress-plugin-tabs": "0.2.0",
|
|
53
53
|
"@sugarat/theme-shared": "0.0.2",
|
|
54
|
-
"vitepress-plugin-
|
|
55
|
-
"vitepress-plugin-
|
|
54
|
+
"vitepress-plugin-rss": "0.2.10",
|
|
55
|
+
"vitepress-plugin-announcement": "0.1.1",
|
|
56
|
+
"vitepress-plugin-pagefind": "0.4.10"
|
|
56
57
|
},
|
|
57
58
|
"devDependencies": {
|
|
58
59
|
"@element-plus/icons-vue": "^2.3.1",
|
|
@@ -11,7 +11,6 @@ import BlogSidebar from './BlogSidebar.vue'
|
|
|
11
11
|
import BlogImagePreview from './BlogImagePreview.vue'
|
|
12
12
|
import BlogArticleAnalyze from './BlogArticleAnalyze.vue'
|
|
13
13
|
import BlogAlert from './BlogAlert.vue'
|
|
14
|
-
import BlogPopover from './BlogPopover.vue'
|
|
15
14
|
import BlogFooter from './BlogFooter.vue'
|
|
16
15
|
import BlogHomeHeaderAvatar from './BlogHomeHeaderAvatar.vue'
|
|
17
16
|
import BlogBackToTop from './BlogBackToTop.vue'
|
|
@@ -40,7 +39,6 @@ const openTransition = useDarkTransitionConfig()
|
|
|
40
39
|
<ClientOnly>
|
|
41
40
|
<BlogOml2d />
|
|
42
41
|
<BlogAlert />
|
|
43
|
-
<BlogPopover />
|
|
44
42
|
</ClientOnly>
|
|
45
43
|
</template>
|
|
46
44
|
|
|
@@ -1,45 +1,13 @@
|
|
|
1
1
|
/* eslint-disable ts/no-namespace */
|
|
2
|
-
import type {
|
|
3
|
-
import type { DefaultTheme, Route } from 'vitepress'
|
|
2
|
+
import type { DefaultTheme } from 'vitepress'
|
|
4
3
|
import type { RSSOptions } from 'vitepress-plugin-rss'
|
|
5
4
|
import type { Mapping, Repo } from '@giscus/vue'
|
|
6
5
|
import type { Options as Oml2dOptions } from 'oh-my-live2d'
|
|
7
|
-
import type { Ref } from 'vue'
|
|
8
6
|
import type { PagefindConfig } from 'vitepress-plugin-pagefind'
|
|
7
|
+
import type { AnnouncementOptions } from 'vitepress-plugin-announcement'
|
|
9
8
|
|
|
10
9
|
type RSSPluginOptions = RSSOptions
|
|
11
10
|
|
|
12
|
-
// TODO: 重构 lint 问题
|
|
13
|
-
export declare namespace BlogPopover {
|
|
14
|
-
export interface Title {
|
|
15
|
-
type: 'title'
|
|
16
|
-
content: string
|
|
17
|
-
style?: string
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface Text {
|
|
21
|
-
type: 'text'
|
|
22
|
-
content: string
|
|
23
|
-
style?: string
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface Image {
|
|
27
|
-
type: 'image'
|
|
28
|
-
src: string
|
|
29
|
-
style?: string
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface Button {
|
|
33
|
-
type: 'button'
|
|
34
|
-
link: string
|
|
35
|
-
content: string
|
|
36
|
-
style?: string
|
|
37
|
-
props?: InstanceType<typeof ElButton>['$props']
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export type Value = Title | Text | Image | Button
|
|
41
|
-
}
|
|
42
|
-
|
|
43
11
|
export type ThemeableImage =
|
|
44
12
|
| string
|
|
45
13
|
| { src: string; alt?: string }
|
|
@@ -293,50 +261,6 @@ export namespace Theme {
|
|
|
293
261
|
html?: string
|
|
294
262
|
}
|
|
295
263
|
|
|
296
|
-
/**
|
|
297
|
-
* 公告
|
|
298
|
-
*/
|
|
299
|
-
export interface Popover {
|
|
300
|
-
title: string
|
|
301
|
-
/**
|
|
302
|
-
* 细粒度的时间控制
|
|
303
|
-
* 默认展示时间,-1 只展示1次,其它数字为每次都展示,一定时间后自动消失,0为不自动消失
|
|
304
|
-
* 配置改变时,会重新触发展示
|
|
305
|
-
*/
|
|
306
|
-
duration: number
|
|
307
|
-
/**
|
|
308
|
-
* 移动端自动最小化
|
|
309
|
-
* @default false
|
|
310
|
-
*/
|
|
311
|
-
mobileMinify?: boolean
|
|
312
|
-
body?: BlogPopover.Value[]
|
|
313
|
-
footer?: BlogPopover.Value[]
|
|
314
|
-
/**
|
|
315
|
-
* 手动重新打开
|
|
316
|
-
* @default true
|
|
317
|
-
*/
|
|
318
|
-
reopen?: boolean
|
|
319
|
-
/**
|
|
320
|
-
* 是否打开闪烁提示,通常需要和 reopen 搭配使用
|
|
321
|
-
* @default true
|
|
322
|
-
*/
|
|
323
|
-
twinkle?: boolean
|
|
324
|
-
/**
|
|
325
|
-
* 设置展示图标,svg
|
|
326
|
-
* @recommend https://iconbuddy.app/search?q=fire
|
|
327
|
-
*/
|
|
328
|
-
icon?: string
|
|
329
|
-
/**
|
|
330
|
-
* 设置关闭图标,svg
|
|
331
|
-
* @recommend https://iconbuddy.app/search?q=fire
|
|
332
|
-
*/
|
|
333
|
-
closeIcon?: string
|
|
334
|
-
/**
|
|
335
|
-
* 自定义展示策略
|
|
336
|
-
* @param to 切换到的目标路由
|
|
337
|
-
*/
|
|
338
|
-
onRouteChanged?: (to: Route, show: Ref<boolean>) => void
|
|
339
|
-
}
|
|
340
264
|
export interface FriendLink {
|
|
341
265
|
nickname: string
|
|
342
266
|
des: string
|
|
@@ -462,7 +386,7 @@ export namespace Theme {
|
|
|
462
386
|
* el-alert
|
|
463
387
|
*/
|
|
464
388
|
alert?: Alert
|
|
465
|
-
popover?:
|
|
389
|
+
popover?: AnnouncementOptions
|
|
466
390
|
friend?: FriendLink[] | FriendConfig
|
|
467
391
|
authorList?: Omit<FriendLink, 'avatar'>[]
|
|
468
392
|
/**
|
package/src/utils/node/theme.ts
CHANGED
|
@@ -43,17 +43,18 @@ export async function getArticleMeta(filepath: string, route: string, timeZone =
|
|
|
43
43
|
if (!meta.title) {
|
|
44
44
|
meta.title = getDefaultTitle(content)
|
|
45
45
|
}
|
|
46
|
+
const utcValue = timeZone >= 0 ? `+${timeZone}` : `${timeZone}`
|
|
46
47
|
const date = await (
|
|
47
48
|
(meta.date
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
&& new Date(`${new Date(meta.date).toUTCString()}${utcValue}`))
|
|
50
|
+
|| getFileLastModifyTime(filepath)
|
|
50
51
|
)
|
|
51
52
|
// 无法获取时兜底当前时间
|
|
52
53
|
meta.date = formatDate(date || new Date())
|
|
53
54
|
|
|
54
55
|
// 处理tags和categories,兼容历史文章
|
|
55
56
|
meta.categories
|
|
56
|
-
|
|
57
|
+
= typeof meta.categories === 'string'
|
|
57
58
|
? [meta.categories]
|
|
58
59
|
: meta.categories
|
|
59
60
|
meta.tags = typeof meta.tags === 'string' ? [meta.tags] : meta.tags
|
|
@@ -66,12 +67,12 @@ export async function getArticleMeta(filepath: string, route: string, timeZone =
|
|
|
66
67
|
// 获取摘要信息
|
|
67
68
|
// TODO:摘要生成优化
|
|
68
69
|
meta.description
|
|
69
|
-
|
|
70
|
+
= meta.description || getTextSummary(content, 100) || excerpt
|
|
70
71
|
|
|
71
72
|
// 获取封面图
|
|
72
73
|
meta.cover
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
= meta.cover
|
|
75
|
+
?? (getFirstImagURLFromMD(fileContent, route))
|
|
75
76
|
|
|
76
77
|
// 是否发布 默认发布
|
|
77
78
|
if (meta.publish === false) {
|
|
@@ -82,9 +83,9 @@ export async function getArticleMeta(filepath: string, route: string, timeZone =
|
|
|
82
83
|
}
|
|
83
84
|
export async function getArticles(cfg: Partial<Theme.BlogConfig>, vpConfig: SiteConfig) {
|
|
84
85
|
const srcDir
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
= cfg?.srcDir || vpConfig.srcDir.replace(vpConfig.root, '').replace(/^\//, '')
|
|
87
|
+
|| process.argv.slice(2)?.[1]
|
|
88
|
+
|| '.'
|
|
88
89
|
const files = glob.sync(`${srcDir}/**/*.md`, { ignore: ['node_modules'], absolute: true })
|
|
89
90
|
|
|
90
91
|
const metaResults = files.reduce((prev, curr) => {
|
|
@@ -124,8 +125,8 @@ export function patchVPConfig(vpConfig: any, cfg?: Partial<Theme.BlogConfig>) {
|
|
|
124
125
|
if (cfg?.comment && 'type' in cfg.comment && cfg?.comment?.type === 'artalk') {
|
|
125
126
|
const server = cfg.comment?.options?.server
|
|
126
127
|
if (server) {
|
|
127
|
-
vpConfig.head.push(['link', { href: `${server}/dist/Artalk.css`, rel: 'stylesheet' }])
|
|
128
|
-
vpConfig.head.push(['script', { src: `${server}/dist/Artalk.js`, id: 'artalk-script' }])
|
|
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' }])
|
|
129
130
|
}
|
|
130
131
|
}
|
|
131
132
|
}
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
import { RssPlugin } from 'vitepress-plugin-rss'
|
|
9
9
|
import type { PluginOption } from 'vite'
|
|
10
10
|
import { joinPath } from '@sugarat/theme-shared'
|
|
11
|
+
import { AnnouncementPlugin } from 'vitepress-plugin-announcement'
|
|
11
12
|
import type { Theme } from '../../composables/config/index'
|
|
12
13
|
import { _require } from './mdPlugins'
|
|
13
14
|
import { themeReloadPlugin } from './hot-reload-plugin'
|
|
@@ -50,6 +51,10 @@ export function getVitePlugins(cfg: Partial<Theme.BlogConfig> = {}) {
|
|
|
50
51
|
if (cfg?.RSS) {
|
|
51
52
|
;[cfg?.RSS].flat().forEach(rssConfig => plugins.push(RssPlugin(rssConfig)))
|
|
52
53
|
}
|
|
54
|
+
|
|
55
|
+
if (cfg?.popover) {
|
|
56
|
+
plugins.push(AnnouncementPlugin(cfg.popover))
|
|
57
|
+
}
|
|
53
58
|
return plugins
|
|
54
59
|
}
|
|
55
60
|
|
|
@@ -1,290 +0,0 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
import { ElButton, ElIcon } from 'element-plus'
|
|
3
|
-
import { CircleCloseFilled } from '@element-plus/icons-vue'
|
|
4
|
-
import { computed, h, onMounted, ref, watch } from 'vue'
|
|
5
|
-
import type { BlogPopover } from '@sugarat/theme'
|
|
6
|
-
import { parseStringStyle } from '@vue/shared'
|
|
7
|
-
import { useDebounceFn, useWindowSize } from '@vueuse/core'
|
|
8
|
-
import { useRoute, useRouter } from 'vitepress'
|
|
9
|
-
import { useBlogConfig } from '../composables/config/blog'
|
|
10
|
-
import { vOuterHtml } from '../directives'
|
|
11
|
-
|
|
12
|
-
const { popover: popoverProps } = useBlogConfig()
|
|
13
|
-
|
|
14
|
-
const show = ref(false)
|
|
15
|
-
|
|
16
|
-
const bodyContent = computed(() => {
|
|
17
|
-
return popoverProps?.body || []
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
const footerContent = computed(() => {
|
|
21
|
-
return popoverProps?.footer || []
|
|
22
|
-
})
|
|
23
|
-
const storageKey = 'theme-blog-popover'
|
|
24
|
-
const closeFlag = `${storageKey}-close`
|
|
25
|
-
|
|
26
|
-
// 移动端最小化
|
|
27
|
-
const { width } = useWindowSize()
|
|
28
|
-
const router = useRouter()
|
|
29
|
-
const route = useRoute()
|
|
30
|
-
onMounted(() => {
|
|
31
|
-
if (!popoverProps?.title) {
|
|
32
|
-
return
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// 取旧值
|
|
36
|
-
const oldValue = localStorage.getItem(storageKey)
|
|
37
|
-
const newValue = JSON.stringify(popoverProps)
|
|
38
|
-
localStorage.setItem(storageKey, newValue)
|
|
39
|
-
|
|
40
|
-
// 移动端最小化
|
|
41
|
-
if (width.value < 768 && popoverProps?.mobileMinify) {
|
|
42
|
-
show.value = false
|
|
43
|
-
return
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// >= 0 每次都展示,区别是否自动消失
|
|
47
|
-
if (Number(popoverProps?.duration ?? '') >= 0) {
|
|
48
|
-
show.value = true
|
|
49
|
-
if (popoverProps?.duration) {
|
|
50
|
-
setTimeout(() => {
|
|
51
|
-
show.value = false
|
|
52
|
-
}, popoverProps?.duration)
|
|
53
|
-
}
|
|
54
|
-
return
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (oldValue !== newValue && popoverProps?.duration === -1) {
|
|
58
|
-
// 当做新值处理
|
|
59
|
-
show.value = true
|
|
60
|
-
localStorage.removeItem(closeFlag)
|
|
61
|
-
return
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// 新旧相等,判断是否点击过close,没点击关闭依然展示
|
|
65
|
-
if (oldValue === newValue && popoverProps?.duration === -1 && !localStorage.getItem(closeFlag)) {
|
|
66
|
-
show.value = true
|
|
67
|
-
}
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
const onAfterRouteChanged = useDebounceFn(() => {
|
|
71
|
-
popoverProps?.onRouteChanged?.(route, show)
|
|
72
|
-
}, 10)
|
|
73
|
-
|
|
74
|
-
watch(route, onAfterRouteChanged, { immediate: true })
|
|
75
|
-
|
|
76
|
-
function handleClose() {
|
|
77
|
-
show.value = false
|
|
78
|
-
if (popoverProps?.duration === -1) {
|
|
79
|
-
localStorage.setItem(closeFlag, `${+new Date()}`)
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function PopoverValue(props: { key: number; item: BlogPopover.Value },
|
|
84
|
-
{ slots }: any) {
|
|
85
|
-
const { key, item } = props
|
|
86
|
-
if (item.type === 'title') {
|
|
87
|
-
return h(
|
|
88
|
-
'h4',
|
|
89
|
-
{
|
|
90
|
-
style: parseStringStyle(item.style || '')
|
|
91
|
-
},
|
|
92
|
-
item.content
|
|
93
|
-
)
|
|
94
|
-
}
|
|
95
|
-
if (item.type === 'text') {
|
|
96
|
-
return h(
|
|
97
|
-
'p',
|
|
98
|
-
{
|
|
99
|
-
style: parseStringStyle(item.style || '')
|
|
100
|
-
},
|
|
101
|
-
item.content
|
|
102
|
-
)
|
|
103
|
-
}
|
|
104
|
-
if (item.type === 'image') {
|
|
105
|
-
return h('img', {
|
|
106
|
-
src: item.src,
|
|
107
|
-
style: parseStringStyle(item.style || '')
|
|
108
|
-
})
|
|
109
|
-
}
|
|
110
|
-
if (item.type === 'button') {
|
|
111
|
-
return h(
|
|
112
|
-
ElButton,
|
|
113
|
-
{
|
|
114
|
-
type: 'primary',
|
|
115
|
-
onClick: () => {
|
|
116
|
-
if (/^\s*http(s)?:\/\//.test(item.link)) {
|
|
117
|
-
window.open(item.link)
|
|
118
|
-
}
|
|
119
|
-
else {
|
|
120
|
-
router.go(item.link)
|
|
121
|
-
}
|
|
122
|
-
},
|
|
123
|
-
style: parseStringStyle(item.style || ''),
|
|
124
|
-
...item.props
|
|
125
|
-
},
|
|
126
|
-
slots
|
|
127
|
-
)
|
|
128
|
-
}
|
|
129
|
-
return h(
|
|
130
|
-
'div',
|
|
131
|
-
{
|
|
132
|
-
key
|
|
133
|
-
},
|
|
134
|
-
''
|
|
135
|
-
)
|
|
136
|
-
}
|
|
137
|
-
</script>
|
|
138
|
-
|
|
139
|
-
<template>
|
|
140
|
-
<div v-show="show" class="theme-blog-popover" data-pagefind-ignore="all">
|
|
141
|
-
<div class="header">
|
|
142
|
-
<div class="title-wrapper">
|
|
143
|
-
<ElIcon size="20px">
|
|
144
|
-
<i v-if="popoverProps?.icon" v-outer-html="popoverProps.icon" />
|
|
145
|
-
<svg v-else t="1716085184855" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4274" width="200" height="200"><path d="M660.48 872.448q6.144 0-3.584 15.36t-29.696 33.792-47.104 33.792-57.856 15.36q-27.648 0-53.248-15.36t-45.056-33.792-29.696-33.792-6.144-15.36l272.384 0zM914.432 785.408q7.168 9.216 6.656 17.92t-4.608 14.848-10.24 9.728-12.288 3.584l-747.52 0q-14.336 0-20.992-11.776t4.608-29.184q17.408-30.72 40.96-68.608t44.544-81.408 36.352-92.16 15.36-101.888q0-51.2 14.336-92.16t37.376-71.68 53.248-52.224 62.976-32.768q-16.384-26.624-16.384-55.296 0-41.984 28.672-70.656t70.656-28.672 70.656 28.672 28.672 70.656q0 14.336-4.096 28.16t-11.264 25.088q34.816 11.264 66.048 32.768t54.272 53.248 36.864 72.704 13.824 91.136q0 51.2 15.36 100.864t36.864 94.208 45.568 81.408 43.52 63.488zM478.208 142.336q0 16.384 11.264 28.16t27.648 11.776l2.048 0q16.384-1.024 27.648-12.288t11.264-27.648q0-17.408-11.264-28.672t-28.672-11.264-28.672 11.264-11.264 28.672z" p-id="4275" /></svg>
|
|
146
|
-
</ElIcon>
|
|
147
|
-
<span class="title">{{ popoverProps?.title }}</span>
|
|
148
|
-
</div>
|
|
149
|
-
<ElIcon class="close-icon" size="20px" @click="handleClose">
|
|
150
|
-
<i v-if="popoverProps?.closeIcon" v-outer-html="popoverProps.closeIcon" />
|
|
151
|
-
<CircleCloseFilled v-else />
|
|
152
|
-
</ElIcon>
|
|
153
|
-
</div>
|
|
154
|
-
<div v-if="bodyContent.length" class="body content">
|
|
155
|
-
<PopoverValue v-for="(v, idx) in bodyContent" :key="idx" :item="v">
|
|
156
|
-
{{ v.type !== 'image' ? v.content : '' }}
|
|
157
|
-
</PopoverValue>
|
|
158
|
-
<hr v-if="footerContent.length">
|
|
159
|
-
</div>
|
|
160
|
-
<div class="footer content">
|
|
161
|
-
<PopoverValue v-for="(v, idx) in footerContent" :key="idx" :item="v">
|
|
162
|
-
{{ v.type !== 'image' ? v.content : '' }}
|
|
163
|
-
</PopoverValue>
|
|
164
|
-
</div>
|
|
165
|
-
</div>
|
|
166
|
-
<div
|
|
167
|
-
v-show="!show && (popoverProps?.reopen ?? true) && popoverProps?.title" class="theme-blog-popover-close"
|
|
168
|
-
:class="{ twinkle: !show && (popoverProps?.twinkle ?? true) }"
|
|
169
|
-
@click="show = true"
|
|
170
|
-
>
|
|
171
|
-
<ElIcon>
|
|
172
|
-
<i v-if="popoverProps?.icon" v-outer-html="popoverProps.icon" />
|
|
173
|
-
<svg v-else t="1716085184855" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4274" width="200" height="200"><path d="M660.48 872.448q6.144 0-3.584 15.36t-29.696 33.792-47.104 33.792-57.856 15.36q-27.648 0-53.248-15.36t-45.056-33.792-29.696-33.792-6.144-15.36l272.384 0zM914.432 785.408q7.168 9.216 6.656 17.92t-4.608 14.848-10.24 9.728-12.288 3.584l-747.52 0q-14.336 0-20.992-11.776t4.608-29.184q17.408-30.72 40.96-68.608t44.544-81.408 36.352-92.16 15.36-101.888q0-51.2 14.336-92.16t37.376-71.68 53.248-52.224 62.976-32.768q-16.384-26.624-16.384-55.296 0-41.984 28.672-70.656t70.656-28.672 70.656 28.672 28.672 70.656q0 14.336-4.096 28.16t-11.264 25.088q34.816 11.264 66.048 32.768t54.272 53.248 36.864 72.704 13.824 91.136q0 51.2 15.36 100.864t36.864 94.208 45.568 81.408 43.52 63.488zM478.208 142.336q0 16.384 11.264 28.16t27.648 11.776l2.048 0q16.384-1.024 27.648-12.288t11.264-27.648q0-17.408-11.264-28.672t-28.672-11.264-28.672 11.264-11.264 28.672z" p-id="4275" /></svg>
|
|
174
|
-
</ElIcon>
|
|
175
|
-
</div>
|
|
176
|
-
</template>
|
|
177
|
-
|
|
178
|
-
<style lang="scss" scoped>
|
|
179
|
-
.theme-blog-popover {
|
|
180
|
-
width: 258px;
|
|
181
|
-
position: fixed;
|
|
182
|
-
top: 80px;
|
|
183
|
-
right: 20px;
|
|
184
|
-
z-index: 22;
|
|
185
|
-
box-sizing: border-box;
|
|
186
|
-
border: 1px solid var(--vp-c-brand-3);
|
|
187
|
-
border-radius: 6px;
|
|
188
|
-
background-color: rgba(var(--bg-gradient-home));
|
|
189
|
-
box-shadow: var(--box-shadow);
|
|
190
|
-
|
|
191
|
-
:deep(.el-button.el-button--primary) {
|
|
192
|
-
background-color: var(--vp-c-brand-2);
|
|
193
|
-
border-color: var(--vp-c-brand-2);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
.header {
|
|
198
|
-
background-color: var(--vp-c-brand-3);
|
|
199
|
-
color: #fff;
|
|
200
|
-
padding: 6px 4px;
|
|
201
|
-
display: flex;
|
|
202
|
-
justify-content: space-between;
|
|
203
|
-
align-items: center;
|
|
204
|
-
|
|
205
|
-
.close-icon {
|
|
206
|
-
cursor: pointer;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
.title-wrapper {
|
|
211
|
-
display: flex;
|
|
212
|
-
align-items: center;
|
|
213
|
-
|
|
214
|
-
.title {
|
|
215
|
-
font-size: 14px;
|
|
216
|
-
padding-left: 6px;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
.body {
|
|
221
|
-
box-sizing: border-box;
|
|
222
|
-
padding: 10px 10px 0;
|
|
223
|
-
|
|
224
|
-
hr {
|
|
225
|
-
border: none;
|
|
226
|
-
border-bottom: 1px solid #eaecef;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
.footer {
|
|
231
|
-
box-sizing: border-box;
|
|
232
|
-
padding: 10px;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
.body.content,
|
|
236
|
-
.footer.content {
|
|
237
|
-
text-align: center;
|
|
238
|
-
|
|
239
|
-
h4 {
|
|
240
|
-
text-align: center;
|
|
241
|
-
font-size: 12px;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
p {
|
|
245
|
-
text-align: center;
|
|
246
|
-
padding: 10px 0;
|
|
247
|
-
font-size: 14px;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
img {
|
|
251
|
-
width: 100%;
|
|
252
|
-
// TODO: 未来优化,自动预获取图片高度填充
|
|
253
|
-
height: 100px;
|
|
254
|
-
object-fit: contain;
|
|
255
|
-
margin: 0 auto;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
.theme-blog-popover-close {
|
|
260
|
-
cursor: pointer;
|
|
261
|
-
opacity: 0.5;
|
|
262
|
-
position: fixed;
|
|
263
|
-
z-index: 22;
|
|
264
|
-
top: 80px;
|
|
265
|
-
right: 10px;
|
|
266
|
-
position: fixed;
|
|
267
|
-
background-color: var(--vp-c-brand-3);
|
|
268
|
-
padding: 8px;
|
|
269
|
-
color: #fff;
|
|
270
|
-
font-size: 12px;
|
|
271
|
-
border-radius: 50%;
|
|
272
|
-
display: flex;
|
|
273
|
-
flex-direction: column;
|
|
274
|
-
}
|
|
275
|
-
.theme-blog-popover-close.twinkle {
|
|
276
|
-
animation: twinkle 1s ease-in-out infinite;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
@keyframes twinkle {
|
|
280
|
-
0% {
|
|
281
|
-
opacity: 0.5;
|
|
282
|
-
}
|
|
283
|
-
50% {
|
|
284
|
-
opacity: 0;
|
|
285
|
-
}
|
|
286
|
-
100% {
|
|
287
|
-
opacity: 0.5;
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
</style>
|