valaxy 0.19.1 → 0.19.3
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 -95
- package/client/components/ValaxyApp.vue +98 -0
- package/client/composables/categories.ts +12 -1
- package/client/composables/outline/headers.ts +8 -100
- package/client/composables/tags.ts +9 -0
- package/client/index.ts +3 -0
- package/client/locales/en.yml +2 -2
- package/client/main.ts +1 -0
- package/client/setup/mermaid.ts +7 -0
- package/client/setups.ts +15 -0
- package/client/types/index.ts +3 -0
- package/client/utils/router.ts +18 -0
- package/client/utils/time.ts +8 -0
- package/dist/{chunk-I6UPHJXQ.cjs → chunk-AFNVTV2C.cjs} +1 -1
- package/dist/chunk-HR5LED6E.cjs +156 -0
- package/dist/chunk-YCKEDOLI.mjs +157 -0
- package/dist/{config-Bz-Xbvue.d.cts → config-BuLv3zWm.d.cts} +0 -7
- package/dist/{config-Bz-Xbvue.d.ts → config-BuLv3zWm.d.ts} +0 -7
- 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 +3 -3
- package/dist/node/index.d.ts +3 -3
- package/dist/node/index.mjs +1 -1
- package/dist/types/index.cjs +1 -1
- package/dist/types/index.d.cts +4 -31
- package/dist/types/index.d.ts +4 -31
- package/dist/types/index.mjs +1 -1
- package/package.json +14 -14
- package/shims.d.ts +1 -1
- package/types/config.ts +0 -7
- package/types/data.ts +1 -28
- package/dist/chunk-O2T7UBQW.cjs +0 -156
- package/dist/chunk-W2X2FWTK.mjs +0 -157
- /package/dist/{chunk-7VTZAWDO.mjs → chunk-GYSOLAXM.mjs} +0 -0
package/client/App.vue
CHANGED
|
@@ -1,97 +1,3 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { computed } from 'vue'
|
|
3
|
-
import { useHead, useSeoMeta } from '@unhead/vue'
|
|
4
|
-
|
|
5
|
-
// @ts-expect-error virtual module
|
|
6
|
-
import ValaxyUserApp from '/@valaxyjs/UserAppVue'
|
|
7
|
-
|
|
8
|
-
// @ts-expect-error virtual module
|
|
9
|
-
import ValaxyThemeApp from '/@valaxyjs/ThemeAppVue'
|
|
10
|
-
import pkg from 'valaxy/package.json'
|
|
11
|
-
import { useI18n } from 'vue-i18n'
|
|
12
|
-
import { definePerson, defineWebPage, defineWebSite, useSchemaOrg } from '@unhead/schema-org'
|
|
13
|
-
|
|
14
|
-
// https://github.com/vueuse/head
|
|
15
|
-
// you can use this to manipulate the document head in any components,
|
|
16
|
-
// they will be rendered correctly in the html results with vite-ssg
|
|
17
|
-
import { useSiteConfig } from './config'
|
|
18
|
-
import ValaxyAddons from './components/ValaxyAddons.vue'
|
|
19
|
-
import { useFrontmatter } from './composables'
|
|
20
|
-
|
|
21
|
-
// <link rel="apple-touch-icon" href="/pwa-192x192.png">
|
|
22
|
-
// <link rel="mask-icon" href="/safari-pinned-tab.svg" color="#00aba9">
|
|
23
|
-
|
|
24
|
-
const siteConfig = useSiteConfig()
|
|
25
|
-
// todo, allow user config
|
|
26
|
-
const fm = useFrontmatter()
|
|
27
|
-
|
|
28
|
-
const { locale } = useI18n()
|
|
29
|
-
|
|
30
|
-
const title = computed(() => fm.value[`title_${locale.value}`] || fm.value.title)
|
|
31
|
-
useHead({
|
|
32
|
-
title,
|
|
33
|
-
titleTemplate: computed(() => fm.value.titleTemplate || ((title: string) => title ? `${title} - ${siteConfig.value.title}` : siteConfig.value.title)),
|
|
34
|
-
link: [
|
|
35
|
-
{
|
|
36
|
-
rel: 'icon',
|
|
37
|
-
href: siteConfig.value.favicon,
|
|
38
|
-
type: siteConfig.value.favicon?.endsWith('svg') ? 'image/svg+xml' : 'image/png',
|
|
39
|
-
},
|
|
40
|
-
],
|
|
41
|
-
meta: [
|
|
42
|
-
{ name: 'description', content: computed(() => siteConfig.value.description) },
|
|
43
|
-
{
|
|
44
|
-
name: 'generator',
|
|
45
|
-
content: `Valaxy ${pkg.version}`,
|
|
46
|
-
},
|
|
47
|
-
],
|
|
48
|
-
|
|
49
|
-
templateParams: {
|
|
50
|
-
schemaOrg: {
|
|
51
|
-
host: siteConfig.value.url,
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
// seo
|
|
57
|
-
// todo: get first image url from markdown
|
|
58
|
-
const siteUrl = computed(() => fm.value.url || siteConfig.value.url)
|
|
59
|
-
const description = computed(() => fm.value.excerpt || fm.value.description || siteConfig.value.description)
|
|
60
|
-
|
|
61
|
-
useSeoMeta({
|
|
62
|
-
description,
|
|
63
|
-
ogDescription: description,
|
|
64
|
-
ogLocale: computed(() => locale.value || fm.value.lang || siteConfig.value.lang || 'en'),
|
|
65
|
-
ogLocaleAlternate: computed(() => siteConfig.value.languages.filter(l => l !== locale.value)),
|
|
66
|
-
ogSiteName: computed(() => siteConfig.value.title),
|
|
67
|
-
ogTitle: computed(() => fm.value.title || siteConfig.value.title),
|
|
68
|
-
ogImage: computed(() => fm.value.ogImage || fm.value.cover || siteConfig.value.favicon),
|
|
69
|
-
ogType: 'website',
|
|
70
|
-
ogUrl: siteUrl,
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
// for SEO
|
|
74
|
-
useSchemaOrg([
|
|
75
|
-
// https://unhead.unjs.io/guide/guides/identity.html
|
|
76
|
-
// Personal Website or Blog
|
|
77
|
-
definePerson({
|
|
78
|
-
name: siteConfig.value.author.name,
|
|
79
|
-
url: siteUrl.value,
|
|
80
|
-
image: siteConfig.value.author.avatar,
|
|
81
|
-
sameAs: siteConfig.value.social.map(s => s.link),
|
|
82
|
-
}),
|
|
83
|
-
defineWebSite({
|
|
84
|
-
name: title.value,
|
|
85
|
-
datePublished: computed(() => fm.value.date),
|
|
86
|
-
dateModified: computed(() => fm.value.updated),
|
|
87
|
-
}),
|
|
88
|
-
defineWebPage(),
|
|
89
|
-
])
|
|
90
|
-
</script>
|
|
91
|
-
|
|
92
1
|
<template>
|
|
93
|
-
<
|
|
94
|
-
<ValaxyAddons />
|
|
95
|
-
<ValaxyUserApp />
|
|
96
|
-
<RouterView />
|
|
2
|
+
<ValaxyApp />
|
|
97
3
|
</template>
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// TODO: add docs to override ValaxyApp
|
|
3
|
+
import { computed } from 'vue'
|
|
4
|
+
import { useHead, useSeoMeta } from '@unhead/vue'
|
|
5
|
+
|
|
6
|
+
// @ts-expect-error virtual module
|
|
7
|
+
import ValaxyUserApp from '/@valaxyjs/UserAppVue'
|
|
8
|
+
// @ts-expect-error virtual module
|
|
9
|
+
import ValaxyThemeApp from '/@valaxyjs/ThemeAppVue'
|
|
10
|
+
|
|
11
|
+
import pkg from 'valaxy/package.json'
|
|
12
|
+
import { useI18n } from 'vue-i18n'
|
|
13
|
+
import { definePerson, defineWebPage, defineWebSite, useSchemaOrg } from '@unhead/schema-org'
|
|
14
|
+
|
|
15
|
+
// https://github.com/vueuse/head
|
|
16
|
+
// you can use this to manipulate the document head in any components,
|
|
17
|
+
// they will be rendered correctly in the html results with vite-ssg
|
|
18
|
+
import { useSiteConfig } from '../config'
|
|
19
|
+
import { useFrontmatter } from '../composables'
|
|
20
|
+
import ValaxyAddons from './ValaxyAddons.vue'
|
|
21
|
+
|
|
22
|
+
// <link rel="apple-touch-icon" href="/pwa-192x192.png">
|
|
23
|
+
// <link rel="mask-icon" href="/safari-pinned-tab.svg" color="#00aba9">
|
|
24
|
+
|
|
25
|
+
const siteConfig = useSiteConfig()
|
|
26
|
+
// todo, allow user config
|
|
27
|
+
const fm = useFrontmatter()
|
|
28
|
+
|
|
29
|
+
const { locale } = useI18n()
|
|
30
|
+
|
|
31
|
+
const title = computed(() => fm.value[`title_${locale.value}`] || fm.value.title)
|
|
32
|
+
useHead({
|
|
33
|
+
title,
|
|
34
|
+
titleTemplate: computed(() => fm.value.titleTemplate || ((title: string) => title ? `${title} - ${siteConfig.value.title}` : siteConfig.value.title)),
|
|
35
|
+
link: [
|
|
36
|
+
{
|
|
37
|
+
rel: 'icon',
|
|
38
|
+
href: siteConfig.value.favicon,
|
|
39
|
+
type: siteConfig.value.favicon?.endsWith('svg') ? 'image/svg+xml' : 'image/png',
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
meta: [
|
|
43
|
+
{ name: 'description', content: computed(() => siteConfig.value.description) },
|
|
44
|
+
{
|
|
45
|
+
name: 'generator',
|
|
46
|
+
content: `Valaxy ${pkg.version}`,
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
|
|
50
|
+
templateParams: {
|
|
51
|
+
schemaOrg: {
|
|
52
|
+
host: siteConfig.value.url,
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
// seo
|
|
58
|
+
// todo: get first image url from markdown
|
|
59
|
+
const siteUrl = computed(() => fm.value.url || siteConfig.value.url)
|
|
60
|
+
const description = computed(() => fm.value.excerpt || fm.value.description || siteConfig.value.description)
|
|
61
|
+
|
|
62
|
+
useSeoMeta({
|
|
63
|
+
description,
|
|
64
|
+
ogDescription: description,
|
|
65
|
+
ogLocale: computed(() => locale.value || fm.value.lang || siteConfig.value.lang || 'en'),
|
|
66
|
+
ogLocaleAlternate: computed(() => siteConfig.value.languages.filter(l => l !== locale.value)),
|
|
67
|
+
ogSiteName: computed(() => siteConfig.value.title),
|
|
68
|
+
ogTitle: computed(() => fm.value.title || siteConfig.value.title),
|
|
69
|
+
ogImage: computed(() => fm.value.ogImage || fm.value.cover || siteConfig.value.favicon),
|
|
70
|
+
ogType: 'website',
|
|
71
|
+
ogUrl: siteUrl,
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
// for SEO
|
|
75
|
+
useSchemaOrg([
|
|
76
|
+
// https://unhead.unjs.io/guide/guides/identity.html
|
|
77
|
+
// Personal Website or Blog
|
|
78
|
+
definePerson({
|
|
79
|
+
name: siteConfig.value.author.name,
|
|
80
|
+
url: siteUrl.value,
|
|
81
|
+
image: siteConfig.value.author.avatar,
|
|
82
|
+
sameAs: siteConfig.value.social.map(s => s.link),
|
|
83
|
+
}),
|
|
84
|
+
defineWebSite({
|
|
85
|
+
name: title.value,
|
|
86
|
+
datePublished: computed(() => fm.value.date),
|
|
87
|
+
dateModified: computed(() => fm.value.updated),
|
|
88
|
+
}),
|
|
89
|
+
defineWebPage(),
|
|
90
|
+
])
|
|
91
|
+
</script>
|
|
92
|
+
|
|
93
|
+
<template>
|
|
94
|
+
<ValaxyThemeApp />
|
|
95
|
+
<ValaxyAddons />
|
|
96
|
+
<ValaxyUserApp />
|
|
97
|
+
<router-view />
|
|
98
|
+
</template>
|
|
@@ -13,6 +13,13 @@ export interface BaseCategory {
|
|
|
13
13
|
total: number
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* @en
|
|
18
|
+
* Category list
|
|
19
|
+
*
|
|
20
|
+
* @zh
|
|
21
|
+
* 分类列表
|
|
22
|
+
*/
|
|
16
23
|
export interface CategoryList {
|
|
17
24
|
/**
|
|
18
25
|
* category name
|
|
@@ -27,7 +34,11 @@ export interface CategoryList {
|
|
|
27
34
|
export type Category = CategoryList
|
|
28
35
|
export type Categories = Map<string, Post | CategoryList>
|
|
29
36
|
|
|
30
|
-
|
|
37
|
+
/**
|
|
38
|
+
* For theme development, you can use this function to determine whether the category is a category list.
|
|
39
|
+
* @todo write unit test
|
|
40
|
+
* @param category
|
|
41
|
+
*/
|
|
31
42
|
export function isCategoryList(category: any): category is CategoryList {
|
|
32
43
|
return category.children
|
|
33
44
|
}
|
|
@@ -1,67 +1,10 @@
|
|
|
1
1
|
import { computed, shallowRef } from 'vue'
|
|
2
|
-
import type { DefaultTheme
|
|
2
|
+
import type { DefaultTheme } from 'valaxy/types'
|
|
3
|
+
import type { MenuItem } from '@valaxyjs/utils'
|
|
4
|
+
import { getHeaders } from '@valaxyjs/utils'
|
|
3
5
|
import { onContentUpdated } from '../../utils'
|
|
4
6
|
import { useFrontmatter, useThemeConfig } from '../..'
|
|
5
7
|
|
|
6
|
-
export type MenuItem = Omit<Header, 'slug' | 'children'> & {
|
|
7
|
-
children?: MenuItem[]
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function resolveHeaders(
|
|
11
|
-
headers: MenuItem[],
|
|
12
|
-
levelsRange: Exclude<DefaultTheme.Config['outline'], false> = [2, 4],
|
|
13
|
-
) {
|
|
14
|
-
const levels: [number, number]
|
|
15
|
-
= typeof levelsRange === 'number'
|
|
16
|
-
? [levelsRange, levelsRange]
|
|
17
|
-
: levelsRange === 'deep'
|
|
18
|
-
? [2, 6]
|
|
19
|
-
: levelsRange
|
|
20
|
-
|
|
21
|
-
return groupHeaders(headers, levels)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function groupHeaders(headers: MenuItem[], levelsRange: [number, number]) {
|
|
25
|
-
const result: MenuItem[] = []
|
|
26
|
-
|
|
27
|
-
headers = headers.map(h => ({ ...h }))
|
|
28
|
-
headers.forEach((h, index) => {
|
|
29
|
-
if (h.level >= levelsRange[0] && h.level <= levelsRange[1]) {
|
|
30
|
-
if (addToParent(index, headers, levelsRange))
|
|
31
|
-
result.push(h)
|
|
32
|
-
}
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
return result
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function addToParent(
|
|
39
|
-
currIndex: number,
|
|
40
|
-
headers: MenuItem[],
|
|
41
|
-
levelsRange: [number, number],
|
|
42
|
-
) {
|
|
43
|
-
if (currIndex === 0)
|
|
44
|
-
return true
|
|
45
|
-
|
|
46
|
-
const currentHeader = headers[currIndex]
|
|
47
|
-
for (let index = currIndex - 1; index >= 0; index--) {
|
|
48
|
-
const header = headers[index]
|
|
49
|
-
|
|
50
|
-
if (
|
|
51
|
-
header.level < currentHeader.level
|
|
52
|
-
&& header.level >= levelsRange[0]
|
|
53
|
-
&& header.level <= levelsRange[1]
|
|
54
|
-
) {
|
|
55
|
-
if (header.children == null)
|
|
56
|
-
header.children = []
|
|
57
|
-
header.children.push(currentHeader)
|
|
58
|
-
return false
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return true
|
|
63
|
-
}
|
|
64
|
-
|
|
65
8
|
/**
|
|
66
9
|
* export headers & handleClick to generate outline
|
|
67
10
|
*/
|
|
@@ -76,7 +19,11 @@ export function useOutline() {
|
|
|
76
19
|
onContentUpdated(() => {
|
|
77
20
|
if (pageOutline.value === false)
|
|
78
21
|
return
|
|
79
|
-
headers.value = getHeaders(
|
|
22
|
+
headers.value = getHeaders({
|
|
23
|
+
range: pageOutline.value,
|
|
24
|
+
selector: '.markdown-body',
|
|
25
|
+
filter: el => !!el.id && el.hasChildNodes(),
|
|
26
|
+
})
|
|
80
27
|
})
|
|
81
28
|
|
|
82
29
|
const handleClick = ({ target: el }: Event) => {
|
|
@@ -100,42 +47,3 @@ export function useOutline() {
|
|
|
100
47
|
handleClick,
|
|
101
48
|
}
|
|
102
49
|
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* get headers from document directly
|
|
106
|
-
*/
|
|
107
|
-
export function getHeaders(range: Exclude<DefaultTheme.Config['outline'], false>) {
|
|
108
|
-
const headers = Array.from(document.querySelectorAll('.markdown-body :where(h1,h2,h3,h4,h5,h6)'))
|
|
109
|
-
.filter(el => el.id && el.hasChildNodes())
|
|
110
|
-
.map((el) => {
|
|
111
|
-
const level = Number(el.tagName[1])
|
|
112
|
-
return {
|
|
113
|
-
title: serializeHeader(el),
|
|
114
|
-
link: `#${el.id}`,
|
|
115
|
-
level,
|
|
116
|
-
// @ts-expect-error lang
|
|
117
|
-
lang: el.lang,
|
|
118
|
-
}
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
return resolveHeaders(headers, range)
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function serializeHeader(h: Element): string {
|
|
125
|
-
let ret = ''
|
|
126
|
-
for (const node of Array.from(h.childNodes)) {
|
|
127
|
-
if (node.nodeType === 1) {
|
|
128
|
-
if (
|
|
129
|
-
(node as Element).classList.contains('VABadge')
|
|
130
|
-
|| (node as Element).classList.contains('header-anchor')
|
|
131
|
-
)
|
|
132
|
-
continue
|
|
133
|
-
|
|
134
|
-
ret += node.textContent
|
|
135
|
-
}
|
|
136
|
-
else if (node.nodeType === 3) {
|
|
137
|
-
ret += node.textContent
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
return ret.trim()
|
|
141
|
-
}
|
|
@@ -2,6 +2,15 @@ import { computed } from 'vue'
|
|
|
2
2
|
import type { Post } from '../../types'
|
|
3
3
|
import { useSiteStore } from '../stores'
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* @en
|
|
7
|
+
* Tag list, key is tag name, value is the object of tag.
|
|
8
|
+
* - count: the number of posts with this tag.
|
|
9
|
+
*
|
|
10
|
+
* @zh
|
|
11
|
+
* 标签列表,键是标签名,值是标签对象。
|
|
12
|
+
* - count: 使用该标签的文章数量。
|
|
13
|
+
*/
|
|
5
14
|
export type Tags = Map<string, {
|
|
6
15
|
count: number
|
|
7
16
|
}>
|
package/client/index.ts
CHANGED
package/client/locales/en.yml
CHANGED
package/client/main.ts
CHANGED
|
@@ -19,6 +19,7 @@ import { setupLayouts } from 'virtual:generated-layouts'
|
|
|
19
19
|
import { initValaxyConfig, valaxyConfigSymbol } from 'valaxy'
|
|
20
20
|
import AppLink from './components/AppLink.vue'
|
|
21
21
|
|
|
22
|
+
// import App from '/@valaxyjs/App.vue'
|
|
22
23
|
import App from './App.vue'
|
|
23
24
|
|
|
24
25
|
import setupMain from './setup/main'
|
package/client/setup/mermaid.ts
CHANGED
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
import { defineMermaidSetup } from 'valaxy'
|
|
4
4
|
import type { MermaidOptions } from '../types'
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* @en
|
|
8
|
+
* Extend the Mermaid configuration.
|
|
9
|
+
*
|
|
10
|
+
* @zh
|
|
11
|
+
* 扩展 Mermaid 配置。
|
|
12
|
+
*/
|
|
6
13
|
export default defineMermaidSetup(() => {
|
|
7
14
|
// eslint-disable-next-line prefer-const
|
|
8
15
|
let injection_return: MermaidOptions = {
|
package/client/setups.ts
CHANGED
|
@@ -2,6 +2,14 @@ import type { ViteSSGContext } from 'vite-ssg'
|
|
|
2
2
|
import type { Awaitable } from '@antfu/utils'
|
|
3
3
|
import type { MermaidOptions } from './types'
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* @see https://github.com/antfu-collective/vite-ssg
|
|
7
|
+
* @en
|
|
8
|
+
* The context object for the application setup function.
|
|
9
|
+
*
|
|
10
|
+
* @zh
|
|
11
|
+
* 应用 setup 函数的上下文对象。(包括了 ViteSSG context)
|
|
12
|
+
*/
|
|
5
13
|
export type AppContext = ViteSSGContext
|
|
6
14
|
|
|
7
15
|
export type AppSetup = (ctx: AppContext) => Awaitable<void>
|
|
@@ -9,6 +17,13 @@ export type AppSetup = (ctx: AppContext) => Awaitable<void>
|
|
|
9
17
|
// client
|
|
10
18
|
export type MermaidSetup = () => Partial<MermaidOptions> | void
|
|
11
19
|
|
|
20
|
+
/**
|
|
21
|
+
* @en
|
|
22
|
+
* Define the setup function for the client application.
|
|
23
|
+
*
|
|
24
|
+
* @zh
|
|
25
|
+
* 扩展客户端应用的 setup 函数。
|
|
26
|
+
*/
|
|
12
27
|
export function defineAppSetup(fn: AppSetup) {
|
|
13
28
|
return fn
|
|
14
29
|
}
|
package/client/types/index.ts
CHANGED
|
@@ -3,4 +3,7 @@ import type mermaid from 'mermaid'
|
|
|
3
3
|
|
|
4
4
|
export type UserModule = (ctx: ViteSSGContext) => void
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* @see https://mermaid.js.org/config/schema-docs/config.html#mermaid-config-schema
|
|
8
|
+
*/
|
|
6
9
|
export type MermaidOptions = (typeof mermaid.initialize) extends (a: infer A) => any ? A : never
|
package/client/utils/router.ts
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
import type { Router } from 'vue-router'
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* @en
|
|
5
|
+
* Options for scrolling to a target element.
|
|
6
|
+
*
|
|
7
|
+
* @zh
|
|
8
|
+
* 滚动到目标元素的选项。
|
|
9
|
+
*/
|
|
3
10
|
export interface ScrollToOptions {
|
|
4
11
|
/**
|
|
12
|
+
* @en
|
|
13
|
+
* Whether to scroll smoothly.
|
|
14
|
+
*
|
|
15
|
+
* @zh
|
|
5
16
|
* 平滑滚动
|
|
6
17
|
*/
|
|
7
18
|
smooth: boolean
|
|
@@ -11,6 +22,13 @@ export interface ScrollToOptions {
|
|
|
11
22
|
targetPadding: number
|
|
12
23
|
}
|
|
13
24
|
|
|
25
|
+
/**
|
|
26
|
+
* For theme developers, you can use this function to scroll to the target element.
|
|
27
|
+
* For example, when you click the anchor link in the markdown file, it will scroll to the target element.
|
|
28
|
+
* @param el
|
|
29
|
+
* @param hash
|
|
30
|
+
* @param options
|
|
31
|
+
*/
|
|
14
32
|
export function scrollTo(el: HTMLElement, hash: string, options: Partial<ScrollToOptions> = {
|
|
15
33
|
smooth: true,
|
|
16
34
|
targetPadding: -64,
|
package/client/utils/time.ts
CHANGED
|
@@ -10,6 +10,14 @@ export function formatDate(date: string | number | Date, template = 'yyyy-MM-dd'
|
|
|
10
10
|
return format(date, template)
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* date-fns format date with 'yyyy-MM-dd HH:mm:ss'
|
|
15
|
+
* @param date
|
|
16
|
+
*/
|
|
17
|
+
export function formatTimestamp(date: string | number | Date): string {
|
|
18
|
+
return format(date, 'yyyy-MM-dd HH:mm:ss')
|
|
19
|
+
}
|
|
20
|
+
|
|
13
21
|
/**
|
|
14
22
|
* sort posts by date
|
|
15
23
|
* @param posts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true});var m=Object.create;var o=Object.defineProperty;var i=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var d=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var l=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,n)=>(typeof require<"u"?require:t)[n]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var p=(e,t)=>()=>(e&&(t=e(e=0)),t);var R=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var a=(e,t,n,c)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of u(t))!f.call(e,r)&&r!==n&&o(e,r,{get:()=>t[r],enumerable:!(c=i(t,r))||c.enumerable});return e};var h=(e,t,n)=>(n=e!=null?m(d(e)):{},a(t||!e||!e.__esModule?o(n,"default",{value:e,enumerable:!0}):n,e));var s,I,U= exports.e =p(()=>{"use strict";s=()=>typeof document>"u"?new URL(
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});var m=Object.create;var o=Object.defineProperty;var i=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var d=Object.getPrototypeOf,f=Object.prototype.hasOwnProperty;var l=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,n)=>(typeof require<"u"?require:t)[n]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var p=(e,t)=>()=>(e&&(t=e(e=0)),t);var R=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var a=(e,t,n,c)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of u(t))!f.call(e,r)&&r!==n&&o(e,r,{get:()=>t[r],enumerable:!(c=i(t,r))||c.enumerable});return e};var h=(e,t,n)=>(n=e!=null?m(d(e)):{},a(t||!e||!e.__esModule?o(n,"default",{value:e,enumerable:!0}):n,e));var s,I,U= exports.e =p(()=>{"use strict";s=()=>typeof document>"u"?new URL(`file:${__filename}`).href:document.currentScript&&document.currentScript.src||new URL("main.js",document.baseURI).href,I= exports.d =s()});exports.a = l; exports.b = R; exports.c = h; exports.d = I; exports.e = U;
|