@sugarat/theme 0.5.7 → 0.5.9
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 +21 -0
- package/node.js +10 -7
- package/node.mjs +12 -9
- package/package.json +5 -5
- package/src/components/BlogAuthor.vue +9 -9
- package/src/components/BlogHomeHeaderAvatar.vue +12 -7
- package/src/components/BlogList.vue +5 -4
- package/src/composables/config/index.ts +22 -0
- package/src/hooks/useHoverSpin.ts +114 -0
- package/src/utils/node/index.ts +2 -3
- package/src/utils/node/theme.ts +1 -1
- package/src/utils/node/vitePlugins.ts +10 -8
package/node.d.ts
CHANGED
|
@@ -186,6 +186,27 @@ declare namespace Theme {
|
|
|
186
186
|
* @default false
|
|
187
187
|
*/
|
|
188
188
|
blogInfoCollapsible?: boolean;
|
|
189
|
+
/**
|
|
190
|
+
* 旋转的配置
|
|
191
|
+
*/
|
|
192
|
+
hoverSpin?: boolean | HoverSpinConfig;
|
|
193
|
+
}
|
|
194
|
+
interface HoverSpinConfig {
|
|
195
|
+
/**
|
|
196
|
+
* 旋转的加速度
|
|
197
|
+
* @default 180
|
|
198
|
+
*/
|
|
199
|
+
accel?: number;
|
|
200
|
+
/**
|
|
201
|
+
* 旋转的最大角速度
|
|
202
|
+
* @default 2160
|
|
203
|
+
*/
|
|
204
|
+
maxVel?: number;
|
|
205
|
+
/**
|
|
206
|
+
* 缓停时长
|
|
207
|
+
* @default 1500
|
|
208
|
+
*/
|
|
209
|
+
decelDuration?: number;
|
|
189
210
|
}
|
|
190
211
|
interface ArticleConfig {
|
|
191
212
|
/**
|
package/node.js
CHANGED
|
@@ -41,7 +41,7 @@ module.exports = __toCommonJS(node_exports);
|
|
|
41
41
|
// src/utils/node/mdPlugins.ts
|
|
42
42
|
var import_module = require("module");
|
|
43
43
|
|
|
44
|
-
// ../../node_modules/.pnpm/vitepress-plugin-tabs@0.2.0_vitepress@
|
|
44
|
+
// ../../node_modules/.pnpm/vitepress-plugin-tabs@0.2.0_vitepress@2.0.0-alpha.15_@types+node@24.5.2_async-validator_06f14e686e1fb3002156f3936c305549/node_modules/vitepress-plugin-tabs/dist/index.js
|
|
45
45
|
var tabsMarker = "=tabs";
|
|
46
46
|
var tabsMarkerLen = tabsMarker.length;
|
|
47
47
|
var ruleBlockTabs = (state, startLine, endLine, silent) => {
|
|
@@ -235,7 +235,7 @@ function getFirstImagURLFromMD(content, route) {
|
|
|
235
235
|
const paths = (0, import_theme_shared.joinPath)("/", route).split("/");
|
|
236
236
|
paths.splice(paths.length - 1, 1);
|
|
237
237
|
const relativePath = url.startsWith("/") ? url : import_node_path.default.join(paths.join("/") || "", url);
|
|
238
|
-
return (0, import_theme_shared.joinPath)("/", relativePath);
|
|
238
|
+
return (0, import_theme_shared.joinPath)("/", (0, import_theme_shared.normalizePath)(relativePath));
|
|
239
239
|
}
|
|
240
240
|
function debounce(func, delay = 1e3) {
|
|
241
241
|
let timeoutId;
|
|
@@ -549,12 +549,12 @@ function themeReloadPlugin() {
|
|
|
549
549
|
function getVitePlugins(cfg = {}) {
|
|
550
550
|
const plugins = [];
|
|
551
551
|
plugins.push(cacheAllGitTimestampsPlugin());
|
|
552
|
-
plugins.push(coverImgTransform());
|
|
553
552
|
if (cfg.themeColor) {
|
|
554
553
|
plugins.push(setThemeScript(cfg.themeColor));
|
|
555
554
|
}
|
|
556
555
|
plugins.push(themeReloadPlugin());
|
|
557
556
|
plugins.push(providePageData(cfg));
|
|
557
|
+
plugins.push(coverImgTransform());
|
|
558
558
|
if (cfg && cfg.search !== false) {
|
|
559
559
|
const ops = cfg.search instanceof Object ? cfg.search : {};
|
|
560
560
|
plugins.push(
|
|
@@ -638,13 +638,16 @@ function coverImgTransform() {
|
|
|
638
638
|
const value = v.meta[k];
|
|
639
639
|
if (value && typeof value === "string" && value.startsWith("/")) {
|
|
640
640
|
const absolutePath = `${vitepressConfig.srcDir}${value}`;
|
|
641
|
-
if (
|
|
642
|
-
Object.assign(v.meta, {
|
|
643
|
-
|
|
641
|
+
if (relativePathMap[absolutePath]) {
|
|
642
|
+
Object.assign(v.meta, {
|
|
643
|
+
[k]: relativeMetaMap[absolutePath][k]
|
|
644
|
+
});
|
|
644
645
|
}
|
|
645
646
|
relativePathMap[value] = absolutePath;
|
|
646
647
|
relativePathMap[absolutePath] = value;
|
|
647
|
-
relativeMeta.
|
|
648
|
+
if (!relativeMeta.includes(v.meta)) {
|
|
649
|
+
relativeMeta.push(v.meta);
|
|
650
|
+
}
|
|
648
651
|
relativeMetaMap[absolutePath] = v.meta;
|
|
649
652
|
}
|
|
650
653
|
});
|
package/node.mjs
CHANGED
|
@@ -9,7 +9,7 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
9
9
|
// src/utils/node/mdPlugins.ts
|
|
10
10
|
import { createRequire } from "module";
|
|
11
11
|
|
|
12
|
-
// ../../node_modules/.pnpm/vitepress-plugin-tabs@0.2.0_vitepress@
|
|
12
|
+
// ../../node_modules/.pnpm/vitepress-plugin-tabs@0.2.0_vitepress@2.0.0-alpha.15_@types+node@24.5.2_async-validator_06f14e686e1fb3002156f3936c305549/node_modules/vitepress-plugin-tabs/dist/index.js
|
|
13
13
|
var tabsMarker = "=tabs";
|
|
14
14
|
var tabsMarkerLen = tabsMarker.length;
|
|
15
15
|
var ruleBlockTabs = (state, startLine, endLine, silent) => {
|
|
@@ -179,7 +179,7 @@ import { groupIconMdPlugin } from "vitepress-plugin-group-icons";
|
|
|
179
179
|
|
|
180
180
|
// src/utils/node/index.ts
|
|
181
181
|
import path from "node:path";
|
|
182
|
-
import { joinPath } from "@sugarat/theme-shared";
|
|
182
|
+
import { joinPath, normalizePath } from "@sugarat/theme-shared";
|
|
183
183
|
function aliasObjectToArray(obj) {
|
|
184
184
|
return Object.entries(obj).map(([find, replacement]) => ({
|
|
185
185
|
find,
|
|
@@ -203,7 +203,7 @@ function getFirstImagURLFromMD(content, route) {
|
|
|
203
203
|
const paths = joinPath("/", route).split("/");
|
|
204
204
|
paths.splice(paths.length - 1, 1);
|
|
205
205
|
const relativePath = url.startsWith("/") ? url : path.join(paths.join("/") || "", url);
|
|
206
|
-
return joinPath("/", relativePath);
|
|
206
|
+
return joinPath("/", normalizePath(relativePath));
|
|
207
207
|
}
|
|
208
208
|
function debounce(func, delay = 1e3) {
|
|
209
209
|
let timeoutId;
|
|
@@ -301,7 +301,7 @@ function patchOptimizeDeps(config) {
|
|
|
301
301
|
|
|
302
302
|
// src/utils/node/theme.ts
|
|
303
303
|
import fs from "node:fs";
|
|
304
|
-
import { getDefaultTitle, getFileLastModifyTime, getTextSummary, getVitePressPages, grayMatter, normalizePath, renderDynamicMarkdown } from "@sugarat/theme-shared";
|
|
304
|
+
import { getDefaultTitle, getFileLastModifyTime, getTextSummary, getVitePressPages, grayMatter, normalizePath as normalizePath2, renderDynamicMarkdown } from "@sugarat/theme-shared";
|
|
305
305
|
|
|
306
306
|
// src/utils/client/index.ts
|
|
307
307
|
function formatDate(d, fmt = "yyyy-MM-dd hh:mm:ss") {
|
|
@@ -517,12 +517,12 @@ function themeReloadPlugin() {
|
|
|
517
517
|
function getVitePlugins(cfg = {}) {
|
|
518
518
|
const plugins = [];
|
|
519
519
|
plugins.push(cacheAllGitTimestampsPlugin());
|
|
520
|
-
plugins.push(coverImgTransform());
|
|
521
520
|
if (cfg.themeColor) {
|
|
522
521
|
plugins.push(setThemeScript(cfg.themeColor));
|
|
523
522
|
}
|
|
524
523
|
plugins.push(themeReloadPlugin());
|
|
525
524
|
plugins.push(providePageData(cfg));
|
|
525
|
+
plugins.push(coverImgTransform());
|
|
526
526
|
if (cfg && cfg.search !== false) {
|
|
527
527
|
const ops = cfg.search instanceof Object ? cfg.search : {};
|
|
528
528
|
plugins.push(
|
|
@@ -606,13 +606,16 @@ function coverImgTransform() {
|
|
|
606
606
|
const value = v.meta[k];
|
|
607
607
|
if (value && typeof value === "string" && value.startsWith("/")) {
|
|
608
608
|
const absolutePath = `${vitepressConfig.srcDir}${value}`;
|
|
609
|
-
if (
|
|
610
|
-
Object.assign(v.meta, {
|
|
611
|
-
|
|
609
|
+
if (relativePathMap[absolutePath]) {
|
|
610
|
+
Object.assign(v.meta, {
|
|
611
|
+
[k]: relativeMetaMap[absolutePath][k]
|
|
612
|
+
});
|
|
612
613
|
}
|
|
613
614
|
relativePathMap[value] = absolutePath;
|
|
614
615
|
relativePathMap[absolutePath] = value;
|
|
615
|
-
relativeMeta.
|
|
616
|
+
if (!relativeMeta.includes(v.meta)) {
|
|
617
|
+
relativeMeta.push(v.meta);
|
|
618
|
+
}
|
|
616
619
|
relativeMetaMap[absolutePath] = v.meta;
|
|
617
620
|
}
|
|
618
621
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sugarat/theme",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.9",
|
|
4
4
|
"description": "简约风的 Vitepress 博客主题,sugarat vitepress blog theme",
|
|
5
5
|
"author": "sugar",
|
|
6
6
|
"license": "MIT",
|
|
@@ -53,10 +53,10 @@
|
|
|
53
53
|
"vitepress-plugin-group-icons": "1.2.4",
|
|
54
54
|
"vitepress-plugin-mermaid": "2.0.13",
|
|
55
55
|
"vitepress-plugin-tabs": "0.2.0",
|
|
56
|
-
"
|
|
56
|
+
"@sugarat/theme-shared": "0.0.6",
|
|
57
|
+
"vitepress-plugin-rss": "0.3.4",
|
|
57
58
|
"vitepress-plugin-announcement": "0.1.5",
|
|
58
|
-
"vitepress-plugin-
|
|
59
|
-
"@sugarat/theme-shared": "0.0.6"
|
|
59
|
+
"vitepress-plugin-pagefind": "0.4.16"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@element-plus/icons-vue": "^2.3.1",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"sass": "^1.80.6",
|
|
67
67
|
"typescript": "^5.4.5",
|
|
68
68
|
"vite": "^5.4.9",
|
|
69
|
-
"vitepress": "
|
|
69
|
+
"vitepress": "2.0.0-alpha.15",
|
|
70
70
|
"vue": "^3.5.12",
|
|
71
71
|
"vitepress-plugin-51la": "0.1.0"
|
|
72
72
|
},
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { useData, withBase } from 'vitepress'
|
|
3
|
-
import { computed } from 'vue'
|
|
4
|
-
import {
|
|
3
|
+
import { computed, ref } from 'vue'
|
|
4
|
+
import { useGlobalAuthor, useHomeConfig } from '../composables/config/blog'
|
|
5
|
+
import { useHoverSpin } from '../hooks/useHoverSpin'
|
|
5
6
|
|
|
6
7
|
const home = useHomeConfig()
|
|
7
8
|
const { frontmatter, site } = useData()
|
|
@@ -20,11 +21,15 @@ const logo = computed(() =>
|
|
|
20
21
|
?? '/logo.png'
|
|
21
22
|
)
|
|
22
23
|
const show = computed(() => author.value || logo.value)
|
|
24
|
+
|
|
25
|
+
const imgRef = ref(null)
|
|
26
|
+
|
|
27
|
+
useHoverSpin(imgRef, home?.value?.hoverSpin)
|
|
23
28
|
</script>
|
|
24
29
|
|
|
25
30
|
<template>
|
|
26
31
|
<div v-if="show" class="blog-author">
|
|
27
|
-
<img v-if="logo" :src="withBase(logo)" alt="avatar">
|
|
32
|
+
<img v-if="logo" ref="imgRef" :src="withBase(logo)" alt="avatar">
|
|
28
33
|
<p v-if="author">
|
|
29
34
|
{{ author }}
|
|
30
35
|
</p>
|
|
@@ -42,12 +47,7 @@ const show = computed(() => author.value || logo.value)
|
|
|
42
47
|
height: 100px;
|
|
43
48
|
border-radius: 50%;
|
|
44
49
|
background-color: rgba(var(--bg-gradient-home));
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
img:hover {
|
|
48
|
-
transform: rotate(666turn);
|
|
49
|
-
transition-duration: 59s;
|
|
50
|
-
transition-timing-function: cubic-bezier(.34, 0, .84, 1)
|
|
50
|
+
cursor: pointer;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
p {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { useData, withBase } from 'vitepress'
|
|
3
|
-
import { computed } from 'vue'
|
|
3
|
+
import { computed, ref } from 'vue'
|
|
4
4
|
import { useHomeConfig } from '../composables/config/blog'
|
|
5
|
+
import { useHoverSpin } from '../hooks/useHoverSpin'
|
|
5
6
|
|
|
6
7
|
const home = useHomeConfig()
|
|
7
8
|
const { frontmatter, site } = useData()
|
|
@@ -13,11 +14,14 @@ const logo = computed(() =>
|
|
|
13
14
|
?? '/logo.png'
|
|
14
15
|
)
|
|
15
16
|
const alwaysHide = computed(() => frontmatter.value.blog?.minScreenAvatar === false)
|
|
17
|
+
|
|
18
|
+
const imgRef = ref(null)
|
|
19
|
+
useHoverSpin(imgRef, home?.value?.hoverSpin)
|
|
16
20
|
</script>
|
|
17
21
|
|
|
18
22
|
<template>
|
|
19
23
|
<div v-show="!alwaysHide" class="blog-home-header-avatar">
|
|
20
|
-
<img :src="withBase(logo)" alt="avatar">
|
|
24
|
+
<img ref="imgRef" :src="withBase(logo)" alt="avatar">
|
|
21
25
|
</div>
|
|
22
26
|
</template>
|
|
23
27
|
|
|
@@ -36,13 +40,14 @@ const alwaysHide = computed(() => frontmatter.value.blog?.minScreenAvatar === fa
|
|
|
36
40
|
background-color: transparent;
|
|
37
41
|
border: 5px solid rgba(var(--bg-gradient-home));
|
|
38
42
|
box-sizing: border-box;
|
|
43
|
+
cursor: pointer;
|
|
39
44
|
}
|
|
40
45
|
|
|
41
|
-
img:hover {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
+
// img:hover {
|
|
47
|
+
// transform: rotate(666turn);
|
|
48
|
+
// transition-duration: 59s;
|
|
49
|
+
// transition-timing-function: cubic-bezier(.34, 0, .84, 1)
|
|
50
|
+
// }
|
|
46
51
|
}
|
|
47
52
|
|
|
48
53
|
@media screen and (min-width: 768px) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed, watch } from 'vue'
|
|
2
|
+
import { computed, nextTick, watch } from 'vue'
|
|
3
3
|
import { ElPagination } from 'element-plus'
|
|
4
4
|
import { useData, useRoute, useRouter } from 'vitepress'
|
|
5
5
|
import {
|
|
@@ -70,7 +70,6 @@ function handleUpdatePageNum(current: number) {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
const route = useRoute()
|
|
73
|
-
|
|
74
73
|
function refreshCurrentPage() {
|
|
75
74
|
if (typeof window === 'undefined')
|
|
76
75
|
return
|
|
@@ -78,7 +77,9 @@ function refreshCurrentPage() {
|
|
|
78
77
|
const searchParams = new URLSearchParams(search)
|
|
79
78
|
const pageNum = Number(searchParams.get(queryPageNumKey)) || 1
|
|
80
79
|
if (pageNum !== currentPage.value) {
|
|
81
|
-
|
|
80
|
+
nextTick(() => {
|
|
81
|
+
currentPage.value = pageNum
|
|
82
|
+
})
|
|
82
83
|
}
|
|
83
84
|
}
|
|
84
85
|
watch(route, () => {
|
|
@@ -86,7 +87,7 @@ watch(route, () => {
|
|
|
86
87
|
}, { immediate: true })
|
|
87
88
|
|
|
88
89
|
// 未覆盖的场景处理 左上回到首页
|
|
89
|
-
router.
|
|
90
|
+
router.onAfterRouteChange = () => {
|
|
90
91
|
refreshCurrentPage()
|
|
91
92
|
}
|
|
92
93
|
</script>
|
|
@@ -191,6 +191,28 @@ export namespace Theme {
|
|
|
191
191
|
* @default false
|
|
192
192
|
*/
|
|
193
193
|
blogInfoCollapsible?: boolean
|
|
194
|
+
/**
|
|
195
|
+
* 旋转的配置
|
|
196
|
+
*/
|
|
197
|
+
hoverSpin?: boolean | HoverSpinConfig
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export interface HoverSpinConfig {
|
|
201
|
+
/**
|
|
202
|
+
* 旋转的加速度
|
|
203
|
+
* @default 180
|
|
204
|
+
*/
|
|
205
|
+
accel?: number
|
|
206
|
+
/**
|
|
207
|
+
* 旋转的最大角速度
|
|
208
|
+
* @default 2160
|
|
209
|
+
*/
|
|
210
|
+
maxVel?: number
|
|
211
|
+
/**
|
|
212
|
+
* 缓停时长
|
|
213
|
+
* @default 1500
|
|
214
|
+
*/
|
|
215
|
+
decelDuration?: number
|
|
194
216
|
}
|
|
195
217
|
|
|
196
218
|
export interface ArticleConfig {
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { type Ref, onMounted, onUnmounted } from 'vue'
|
|
2
|
+
import type { Theme } from '../composables/config/index'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 元素悬停旋转
|
|
6
|
+
* @param elRef 元素引用
|
|
7
|
+
* @param accel 加速度
|
|
8
|
+
* @param maxVel 最大角速度
|
|
9
|
+
* @param decelDuration 缓停时长
|
|
10
|
+
*/
|
|
11
|
+
export function useHoverSpin(elRef: Ref<HTMLElement | null>, hoverSpinConfig?: Theme.HoverSpinConfig | boolean) {
|
|
12
|
+
const { accel = 180, maxVel = 2160, decelDuration = 1500 } = hoverSpinConfig === true ? {} : hoverSpinConfig || {}
|
|
13
|
+
let rafId = 0
|
|
14
|
+
let lastTs = 0
|
|
15
|
+
let rotation = 0
|
|
16
|
+
let velocity = 0
|
|
17
|
+
let decelStart = 0
|
|
18
|
+
let decelStartRotation = 0
|
|
19
|
+
let decelTargetRotation = 0
|
|
20
|
+
let decelBias = 0
|
|
21
|
+
let isDecel = false
|
|
22
|
+
let hovering = false
|
|
23
|
+
|
|
24
|
+
function animate(ts: number) {
|
|
25
|
+
if (!lastTs)
|
|
26
|
+
lastTs = ts
|
|
27
|
+
const dt = (ts - lastTs) / 1000
|
|
28
|
+
lastTs = ts
|
|
29
|
+
|
|
30
|
+
if (hovering) {
|
|
31
|
+
isDecel = false
|
|
32
|
+
decelStart = 0
|
|
33
|
+
velocity = Math.min(velocity + accel * dt, maxVel)
|
|
34
|
+
rotation += velocity * dt
|
|
35
|
+
}
|
|
36
|
+
else if (isDecel) {
|
|
37
|
+
const t = Math.min((ts - decelStart) / decelDuration, 1)
|
|
38
|
+
const durSec = decelDuration / 1000
|
|
39
|
+
const base = velocity * durSec * (t - t * t / 2)
|
|
40
|
+
const smooth = 3 * t * t - 2 * t * t * t
|
|
41
|
+
rotation = decelStartRotation + base + decelBias * smooth
|
|
42
|
+
if (t >= 1) {
|
|
43
|
+
decelTargetRotation = 0
|
|
44
|
+
decelStartRotation = 0
|
|
45
|
+
decelBias = 0
|
|
46
|
+
rotation = decelTargetRotation
|
|
47
|
+
velocity = 0
|
|
48
|
+
isDecel = false
|
|
49
|
+
if (rafId) {
|
|
50
|
+
cancelAnimationFrame(rafId)
|
|
51
|
+
rafId = 0
|
|
52
|
+
}
|
|
53
|
+
const el2 = elRef.value as HTMLElement | null
|
|
54
|
+
if (el2)
|
|
55
|
+
el2.style.transform = `rotate(${rotation}deg)`
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const el = elRef.value as HTMLElement | null
|
|
61
|
+
if (el)
|
|
62
|
+
el.style.transform = `rotate(${rotation}deg)`
|
|
63
|
+
if (hovering || isDecel) {
|
|
64
|
+
rafId = requestAnimationFrame(animate)
|
|
65
|
+
}
|
|
66
|
+
else if (rafId) {
|
|
67
|
+
cancelAnimationFrame(rafId)
|
|
68
|
+
rafId = 0
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function onEnter() {
|
|
73
|
+
hovering = true
|
|
74
|
+
if (!rafId) {
|
|
75
|
+
lastTs = 0
|
|
76
|
+
rafId = requestAnimationFrame(animate)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function onLeave() {
|
|
81
|
+
hovering = false
|
|
82
|
+
isDecel = true
|
|
83
|
+
decelStart = performance.now()
|
|
84
|
+
decelStartRotation = rotation
|
|
85
|
+
const durSec = decelDuration / 1000
|
|
86
|
+
const S = velocity * durSec / 2
|
|
87
|
+
const minTarget = decelStartRotation + S
|
|
88
|
+
decelTargetRotation = Math.ceil(minTarget / 360) * 360
|
|
89
|
+
decelBias = (decelTargetRotation - decelStartRotation) - S
|
|
90
|
+
lastTs = 0
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
onMounted(() => {
|
|
94
|
+
if (hoverSpinConfig === false)
|
|
95
|
+
return
|
|
96
|
+
const el = elRef.value
|
|
97
|
+
if (!el)
|
|
98
|
+
return
|
|
99
|
+
el.addEventListener('mouseenter', onEnter)
|
|
100
|
+
el.addEventListener('mouseleave', onLeave)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
onUnmounted(() => {
|
|
104
|
+
if (hoverSpinConfig === false)
|
|
105
|
+
return
|
|
106
|
+
const el = elRef.value
|
|
107
|
+
if (el) {
|
|
108
|
+
el.removeEventListener('mouseenter', onEnter)
|
|
109
|
+
el.removeEventListener('mouseleave', onLeave)
|
|
110
|
+
}
|
|
111
|
+
if (rafId)
|
|
112
|
+
cancelAnimationFrame(rafId)
|
|
113
|
+
})
|
|
114
|
+
}
|
package/src/utils/node/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from 'node:path'
|
|
2
|
-
import { joinPath } from '@sugarat/theme-shared'
|
|
2
|
+
import { joinPath, normalizePath } from '@sugarat/theme-shared'
|
|
3
3
|
|
|
4
4
|
export function aliasObjectToArray(obj: Record<string, string>) {
|
|
5
5
|
return Object.entries(obj).map(([find, replacement]) => ({
|
|
@@ -34,8 +34,7 @@ export function getFirstImagURLFromMD(content: string, route: string) {
|
|
|
34
34
|
const paths = joinPath('/', route).split('/')
|
|
35
35
|
paths.splice(paths.length - 1, 1)
|
|
36
36
|
const relativePath = url.startsWith('/') ? url : path.join(paths.join('/') || '', url)
|
|
37
|
-
|
|
38
|
-
return joinPath('/', relativePath)
|
|
37
|
+
return joinPath('/', normalizePath(relativePath))
|
|
39
38
|
}
|
|
40
39
|
|
|
41
40
|
export function debounce(func: any, delay = 1000) {
|
package/src/utils/node/theme.ts
CHANGED
|
@@ -18,9 +18,6 @@ export function getVitePlugins(cfg: Partial<Theme.BlogConfig> = {}) {
|
|
|
18
18
|
// 缓存所有文章的 git 提交时间
|
|
19
19
|
plugins.push(cacheAllGitTimestampsPlugin())
|
|
20
20
|
|
|
21
|
-
// 处理 cover image 的路径(暂只支持自动识别的文章首图)
|
|
22
|
-
plugins.push(coverImgTransform())
|
|
23
|
-
|
|
24
21
|
// 处理自定义主题色
|
|
25
22
|
if (cfg.themeColor) {
|
|
26
23
|
plugins.push(setThemeScript(cfg.themeColor))
|
|
@@ -31,6 +28,8 @@ export function getVitePlugins(cfg: Partial<Theme.BlogConfig> = {}) {
|
|
|
31
28
|
// 主题 pageData生成
|
|
32
29
|
plugins.push(providePageData(cfg))
|
|
33
30
|
|
|
31
|
+
// 处理 cover image 的路径(暂只支持自动识别的文章首图)
|
|
32
|
+
plugins.push(coverImgTransform())
|
|
34
33
|
// 内置 pagefind
|
|
35
34
|
if (cfg && cfg.search !== false) {
|
|
36
35
|
const ops = cfg.search instanceof Object ? cfg.search : {}
|
|
@@ -165,15 +164,18 @@ export function coverImgTransform() {
|
|
|
165
164
|
if (value && typeof value === 'string' && value.startsWith('/')) {
|
|
166
165
|
const absolutePath = `${vitepressConfig.srcDir}${value}`
|
|
167
166
|
|
|
168
|
-
//
|
|
169
|
-
if (
|
|
170
|
-
Object.assign(v.meta, {
|
|
171
|
-
|
|
167
|
+
// 已经映射后的值
|
|
168
|
+
if (relativePathMap[absolutePath]) {
|
|
169
|
+
Object.assign(v.meta, {
|
|
170
|
+
[k]: relativeMetaMap[absolutePath][k]
|
|
171
|
+
})
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
relativePathMap[value] = absolutePath
|
|
175
175
|
relativePathMap[absolutePath] = value
|
|
176
|
-
relativeMeta.
|
|
176
|
+
if (!relativeMeta.includes(v.meta)) {
|
|
177
|
+
relativeMeta.push(v.meta)
|
|
178
|
+
}
|
|
177
179
|
relativeMetaMap[absolutePath] = v.meta
|
|
178
180
|
}
|
|
179
181
|
})
|