valaxy 0.4.0 → 0.6.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.
Files changed (155) hide show
  1. package/README.md +0 -4
  2. package/{src/client → client}/App.vue +0 -0
  3. package/{src/client/composables/search/index.ts → client/app/data.ts} +0 -0
  4. package/{src/client → client}/components/AppLink.vue +0 -0
  5. package/client/components/PostCard.vue +84 -0
  6. package/{src/client → client}/components/PostList.vue +0 -0
  7. package/{src/client → client}/components/README.md +0 -0
  8. package/{src/client → client}/components/ValaxyBg.vue +0 -0
  9. package/{src/client → client}/components/ValaxyCopyright.vue +0 -0
  10. package/{src/client → client}/components/ValaxyFooter.vue +1 -1
  11. package/{src/client → client}/components/ValaxyHamburger.vue +0 -0
  12. package/client/components/ValaxyMd.vue +74 -0
  13. package/{src/client → client}/components/ValaxyOverlay.vue +0 -0
  14. package/{src/client → client}/components/ValaxyPagination.vue +0 -0
  15. package/{src/client → client}/components/ValaxyRightSidebar.vue +0 -0
  16. package/{src/client → client}/components/ValaxySidebar.vue +0 -0
  17. package/{src/client → client}/components/ValaxyToc.vue +3 -3
  18. package/{src/client → client}/composables/category.ts +0 -0
  19. package/{src/client → client}/composables/comments/index.ts +0 -0
  20. package/{src/client → client}/composables/comments/twikoo.ts +0 -0
  21. package/{src/client → client}/composables/comments/waline.ts +0 -0
  22. package/{src/client → client}/composables/common.ts +0 -0
  23. package/client/composables/copy-code.ts +92 -0
  24. package/{src/client → client}/composables/dark.ts +0 -0
  25. package/client/composables/features/index.ts +0 -0
  26. package/{src/client → client}/composables/helper.ts +0 -0
  27. package/{src/client → client}/composables/index.ts +1 -1
  28. package/{src/client → client}/composables/layout.ts +0 -0
  29. package/client/composables/outline.ts +168 -0
  30. package/{src/client → client}/composables/post.ts +0 -0
  31. package/client/composables/search/index.ts +0 -0
  32. package/{src/client → client}/composables/sidebar.ts +46 -1
  33. package/{src/client → client}/composables/tag.ts +0 -0
  34. package/{src/client → client}/composables/widgets/aplayer.ts +0 -0
  35. package/{src/client → client}/composables/widgets/backToTop.ts +0 -0
  36. package/{src/client → client}/composables/widgets/codepen.ts +0 -0
  37. package/{src/client → client}/composables/widgets/index.ts +0 -0
  38. package/client/config.ts +75 -0
  39. package/{src/client → client}/index.html +0 -0
  40. package/{src/client → client}/index.ts +0 -0
  41. package/{src/client → client}/layouts/404.vue +0 -0
  42. package/{src/client → client}/layouts/README.md +0 -0
  43. package/{src/client → client}/locales/README.md +0 -0
  44. package/{src/client → client}/locales/en.yml +1 -0
  45. package/{src/client → client}/locales/zh-CN.yml +4 -3
  46. package/{src/client → client}/main.ts +4 -1
  47. package/{src/client → client}/modules/README.md +0 -0
  48. package/{src/client → client}/modules/nprogress.ts +0 -0
  49. package/{src/client → client}/modules/pinia.ts +0 -0
  50. package/{src/client → client}/modules/valaxy.ts +19 -7
  51. package/{src/client → client}/pages/README.md +0 -0
  52. package/{src/client → client}/pages/[...all].vue +0 -0
  53. package/{src/client → client}/pages/hi/[name].vue +0 -0
  54. package/{src/client → client}/pages/index.vue +0 -0
  55. package/{src/client → client}/pages/page/[page].vue +0 -0
  56. package/{src/client → client}/shims.d.ts +7 -1
  57. package/{src/client → client}/stores/app.ts +0 -0
  58. package/{src/client → client}/stores/user.ts +0 -0
  59. package/{src/client → client}/styles/common/button.scss +0 -0
  60. package/client/styles/common/code.scss +231 -0
  61. package/{src/client → client}/styles/common/custom-blocks.scss +0 -0
  62. package/{src/client → client}/styles/common/hamburger.scss +0 -0
  63. package/{src/client → client}/styles/common/markdown.scss +0 -2
  64. package/client/styles/common/scrollbar.scss +28 -0
  65. package/{src/client → client}/styles/common/sidebar.scss +0 -0
  66. package/{src/client → client}/styles/common/transition.scss +0 -0
  67. package/client/styles/css-vars.scss +62 -0
  68. package/{src/client → client}/styles/global/helper.scss +0 -0
  69. package/{src/client → client}/styles/global/i18n.scss +0 -0
  70. package/{src/client → client}/styles/global/index.scss +0 -0
  71. package/{src/client → client}/styles/global/nprogress.scss +0 -0
  72. package/{src/client → client}/styles/global/reset.scss +0 -0
  73. package/{src/client → client}/styles/index.scss +0 -0
  74. package/{src/client → client}/styles/mixins/config.scss +0 -0
  75. package/{src/client → client}/styles/mixins/index.scss +0 -0
  76. package/{src/client → client}/styles/mixins/size.scss +0 -0
  77. package/{src/client → client}/styles/mixins/variable.scss +0 -0
  78. package/{src/client → client}/styles/palette.scss +21 -2
  79. package/client/styles/third/katex.scss +3 -0
  80. package/client/styles/vars.scss +41 -0
  81. package/{src/client → client}/styles/widgets/banner.scss +0 -0
  82. package/{src/client → client}/types.ts +0 -0
  83. package/{src/client → client}/utils/helper.ts +22 -0
  84. package/{src/client → client}/utils/index.ts +0 -0
  85. package/client/utils/sidebar.ts +26 -0
  86. package/{src/client → client}/utils/time.ts +0 -0
  87. package/config/index.ts +18 -0
  88. package/dist/chunk-EAN2KU6W.mjs +1 -0
  89. package/dist/chunk-HMUGSKPK.mjs +40 -0
  90. package/dist/chunk-U5OMNIOK.js +1 -0
  91. package/dist/chunk-ZHHNO5RK.js +40 -0
  92. package/dist/{config-de04677b.d.ts → config-112ac884.d.ts} +37 -14
  93. package/dist/index.d.ts +65 -111
  94. package/dist/index.js +1 -1
  95. package/dist/index.mjs +1 -1
  96. package/dist/node/cli.js +7 -11
  97. package/dist/node/cli.mjs +7 -11
  98. package/dist/node/index.d.ts +3 -2
  99. package/dist/node/index.js +1 -1
  100. package/dist/node/index.mjs +1 -1
  101. package/{src/index.ts → index.ts} +1 -0
  102. package/{src/node → node}/build.ts +0 -0
  103. package/{src/node → node}/cli.ts +3 -2
  104. package/node/config.ts +156 -0
  105. package/{src/node → node}/index.ts +0 -0
  106. package/{src/node → node}/markdown/check.ts +0 -0
  107. package/node/markdown/highlight.ts +38 -0
  108. package/{src/node → node}/markdown/index.ts +30 -16
  109. package/{src/node → node}/markdown/markdown-it/container.ts +0 -0
  110. package/{src/node → node}/markdown/markdown-it/headings.ts +0 -0
  111. package/{src/node → node}/markdown/markdown-it/highlightLines.ts +1 -1
  112. package/{src/node → node}/markdown/markdown-it/katex.ts +0 -0
  113. package/{src/node → node}/markdown/markdown-it/parseHeader.ts +0 -0
  114. package/node/markdown/markdownToVue.ts +274 -0
  115. package/{src/node → node}/markdown/slugify.ts +0 -0
  116. package/{src/node → node}/options.ts +18 -2
  117. package/{src/node → node}/plugins/extendConfig.ts +5 -3
  118. package/node/plugins/index.ts +224 -0
  119. package/{src/node → node}/plugins/preset.ts +8 -8
  120. package/{src/node → node}/plugins/unocss.ts +0 -0
  121. package/{src/node → node}/plugins/valaxy.ts +0 -0
  122. package/{src/node → node}/rss.ts +1 -1
  123. package/{src/node → node}/server.ts +0 -0
  124. package/{src/node → node}/shims.d.ts +0 -5
  125. package/{src/node → node}/utils/cli.ts +1 -1
  126. package/node/utils/getGitTimestamp.ts +13 -0
  127. package/node/utils/index.ts +59 -0
  128. package/node/utils/net.ts +20 -0
  129. package/{src/node → node}/vite.ts +5 -1
  130. package/package.json +32 -13
  131. package/shared/index.ts +1 -0
  132. package/tsup.config.ts +7 -4
  133. package/{src/types → types}/config.ts +31 -108
  134. package/types/data.ts +31 -0
  135. package/{src/types → types}/index.ts +1 -0
  136. package/{src/types → types}/posts.ts +6 -1
  137. package/dist/chunk-6LIOFBAA.mjs +0 -1
  138. package/dist/chunk-HRARZPSA.js +0 -83
  139. package/dist/chunk-N6HD5SHF.mjs +0 -83
  140. package/dist/chunk-V3BMKLEW.js +0 -1
  141. package/src/client/components/PostCard.vue +0 -68
  142. package/src/client/components/ValaxyMd.vue +0 -71
  143. package/src/client/composables/features/index.ts +0 -1
  144. package/src/client/composables/features/katex.ts +0 -15
  145. package/src/client/composables/search/algolia.ts +0 -115
  146. package/src/client/config.ts +0 -51
  147. package/src/client/styles/common/code.scss +0 -207
  148. package/src/client/styles/common/scrollbar.scss +0 -34
  149. package/src/client/styles/css-vars.scss +0 -39
  150. package/src/client/styles/vars.scss +0 -27
  151. package/src/node/config.ts +0 -52
  152. package/src/node/markdown/highlight.ts +0 -50
  153. package/src/node/plugins/index.ts +0 -120
  154. package/src/node/plugins/markdown.ts +0 -57
  155. package/src/node/utils/index.ts +0 -26
package/README.md CHANGED
@@ -7,7 +7,3 @@ Read [YunYouJun/valaxy](https://github.com/YunYouJun/valaxy) for more info.
7
7
  ## FAQ
8
8
 
9
9
  - `exports`: `src/index.ts` for virtual module
10
-
11
- ### Downgrade vite-plugin-md to `v0.13.1`
12
-
13
- `v0.14.0` has some problem with `wrapperComponent`.
File without changes
File without changes
@@ -0,0 +1,84 @@
1
+ <script lang="ts" setup>
2
+ import { useI18n } from 'vue-i18n'
3
+ import type { Post } from '../../types'
4
+ import { usePostProperty } from '~/composables'
5
+
6
+ const props = defineProps<{
7
+ post: Post
8
+ }>()
9
+
10
+ const { t } = useI18n()
11
+
12
+ const { icon, styles } = usePostProperty(props.post.type)
13
+ </script>
14
+
15
+ <template>
16
+ <YunCard m="y-4 auto" :class="post.cover ? 'post-card-image' : 'post-card'" :style="styles">
17
+ <div class="flex flex-1 of-hidden justify-start items-start post-card-info" w="full">
18
+ <img
19
+ v-if="post.cover"
20
+ :src="post.cover"
21
+ :alt="t('post.cover')"
22
+ w="40%"
23
+ h="54"
24
+ class="object-cover object-center md:shadow"
25
+ >
26
+
27
+ <div class="post-card-image-info-text flex-1" w="full">
28
+ <div class="flex flex-col flex-1 justify-center items-center" w="full">
29
+ <AppLink
30
+ class="post-title-link"
31
+ :to="post.path || ''"
32
+ m="t-3"
33
+ >
34
+ <div class="flex justify-center items-center title text-2xl" font="serif black">
35
+ <div v-if="post.type" class="inline-flex" m="r-1" :class="icon" />{{ post.title }}
36
+ </div>
37
+ </AppLink>
38
+
39
+ <YunPostMeta :frontmatter="post" />
40
+
41
+ <div v-if="post.excerpt" class="markdown-body" text="left" w="full" p="x-6 lt-sm:4" v-html="post.excerpt" />
42
+ <div m="b-5" />
43
+
44
+ <a
45
+ v-if="post.url"
46
+ :href="post.url"
47
+ class="post-link-btn shadow hover:shadow-md"
48
+ rounded
49
+ target="_blank"
50
+ m="b-4"
51
+ >
52
+ {{ t('post.view_link') }}
53
+ </a>
54
+ </div>
55
+ </div>
56
+ </div>
57
+
58
+ <!-- always show -->
59
+ <div w="full" class="yun-card-actions flex justify-between" border="t" text="sm">
60
+ <div class="inline-flex">
61
+ <router-link
62
+ v-if="post.categories"
63
+ :to="{
64
+ path: '/categories/',
65
+ query: { category: Array.isArray(post.categories) ? post.categories[post.categories.length - 1] : post.categories },
66
+ }"
67
+ class="post-categories inline-flex justify-center items-center" m="l-2"
68
+ >
69
+ <div m="x-1" i-ri-folder-2-line />
70
+ {{ Array.isArray(post.categories) ? post.categories.join(' > ') : post.categories }}
71
+ </router-link>
72
+ </div>
73
+
74
+ <div class="post-tags inline-flex" m="r-2">
75
+ <template v-if="post.tags">
76
+ <router-link v-for="tag, i in post.tags" :key="i" :to="{ path: '/tags/', query: { tag } }" m="x-1" class="post-tag inline-flex justify-center items-center">
77
+ <div m="r-1" i-ri-price-tag-3-line />
78
+ {{ tag }}
79
+ </router-link>
80
+ </template>
81
+ </div>
82
+ </div>
83
+ </YunCard>
84
+ </template>
File without changes
File without changes
File without changes
@@ -3,7 +3,7 @@ import { capitalize, computed } from 'vue'
3
3
  import { useConfig, useThemeConfig } from 'valaxy'
4
4
  import { useI18n } from 'vue-i18n'
5
5
 
6
- import pkg from '~/../../package.json'
6
+ import pkg from '../../package.json'
7
7
 
8
8
  const { t } = useI18n()
9
9
 
@@ -0,0 +1,74 @@
1
+ <script lang="ts" setup>
2
+ import type { Post } from 'valaxy'
3
+ import { onMounted, ref } from 'vue'
4
+ import { useI18n } from 'vue-i18n'
5
+ import { useAplayer, useCodePen } from '~/composables'
6
+ import { useCopyCode } from '~/composables/copy-code'
7
+ import { wrapTable } from '~/utils'
8
+
9
+ const props = defineProps<{
10
+ frontmatter: Post
11
+ excerpt?: string
12
+ }>()
13
+
14
+ const { t } = useI18n()
15
+
16
+ const content = ref()
17
+ function updateDom() {
18
+ wrapTable(content.value)
19
+ }
20
+
21
+ onMounted(() => {
22
+ updateDom()
23
+ })
24
+
25
+ // widgets
26
+ if (props.frontmatter.aplayer)
27
+ useAplayer()
28
+
29
+ if (props.frontmatter.codepen)
30
+ useCodePen()
31
+
32
+ useCopyCode()
33
+ </script>
34
+
35
+ <template>
36
+ <Transition appear>
37
+ <article v-if="$slots.default" :class="frontmatter.markdown !== false && 'markdown-body'">
38
+ <slot ref="content" @vnode-updated="updateDom" />
39
+
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>
51
+ </div>
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>
64
+ </template>
65
+
66
+ <style lang="scss">
67
+ .markdown-body {
68
+ .end {
69
+ .line {
70
+ height: 1px;
71
+ }
72
+ }
73
+ }
74
+ </style>
@@ -1,9 +1,11 @@
1
1
  <script lang="ts" setup>
2
+ // this is a runtime toc
3
+ // prebuild toc see composables/outline.ts
2
4
  import { onMounted, ref, watch } from 'vue'
3
5
  import { useI18n } from 'vue-i18n'
4
6
  import { useRoute } from 'vue-router'
5
7
 
6
- import type { Header } from '../../node/markdown'
8
+ import type { Header } from '../../types'
7
9
  import { useActiveSidebarLinks } from '~/composables'
8
10
  import { useConfig } from '~/config'
9
11
 
@@ -66,8 +68,6 @@ if (import.meta.hot) {
66
68
  }, 600)
67
69
  })
68
70
  }
69
-
70
- // todo mobile toc widget
71
71
  </script>
72
72
 
73
73
  <template>
File without changes
File without changes
@@ -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
+ }
File without changes
File without changes
File without changes
@@ -5,7 +5,7 @@ export * from './tag'
5
5
 
6
6
  // common
7
7
  export * from './common'
8
- export * from './features'
8
+ // export * from './features'
9
9
  export * from './helper'
10
10
  export * from './dark'
11
11
  export * from './layout'
File without changes
@@ -0,0 +1,168 @@
1
+ import type { Ref } from 'vue'
2
+ import { onMounted, onUnmounted, onUpdated } from 'vue'
3
+ import type { Header } from '../../types'
4
+ import { throttleAndDebounce } from '~/utils'
5
+
6
+ interface HeaderWithChildren extends Header {
7
+ children?: Header[]
8
+ hidden?: boolean
9
+ }
10
+
11
+ interface MenuItemWithLinkAndChildren {
12
+ text: string
13
+ link: string
14
+ children?: MenuItemWithLinkAndChildren[]
15
+ hidden?: boolean
16
+ lang?: string
17
+ }
18
+
19
+ export function resolveHeaders(headers: Header[]) {
20
+ return mapHeaders(groupHeaders(headers))
21
+ }
22
+
23
+ function groupHeaders(headers: Header[]): HeaderWithChildren[] {
24
+ headers = headers.map(h => Object.assign({}, h))
25
+
26
+ let lastH2: HeaderWithChildren | undefined
27
+
28
+ for (const h of headers) {
29
+ if (h.level === 2)
30
+ lastH2 = h
31
+
32
+ else if (lastH2 && h.level <= 3)
33
+ (lastH2.children || (lastH2.children = [])).push(h)
34
+ }
35
+
36
+ return headers.filter(h => h.level === 2)
37
+ }
38
+
39
+ function mapHeaders(
40
+ headers: HeaderWithChildren[],
41
+ ): MenuItemWithLinkAndChildren[] {
42
+ return headers.map(header => ({
43
+ text: header.title,
44
+ link: `#${header.slug}`,
45
+ children: header.children ? mapHeaders(header.children) : undefined,
46
+ hidden: header.hidden,
47
+ lang: header.lang,
48
+ }))
49
+ }
50
+
51
+ // magic number to avoid repeated retrieval
52
+ const PAGE_OFFSET = 56
53
+
54
+ export function useActiveAnchor(
55
+ container: Ref<HTMLElement>,
56
+ marker: Ref<HTMLElement>,
57
+ ) {
58
+ const onScroll = throttleAndDebounce(setActiveLink, 100)
59
+
60
+ let prevActiveLink: HTMLAnchorElement | null = null
61
+
62
+ onMounted(() => {
63
+ requestAnimationFrame(setActiveLink)
64
+ window.addEventListener('scroll', onScroll)
65
+ })
66
+
67
+ onUpdated(() => {
68
+ // sidebar update means a route change
69
+ activateLink(location.hash)
70
+ })
71
+
72
+ onUnmounted(() => {
73
+ window.removeEventListener('scroll', onScroll)
74
+ })
75
+
76
+ function setActiveLink() {
77
+ const links = [].slice.call(
78
+ container.value.querySelectorAll('.outline-link'),
79
+ ) as HTMLAnchorElement[]
80
+
81
+ const anchors = [].slice
82
+ .call(document.querySelectorAll('.content .header-anchor'))
83
+ .filter((anchor: HTMLAnchorElement) => {
84
+ return links.some((link) => {
85
+ return link.hash === anchor.hash && anchor.offsetParent !== null
86
+ })
87
+ }) as HTMLAnchorElement[]
88
+
89
+ const scrollY = window.scrollY
90
+ const innerHeight = window.innerHeight
91
+ const offsetHeight = (document.querySelector('.yun-main') as HTMLElement)!.offsetHeight
92
+ const isBottom = (scrollY + innerHeight) === offsetHeight
93
+
94
+ // console.log(scrollY, innerHeight, offsetHeight)
95
+ // console.log(isBottom)
96
+
97
+ // page bottom - highlight last one
98
+ if (anchors.length && isBottom) {
99
+ activateLink(null)
100
+ return
101
+ }
102
+
103
+ // isTop
104
+ if (anchors.length && scrollY === 0)
105
+ activateLink('#')
106
+
107
+ for (let i = 0; i < anchors.length; i++) {
108
+ const anchor = anchors[i]
109
+ const nextAnchor = anchors[i + 1]
110
+
111
+ const [isActive, hash] = isAnchorActive(i, anchor, nextAnchor)
112
+
113
+ if (isActive) {
114
+ history.replaceState(null, document.title, hash || ' ')
115
+ activateLink(hash)
116
+ return
117
+ }
118
+ }
119
+ }
120
+
121
+ function activateLink(hash: string | null) {
122
+ if (prevActiveLink)
123
+ prevActiveLink.classList.remove('active')
124
+
125
+ if (hash !== null) {
126
+ prevActiveLink = container.value.querySelector(
127
+ `a[href="${decodeURIComponent(hash)}"]`,
128
+ ) as HTMLAnchorElement
129
+ }
130
+
131
+ const activeLink = prevActiveLink
132
+
133
+ const topOffset = 33
134
+
135
+ if (activeLink) {
136
+ activeLink.classList.add('active')
137
+ marker.value.style.top = `${activeLink.offsetTop + topOffset}px`
138
+ marker.value.style.opacity = '1'
139
+ }
140
+ else {
141
+ marker.value.style.top = `${topOffset}px`
142
+ marker.value.style.opacity = '0'
143
+ }
144
+ }
145
+ }
146
+
147
+ function getAnchorTop(anchor: HTMLAnchorElement): number {
148
+ return anchor.parentElement!.offsetTop - PAGE_OFFSET - 15
149
+ }
150
+
151
+ function isAnchorActive(
152
+ index: number,
153
+ anchor: HTMLAnchorElement,
154
+ nextAnchor: HTMLAnchorElement | undefined,
155
+ ): [boolean, string | null] {
156
+ const scrollTop = window.scrollY
157
+
158
+ if (index === 0 && scrollTop === 0)
159
+ return [true, null]
160
+
161
+ if (scrollTop < getAnchorTop(anchor))
162
+ return [false, null]
163
+
164
+ if (!nextAnchor || scrollTop < getAnchorTop(nextAnchor))
165
+ return [true, anchor.hash]
166
+
167
+ return [false, null]
168
+ }
File without changes
File without changes
@@ -1,8 +1,53 @@
1
1
  import type { Ref } from 'vue'
2
- import { onMounted, onUnmounted } from 'vue'
2
+ import { computed, onMounted, onUnmounted, ref } from 'vue'
3
+ import { useRoute } from 'vue-router'
4
+ import { useThemeConfig } from '..'
5
+ import { getSidebar } from '../utils/sidebar'
6
+ import { useFrontmatter } from './common'
3
7
 
4
8
  // todo: refactor
5
9
 
10
+ export function useSidebar() {
11
+ const route = useRoute()
12
+ const frontmatter = useFrontmatter()
13
+ const themeConfig = useThemeConfig()
14
+
15
+ const isOpen = ref(false)
16
+
17
+ const sidebar = computed(() => {
18
+ const sidebarConfig = themeConfig.value.sidebar
19
+ const relativePath = route.path
20
+
21
+ return sidebarConfig ? getSidebar(sidebarConfig, relativePath) : []
22
+ })
23
+
24
+ const hasSidebar = computed(() => {
25
+ // return frontmatter.value.sidebar !== false && sidebar.value.length > 0
26
+ return frontmatter.value.sidebar !== false
27
+ })
28
+
29
+ function open() {
30
+ isOpen.value = true
31
+ }
32
+
33
+ function close() {
34
+ isOpen.value = false
35
+ }
36
+
37
+ function toggle() {
38
+ isOpen.value ? close() : open()
39
+ }
40
+
41
+ return {
42
+ isOpen,
43
+ sidebar,
44
+ hasSidebar,
45
+ open,
46
+ close,
47
+ toggle,
48
+ }
49
+ }
50
+
6
51
  export function useActiveSidebarLinks(container: Ref<HTMLElement>, marker: Ref<HTMLElement>) {
7
52
  const onScroll = throttleAndDebounce(setActiveLink, 200)
8
53
 
File without changes
@@ -0,0 +1,75 @@
1
+ // @ts-expect-error virtual module @valaxyjs/config
2
+ import valaxyConfig from '@valaxyjs/config'
3
+ // @ts-expect-error virtual module @valaxyjs/context
4
+ import valaxyContext from '@valaxyjs/context'
5
+ import type { ComputedRef, InjectionKey, Ref } from 'vue'
6
+ import { computed, inject, readonly, shallowRef } from 'vue'
7
+ import type { ThemeConfig } from 'valaxy-theme-yun'
8
+ // import type { RouteMeta } from 'vue-router'
9
+ import type { PageData, ValaxyConfig } from '../types'
10
+
11
+ /**
12
+ * parse valaxy config
13
+ * @param data
14
+ * @returns
15
+ */
16
+ function parse<T=any>(data: string): T {
17
+ const parsed = JSON.parse(data)
18
+ return (import.meta.env.DEV ? readonly(parsed) : parsed) as T
19
+ }
20
+
21
+ interface ValaxyContext {
22
+ userRoot: string
23
+ }
24
+
25
+ export const valaxyConfigSymbol: InjectionKey<ComputedRef<ValaxyConfig<ThemeConfig>>> = Symbol('valaxy:config')
26
+ export const valaxyConfigRef = shallowRef<ValaxyConfig>(parse<ValaxyConfig>(valaxyConfig))
27
+
28
+ export const valaxyContextRef = shallowRef<ValaxyContext>(parse<ValaxyContext>(valaxyContext))
29
+ // export const valaxyDataRef = shallowRef<PageData>(parse(valaxyConfig))
30
+
31
+ // hmr
32
+ if (import.meta.hot) {
33
+ // /@valaxyjs/config must be static string
34
+ import.meta.hot.accept('/@valaxyjs/config', (m) => {
35
+ valaxyConfigRef.value = parse<ValaxyConfig>(m.default)
36
+ })
37
+
38
+ // context
39
+ import.meta.hot.accept('/@valaxyjs/context', (m) => {
40
+ valaxyContextRef.value = parse<ValaxyContext>(m.default)
41
+ })
42
+ }
43
+
44
+ export function initConfig() {
45
+ return computed(() => valaxyConfigRef.value)
46
+ }
47
+
48
+ export function initContext() {
49
+ return computed(() => valaxyContextRef.value)
50
+ }
51
+
52
+ /*
53
+ * get Config
54
+ * @returns
55
+ */
56
+ export function useConfig() {
57
+ const config = inject(valaxyConfigSymbol)
58
+ if (!config)
59
+ throw new Error('[Valaxy] config not properly injected in app')
60
+ return config!
61
+ }
62
+
63
+ /**
64
+ * getThemeConfig
65
+ * @returns
66
+ */
67
+ export function useThemeConfig() {
68
+ const config = useConfig()
69
+ return computed(() => config!.value.themeConfig)
70
+ }
71
+
72
+ export interface ValaxyData<T = any> {
73
+ page: Ref<PageData>
74
+ theme: Ref<T>
75
+ }
File without changes
File without changes
File without changes
File without changes
File without changes