valaxy 0.19.13 → 0.20.0-beta.5

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 (33) hide show
  1. package/client/components/ValaxyFootnoteTooltip.vue +0 -2
  2. package/client/components/ValaxyOverlay.vue +1 -1
  3. package/client/composables/helper/index.ts +2 -0
  4. package/client/composables/helper/useScreenSize.ts +22 -0
  5. package/client/composables/outline/anchor.ts +64 -63
  6. package/client/composables/post/index.ts +1 -0
  7. package/client/composables/post/usePagination.ts +65 -0
  8. package/client/composables/sidebar.ts +3 -40
  9. package/client/modules/floating-vue.ts +9 -1
  10. package/client/stores/app.ts +0 -7
  11. package/client/styles/common/code.scss +2 -2
  12. package/client/styles/components/code-group.scss +3 -4
  13. package/client/styles/palette.scss +9 -9
  14. package/client/utils/helper.ts +7 -0
  15. package/dist/{chunk-X25DVJU7.mjs → chunk-UCIXONQT.mjs} +34 -34
  16. package/dist/{chunk-J5LLA2M3.cjs → chunk-V2BCVIX4.cjs} +34 -34
  17. package/dist/{config-BNXiUUii.d.cts → config-DRImYfNf.d.cts} +4 -0
  18. package/dist/{config-BNXiUUii.d.ts → config-DRImYfNf.d.ts} +4 -0
  19. package/dist/node/cli/index.cjs +1 -1
  20. package/dist/node/cli/index.mjs +1 -1
  21. package/dist/node/index.cjs +1 -1
  22. package/dist/node/index.d.cts +1 -1
  23. package/dist/node/index.d.ts +1 -1
  24. package/dist/node/index.mjs +1 -1
  25. package/dist/types/index.cjs +1 -1
  26. package/dist/types/index.d.cts +2 -2
  27. package/dist/types/index.d.ts +2 -2
  28. package/dist/types/index.mjs +1 -1
  29. package/package.json +8 -9
  30. package/types/config.ts +4 -0
  31. /package/client/composables/{helper.ts → helper/useInvisibleElement.ts} +0 -0
  32. /package/dist/{chunk-LD7IYUN2.mjs → chunk-TNTV5UAJ.mjs} +0 -0
  33. /package/dist/{chunk-2PA6UTKF.cjs → chunk-VWINQN6R.cjs} +0 -0
@@ -11,8 +11,6 @@ export default Component
11
11
  </script>
12
12
 
13
13
  <style scoped>
14
- @import 'floating-vue/dist/style.css';
15
-
16
14
  div .v-popper {
17
15
  display: inline
18
16
  }
@@ -17,7 +17,7 @@ withDefaults(defineProps<{
17
17
  @use "valaxy/client/styles/mixins/index.scss" as *;
18
18
 
19
19
  .va-overlay {
20
- background-color: rgba(0, 0, 0, 0.3);
20
+ background-color: rgb(0 0 0 / 0.3);
21
21
  position: fixed;
22
22
  inset: 0;
23
23
  z-index: calc(var(--va-z-overlay) - 1);
@@ -0,0 +1,2 @@
1
+ export * from './useInvisibleElement'
2
+ export * from './useScreenSize'
@@ -0,0 +1,22 @@
1
+ import { useMediaQuery } from '@vueuse/core'
2
+
3
+ /**
4
+ * breakpoints ref https://tailwindcss.com/docs/screens
5
+ */
6
+ export function useScreenSize() {
7
+ const isXs = useMediaQuery('(max-width: 639px)')
8
+ const isSm = useMediaQuery('(min-width: 640px)')
9
+ const isMd = useMediaQuery('(min-width: 768px)')
10
+ const isLg = useMediaQuery('(min-width: 1024px)')
11
+ const isXl = useMediaQuery('(min-width: 1280px)')
12
+ const is2xl = useMediaQuery('(min-width: 1536px)')
13
+
14
+ return {
15
+ isXs,
16
+ isSm,
17
+ isMd,
18
+ isLg,
19
+ isXl,
20
+ is2xl,
21
+ }
22
+ }
@@ -1,12 +1,29 @@
1
1
  import type { Ref } from 'vue'
2
2
  import { onMounted, onUnmounted, onUpdated } from 'vue'
3
+ import { resolvedHeaders } from '@valaxyjs/utils'
3
4
  import { throttleAndDebounce } from '../../utils'
4
5
  import { useAside } from '../aside'
5
6
 
6
7
  // magic number to avoid repeated retrieval
7
- const PAGE_OFFSET = 56
8
+ const PAGE_OFFSET = 130
8
9
  const topOffset = 33
9
10
 
11
+ function getAbsoluteTop(element: HTMLElement): number {
12
+ let offsetTop = 0
13
+ while (element !== document.body) {
14
+ if (element === null) {
15
+ // child element is:
16
+ // - not attached to the DOM (display: none)
17
+ // - set to fixed position (not scrollable)
18
+ // - body or html element (null offsetParent)
19
+ return Number.NaN
20
+ }
21
+ offsetTop += element.offsetTop
22
+ element = element.offsetParent as HTMLElement
23
+ }
24
+ return offsetTop
25
+ }
26
+
10
27
  export function useActiveAnchor(
11
28
  container: Ref<HTMLElement>,
12
29
  marker: Ref<HTMLElement>,
@@ -30,63 +47,70 @@ export function useActiveAnchor(
30
47
  window.removeEventListener('scroll', onScroll)
31
48
  })
32
49
 
33
- function setActiveLink() {
34
- if (!isAsideEnabled.value)
50
+ const checkActiveLinkInViewport = () => {
51
+ const activeLink = prevActiveLink
52
+ if (!activeLink) {
53
+ // container.value.scrollIntoView({ behavior: 'smooth', block: 'start' })
35
54
  return
55
+ }
36
56
 
37
- const links = [].slice.call(
38
- container.value.querySelectorAll('.outline-link'),
39
- ) as HTMLAnchorElement[]
57
+ const top = activeLink.getBoundingClientRect().top
58
+ const bottom = activeLink.getBoundingClientRect().bottom
59
+
60
+ const parentEl = document.querySelector('.yun-aside') as HTMLElement
61
+ if (parentEl) {
62
+ if (top < parentEl.scrollTop)
63
+ parentEl.scrollTo({ top: 0, behavior: 'smooth' })
64
+ if (bottom > parentEl.offsetHeight + parentEl.scrollTop)
65
+ parentEl.scrollTo({ top: bottom + 40, behavior: 'smooth' })
66
+ }
67
+ }
40
68
 
41
- const anchors = [].slice
42
- .call(document.querySelectorAll('.content .header-anchor'))
43
- .filter((anchor: HTMLAnchorElement) => {
44
- return links.some((link) => {
45
- return link.hash === anchor.hash && anchor.offsetParent !== null
46
- })
47
- }) as HTMLAnchorElement[]
69
+ function setActiveLink() {
70
+ if (!isAsideEnabled.value)
71
+ return
48
72
 
49
73
  const scrollY = window.scrollY
50
74
  const innerHeight = window.innerHeight
51
75
  const offsetHeight = document.body.offsetHeight
52
76
  const isBottom = Math.abs(scrollY + innerHeight - offsetHeight) < 1
53
77
 
54
- // page bottom - highlight last one
55
- if (anchors.length && isBottom) {
56
- activateLink(anchors[anchors.length - 1].hash)
57
- // activateLink(null)
78
+ // resolvedHeaders may be repositioned, hidden or fix positioned
79
+ const headers = resolvedHeaders
80
+ .map(({ element, link }) => ({
81
+ link,
82
+ top: getAbsoluteTop(element),
83
+ }))
84
+ .filter(({ top }) => !Number.isNaN(top))
85
+ .sort((a, b) => a.top - b.top)
86
+
87
+ // no headers available for active link
88
+ if (!headers.length) {
89
+ activateLink(null)
58
90
  return
59
91
  }
60
92
 
61
- // isTop
62
- // if (anchors.length && scrollY === 0)
63
- // activateLink('#')
64
-
65
- for (let i = 0; i < anchors.length; i++) {
66
- const anchor = anchors[i]
67
- const nextAnchor = anchors[i + 1]
68
-
69
- const [isActive, hash] = isAnchorActive(i, anchor, nextAnchor)
70
-
71
- if (isActive) {
72
- activateLink(hash)
73
- return
74
- }
93
+ // page top
94
+ if (scrollY < 1) {
95
+ activateLink(null)
96
+ return
75
97
  }
76
- }
77
98
 
78
- const checkActiveLinkInViewport = () => {
79
- const activeLink = prevActiveLink
80
- if (!activeLink) {
81
- // container.value.scrollIntoView({ behavior: 'smooth', block: 'start' })
99
+ // page bottom - highlight last link
100
+ if (isBottom) {
101
+ activateLink(headers[headers.length - 1].link)
82
102
  return
83
103
  }
84
104
 
85
- const top = activeLink.getBoundingClientRect().top
86
- const bottom = activeLink.getBoundingClientRect().bottom
105
+ // find the last header above the top of viewport
106
+ let activeLink: string | null = null
107
+ for (const { link, top } of headers) {
108
+ if (top > scrollY + 4 + PAGE_OFFSET)
109
+ break
87
110
 
88
- if (top < topOffset || bottom > window.innerHeight - topOffset)
89
- activeLink.scrollIntoView()
111
+ activeLink = link
112
+ }
113
+ activateLink(activeLink)
90
114
  }
91
115
 
92
116
  function activateLink(hash: string | null) {
@@ -116,26 +140,3 @@ export function useActiveAnchor(
116
140
  }
117
141
  }
118
142
  }
119
-
120
- function getAnchorTop(anchor: HTMLAnchorElement): number {
121
- return anchor.parentElement!.offsetTop - PAGE_OFFSET - 15
122
- }
123
-
124
- function isAnchorActive(
125
- index: number,
126
- anchor: HTMLAnchorElement,
127
- nextAnchor: HTMLAnchorElement | undefined,
128
- ): [boolean, string | null] {
129
- const scrollTop = window.scrollY
130
-
131
- if (index === 0 && scrollTop === 0)
132
- return [true, null]
133
-
134
- if (scrollTop < getAnchorTop(anchor))
135
- return [false, null]
136
-
137
- if (!nextAnchor || scrollTop < getAnchorTop(nextAnchor))
138
- return [true, anchor.hash]
139
-
140
- return [false, null]
141
- }
@@ -6,6 +6,7 @@ import { sortByDate } from '../../utils'
6
6
  import { useRouterStore } from '../../stores'
7
7
 
8
8
  export * from './usePrevNext'
9
+ export * from './usePagination'
9
10
 
10
11
  export function usePostTitle(post: ComputedRef<Post>) {
11
12
  const { locale } = useI18n()
@@ -0,0 +1,65 @@
1
+ import { computed } from 'vue'
2
+ import { useRoute } from 'vue-router'
3
+
4
+ export function usePagination(options: {
5
+ /**
6
+ * Post 总数
7
+ */
8
+ total: number
9
+ /**
10
+ * 每页数量
11
+ */
12
+ pageSize: number
13
+ }) {
14
+ const route = useRoute()
15
+ const curPage = computed<number>(() => Number.parseInt((route.params as { page: string }).page || '1'))
16
+
17
+ const totalPages = computed(() => Math.ceil(options.total / options.pageSize))
18
+
19
+ /**
20
+ * 围绕的长度
21
+ */
22
+ const surLen = computed(() => {
23
+ if (curPage.value === 1 || curPage.value === totalPages.value)
24
+ return 3
25
+ else
26
+ return 2
27
+ })
28
+
29
+ function showPage(i: number) {
30
+ if (i === 1)
31
+ return true
32
+ else if (i === totalPages.value)
33
+ return true
34
+ return i > curPage.value - surLen.value && i < curPage.value + surLen.value
35
+ }
36
+
37
+ function getTo(i: number) {
38
+ if (i === 1)
39
+ return '/'
40
+ else return `/page/${i}`
41
+ }
42
+
43
+ const prevTo = computed(() => {
44
+ return getTo(curPage.value - 1)
45
+ })
46
+ const nextTo = computed(() => {
47
+ return getTo(curPage.value + 1)
48
+ })
49
+
50
+ const showPrev = computed(() => curPage.value > 1)
51
+ const showNext = computed(() => curPage.value < totalPages.value)
52
+
53
+ return {
54
+ curPage,
55
+ totalPages,
56
+ showPage,
57
+ surLen,
58
+
59
+ getTo,
60
+ prevTo,
61
+ nextTo,
62
+ showPrev,
63
+ showNext,
64
+ }
65
+ }
@@ -1,9 +1,10 @@
1
- import { computed, ref, watchEffect } from 'vue'
1
+ import { computed, ref } from 'vue'
2
2
  import { useFrontmatter } from './common'
3
- import { useLayout, useMobile } from './layout'
3
+ import { useLayout } from './layout'
4
4
 
5
5
  /**
6
6
  * helper for sidebar
7
+ * @inner
7
8
  */
8
9
  export function useSidebar() {
9
10
  const isOpen = ref(false)
@@ -37,41 +38,3 @@ export function useSidebar() {
37
38
  toggle,
38
39
  }
39
40
  }
40
-
41
- /**
42
- * dynamic left sidebar logic
43
- * - sidebar is hidden by default when home or mobile
44
- * - sidebar is shown by default when not home and not mobile
45
- * - sidebar can be toggled by user
46
- */
47
- export function useDynamicLeftSidebar() {
48
- const layout = useLayout()
49
- const isMobile = useMobile()
50
- const isOpen = ref(isMobile.value ? false : layout.value !== 'home')
51
-
52
- watchEffect(() => {
53
- if (isMobile.value)
54
- close()
55
- else if (layout.value !== 'home')
56
- open()
57
- })
58
-
59
- function open() {
60
- isOpen.value = true
61
- }
62
-
63
- function close() {
64
- isOpen.value = false
65
- }
66
-
67
- function toggle() {
68
- isOpen.value ? close() : open()
69
- }
70
-
71
- return {
72
- isOpen,
73
- open,
74
- close,
75
- toggle,
76
- }
77
- }
@@ -6,5 +6,13 @@ import type { DefaultTheme, ValaxyConfig } from 'valaxy/types'
6
6
  import type { ComputedRef } from 'vue'
7
7
 
8
8
  export async function install({ app }: ViteSSGContext, config: ComputedRef<ValaxyConfig<DefaultTheme.Config>>) {
9
- app.use(FloatingVue, config.value.siteConfig.floatingVue)
9
+ app.use(FloatingVue, Object.assign({
10
+ themes: {
11
+ tooltip: {
12
+ delay: {
13
+ show: 0,
14
+ },
15
+ },
16
+ },
17
+ }, config.value.siteConfig.floatingVue || {}))
10
18
  }
@@ -1,5 +1,4 @@
1
1
  import { acceptHMRUpdate, defineStore } from 'pinia'
2
- import { useToggle } from '@vueuse/core'
3
2
  import { ref } from 'vue'
4
3
  import { useMobile, useThemeConfig, useValaxyDark } from 'valaxy'
5
4
 
@@ -18,9 +17,6 @@ export const useAppStore = defineStore('app', () => {
18
17
  const isMobile = useMobile()
19
18
  const showLoading = ref(true)
20
19
 
21
- // right sidebar with toc
22
- const [isRightSidebarOpen, toggleRightSidebar] = useToggle(false)
23
-
24
20
  return {
25
21
  isMobile,
26
22
  // for dark
@@ -30,9 +26,6 @@ export const useAppStore = defineStore('app', () => {
30
26
  toggleDarkWithTransition,
31
27
 
32
28
  showLoading,
33
-
34
- isRightSidebarOpen,
35
- toggleRightSidebar,
36
29
  }
37
30
  })
38
31
 
@@ -25,7 +25,7 @@ html:not(.dark) .vp-code-dark {
25
25
  }
26
26
  }
27
27
 
28
- @media (width <= 639px) {
28
+ @media (width <= 639.9px) {
29
29
  .markdown-body li div[class*="language-"] {
30
30
  border-radius: 6px 0 0 6px;
31
31
  }
@@ -232,7 +232,7 @@ html:not(.dark) .vp-code-dark {
232
232
  height: 24px;
233
233
  opacity: 1;
234
234
  cursor: pointer;
235
- background-image: linear-gradient(-180deg,rgba(0,0,0,0) 0%,var(--va-c-bg-dark) 100%);
235
+ background-image: linear-gradient(-180deg,rgb(0 0 0 / 0) 0%,var(--va-c-bg-dark) 100%);
236
236
 
237
237
  &::before {
238
238
  display: block;
@@ -5,12 +5,11 @@
5
5
  .vp-code-group .tabs {
6
6
  position: relative;
7
7
  display: flex;
8
- margin-right: -24px;
9
- margin-left: -24px;
8
+ margin-right: -1rem;
9
+ margin-left: -1rem;
10
10
  padding: 0 12px;
11
11
  background-color: var(--va-code-tab-bg);
12
- overflow-x: auto;
13
- overflow-y: hidden;
12
+ overflow: auto hidden;
14
13
  box-shadow: inset 0 -1px var(--va-code-tab-divider);
15
14
  }
16
15
 
@@ -13,13 +13,13 @@ $palette: map.merge(
13
13
  "warning": #f2711c,
14
14
 
15
15
  "text-light-1": #213547,
16
- "text-light-2": rgba(60, 60, 60, 0.7),
17
- "text-light-3": rgba(60, 60, 60, 0.33),
18
- "text-light-4": rgba(60, 60, 60, 0.18),
19
- "text-dark-1": rgba(255 ,255 ,255, 0.87),
20
- "text-dark-2": rgba(235 ,235 ,235, 0.6),
21
- "text-dark-3": rgba(235 ,235 ,235, 0.38),
22
- "text-dark-4": rgba(235 ,235 ,235, 0.18),
16
+ "text-light-2": rgb(60 60 60 / 0.7),
17
+ "text-light-3": rgb(60 60 60 / 0.33),
18
+ "text-light-4": rgb(60 60 60 / 0.18),
19
+ "text-dark-1": rgb(255 255 255 / 0.87),
20
+ "text-dark-2": rgb(235 235 235 / 0.6),
21
+ "text-dark-3": rgb(235 235 235 / 0.38),
22
+ "text-dark-4": rgb(235 235 235 / 0.18),
23
23
  ),
24
24
  $palette
25
25
  );
@@ -38,7 +38,7 @@ $colors: map.merge(
38
38
  (
39
39
  "primary-light": color.scale($c-primary, $lightness: 10%),
40
40
  "primary-lighter": color.scale($c-primary, $lightness: 20%),
41
- "primary-dark": color.scale($c-primary, $lightness: -5%),
41
+ "primary-dark": color.scale($c-primary, $lightness: -10%),
42
42
  ),
43
43
  $colors
44
44
  );
@@ -70,7 +70,7 @@ $dark: map.merge(
70
70
  "c-text-light": #ddd,
71
71
  "c-text-lighter": #eee,
72
72
  "c-text-dark": rgba(#ebebeb, 0.8),
73
- "c-link": map.get($colors, "primary-light"),
73
+ "c-link": map.get($colors, "primary-lighter"),
74
74
  ),
75
75
  $dark
76
76
  );
@@ -25,3 +25,10 @@ export function throttleAndDebounce(fn: () => void, delay: number): () => void {
25
25
  }
26
26
  }
27
27
  }
28
+
29
+ /**
30
+ * 等待指定时间 (ms)
31
+ */
32
+ export function sleep(ms: number) {
33
+ return new Promise(resolve => setTimeout(resolve, ms))
34
+ }