valaxy 0.18.9 → 0.19.1
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/client/App.vue +1 -10
- package/client/components/ValaxyMd.vue +1 -1
- package/client/components/builtin/ValaxyMermaid.vue +4 -3
- package/client/composables/aside.ts +12 -5
- package/client/composables/dark.ts +77 -38
- package/client/composables/layout.ts +10 -2
- package/client/composables/sidebar.ts +41 -2
- package/client/locales/zh-CN.yml +1 -1
- package/client/main.ts +12 -10
- package/client/setup/main.ts +0 -2
- package/client/shims.d.ts +3 -0
- package/client/stores/app.ts +20 -4
- package/client/styles/css/css-vars.css +19 -0
- package/client/styles/{global/index.scss → css/main.css} +1 -1
- package/client/styles/css-vars.scss +1 -1
- package/client/styles/index.scss +0 -1
- package/client/styles/palette.scss +0 -18
- package/client/utils/router.ts +48 -0
- package/dist/chunk-O2T7UBQW.cjs +156 -0
- package/dist/chunk-W2X2FWTK.mjs +157 -0
- package/dist/{config-Kdq8Mya1.d.cts → config-Bz-Xbvue.d.cts} +102 -26
- package/dist/{config-Kdq8Mya1.d.ts → config-Bz-Xbvue.d.ts} +102 -26
- package/dist/node/cli/index.cjs +1 -1
- package/dist/node/cli/index.mjs +1 -1
- package/dist/node/index.cjs +1 -1
- package/dist/node/index.d.cts +2 -1
- package/dist/node/index.d.ts +2 -1
- package/dist/node/index.mjs +1 -1
- package/dist/types/index.cjs +1 -1
- package/dist/types/index.d.cts +7 -3
- package/dist/types/index.d.ts +7 -3
- package/dist/types/index.mjs +1 -1
- package/package.json +20 -18
- package/types/config.ts +5 -1
- package/types/default-theme.ts +38 -0
- package/types/frontmatter/index.ts +2 -0
- package/types/frontmatter/page.ts +191 -0
- package/types/frontmatter/post.ts +103 -0
- package/types/index.ts +1 -0
- package/types/posts.ts +1 -253
- package/dist/chunk-4B74DZJ5.cjs +0 -149
- package/dist/chunk-F2X3NOEJ.mjs +0 -150
- /package/dist/{chunk-42NDXDT3.mjs → chunk-7VTZAWDO.mjs} +0 -0
- /package/dist/{chunk-YO6XYYV3.cjs → chunk-I6UPHJXQ.cjs} +0 -0
package/client/App.vue
CHANGED
|
@@ -16,14 +16,13 @@ import { definePerson, defineWebPage, defineWebSite, useSchemaOrg } from '@unhea
|
|
|
16
16
|
// they will be rendered correctly in the html results with vite-ssg
|
|
17
17
|
import { useSiteConfig } from './config'
|
|
18
18
|
import ValaxyAddons from './components/ValaxyAddons.vue'
|
|
19
|
-
import {
|
|
19
|
+
import { useFrontmatter } from './composables'
|
|
20
20
|
|
|
21
21
|
// <link rel="apple-touch-icon" href="/pwa-192x192.png">
|
|
22
22
|
// <link rel="mask-icon" href="/safari-pinned-tab.svg" color="#00aba9">
|
|
23
23
|
|
|
24
24
|
const siteConfig = useSiteConfig()
|
|
25
25
|
// todo, allow user config
|
|
26
|
-
const themeColor = computed(() => isDark.value ? '#000' : '#ffffff')
|
|
27
26
|
const fm = useFrontmatter()
|
|
28
27
|
|
|
29
28
|
const { locale } = useI18n()
|
|
@@ -41,14 +40,6 @@ useHead({
|
|
|
41
40
|
],
|
|
42
41
|
meta: [
|
|
43
42
|
{ name: 'description', content: computed(() => siteConfig.value.description) },
|
|
44
|
-
{
|
|
45
|
-
name: 'theme-color',
|
|
46
|
-
content: themeColor,
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
name: 'msapplication-TileColor',
|
|
50
|
-
content: themeColor,
|
|
51
|
-
},
|
|
52
43
|
{
|
|
53
44
|
name: 'generator',
|
|
54
45
|
content: `Valaxy ${pkg.version}`,
|
|
@@ -44,7 +44,7 @@ useVanillaLazyLoad()
|
|
|
44
44
|
</script>
|
|
45
45
|
|
|
46
46
|
<template>
|
|
47
|
-
<article v-if="$slots.default" :class="frontmatter.
|
|
47
|
+
<article v-if="$slots.default" :class="frontmatter.markdownClass || 'markdown-body'">
|
|
48
48
|
<slot ref="contentRef" @vue:updated="runContentUpdated" />
|
|
49
49
|
|
|
50
50
|
<div v-if="frontmatter.url" text="center">
|
|
@@ -16,11 +16,10 @@ pie
|
|
|
16
16
|
import { getCurrentInstance, ref, watch, watchEffect } from 'vue'
|
|
17
17
|
|
|
18
18
|
import { isClient } from '@vueuse/core'
|
|
19
|
+
import { useAppStore } from 'valaxy'
|
|
19
20
|
import { renderMermaid } from '../../modules/mermaid'
|
|
20
21
|
import ShadowRoot from '../internals/ShadowRoot.vue'
|
|
21
22
|
|
|
22
|
-
import { isDark } from '../../composables'
|
|
23
|
-
|
|
24
23
|
const props = defineProps<{
|
|
25
24
|
code: string
|
|
26
25
|
scale?: number
|
|
@@ -31,6 +30,8 @@ const vm = getCurrentInstance()
|
|
|
31
30
|
const el = ref<ShadowRoot>()
|
|
32
31
|
const html = ref('')
|
|
33
32
|
|
|
33
|
+
const appStore = useAppStore()
|
|
34
|
+
|
|
34
35
|
if (isClient) {
|
|
35
36
|
// dynamic import to reduce initial bundle size
|
|
36
37
|
import('mermaid').then(m => m.default)
|
|
@@ -47,7 +48,7 @@ if (isClient) {
|
|
|
47
48
|
mermaid,
|
|
48
49
|
props.code || '',
|
|
49
50
|
{
|
|
50
|
-
theme: props.theme || (isDark
|
|
51
|
+
theme: props.theme || (appStore.isDark ? 'dark' : undefined),
|
|
51
52
|
...vm!.attrs,
|
|
52
53
|
},
|
|
53
54
|
)
|
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useMediaQuery } from '@vueuse/core'
|
|
2
|
+
import { useSidebar } from 'valaxy'
|
|
3
|
+
import { computed } from 'vue'
|
|
2
4
|
|
|
3
5
|
export function useAside() {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
const { hasSidebar } = useSidebar()
|
|
7
|
+
const is960 = useMediaQuery('(min-width: 960px)')
|
|
8
|
+
const is1280 = useMediaQuery('(min-width: 1280px)')
|
|
7
9
|
|
|
8
|
-
const isAsideEnabled =
|
|
10
|
+
const isAsideEnabled = computed(() => {
|
|
11
|
+
if (!is1280.value && !is960.value)
|
|
12
|
+
return false
|
|
13
|
+
|
|
14
|
+
return hasSidebar.value ? is1280.value : is960.value
|
|
15
|
+
})
|
|
9
16
|
|
|
10
17
|
return {
|
|
11
18
|
isAsideEnabled,
|
|
@@ -1,44 +1,83 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { UseDarkOptions } from '@vueuse/core'
|
|
2
|
+
import { useDark, useToggle } from '@vueuse/core'
|
|
3
|
+
import { computed } from 'vue'
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
+
export function useValaxyDark(options: {
|
|
6
|
+
/**
|
|
7
|
+
* Options for `useDark`
|
|
8
|
+
* disableTransition default is `true`
|
|
9
|
+
* @see https://vueuse.org/core/useDark
|
|
10
|
+
* @url https://paco.me/writing/disable-theme-transitions
|
|
11
|
+
*/
|
|
12
|
+
useDarkOptions?: UseDarkOptions
|
|
13
|
+
/**
|
|
14
|
+
* Enable circle transition when toggling dark mode
|
|
15
|
+
* Then use `toggleDarkWithTransition` instead of `toggleDark`
|
|
16
|
+
*/
|
|
17
|
+
circleTransition?: boolean
|
|
5
18
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export function toggleDarkWithTransition(event: MouseEvent, options: { duration?: number, easing?: EffectTiming['easing'] } = {}) {
|
|
10
|
-
// @ts-expect-error startViewTransition is not defined
|
|
11
|
-
if (!document.startViewTransition) {
|
|
12
|
-
toggleDark()
|
|
13
|
-
return
|
|
19
|
+
themeColor?: {
|
|
20
|
+
light?: string
|
|
21
|
+
dark?: string
|
|
14
22
|
}
|
|
23
|
+
} = {}) {
|
|
24
|
+
const isDark = useDark(options.useDarkOptions)
|
|
25
|
+
const toggleDark = useToggle(isDark)
|
|
26
|
+
|
|
27
|
+
const themeColor = computed(() => isDark.value
|
|
28
|
+
? (options.themeColor?.dark || '#000')
|
|
29
|
+
: (options.themeColor?.light || '#fff'))
|
|
30
|
+
|
|
31
|
+
if (options.circleTransition)
|
|
32
|
+
import('valaxy/client/styles/common/view-transition.css')
|
|
15
33
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
transition.ready.then(() => {
|
|
29
|
-
const clipPath = [
|
|
30
|
-
`circle(0px at ${x}px ${y}px)`,
|
|
31
|
-
`circle(${endRadius}px at ${x}px ${y}px)`,
|
|
32
|
-
]
|
|
33
|
-
document.documentElement.animate(
|
|
34
|
-
{
|
|
35
|
-
clipPath: isDark.value ? clipPath.reverse() : clipPath,
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
duration: options.duration || 300,
|
|
39
|
-
easing: options.easing || 'ease-in',
|
|
40
|
-
pseudoElement: isDark.value ? '::view-transition-old(root)' : '::view-transition-new(root)',
|
|
41
|
-
},
|
|
34
|
+
function toggleDarkWithTransition(event: MouseEvent, options: { duration?: number, easing?: EffectTiming['easing'] } = {}) {
|
|
35
|
+
// @ts-expect-error startViewTransition is not defined
|
|
36
|
+
if (!document.startViewTransition) {
|
|
37
|
+
toggleDark()
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const x = event.clientX
|
|
42
|
+
const y = event.clientY
|
|
43
|
+
const endRadius = Math.hypot(
|
|
44
|
+
Math.max(x, innerWidth - x),
|
|
45
|
+
Math.max(y, innerHeight - y),
|
|
42
46
|
)
|
|
43
|
-
|
|
47
|
+
|
|
48
|
+
// @ts-expect-error startViewTransition is not defined
|
|
49
|
+
const transition = document.startViewTransition(() => {
|
|
50
|
+
toggleDark()
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
transition.ready.then(() => {
|
|
54
|
+
const clipPath = [
|
|
55
|
+
`circle(0px at ${x}px ${y}px)`,
|
|
56
|
+
`circle(${endRadius}px at ${x}px ${y}px)`,
|
|
57
|
+
]
|
|
58
|
+
document.documentElement.animate(
|
|
59
|
+
{
|
|
60
|
+
clipPath: isDark.value ? clipPath.reverse() : clipPath,
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
duration: options.duration || 300,
|
|
64
|
+
easing: options.easing || 'ease-in',
|
|
65
|
+
pseudoElement: isDark.value ? '::view-transition-old(root)' : '::view-transition-new(root)',
|
|
66
|
+
},
|
|
67
|
+
)
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
/**
|
|
73
|
+
* Dark mode state, sync with app store
|
|
74
|
+
*
|
|
75
|
+
* You can also use `const appStore = useAppStore(); appStore.isDark` to get the value
|
|
76
|
+
*/
|
|
77
|
+
isDark,
|
|
78
|
+
themeColor,
|
|
79
|
+
|
|
80
|
+
toggleDark,
|
|
81
|
+
toggleDarkWithTransition,
|
|
82
|
+
}
|
|
44
83
|
}
|
|
@@ -1,10 +1,18 @@
|
|
|
1
|
+
import { useMediaQuery } from '@vueuse/core'
|
|
1
2
|
import { computed } from 'vue'
|
|
2
3
|
import { useRoute } from 'vue-router'
|
|
3
4
|
|
|
4
5
|
export function useLayout(layout?: string) {
|
|
5
6
|
const route = useRoute()
|
|
6
7
|
if (layout)
|
|
7
|
-
return computed(() => route.meta
|
|
8
|
+
return computed(() => route.meta?.layout === layout)
|
|
8
9
|
else
|
|
9
|
-
return computed(() => route.meta
|
|
10
|
+
return computed(() => route.meta?.layout)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* is mobile media query
|
|
15
|
+
*/
|
|
16
|
+
export function useMobile() {
|
|
17
|
+
return useMediaQuery('(max-width: 768px)')
|
|
10
18
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { computed, ref } from 'vue'
|
|
1
|
+
import { computed, ref, watchEffect } from 'vue'
|
|
2
2
|
import { useFrontmatter } from './common'
|
|
3
|
-
import { useLayout } from './layout'
|
|
3
|
+
import { useLayout, useMobile } from './layout'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* helper for sidebar
|
|
@@ -9,6 +9,7 @@ export function useSidebar() {
|
|
|
9
9
|
const isOpen = ref(false)
|
|
10
10
|
const fm = useFrontmatter()
|
|
11
11
|
const layout = useLayout()
|
|
12
|
+
|
|
12
13
|
const hasSidebar = computed(() => {
|
|
13
14
|
return (
|
|
14
15
|
fm.value.sidebar !== false
|
|
@@ -36,3 +37,41 @@ export function useSidebar() {
|
|
|
36
37
|
toggle,
|
|
37
38
|
}
|
|
38
39
|
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* dynamic left sidebar logic
|
|
43
|
+
* - sidebar is hidden by default when home or mobile
|
|
44
|
+
* - sidebar is shown by default when not home and not mobile
|
|
45
|
+
* - sidebar can be toggled by user
|
|
46
|
+
*/
|
|
47
|
+
export function useDynamicLeftSidebar() {
|
|
48
|
+
const layout = useLayout()
|
|
49
|
+
const isMobile = useMobile()
|
|
50
|
+
const isOpen = ref(isMobile.value ? false : layout.value !== 'home')
|
|
51
|
+
|
|
52
|
+
watchEffect(() => {
|
|
53
|
+
if (isMobile.value)
|
|
54
|
+
close()
|
|
55
|
+
else if (layout.value !== 'home')
|
|
56
|
+
open()
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
function open() {
|
|
60
|
+
isOpen.value = true
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function close() {
|
|
64
|
+
isOpen.value = false
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function toggle() {
|
|
68
|
+
isOpen.value ? close() : open()
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
isOpen,
|
|
73
|
+
open,
|
|
74
|
+
close,
|
|
75
|
+
toggle,
|
|
76
|
+
}
|
|
77
|
+
}
|
package/client/locales/zh-CN.yml
CHANGED
package/client/main.ts
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
// reset styles, load css before app
|
|
2
|
+
// import '@unocss/reset/tailwind.css'
|
|
3
|
+
// https://unocss.dev/guide/style-reset#tailwind-compat
|
|
4
|
+
// minus the background color override for buttons to avoid conflicts with UI frameworks
|
|
5
|
+
import '@unocss/reset/tailwind-compat.css'
|
|
6
|
+
// css
|
|
7
|
+
import './styles/css/css-vars.css'
|
|
8
|
+
import './styles/css/main.css'
|
|
9
|
+
// generate user styles
|
|
10
|
+
import '/@valaxyjs/styles'
|
|
11
|
+
import 'uno.css'
|
|
12
|
+
|
|
1
13
|
import type { ViteSSGContext } from 'vite-ssg'
|
|
2
14
|
import { ViteSSG } from 'vite-ssg'
|
|
3
15
|
|
|
@@ -9,16 +21,6 @@ import AppLink from './components/AppLink.vue'
|
|
|
9
21
|
|
|
10
22
|
import App from './App.vue'
|
|
11
23
|
|
|
12
|
-
// reset styles
|
|
13
|
-
// import '@unocss/reset/tailwind.css'
|
|
14
|
-
// https://unocss.dev/guide/style-reset#tailwind-compat
|
|
15
|
-
// minus the background color override for buttons to avoid conflicts with UI frameworks
|
|
16
|
-
import '@unocss/reset/tailwind-compat.css'
|
|
17
|
-
|
|
18
|
-
// generate user styles
|
|
19
|
-
import '/@valaxyjs/styles'
|
|
20
|
-
import 'uno.css'
|
|
21
|
-
|
|
22
24
|
import setupMain from './setup/main'
|
|
23
25
|
import { setupValaxyDevTools } from './utils/dev'
|
|
24
26
|
|
package/client/setup/main.ts
CHANGED
package/client/stores/app.ts
CHANGED
|
@@ -1,19 +1,35 @@
|
|
|
1
1
|
import { acceptHMRUpdate, defineStore } from 'pinia'
|
|
2
2
|
import { useToggle } from '@vueuse/core'
|
|
3
3
|
import { ref } from 'vue'
|
|
4
|
+
import { useMobile, useThemeConfig, useValaxyDark } from 'valaxy'
|
|
4
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Global store for users
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { useAppStore } from 'valaxy'
|
|
11
|
+
* const appStore = useAppStore()
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
5
14
|
export const useAppStore = defineStore('app', () => {
|
|
15
|
+
const themeConfig = useThemeConfig()
|
|
16
|
+
const { isDark, toggleDark, toggleDarkWithTransition, themeColor } = useValaxyDark(themeConfig.value.valaxyDarkOptions)
|
|
17
|
+
|
|
18
|
+
const isMobile = useMobile()
|
|
6
19
|
const showLoading = ref(true)
|
|
7
20
|
|
|
8
|
-
const [isSidebarOpen, toggleSidebar] = useToggle(false)
|
|
9
21
|
// right sidebar with toc
|
|
10
22
|
const [isRightSidebarOpen, toggleRightSidebar] = useToggle(false)
|
|
11
23
|
|
|
12
24
|
return {
|
|
13
|
-
|
|
25
|
+
isMobile,
|
|
26
|
+
// for dark
|
|
27
|
+
isDark,
|
|
28
|
+
themeColor,
|
|
29
|
+
toggleDark,
|
|
30
|
+
toggleDarkWithTransition,
|
|
14
31
|
|
|
15
|
-
|
|
16
|
-
toggleSidebar,
|
|
32
|
+
showLoading,
|
|
17
33
|
|
|
18
34
|
isRightSidebarOpen,
|
|
19
35
|
toggleRightSidebar,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--va-c-bg: #ffffff;
|
|
3
|
+
--va-c-bg-light: #ffffff;
|
|
4
|
+
--va-c-bg-dark: #fafafa;
|
|
5
|
+
--va-c-bg-opacity: rgba(255, 255, 255, 0.8);
|
|
6
|
+
--va-c-bg-soft: #f9f9f9;
|
|
7
|
+
--va-c-bg-alt: #f9f9f9;
|
|
8
|
+
--va-c-bg-mute: #f1f1f1;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
html.dark {
|
|
12
|
+
--va-c-bg: #1b1b1f;
|
|
13
|
+
--va-c-bg-light: #202127;
|
|
14
|
+
--va-c-bg-dark: #1a1a1a;
|
|
15
|
+
--va-c-bg-opacity: rgba(0, 0, 0, 0.8);
|
|
16
|
+
--va-c-bg-alt: #161618;
|
|
17
|
+
--va-c-bg-soft: #202127;
|
|
18
|
+
--va-c-bg-mute: #2f2f2f;
|
|
19
|
+
}
|
package/client/styles/index.scss
CHANGED
|
@@ -46,15 +46,6 @@ $light: map.merge(
|
|
|
46
46
|
|
|
47
47
|
"border-color": #222,
|
|
48
48
|
|
|
49
|
-
"c-bg": white,
|
|
50
|
-
"c-bg-light": white,
|
|
51
|
-
"c-bg-dark": #fafafa,
|
|
52
|
-
"c-bg-opacity": rgba(255, 255, 255 , 0.8),
|
|
53
|
-
|
|
54
|
-
"c-bg-soft": #f9f9f9,
|
|
55
|
-
"c-bg-alt": #f9f9f9,
|
|
56
|
-
"c-bg-mute": #f1f1f1,
|
|
57
|
-
|
|
58
49
|
"c-text": #333,
|
|
59
50
|
"c-text-light": #555,
|
|
60
51
|
"c-text-lighter": #666,
|
|
@@ -71,15 +62,6 @@ $dark: map.merge(
|
|
|
71
62
|
(
|
|
72
63
|
"border-color": #e6e6e6,
|
|
73
64
|
|
|
74
|
-
"c-bg": #1b1b1f,
|
|
75
|
-
"c-bg-light": #202127,
|
|
76
|
-
"c-bg-dark": #1a1a1a,
|
|
77
|
-
"c-bg-opacity": rgba(0, 0, 0, 0.8),
|
|
78
|
-
|
|
79
|
-
"c-bg-alt": #161618,
|
|
80
|
-
"c-bg-soft": #202127,
|
|
81
|
-
"c-bg-mute": #2f2f2f,
|
|
82
|
-
|
|
83
65
|
"c-text": #f2f2f2,
|
|
84
66
|
"c-text-light": #ddd,
|
|
85
67
|
"c-text-lighter": #eee,
|
package/client/utils/router.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { Router } from 'vue-router'
|
|
2
|
+
|
|
1
3
|
export interface ScrollToOptions {
|
|
2
4
|
/**
|
|
3
5
|
* 平滑滚动
|
|
@@ -43,3 +45,49 @@ export function scrollTo(el: HTMLElement, hash: string, options: Partial<ScrollT
|
|
|
43
45
|
}
|
|
44
46
|
}
|
|
45
47
|
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @description Intercept click events and handle offset positions for jump links on the same page
|
|
51
|
+
* @description:zh-CN 拦截点击事件,处理同一页面下跳转链接的偏移位置
|
|
52
|
+
* @param router Vue Router
|
|
53
|
+
*/
|
|
54
|
+
export function onClickHref(router: Router) {
|
|
55
|
+
// to extract
|
|
56
|
+
// click title scroll
|
|
57
|
+
window.addEventListener(
|
|
58
|
+
'click',
|
|
59
|
+
async (e) => {
|
|
60
|
+
const link = (e.target as Element).closest('a')
|
|
61
|
+
if (link) {
|
|
62
|
+
const { protocol, hostname, pathname, hash, target } = link
|
|
63
|
+
const currentUrl = window.location
|
|
64
|
+
const extMatch = pathname.match(/\.\w+$/)
|
|
65
|
+
// only intercept inbound links
|
|
66
|
+
if (
|
|
67
|
+
!e.ctrlKey
|
|
68
|
+
&& !e.shiftKey
|
|
69
|
+
&& !e.altKey
|
|
70
|
+
&& !e.metaKey
|
|
71
|
+
&& target !== '_blank'
|
|
72
|
+
&& protocol === currentUrl.protocol
|
|
73
|
+
&& hostname === currentUrl.hostname
|
|
74
|
+
&& !(extMatch && extMatch[0] !== '.html')
|
|
75
|
+
) {
|
|
76
|
+
if (pathname === currentUrl.pathname) {
|
|
77
|
+
e.preventDefault()
|
|
78
|
+
// scroll between hash anchors in the same page
|
|
79
|
+
if (hash && hash !== currentUrl.hash) {
|
|
80
|
+
await router.push({ hash: decodeURIComponent(hash) })
|
|
81
|
+
|
|
82
|
+
// use smooth scroll when clicking on header anchor links
|
|
83
|
+
scrollTo(link, hash, {
|
|
84
|
+
smooth: link.classList.contains('header-anchor'),
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
{ capture: true },
|
|
92
|
+
)
|
|
93
|
+
}
|