valaxy 0.6.0 → 0.6.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/components/ValaxyMd.vue +34 -27
- package/client/composables/copy-code.ts +92 -0
- package/client/composables/outline.ts +1 -14
- package/client/composables/sidebar.ts +0 -12
- package/client/locales/en.yml +18 -17
- package/client/locales/zh-CN.yml +5 -4
- package/client/modules/valaxy.ts +1 -14
- package/client/styles/common/code.scss +191 -167
- package/client/styles/common/markdown.scss +0 -2
- package/client/styles/css-vars.scss +30 -7
- package/client/styles/palette.scss +15 -0
- package/client/styles/vars.scss +32 -18
- package/dist/chunk-4TQV23CA.mjs +40 -0
- package/dist/chunk-C4MEVIMD.js +40 -0
- package/dist/{config-ad23e743.d.ts → config-112ac884.d.ts} +9 -0
- package/dist/index.d.ts +4 -6
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/node/cli.js +3 -3
- package/dist/node/cli.mjs +2 -2
- package/dist/node/index.d.ts +2 -1
- package/dist/node/index.js +1 -1
- package/dist/node/index.mjs +1 -1
- package/node/markdown/highlight.ts +27 -39
- package/node/markdown/index.ts +11 -5
- package/node/markdown/markdown-it/highlightLines.ts +1 -1
- package/node/markdown/markdownToVue.ts +28 -4
- package/node/plugins/index.ts +1 -1
- package/node/plugins/preset.ts +2 -2
- package/node/shims.d.ts +0 -5
- package/node/utils/index.ts +1 -1
- package/package.json +1 -3
- package/dist/chunk-CP3UCJ2D.js +0 -34
- package/dist/chunk-HCVZ2UUO.mjs +0 -34
|
@@ -3,6 +3,7 @@ import type { Post } from 'valaxy'
|
|
|
3
3
|
import { onMounted, ref } from 'vue'
|
|
4
4
|
import { useI18n } from 'vue-i18n'
|
|
5
5
|
import { useAplayer, useCodePen } from '~/composables'
|
|
6
|
+
import { useCopyCode } from '~/composables/copy-code'
|
|
6
7
|
import { wrapTable } from '~/utils'
|
|
7
8
|
|
|
8
9
|
const props = defineProps<{
|
|
@@ -27,41 +28,47 @@ if (props.frontmatter.aplayer)
|
|
|
27
28
|
|
|
28
29
|
if (props.frontmatter.codepen)
|
|
29
30
|
useCodePen()
|
|
31
|
+
|
|
32
|
+
useCopyCode()
|
|
30
33
|
</script>
|
|
31
34
|
|
|
32
35
|
<template>
|
|
33
|
-
<
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
<div text="center">
|
|
37
|
-
<a
|
|
38
|
-
v-if="frontmatter.url"
|
|
39
|
-
:href="frontmatter.url"
|
|
40
|
-
class="post-link-btn shadow hover:shadow-md"
|
|
41
|
-
rounded
|
|
42
|
-
target="_blank"
|
|
43
|
-
m="b-4"
|
|
44
|
-
>
|
|
45
|
-
{{ t('post.view_link') }}
|
|
46
|
-
</a>
|
|
47
|
-
</div>
|
|
36
|
+
<Transition appear>
|
|
37
|
+
<article v-if="$slots.default" :class="frontmatter.markdown !== false && 'markdown-body'">
|
|
38
|
+
<slot ref="content" @vnode-updated="updateDom" />
|
|
48
39
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
40
|
+
<div text="center">
|
|
41
|
+
<a
|
|
42
|
+
v-if="frontmatter.url"
|
|
43
|
+
:href="frontmatter.url"
|
|
44
|
+
class="post-link-btn shadow hover:shadow-md"
|
|
45
|
+
rounded
|
|
46
|
+
target="_blank"
|
|
47
|
+
m="b-4"
|
|
48
|
+
>
|
|
49
|
+
{{ t('post.view_link') }}
|
|
50
|
+
</a>
|
|
56
51
|
</div>
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
|
|
53
|
+
<slot v-if="frontmatter.end !== undefined" name="end">
|
|
54
|
+
<div m="y-4" class="end flex justify-center items-center">
|
|
55
|
+
<hr class="line inline-flex" w="full" m="!y-2">
|
|
56
|
+
<span p="x-4" font="serif bold" class="whitespace-nowrap">
|
|
57
|
+
{{ frontmatter.end ? 'Q.E.D.' : 'To Be Continued.' }}
|
|
58
|
+
</span>
|
|
59
|
+
<hr class="line inline-flex" w="full" m="!y-2">
|
|
60
|
+
</div>
|
|
61
|
+
</slot>
|
|
62
|
+
</article>
|
|
63
|
+
</Transition>
|
|
59
64
|
</template>
|
|
60
65
|
|
|
61
66
|
<style lang="scss">
|
|
62
|
-
.
|
|
63
|
-
.
|
|
64
|
-
|
|
67
|
+
.markdown-body {
|
|
68
|
+
.end {
|
|
69
|
+
.line {
|
|
70
|
+
height: 1px;
|
|
71
|
+
}
|
|
65
72
|
}
|
|
66
73
|
}
|
|
67
74
|
</style>
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { nextTick, watch } from 'vue'
|
|
2
|
+
import { isClient } from '@vueuse/core'
|
|
3
|
+
import { useRoute } from 'vue-router'
|
|
4
|
+
|
|
5
|
+
export function useCopyCode() {
|
|
6
|
+
const route = useRoute()
|
|
7
|
+
|
|
8
|
+
if (isClient) {
|
|
9
|
+
watch(
|
|
10
|
+
() => route.path,
|
|
11
|
+
() => {
|
|
12
|
+
nextTick(() => {
|
|
13
|
+
document
|
|
14
|
+
.querySelectorAll<HTMLSpanElement>(
|
|
15
|
+
'.markdown-body div[class*="language-"]>span.copy',
|
|
16
|
+
)
|
|
17
|
+
.forEach(handleElement)
|
|
18
|
+
})
|
|
19
|
+
},
|
|
20
|
+
{ immediate: true, flush: 'post' },
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function copyToClipboard(text: string) {
|
|
26
|
+
try {
|
|
27
|
+
return navigator.clipboard.writeText(text)
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
const element = document.createElement('textarea')
|
|
31
|
+
const previouslyFocusedElement = document.activeElement
|
|
32
|
+
|
|
33
|
+
element.value = text
|
|
34
|
+
|
|
35
|
+
// Prevent keyboard from showing on mobile
|
|
36
|
+
element.setAttribute('readonly', '')
|
|
37
|
+
|
|
38
|
+
element.style.contain = 'strict'
|
|
39
|
+
element.style.position = 'absolute'
|
|
40
|
+
element.style.left = '-9999px'
|
|
41
|
+
element.style.fontSize = '12pt' // Prevent zooming on iOS
|
|
42
|
+
|
|
43
|
+
const selection = document.getSelection()
|
|
44
|
+
const originalRange = selection
|
|
45
|
+
? selection.rangeCount > 0 && selection.getRangeAt(0)
|
|
46
|
+
: null
|
|
47
|
+
|
|
48
|
+
document.body.appendChild(element)
|
|
49
|
+
element.select()
|
|
50
|
+
|
|
51
|
+
// Explicit selection workaround for iOS
|
|
52
|
+
element.selectionStart = 0
|
|
53
|
+
element.selectionEnd = text.length
|
|
54
|
+
|
|
55
|
+
document.execCommand('copy')
|
|
56
|
+
document.body.removeChild(element)
|
|
57
|
+
|
|
58
|
+
if (originalRange) {
|
|
59
|
+
selection!.removeAllRanges() // originalRange can't be truthy when selection is falsy
|
|
60
|
+
selection!.addRange(originalRange)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Get the focus back on the previously focused element, if any
|
|
64
|
+
if (previouslyFocusedElement)
|
|
65
|
+
(previouslyFocusedElement as HTMLElement).focus()
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function handleElement(el: HTMLElement) {
|
|
70
|
+
el.onclick = () => {
|
|
71
|
+
const parent = el.parentElement
|
|
72
|
+
|
|
73
|
+
if (!parent)
|
|
74
|
+
return
|
|
75
|
+
|
|
76
|
+
const isShell
|
|
77
|
+
= parent.classList.contains('language-sh')
|
|
78
|
+
|| parent.classList.contains('language-bash')
|
|
79
|
+
|
|
80
|
+
let { innerText: text = '' } = parent
|
|
81
|
+
|
|
82
|
+
if (isShell)
|
|
83
|
+
text = text.replace(/^ *\$ /gm, '')
|
|
84
|
+
|
|
85
|
+
copyToClipboard(text).then(() => {
|
|
86
|
+
el.classList.add('copied')
|
|
87
|
+
setTimeout(() => {
|
|
88
|
+
el.classList.remove('copied')
|
|
89
|
+
}, 3000)
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { Ref } from 'vue'
|
|
2
|
-
import {
|
|
3
|
-
import { useRoute } from 'vue-router'
|
|
2
|
+
import { onMounted, onUnmounted, onUpdated } from 'vue'
|
|
4
3
|
import type { Header } from '../../types'
|
|
5
4
|
import { throttleAndDebounce } from '~/utils'
|
|
6
5
|
|
|
@@ -52,18 +51,6 @@ function mapHeaders(
|
|
|
52
51
|
// magic number to avoid repeated retrieval
|
|
53
52
|
const PAGE_OFFSET = 56
|
|
54
53
|
|
|
55
|
-
export function useOutline() {
|
|
56
|
-
const route = useRoute()
|
|
57
|
-
|
|
58
|
-
const hasOutline = computed(() => {
|
|
59
|
-
return route.meta?.headers?.length > 0
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
return {
|
|
63
|
-
hasOutline,
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
54
|
export function useActiveAnchor(
|
|
68
55
|
container: Ref<HTMLElement>,
|
|
69
56
|
marker: Ref<HTMLElement>,
|
|
@@ -158,15 +158,3 @@ function throttleAndDebounce(fn: () => void, delay: number): () => void {
|
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
|
-
|
|
162
|
-
export function useOutline() {
|
|
163
|
-
const route = useRoute()
|
|
164
|
-
|
|
165
|
-
const hasOutline = computed(() => {
|
|
166
|
-
return route.meta.headers.length > 0
|
|
167
|
-
})
|
|
168
|
-
|
|
169
|
-
return {
|
|
170
|
-
hasOutline,
|
|
171
|
-
}
|
|
172
|
-
}
|
package/client/locales/en.yml
CHANGED
|
@@ -3,12 +3,13 @@ button:
|
|
|
3
3
|
back: Back
|
|
4
4
|
go: GO
|
|
5
5
|
home: Home
|
|
6
|
-
|
|
6
|
+
toggle_light: Switch to light mode
|
|
7
|
+
toggle_dark: Switch to dark mode
|
|
7
8
|
toggle_langs: Change languages
|
|
8
9
|
intro:
|
|
9
10
|
desc: Theme Yun | Valaxy
|
|
10
11
|
hi: Hi, {name}!
|
|
11
|
-
not-found: Oops! Space
|
|
12
|
+
not-found: Oops! Space collapsed!
|
|
12
13
|
|
|
13
14
|
title:
|
|
14
15
|
archive: Archive
|
|
@@ -40,8 +41,8 @@ post:
|
|
|
40
41
|
toc_empty: This post does not have a Table of Contents
|
|
41
42
|
views: Views
|
|
42
43
|
comments_count: Comments
|
|
43
|
-
related_posts: Related
|
|
44
|
-
view_link: View
|
|
44
|
+
related_posts: Related posts
|
|
45
|
+
view_link: View link
|
|
45
46
|
read_more: READ MORE
|
|
46
47
|
cover: Cover
|
|
47
48
|
copyright:
|
|
@@ -61,24 +62,24 @@ footer:
|
|
|
61
62
|
total_visitors: Total Visitors
|
|
62
63
|
|
|
63
64
|
counter:
|
|
64
|
-
archives: No
|
|
65
|
-
categories: No
|
|
66
|
-
tags: No
|
|
65
|
+
archives: No posts | 1 post | {count} posts
|
|
66
|
+
categories: No categories | 1 category | {count} categories
|
|
67
|
+
tags: No tags | 1 tag | {count} tags
|
|
67
68
|
albums:
|
|
68
69
|
zero: No album
|
|
69
|
-
one: 1 album
|
|
70
|
-
other: '%d albums
|
|
70
|
+
one: 1 album
|
|
71
|
+
other: '%d albums'
|
|
71
72
|
photos:
|
|
72
73
|
zero: No photo
|
|
73
|
-
one: 1 photo
|
|
74
|
-
other: '%d photos
|
|
74
|
+
one: 1 photo
|
|
75
|
+
other: '%d photos'
|
|
75
76
|
|
|
76
77
|
category:
|
|
77
78
|
uncategorized: Uncategorized
|
|
78
79
|
|
|
79
80
|
search:
|
|
80
81
|
placeholder: Searching...
|
|
81
|
-
empty: 'We
|
|
82
|
+
empty: 'We could not find any results for the search: {query}.'
|
|
82
83
|
hits_time: '{hits} results found in {time} ms'
|
|
83
84
|
|
|
84
85
|
symbol:
|
|
@@ -97,12 +98,12 @@ accessibility:
|
|
|
97
98
|
|
|
98
99
|
wordcount:
|
|
99
100
|
count: Word count in article
|
|
100
|
-
count_total:
|
|
101
|
+
count_total: Total words
|
|
101
102
|
time: Reading time
|
|
102
103
|
time_total: Total reading time
|
|
103
104
|
|
|
104
105
|
time:
|
|
105
|
-
day: Days
|
|
106
|
-
hour: Hours
|
|
107
|
-
minute: Minutes
|
|
108
|
-
second: Seconds
|
|
106
|
+
day: 1 Day | %d Days
|
|
107
|
+
hour: 1 Hour | %d Hours
|
|
108
|
+
minute: 1 Minute | %d Minutes
|
|
109
|
+
second: 1 Second | %d Seconds
|
package/client/locales/zh-CN.yml
CHANGED
|
@@ -3,6 +3,7 @@ button:
|
|
|
3
3
|
back: 返回
|
|
4
4
|
go: 确定
|
|
5
5
|
home: 首页
|
|
6
|
+
toggle_light: 切换亮色模式
|
|
6
7
|
toggle_dark: 切换深色模式
|
|
7
8
|
toggle_langs: 切换语言
|
|
8
9
|
intro:
|
|
@@ -101,7 +102,7 @@ wordcount:
|
|
|
101
102
|
time_total: 站点阅读时长
|
|
102
103
|
|
|
103
104
|
time:
|
|
104
|
-
day: 天
|
|
105
|
-
hour: 小时
|
|
106
|
-
minute: 分
|
|
107
|
-
second: 秒
|
|
105
|
+
day: 1 天 | %d 天
|
|
106
|
+
hour: 1 小时 | %d 小时
|
|
107
|
+
minute: 1 分 | %d 分
|
|
108
|
+
second: 1 秒 | %d 秒
|
package/client/modules/valaxy.ts
CHANGED
|
@@ -12,7 +12,7 @@ import { useStorage } from '@vueuse/core'
|
|
|
12
12
|
|
|
13
13
|
import type { Router } from 'vue-router'
|
|
14
14
|
import type { PageDataPayload } from '../../types'
|
|
15
|
-
import { initConfig,
|
|
15
|
+
import { initConfig, valaxyConfigSymbol } from '../config'
|
|
16
16
|
import { ensureSuffix } from '@antfu/utils'
|
|
17
17
|
|
|
18
18
|
import type { UserModule } from '~/types'
|
|
@@ -45,7 +45,6 @@ function shouldHotReload(payload: PageDataPayload): boolean {
|
|
|
45
45
|
|
|
46
46
|
export const install: UserModule = ({ app, router }) => {
|
|
47
47
|
// inject valaxy config before modules
|
|
48
|
-
const ctx = initContext()
|
|
49
48
|
const config = initConfig()
|
|
50
49
|
app.provide(valaxyConfigSymbol, config)
|
|
51
50
|
|
|
@@ -62,18 +61,6 @@ export const install: UserModule = ({ app, router }) => {
|
|
|
62
61
|
router.isReady().then(() => {
|
|
63
62
|
handleHMR(router)
|
|
64
63
|
})
|
|
65
|
-
|
|
66
|
-
function pathToUrl(path: string): string {
|
|
67
|
-
return `${location.origin}/@fs${ctx.value.userRoot}/pages${path}.md?import`
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
router.beforeEach(async (to) => {
|
|
71
|
-
try {
|
|
72
|
-
const { __pageData } = await import(/* @vite-ignore */pathToUrl(to.path))
|
|
73
|
-
to.meta = Object.assign(to.meta, __pageData)
|
|
74
|
-
}
|
|
75
|
-
catch {}
|
|
76
|
-
})
|
|
77
64
|
}
|
|
78
65
|
|
|
79
66
|
function handleHMR(router: Router): void {
|