valaxy 0.5.0 → 0.6.0

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 (55) hide show
  1. package/README.md +0 -4
  2. package/{dist/types/index.mjs → client/app/data.ts} +0 -0
  3. package/client/components/PostCard.vue +4 -2
  4. package/client/components/ValaxyBg.vue +1 -1
  5. package/client/components/ValaxyFooter.vue +1 -1
  6. package/client/components/ValaxyToc.vue +3 -3
  7. package/client/composables/outline.ts +181 -0
  8. package/client/composables/sidebar.ts +58 -1
  9. package/client/config.ts +30 -7
  10. package/client/main.ts +4 -1
  11. package/client/modules/valaxy.ts +33 -8
  12. package/client/shims.d.ts +6 -1
  13. package/client/styles/palette.scss +6 -2
  14. package/client/utils/helper.ts +22 -0
  15. package/client/utils/sidebar.ts +26 -0
  16. package/config/index.ts +18 -0
  17. package/dist/chunk-CP3UCJ2D.js +34 -0
  18. package/dist/chunk-HCVZ2UUO.mjs +34 -0
  19. package/dist/{config-7bd43d41.d.ts → config-ad23e743.d.ts} +6 -4
  20. package/dist/index.d.ts +363 -0
  21. package/dist/index.js +1 -0
  22. package/dist/index.mjs +1 -0
  23. package/dist/node/cli.js +7 -11
  24. package/dist/node/cli.mjs +7 -11
  25. package/dist/node/index.d.ts +2 -2
  26. package/dist/node/index.js +1 -1
  27. package/dist/node/index.mjs +1 -1
  28. package/index.ts +3 -0
  29. package/node/config.ts +9 -23
  30. package/node/markdown/index.ts +21 -13
  31. package/node/markdown/markdownToVue.ts +253 -0
  32. package/node/options.ts +16 -0
  33. package/node/plugins/extendConfig.ts +4 -3
  34. package/node/plugins/index.ts +103 -6
  35. package/node/plugins/preset.ts +6 -6
  36. package/node/rss.ts +1 -1
  37. package/node/utils/getGitTimestamp.ts +13 -0
  38. package/node/utils/index.ts +11 -0
  39. package/package.json +20 -7
  40. package/shared/index.ts +1 -0
  41. package/tsup.config.ts +5 -3
  42. package/types/config.ts +7 -4
  43. package/types/data.ts +31 -0
  44. package/types/index.ts +1 -0
  45. package/types/posts.ts +1 -1
  46. package/dist/chunk-RSQONJW3.mjs +0 -86
  47. package/dist/chunk-XQIGHIAX.js +0 -86
  48. package/dist/client/index.d.ts +0 -188
  49. package/dist/client/index.js +0 -1
  50. package/dist/client/index.mjs +0 -1
  51. package/dist/posts-32f55e33.d.ts +0 -117
  52. package/dist/types/index.d.ts +0 -8
  53. package/dist/types/index.js +0 -1
  54. package/index.d.ts +0 -3
  55. package/node/plugins/markdown.ts +0 -54
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
@@ -20,7 +20,8 @@ const { icon, styles } = usePostProperty(props.post.type)
20
20
  :src="post.cover"
21
21
  :alt="t('post.cover')"
22
22
  w="40%"
23
- class="object-contain self-center"
23
+ h="54"
24
+ class="object-cover object-center md:shadow"
24
25
  >
25
26
 
26
27
  <div class="post-card-image-info-text flex-1" w="full">
@@ -54,7 +55,8 @@ const { icon, styles } = usePostProperty(props.post.type)
54
55
  </div>
55
56
  </div>
56
57
 
57
- <div v-if="post.categories || post.tags" w="full" class="yun-card-actions flex justify-between" border="t" text="sm">
58
+ <!-- always show -->
59
+ <div w="full" class="yun-card-actions flex justify-between" border="t" text="sm">
58
60
  <div class="inline-flex">
59
61
  <router-link
60
62
  v-if="post.categories"
@@ -1,6 +1,6 @@
1
1
  <script lang="ts" setup>
2
2
  import { computed } from 'vue'
3
- import { useThemeConfig } from 'valaxy/client'
3
+ import { useThemeConfig } from 'valaxy'
4
4
  import { useCssVar } from '@vueuse/core'
5
5
  import { isDark } from '~/composables'
6
6
 
@@ -1,6 +1,6 @@
1
1
  <script lang="ts" setup>
2
2
  import { capitalize, computed } from 'vue'
3
- import { useConfig, useThemeConfig } from 'valaxy/client'
3
+ import { useConfig, useThemeConfig } from 'valaxy'
4
4
  import { useI18n } from 'vue-i18n'
5
5
 
6
6
  import pkg from '../../package.json'
@@ -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>
@@ -0,0 +1,181 @@
1
+ import type { Ref } from 'vue'
2
+ import { computed, onMounted, onUnmounted, onUpdated } from 'vue'
3
+ import { useRoute } from 'vue-router'
4
+ import type { Header } from '../../types'
5
+ import { throttleAndDebounce } from '~/utils'
6
+
7
+ interface HeaderWithChildren extends Header {
8
+ children?: Header[]
9
+ hidden?: boolean
10
+ }
11
+
12
+ interface MenuItemWithLinkAndChildren {
13
+ text: string
14
+ link: string
15
+ children?: MenuItemWithLinkAndChildren[]
16
+ hidden?: boolean
17
+ lang?: string
18
+ }
19
+
20
+ export function resolveHeaders(headers: Header[]) {
21
+ return mapHeaders(groupHeaders(headers))
22
+ }
23
+
24
+ function groupHeaders(headers: Header[]): HeaderWithChildren[] {
25
+ headers = headers.map(h => Object.assign({}, h))
26
+
27
+ let lastH2: HeaderWithChildren | undefined
28
+
29
+ for (const h of headers) {
30
+ if (h.level === 2)
31
+ lastH2 = h
32
+
33
+ else if (lastH2 && h.level <= 3)
34
+ (lastH2.children || (lastH2.children = [])).push(h)
35
+ }
36
+
37
+ return headers.filter(h => h.level === 2)
38
+ }
39
+
40
+ function mapHeaders(
41
+ headers: HeaderWithChildren[],
42
+ ): MenuItemWithLinkAndChildren[] {
43
+ return headers.map(header => ({
44
+ text: header.title,
45
+ link: `#${header.slug}`,
46
+ children: header.children ? mapHeaders(header.children) : undefined,
47
+ hidden: header.hidden,
48
+ lang: header.lang,
49
+ }))
50
+ }
51
+
52
+ // magic number to avoid repeated retrieval
53
+ const PAGE_OFFSET = 56
54
+
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
+ export function useActiveAnchor(
68
+ container: Ref<HTMLElement>,
69
+ marker: Ref<HTMLElement>,
70
+ ) {
71
+ const onScroll = throttleAndDebounce(setActiveLink, 100)
72
+
73
+ let prevActiveLink: HTMLAnchorElement | null = null
74
+
75
+ onMounted(() => {
76
+ requestAnimationFrame(setActiveLink)
77
+ window.addEventListener('scroll', onScroll)
78
+ })
79
+
80
+ onUpdated(() => {
81
+ // sidebar update means a route change
82
+ activateLink(location.hash)
83
+ })
84
+
85
+ onUnmounted(() => {
86
+ window.removeEventListener('scroll', onScroll)
87
+ })
88
+
89
+ function setActiveLink() {
90
+ const links = [].slice.call(
91
+ container.value.querySelectorAll('.outline-link'),
92
+ ) as HTMLAnchorElement[]
93
+
94
+ const anchors = [].slice
95
+ .call(document.querySelectorAll('.content .header-anchor'))
96
+ .filter((anchor: HTMLAnchorElement) => {
97
+ return links.some((link) => {
98
+ return link.hash === anchor.hash && anchor.offsetParent !== null
99
+ })
100
+ }) as HTMLAnchorElement[]
101
+
102
+ const scrollY = window.scrollY
103
+ const innerHeight = window.innerHeight
104
+ const offsetHeight = (document.querySelector('.yun-main') as HTMLElement)!.offsetHeight
105
+ const isBottom = (scrollY + innerHeight) === offsetHeight
106
+
107
+ // console.log(scrollY, innerHeight, offsetHeight)
108
+ // console.log(isBottom)
109
+
110
+ // page bottom - highlight last one
111
+ if (anchors.length && isBottom) {
112
+ activateLink(null)
113
+ return
114
+ }
115
+
116
+ // isTop
117
+ if (anchors.length && scrollY === 0)
118
+ activateLink('#')
119
+
120
+ for (let i = 0; i < anchors.length; i++) {
121
+ const anchor = anchors[i]
122
+ const nextAnchor = anchors[i + 1]
123
+
124
+ const [isActive, hash] = isAnchorActive(i, anchor, nextAnchor)
125
+
126
+ if (isActive) {
127
+ history.replaceState(null, document.title, hash || ' ')
128
+ activateLink(hash)
129
+ return
130
+ }
131
+ }
132
+ }
133
+
134
+ function activateLink(hash: string | null) {
135
+ if (prevActiveLink)
136
+ prevActiveLink.classList.remove('active')
137
+
138
+ if (hash !== null) {
139
+ prevActiveLink = container.value.querySelector(
140
+ `a[href="${decodeURIComponent(hash)}"]`,
141
+ ) as HTMLAnchorElement
142
+ }
143
+
144
+ const activeLink = prevActiveLink
145
+
146
+ const topOffset = 33
147
+
148
+ if (activeLink) {
149
+ activeLink.classList.add('active')
150
+ marker.value.style.top = `${activeLink.offsetTop + topOffset}px`
151
+ marker.value.style.opacity = '1'
152
+ }
153
+ else {
154
+ marker.value.style.top = `${topOffset}px`
155
+ marker.value.style.opacity = '0'
156
+ }
157
+ }
158
+ }
159
+
160
+ function getAnchorTop(anchor: HTMLAnchorElement): number {
161
+ return anchor.parentElement!.offsetTop - PAGE_OFFSET - 15
162
+ }
163
+
164
+ function isAnchorActive(
165
+ index: number,
166
+ anchor: HTMLAnchorElement,
167
+ nextAnchor: HTMLAnchorElement | undefined,
168
+ ): [boolean, string | null] {
169
+ const scrollTop = window.scrollY
170
+
171
+ if (index === 0 && scrollTop === 0)
172
+ return [true, null]
173
+
174
+ if (scrollTop < getAnchorTop(anchor))
175
+ return [false, null]
176
+
177
+ if (!nextAnchor || scrollTop < getAnchorTop(nextAnchor))
178
+ return [true, anchor.hash]
179
+
180
+ return [false, null]
181
+ }
@@ -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
 
@@ -113,3 +158,15 @@ function throttleAndDebounce(fn: () => void, delay: number): () => void {
113
158
  }
114
159
  }
115
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/config.ts CHANGED
@@ -1,28 +1,43 @@
1
1
  // @ts-expect-error virtual module @valaxyjs/config
2
2
  import valaxyConfig from '@valaxyjs/config'
3
- import type { ComputedRef, InjectionKey } from 'vue'
3
+ // @ts-expect-error virtual module @valaxyjs/context
4
+ import valaxyContext from '@valaxyjs/context'
5
+ import type { ComputedRef, InjectionKey, Ref } from 'vue'
4
6
  import { computed, inject, readonly, shallowRef } from 'vue'
5
7
  import type { ThemeConfig } from 'valaxy-theme-yun'
6
- import type { ValaxyConfig } from '../types'
8
+ // import type { RouteMeta } from 'vue-router'
9
+ import type { PageData, ValaxyConfig } from '../types'
7
10
 
8
11
  /**
9
12
  * parse valaxy config
10
13
  * @param data
11
14
  * @returns
12
15
  */
13
- function parse(data: string): ValaxyConfig {
16
+ function parse<T=any>(data: string): T {
14
17
  const parsed = JSON.parse(data)
15
- return (import.meta.env.DEV ? readonly(parsed) : parsed) as ValaxyConfig
18
+ return (import.meta.env.DEV ? readonly(parsed) : parsed) as T
19
+ }
20
+
21
+ interface ValaxyContext {
22
+ userRoot: string
16
23
  }
17
24
 
18
25
  export const valaxyConfigSymbol: InjectionKey<ComputedRef<ValaxyConfig<ThemeConfig>>> = Symbol('valaxy:config')
19
- export const valaxyConfigRef = shallowRef<ValaxyConfig>(parse(valaxyConfig))
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))
20
30
 
21
31
  // hmr
22
32
  if (import.meta.hot) {
23
33
  // /@valaxyjs/config must be static string
24
34
  import.meta.hot.accept('/@valaxyjs/config', (m) => {
25
- valaxyConfigRef.value = parse(m.default)
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)
26
41
  })
27
42
  }
28
43
 
@@ -30,6 +45,10 @@ export function initConfig() {
30
45
  return computed(() => valaxyConfigRef.value)
31
46
  }
32
47
 
48
+ export function initContext() {
49
+ return computed(() => valaxyContextRef.value)
50
+ }
51
+
33
52
  /*
34
53
  * get Config
35
54
  * @returns
@@ -37,7 +56,7 @@ export function initConfig() {
37
56
  export function useConfig() {
38
57
  const config = inject(valaxyConfigSymbol)
39
58
  if (!config)
40
- throw new Error('[Valaxy] config not properly injected in qpp')
59
+ throw new Error('[Valaxy] config not properly injected in app')
41
60
  return config!
42
61
  }
43
62
 
@@ -50,3 +69,7 @@ export function useThemeConfig() {
50
69
  return computed(() => config!.value.themeConfig)
51
70
  }
52
71
 
72
+ export interface ValaxyData<T = any> {
73
+ page: Ref<PageData>
74
+ theme: Ref<T>
75
+ }
package/client/main.ts CHANGED
@@ -18,7 +18,10 @@ export const createApp = ViteSSG(
18
18
  {
19
19
  routes,
20
20
  base: import.meta.env.BASE_URL,
21
- scrollBehavior() { return { top: 0 } },
21
+ scrollBehavior(to, from) {
22
+ if (to.path !== from.path)
23
+ return { top: 0 }
24
+ },
22
25
  },
23
26
  (ctx) => {
24
27
  // install all modules under `modules/`
@@ -10,7 +10,10 @@ import { createI18n } from 'vue-i18n'
10
10
 
11
11
  import { useStorage } from '@vueuse/core'
12
12
 
13
- import { initConfig, valaxyConfigSymbol } from '../config'
13
+ import type { Router } from 'vue-router'
14
+ import type { PageDataPayload } from '../../types'
15
+ import { initConfig, initContext, valaxyConfigSymbol } from '../config'
16
+ import { ensureSuffix } from '@antfu/utils'
14
17
 
15
18
  import type { UserModule } from '~/types'
16
19
 
@@ -33,14 +36,16 @@ import messages from '/@valaxyjs/locales'
33
36
  // import zh from '../../../../../demo/yun/locales/zh-CN.yml'
34
37
  // import en from '../../../../../demo/yun/locales/en.yml'
35
38
 
36
- function shouldHotReload(payload: any): boolean {
39
+ function shouldHotReload(payload: PageDataPayload): boolean {
37
40
  const payloadPath = payload.path.replace(/(\bindex)?\.md$/, '')
38
41
  const locationPath = location.pathname.replace(/(\bindex)?\.html$/, '')
39
- return payloadPath === locationPath
42
+ // console.log(payloadPath, locationPath)
43
+ return ensureSuffix('/', payloadPath) === ensureSuffix('/', locationPath)
40
44
  }
41
45
 
42
46
  export const install: UserModule = ({ app, router }) => {
43
47
  // inject valaxy config before modules
48
+ const ctx = initContext()
44
49
  const config = initConfig()
45
50
  app.provide(valaxyConfigSymbol, config)
46
51
 
@@ -54,11 +59,31 @@ export const install: UserModule = ({ app, router }) => {
54
59
  })
55
60
  app.use(i18n)
56
61
 
57
- // for dev
58
- if (__DEV__) {
59
- import.meta.hot!.on('valaxy:pageHeaders', (payload) => {
60
- if (shouldHotReload(payload))
61
- router.currentRoute.value.meta.headers = payload.pageHeaders
62
+ router.isReady().then(() => {
63
+ handleHMR(router)
64
+ })
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
+ }
78
+
79
+ function handleHMR(router: Router): void {
80
+ // update route.data on HMR updates of active page
81
+ if (import.meta.hot) {
82
+ import.meta.hot!.on('valaxy:pageData', (payload: PageDataPayload) => {
83
+ if (shouldHotReload(payload)) {
84
+ // console.log(payload.pageData.headers)
85
+ Object.assign(router.currentRoute.value.meta, payload.pageData)
86
+ }
62
87
  })
63
88
  }
64
89
  }
package/client/shims.d.ts CHANGED
@@ -3,7 +3,7 @@ import 'vue-router'
3
3
  import type { Post } from 'valaxy'
4
4
  import type { Header } from '../node/markdown'
5
5
 
6
- // with vite-plugin-md, markdowns can be treat as Vue components
6
+ // markdowns can be treat as Vue components
7
7
  declare module '*.md' {
8
8
  import type { DefineComponent } from 'vue'
9
9
  const component: DefineComponent<{}, {}, any>
@@ -23,6 +23,11 @@ declare module '@valaxyjs/config' {
23
23
  export default config
24
24
  }
25
25
 
26
+ declare module '@valaxyjs/context' {
27
+ const ctx: string
28
+ export default ctx
29
+ }
30
+
26
31
  declare module '/@valaxyjs/locales' {
27
32
  const messages: {}
28
33
  export default messages
@@ -37,6 +37,8 @@ $colors: map.merge(
37
37
  $light: () !default;
38
38
  $light: map.merge(
39
39
  (
40
+ "c-brand": $c-primary,
41
+
40
42
  "border-color": #222,
41
43
 
42
44
  "c-bg": white,
@@ -44,6 +46,7 @@ $light: map.merge(
44
46
  "c-bg-dark": #fafafa,
45
47
  "c-text": #333,
46
48
  "c-text-light": #555,
49
+ "c-text-lighter": #666,
47
50
  "c-text-dark": #111,
48
51
 
49
52
  "c-primary-rgb": #{red($c-primary),
@@ -53,6 +56,7 @@ $light: map.merge(
53
56
  blue($c-primary)},
54
57
 
55
58
  "c-link": get-css-var("c-primary-dark"),
59
+ "c-divider": rgba(60, 60, 60, 0.2),
56
60
  ),
57
61
  $light
58
62
  );
@@ -67,8 +71,8 @@ $dark: map.merge(
67
71
  "c-bg-dark": #1a1a1a,
68
72
 
69
73
  "c-text": #f2f2f2,
70
- "c-text-light": #eee,
71
- "c-text-lighter": #ddd,
74
+ "c-text-light": #ddd,
75
+ "c-text-lighter": #eee,
72
76
  "c-text-dark": rgba(#ebebeb, 0.8),
73
77
  "c-link": map.get($colors, "primary-light"),
74
78
  ),
@@ -28,3 +28,25 @@ export const wrapTable = (container: HTMLElement | Document = document) => {
28
28
  wrap(el, 'table-container')
29
29
  })
30
30
  }
31
+
32
+ export function throttleAndDebounce(fn: () => void, delay: number): () => void {
33
+ let timeout: number
34
+ let called = false
35
+
36
+ return () => {
37
+ if (timeout)
38
+ clearTimeout(timeout)
39
+
40
+ if (!called) {
41
+ fn()
42
+ called = true
43
+ setTimeout(() => {
44
+ called = false
45
+ }, delay)
46
+ }
47
+ else {
48
+ // @ts-expect-error browser setTimeout
49
+ timeout = setTimeout(fn, delay)
50
+ }
51
+ }
52
+ }
@@ -0,0 +1,26 @@
1
+ import type { YunTheme } from 'valaxy-theme-yun'
2
+ import { ensurePrefix } from '@antfu/utils'
3
+
4
+ /**
5
+ * Get the `Sidebar` from sidebar option. This method will ensure to get correct
6
+ * sidebar config from `MultiSideBarConfig` with various path combinations such
7
+ * as matching `guide/` and `/guide/`. If no matching config was found, it will
8
+ * return empty array.
9
+ */
10
+ export function getSidebar(
11
+ sidebar: YunTheme.Sidebar,
12
+ path: string,
13
+ ) {
14
+ if (Array.isArray(sidebar))
15
+ return sidebar
16
+
17
+ path = ensurePrefix('/', path)
18
+
19
+ for (const dir in sidebar) {
20
+ // make sure the multi sidebar key starts with slash too
21
+ if (path.startsWith(ensurePrefix('/', dir)))
22
+ return sidebar[dir]
23
+ }
24
+
25
+ return []
26
+ }
@@ -0,0 +1,18 @@
1
+ import type { YunTheme } from 'valaxy-theme-yun'
2
+ import type { UserConfig } from '../types'
3
+
4
+ /**
5
+ * Type config helper
6
+ */
7
+ export function defineConfig(config: UserConfig<YunTheme.Config>) {
8
+ return config
9
+ }
10
+
11
+ /**
12
+ * Type config helper for custom theme config
13
+ */
14
+ export function defineConfigWithTheme<ThemeConfig>(
15
+ config: UserConfig<ThemeConfig>,
16
+ ) {
17
+ return config
18
+ }