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.
@@ -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
- <article v-if="$slots.default" :class="frontmatter.markdown !== false && 'markdown-body'">
34
- <slot ref="content" @vnode-updated="updateDom" />
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
- <slot v-if="typeof frontmatter.end !== 'undefined'" name="end">
50
- <div m="y-4" class="end flex justify-center items-center">
51
- <hr class="line inline-flex" w="full" m="!y-2">
52
- <span p="x-4" font="serif bold" class="whitespace-nowrap">
53
- {{ frontmatter.end ? 'Q.E.D.' : 'To Be Continued.' }}
54
- </span>
55
- <hr class="line inline-flex" w="full" m="!y-2">
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
- </slot>
58
- </article>
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
- .end {
63
- .line {
64
- height: 1px;
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 { computed, onMounted, onUnmounted, onUpdated } from 'vue'
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
- }
@@ -3,12 +3,13 @@ button:
3
3
  back: Back
4
4
  go: GO
5
5
  home: Home
6
- toggle_dark: Toggle dark mode
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 collapse!
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 Posts
44
- view_link: View Link
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 post | 1 post in total | {count} posts in total
65
- categories: No category | 1 category in total | {count} categories in total
66
- tags: No tag | 1 tag in total | {count} tags in total
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 in total
70
- other: '%d albums in total'
70
+ one: 1 album
71
+ other: '%d albums'
71
72
  photos:
72
73
  zero: No photo
73
- one: 1 photo in total
74
- other: '%d photos in total'
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 didn''t find any results for the search: {query}.'
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: Word 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
@@ -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 秒
@@ -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, initContext, valaxyConfigSymbol } from '../config'
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 {