vitepress-theme-element-plus 0.0.3 → 0.0.4

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 (41) hide show
  1. package/README.md +3 -3
  2. package/client/components/A11yTag.vue +29 -29
  3. package/client/components/ApiTyping.vue +54 -54
  4. package/client/components/Backdrop.vue +41 -41
  5. package/client/components/Bili.vue +94 -94
  6. package/client/components/Content.vue +148 -150
  7. package/client/components/DeprecatedTag.vue +19 -19
  8. package/client/components/Doc.vue +181 -181
  9. package/client/components/DocAside.vue +46 -46
  10. package/client/components/DocAsideOutline.vue +82 -82
  11. package/client/components/DocFooter.vue +159 -159
  12. package/client/components/Footer.vue +77 -77
  13. package/client/components/FooterCopyright.vue +27 -27
  14. package/client/components/Layout.vue +156 -156
  15. package/client/components/Link.vue +41 -41
  16. package/client/components/LocalNav.vue +160 -160
  17. package/client/components/Nav.vue +69 -69
  18. package/client/components/NavBar.vue +203 -203
  19. package/client/components/NavBarTitle.vue +75 -75
  20. package/client/components/Sidebar.vue +129 -129
  21. package/client/components/SidebarGroup.vue +51 -51
  22. package/client/components/SidebarItem.vue +302 -302
  23. package/client/components/Tag.vue +25 -25
  24. package/client/components/VPNavBarSearch.vue +23 -23
  25. package/client/components/VersionTag.vue +18 -18
  26. package/client/hooks/useBackTop.ts +71 -71
  27. package/client/hooks/useLangs.ts +50 -50
  28. package/client/hooks/useSidebar.ts +93 -18
  29. package/client/hooks/useSidebarControl.ts +78 -78
  30. package/client/hooks/useSize.ts +69 -69
  31. package/client/utils/client/common.ts +49 -49
  32. package/client/utils/client/outline.ts +113 -113
  33. package/client/utils/common.ts +90 -90
  34. package/index.ts +26 -26
  35. package/package.json +73 -73
  36. package/shared/constants.ts +3 -3
  37. package/styles/base.scss +37 -37
  38. package/styles/code.scss +282 -282
  39. package/styles/doc-content.scss +161 -161
  40. package/styles/index.scss +69 -69
  41. package/styles/tag-content.scss +30 -30
@@ -1,23 +1,23 @@
1
- <script lang="ts" setup>
2
- import VPNavBarSearch from 'vitepress/dist/client/theme-default/components/VPNavBarSearch.vue'
3
- // compatible with vitepress-plugin-pagefind
4
- </script>
5
-
6
- <template>
7
- <VPNavBarSearch />
8
- </template>
9
-
10
- <style>
11
- @media (min-width: 768px) {
12
- .VPNavBarSearch.VPNavBarSearch {
13
- flex-grow: unset;
14
- padding-right: 24px;
15
- }
16
- }
17
-
18
- @media (min-width: 960px) {
19
- .VPNavBarSearch.VPNavBarSearch {
20
- padding-right: 32px;
21
- }
22
- }
23
- </style>
1
+ <script lang="ts" setup>
2
+ import VPNavBarSearch from 'vitepress/dist/client/theme-default/components/VPNavBarSearch.vue'
3
+ // compatible with vitepress-plugin-pagefind
4
+ </script>
5
+
6
+ <template>
7
+ <VPNavBarSearch />
8
+ </template>
9
+
10
+ <style>
11
+ @media (min-width: 768px) {
12
+ .VPNavBarSearch.VPNavBarSearch {
13
+ flex-grow: unset;
14
+ padding-right: 24px;
15
+ }
16
+ }
17
+
18
+ @media (min-width: 960px) {
19
+ .VPNavBarSearch.VPNavBarSearch {
20
+ padding-right: 32px;
21
+ }
22
+ }
23
+ </style>
@@ -1,18 +1,18 @@
1
- <script lang="ts" setup>
2
- import { ElTag } from 'element-plus'
3
-
4
- defineProps<{
5
- version: string
6
- }>()
7
- </script>
8
-
9
- <template>
10
- <ElTag
11
- size="small"
12
- effect="plain"
13
- hit
14
- round
15
- >
16
- {{ version }}
17
- </ElTag>
18
- </template>
1
+ <script lang="ts" setup>
2
+ import { ElTag } from 'element-plus'
3
+
4
+ defineProps<{
5
+ version: string
6
+ }>()
7
+ </script>
8
+
9
+ <template>
10
+ <ElTag
11
+ size="small"
12
+ effect="plain"
13
+ hit
14
+ round
15
+ >
16
+ {{ version }}
17
+ </ElTag>
18
+ </template>
@@ -1,74 +1,74 @@
1
1
  import { isClient } from '@vueuse/core'
2
2
  import { onBeforeUnmount, onMounted, ref } from 'vue'
3
3
  import { throttle } from '../utils/throttle'
4
-
5
- const threshold = 960
6
-
7
- const cubic = (value: number): number => value ** 3
8
- function easeInOutCubic(value: number): number {
9
- return value < 0.5 ? cubic(value * 2) / 2 : 1 - cubic((1 - value) * 2) / 2
10
- }
11
-
12
- export function useBackTop(offset = 200) {
13
- const shouldShow = ref(false)
14
- const throttleResize = throttle(onResize, 300)
15
- const throttleScroll = throttle(onScroll, 160)
16
-
17
- onMounted(() => {
18
- if (!isClient)
19
- return
20
- onResize()
21
- onScroll()
22
- window.addEventListener('resize', throttleResize)
23
- })
24
-
25
- onBeforeUnmount(() => {
26
- if (!isClient)
27
- return
28
- window.removeEventListener('resize', throttleResize)
29
- window.removeEventListener('scroll', throttleScroll)
30
- })
31
-
32
- const scrollToTop = () => {
33
- const beginTime = Date.now()
34
- const beginValue = document.documentElement.scrollTop
35
- const rAF = window.requestAnimationFrame
36
- const frameFunc = () => {
37
- const progress = (Date.now() - beginTime) / 500
38
- if (progress < 1) {
39
- document.documentElement.scrollTop
40
- = beginValue * (1 - easeInOutCubic(progress))
41
- rAF(frameFunc)
42
- }
43
- else {
44
- document.documentElement.scrollTop = 0
45
- }
46
- }
47
- rAF(frameFunc)
48
- }
49
-
50
- function onResize() {
51
- if (!isClient)
52
- return
53
-
54
- const { clientWidth } = document.body
55
-
56
- if (clientWidth < threshold) {
57
- window.addEventListener('scroll', throttleScroll)
58
- }
59
- else {
60
- window.removeEventListener('scroll', throttleScroll)
61
- }
62
- }
63
-
64
- function onScroll() {
65
- if (!isClient)
66
- return
67
- shouldShow.value = document.documentElement.scrollTop > offset
68
- }
69
-
70
- return {
71
- shouldShow,
72
- scrollToTop,
73
- }
74
- }
4
+
5
+ const threshold = 960
6
+
7
+ const cubic = (value: number): number => value ** 3
8
+ function easeInOutCubic(value: number): number {
9
+ return value < 0.5 ? cubic(value * 2) / 2 : 1 - cubic((1 - value) * 2) / 2
10
+ }
11
+
12
+ export function useBackTop(offset = 200) {
13
+ const shouldShow = ref(false)
14
+ const throttleResize = throttle(onResize, 300)
15
+ const throttleScroll = throttle(onScroll, 160)
16
+
17
+ onMounted(() => {
18
+ if (!isClient)
19
+ return
20
+ onResize()
21
+ onScroll()
22
+ window.addEventListener('resize', throttleResize)
23
+ })
24
+
25
+ onBeforeUnmount(() => {
26
+ if (!isClient)
27
+ return
28
+ window.removeEventListener('resize', throttleResize)
29
+ window.removeEventListener('scroll', throttleScroll)
30
+ })
31
+
32
+ const scrollToTop = () => {
33
+ const beginTime = Date.now()
34
+ const beginValue = document.documentElement.scrollTop
35
+ const rAF = window.requestAnimationFrame
36
+ const frameFunc = () => {
37
+ const progress = (Date.now() - beginTime) / 500
38
+ if (progress < 1) {
39
+ document.documentElement.scrollTop
40
+ = beginValue * (1 - easeInOutCubic(progress))
41
+ rAF(frameFunc)
42
+ }
43
+ else {
44
+ document.documentElement.scrollTop = 0
45
+ }
46
+ }
47
+ rAF(frameFunc)
48
+ }
49
+
50
+ function onResize() {
51
+ if (!isClient)
52
+ return
53
+
54
+ const { clientWidth } = document.body
55
+
56
+ if (clientWidth < threshold) {
57
+ window.addEventListener('scroll', throttleScroll)
58
+ }
59
+ else {
60
+ window.removeEventListener('scroll', throttleScroll)
61
+ }
62
+ }
63
+
64
+ function onScroll() {
65
+ if (!isClient)
66
+ return
67
+ shouldShow.value = document.documentElement.scrollTop > offset
68
+ }
69
+
70
+ return {
71
+ shouldShow,
72
+ scrollToTop,
73
+ }
74
+ }
@@ -1,50 +1,50 @@
1
- import { useData } from 'vitepress'
2
- import { computed } from 'vue'
3
- import { ensureStartingSlash } from '../utils/common'
4
-
5
- export function useLangs({ correspondingLink = false } = {}) {
6
- const { site, localeIndex, page, theme, hash } = useData()
7
- const currentLang = computed(() => ({
8
- label: site.value.locales[localeIndex.value]?.label,
9
- link:
10
- site.value.locales[localeIndex.value]?.link
11
- || (localeIndex.value === 'root' ? '/' : `/${localeIndex.value}/`),
12
- }))
13
-
14
- const localeLinks = computed(() =>
15
- Object.entries(site.value.locales).flatMap(([key, value]) =>
16
- currentLang.value.label === value.label
17
- ? []
18
- : {
19
- text: value.label,
20
- link:
21
- normalizeLink(
22
- value.link || (key === 'root' ? '/' : `/${key}/`),
23
- theme.value.i18nRouting !== false && correspondingLink,
24
- page.value.relativePath.slice(
25
- currentLang.value.link.length - 1,
26
- ),
27
- !site.value.cleanUrls,
28
- ) + hash.value,
29
- },
30
- ),
31
- )
32
-
33
- return { localeLinks, currentLang }
34
- }
35
-
36
- function normalizeLink(
37
- link: string,
38
- addPath: boolean,
39
- path: string,
40
- addExt: boolean,
41
- ) {
42
- return addPath
43
- ? link.replace(/\/$/, '')
44
- + ensureStartingSlash(
45
- path
46
- .replace(/(^|\/)index\.md$/, '$1')
47
- .replace(/\.md$/, addExt ? '.html' : ''),
48
- )
49
- : link
50
- }
1
+ import { useData } from 'vitepress'
2
+ import { computed } from 'vue'
3
+ import { ensureStartingSlash } from '../utils/common'
4
+
5
+ export function useLangs({ correspondingLink = false } = {}) {
6
+ const { site, localeIndex, page, theme, hash } = useData()
7
+ const currentLang = computed(() => ({
8
+ label: site.value.locales[localeIndex.value]?.label,
9
+ link:
10
+ site.value.locales[localeIndex.value]?.link
11
+ || (localeIndex.value === 'root' ? '/' : `/${localeIndex.value}/`),
12
+ }))
13
+
14
+ const localeLinks = computed(() =>
15
+ Object.entries(site.value.locales).flatMap(([key, value]) =>
16
+ currentLang.value.label === value.label
17
+ ? []
18
+ : {
19
+ text: value.label,
20
+ link:
21
+ normalizeLink(
22
+ value.link || (key === 'root' ? '/' : `/${key}/`),
23
+ theme.value.i18nRouting !== false && correspondingLink,
24
+ page.value.relativePath.slice(
25
+ currentLang.value.link.length - 1,
26
+ ),
27
+ !site.value.cleanUrls,
28
+ ) + hash.value,
29
+ },
30
+ ),
31
+ )
32
+
33
+ return { localeLinks, currentLang }
34
+ }
35
+
36
+ function normalizeLink(
37
+ link: string,
38
+ addPath: boolean,
39
+ path: string,
40
+ addExt: boolean,
41
+ ) {
42
+ return addPath
43
+ ? link.replace(/\/$/, '')
44
+ + ensureStartingSlash(
45
+ path
46
+ .replace(/(^|\/)index\.md$/, '$1')
47
+ .replace(/\.md$/, addExt ? '.html' : ''),
48
+ )
49
+ : link
50
+ }
@@ -1,23 +1,30 @@
1
+ import type { DefaultTheme } from 'vitepress'
1
2
  import { useMediaQuery } from '@vueuse/core'
2
3
  import { useData } from 'vitepress'
3
4
  import { computed, onMounted, onUnmounted, ref, watch, watchEffect } from 'vue'
4
5
  import { NOT_ARTICLE_LAYOUTS } from '../../shared/constants'
6
+ import { ensureStartingSlash } from '../utils/common'
5
7
 
6
8
  export function useSidebar() {
7
- const { frontmatter, theme } = useData()
9
+ const { frontmatter, theme, page } = useData()
8
10
  const is960 = useMediaQuery('(min-width: 960px)')
9
11
  const isOpen = ref(false)
10
- const _sidebar = computed(() => {
12
+ const sidebar = ref<DefaultTheme.SidebarItem[]>([])
13
+
14
+ function updateSidebar() {
11
15
  const sidebarConfig = theme.value.sidebar
12
- return sidebarConfig ?? []
13
- })
16
+ const relativePath = page.value?.relativePath ?? '/'
17
+ const nextSidebar = resolveSidebar(sidebarConfig, relativePath)
14
18
 
15
- const sidebar = ref(_sidebar.value)
19
+ if (JSON.stringify(nextSidebar) !== JSON.stringify(sidebar.value))
20
+ sidebar.value = nextSidebar
21
+ }
16
22
 
17
- watch(_sidebar, (next, prev) => {
18
- if (JSON.stringify(next) !== JSON.stringify(prev))
19
- sidebar.value = _sidebar.value
20
- })
23
+ watch(
24
+ () => [page.value?.relativePath, theme.value.sidebar],
25
+ () => updateSidebar(),
26
+ { immediate: true, deep: true, flush: 'sync' },
27
+ )
21
28
 
22
29
  const hasSidebar = computed(() => {
23
30
  return (
@@ -28,9 +35,9 @@ export function useSidebar() {
28
35
  })
29
36
 
30
37
  const hasAside = computed(() => {
31
- if (NOT_ARTICLE_LAYOUTS.includes(frontmatter.value.layout)) {
38
+ if (NOT_ARTICLE_LAYOUTS.includes(frontmatter.value.layout))
32
39
  return false
33
- }
40
+
34
41
  if (frontmatter.value.aside !== undefined && frontmatter.value.aside !== null)
35
42
  return !!frontmatter.value.aside
36
43
 
@@ -38,18 +45,18 @@ export function useSidebar() {
38
45
  })
39
46
 
40
47
  const leftAside = computed(() => {
41
- if (hasAside) {
42
- return frontmatter.value.aside === null
43
- ? theme.value.aside === 'left'
44
- : frontmatter.value.aside === 'left'
45
- }
46
- return false
48
+ if (!hasAside.value)
49
+ return false
50
+
51
+ return frontmatter.value.aside === null
52
+ ? theme.value.aside === 'left'
53
+ : frontmatter.value.aside === 'left'
47
54
  })
48
55
 
49
56
  const isSidebarEnabled = computed(() => hasSidebar.value && is960.value)
50
57
 
51
58
  const sidebarGroups = computed(() => {
52
- return hasSidebar.value ?? []
59
+ return hasSidebar.value ? groupSidebarItems(sidebar.value) : []
53
60
  })
54
61
 
55
62
  function open() {
@@ -103,3 +110,71 @@ export function useCloseSidebarOnEscape() {
103
110
  }
104
111
  }
105
112
  }
113
+
114
+ function resolveSidebar(
115
+ sidebarConfig: DefaultTheme.Sidebar | undefined,
116
+ relativePath: string,
117
+ ): DefaultTheme.SidebarItem[] {
118
+ if (!sidebarConfig)
119
+ return []
120
+
121
+ if (Array.isArray(sidebarConfig))
122
+ return withBase(sidebarConfig)
123
+
124
+ const normalizedPath = ensureStartingSlash(relativePath)
125
+ const matchingDir = Object.keys(sidebarConfig)
126
+ .sort((a, b) => b.split('/').length - a.split('/').length)
127
+ .find(dir => normalizedPath.startsWith(ensureStartingSlash(dir)))
128
+
129
+ const matched = matchingDir ? sidebarConfig[matchingDir] : []
130
+
131
+ if (Array.isArray(matched))
132
+ return withBase(matched)
133
+
134
+ return withBase(matched?.items ?? [], matched?.base)
135
+ }
136
+
137
+ function withBase(
138
+ items: DefaultTheme.SidebarItem[],
139
+ base?: string,
140
+ ): DefaultTheme.SidebarItem[] {
141
+ return items.map((_item) => {
142
+ const item: DefaultTheme.SidebarItem = { ..._item }
143
+ const resolvedBase = item.base || base
144
+
145
+ if (resolvedBase && item.link) {
146
+ item.link = resolvedBase
147
+ + item.link.replace(/^\//, resolvedBase.endsWith('/') ? '' : '/')
148
+ }
149
+
150
+ if (item.items)
151
+ item.items = withBase(item.items, resolvedBase)
152
+
153
+ return item
154
+ })
155
+ }
156
+
157
+ function groupSidebarItems(
158
+ sidebarItems: DefaultTheme.SidebarItem[],
159
+ ): DefaultTheme.SidebarItem[] {
160
+ const groups: DefaultTheme.SidebarItem[] = []
161
+ let lastGroupIndex = 0
162
+
163
+ sidebarItems.forEach((item) => {
164
+ if (item.items && item.items.length) {
165
+ lastGroupIndex = groups.push(item)
166
+ return
167
+ }
168
+
169
+ if (!groups[lastGroupIndex])
170
+ groups.push({ items: [] })
171
+
172
+ const group = groups[lastGroupIndex]
173
+ if (!group.items)
174
+ group.items = []
175
+
176
+ group.items.push(item)
177
+ })
178
+
179
+ return groups
180
+ }
@@ -1,78 +1,78 @@
1
- import type { DefaultTheme } from 'vitepress'
2
- import type { ComputedRef, Ref } from 'vue'
3
- import { useData } from 'vitepress'
4
- import { computed, onMounted, ref, watch, watchEffect, watchPostEffect } from 'vue'
5
- import { hasActiveLink as containsActiveLink } from '../utils/client/common'
6
-
7
- import { isActive } from '../utils/common'
8
-
9
- export interface SidebarControl {
10
- collapsed: Ref<boolean>
11
- collapsible: ComputedRef<boolean>
12
- isLink: ComputedRef<boolean>
13
- isActiveLink: Ref<boolean>
14
- hasActiveLink: ComputedRef<boolean>
15
- hasChildren: ComputedRef<boolean>
16
- toggle: () => void
17
- }
18
-
19
- export function useSidebarControl(
20
- item: ComputedRef<DefaultTheme.SidebarItem>,
21
- ): SidebarControl {
22
- const { page, hash } = useData()
23
- const collapsed = ref(false)
24
-
25
- const collapsible = computed(() => {
26
- return item.value.collapsed !== undefined
27
- })
28
-
29
- const isLink = computed(() => {
30
- return !!item.value.link
31
- })
32
-
33
- const isActiveLink = ref(false)
34
- const updateIsActiveLink = () => {
35
- isActiveLink.value = isActive(page.value.relativePath, item.value.link)
36
- }
37
-
38
- watch([page, item, hash], updateIsActiveLink)
39
- onMounted(updateIsActiveLink)
40
-
41
- const hasActiveLink = computed(() => {
42
- if (isActiveLink.value) {
43
- return true
44
- }
45
-
46
- return item.value.items
47
- ? containsActiveLink(page.value.relativePath, item.value.items)
48
- : false
49
- })
50
-
51
- const hasChildren = computed(() => {
52
- return !!(item.value.items && item.value.items.length)
53
- })
54
-
55
- watchEffect(() => {
56
- collapsed.value = !!(collapsible.value && item.value.collapsed)
57
- })
58
-
59
- watchPostEffect(() => {
60
- ;(isActiveLink.value || hasActiveLink.value) && (collapsed.value = false)
61
- })
62
-
63
- function toggle() {
64
- if (collapsible.value) {
65
- collapsed.value = !collapsed.value
66
- }
67
- }
68
-
69
- return {
70
- collapsed,
71
- collapsible,
72
- isLink,
73
- isActiveLink,
74
- hasActiveLink,
75
- hasChildren,
76
- toggle,
77
- }
78
- }
1
+ import type { DefaultTheme } from 'vitepress'
2
+ import type { ComputedRef, Ref } from 'vue'
3
+ import { useData } from 'vitepress'
4
+ import { computed, onMounted, ref, watch, watchEffect, watchPostEffect } from 'vue'
5
+ import { hasActiveLink as containsActiveLink } from '../utils/client/common'
6
+
7
+ import { isActive } from '../utils/common'
8
+
9
+ export interface SidebarControl {
10
+ collapsed: Ref<boolean>
11
+ collapsible: ComputedRef<boolean>
12
+ isLink: ComputedRef<boolean>
13
+ isActiveLink: Ref<boolean>
14
+ hasActiveLink: ComputedRef<boolean>
15
+ hasChildren: ComputedRef<boolean>
16
+ toggle: () => void
17
+ }
18
+
19
+ export function useSidebarControl(
20
+ item: ComputedRef<DefaultTheme.SidebarItem>,
21
+ ): SidebarControl {
22
+ const { page, hash } = useData()
23
+ const collapsed = ref(false)
24
+
25
+ const collapsible = computed(() => {
26
+ return item.value.collapsed !== undefined
27
+ })
28
+
29
+ const isLink = computed(() => {
30
+ return !!item.value.link
31
+ })
32
+
33
+ const isActiveLink = ref(false)
34
+ const updateIsActiveLink = () => {
35
+ isActiveLink.value = isActive(page.value.relativePath, item.value.link)
36
+ }
37
+
38
+ watch([page, item, hash], updateIsActiveLink)
39
+ onMounted(updateIsActiveLink)
40
+
41
+ const hasActiveLink = computed(() => {
42
+ if (isActiveLink.value) {
43
+ return true
44
+ }
45
+
46
+ return item.value.items
47
+ ? containsActiveLink(page.value.relativePath, item.value.items)
48
+ : false
49
+ })
50
+
51
+ const hasChildren = computed(() => {
52
+ return !!(item.value.items && item.value.items.length)
53
+ })
54
+
55
+ watchEffect(() => {
56
+ collapsed.value = !!(collapsible.value && item.value.collapsed)
57
+ })
58
+
59
+ watchPostEffect(() => {
60
+ ;(isActiveLink.value || hasActiveLink.value) && (collapsed.value = false)
61
+ })
62
+
63
+ function toggle() {
64
+ if (collapsible.value) {
65
+ collapsed.value = !collapsed.value
66
+ }
67
+ }
68
+
69
+ return {
70
+ collapsed,
71
+ collapsible,
72
+ isLink,
73
+ isActiveLink,
74
+ hasActiveLink,
75
+ hasChildren,
76
+ toggle,
77
+ }
78
+ }