Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit b5ecc13

Browse filesBrowse files
committed
release: v4.0.0-beta.2
1 parent c6f9161 commit b5ecc13
Copy full SHA for b5ecc13
Expand file treeCollapse file tree

20 files changed

+2042
-1
lines changed

‎__old/SidebarChild.ts

Copy file name to clipboard
+100Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import { h } from 'vue'
2+
import type { FunctionalComponent, VNode } from 'vue'
3+
import { RouterLink, useRoute } from 'vue-router'
4+
import type { RouteLocationNormalizedLoaded } from 'vue-router'
5+
import type { ResolvedSidebarItem } from '../../shared'
6+
7+
import { CNavGroup, CNavItem } from './../../../../../../src'
8+
import { CIcon } from '@coreui/icons-vue'
9+
10+
const normalizePath = (path: string): string =>
11+
decodeURI(path)
12+
.replace(/#.*$/, '')
13+
.replace(/(index)?\.(md|html)$/, '')
14+
15+
const isActiveLink = (route: RouteLocationNormalizedLoaded, link?: string): boolean => {
16+
if (link === undefined) {
17+
return false
18+
}
19+
20+
if (route.hash === link) {
21+
return true
22+
}
23+
24+
const currentPath = normalizePath(route.path)
25+
const targetPath = normalizePath(link)
26+
27+
return currentPath === targetPath
28+
}
29+
30+
const isActiveItem = (route: RouteLocationNormalizedLoaded, item: ResolvedSidebarItem): boolean => {
31+
if (isActiveLink(route, item.link)) {
32+
return true
33+
}
34+
35+
if (item.children) {
36+
return item.children.some((child) => isActiveItem(route, child))
37+
}
38+
39+
return false
40+
}
41+
42+
const renderItem = (item: ResolvedSidebarItem): VNode => {
43+
const route = useRoute()
44+
if (item.children && !item.link.includes('.html')) {
45+
return h(
46+
CNavGroup,
47+
{
48+
compact: true,
49+
visible: item.children.some((child) => isActiveItem(route, child)),
50+
// href: props.href,
51+
},
52+
{
53+
togglerContent: () => [
54+
h(CIcon, {
55+
customClassName: 'nav-icon text-primary',
56+
icon: ['512 512', item.icon],
57+
height: 64,
58+
width: 64,
59+
}),
60+
item.text,
61+
],
62+
default: () => item.children.map((child) => renderItem(child)),
63+
},
64+
)
65+
}
66+
67+
return h(
68+
RouterLink,
69+
{
70+
to: item.link,
71+
custom: true,
72+
},
73+
{
74+
default: (props) =>
75+
h(
76+
CNavItem,
77+
{
78+
active: props.isActive,
79+
href: item.link,
80+
},
81+
{
82+
default: () => item.text,
83+
},
84+
),
85+
},
86+
)
87+
}
88+
89+
export const SidebarChild: FunctionalComponent<{
90+
item: ResolvedSidebarItem
91+
}> = ({ item }) => renderItem(item)
92+
93+
SidebarChild.displayName = 'SidebarChild'
94+
95+
SidebarChild.props = {
96+
item: {
97+
type: Object,
98+
required: true,
99+
},
100+
}

‎__old/_DropdownLink.vue

Copy file name to clipboard
+141Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
<template>
2+
<div class="dropdown-wrapper" :class="{ open }">
3+
<button
4+
class="dropdown-title"
5+
type="button"
6+
:aria-label="dropdownAriaLabel"
7+
@click="handleDropdown"
8+
>
9+
<span class="title">{{ item.text }}</span>
10+
<span class="arrow down" />
11+
</button>
12+
13+
<button
14+
class="mobile-dropdown-title"
15+
type="button"
16+
:aria-label="dropdownAriaLabel"
17+
@click="open = !open"
18+
>
19+
<span class="title">{{ item.text }}</span>
20+
<span class="arrow" :class="open ? 'down' : 'right'" />
21+
</button>
22+
23+
<!-- Transition will somehow break the Select Languages dropdown -->
24+
<!-- So we remove DropdownTransition until we figure out the reason -->
25+
<ul v-show="open" class="nav-dropdown">
26+
<li
27+
v-for="(child, index) in item.children"
28+
:key="child.link || index"
29+
class="dropdown-item"
30+
>
31+
<template v-if="child.children">
32+
<h4 class="dropdown-subtitle">
33+
<NavLink
34+
v-if="child.link"
35+
:item="child"
36+
@focusout="
37+
isLastItemOfArray(child, item.children) &&
38+
child.children.length === 0 &&
39+
(open = false)
40+
"
41+
/>
42+
43+
<span v-else>{{ child.text }}</span>
44+
</h4>
45+
46+
<ul class="dropdown-subitem-wrapper">
47+
<li
48+
v-for="grandchild in child.children"
49+
:key="grandchild.link"
50+
class="dropdown-subitem"
51+
>
52+
<NavLink
53+
:item="grandchild"
54+
@focusout="
55+
isLastItemOfArray(grandchild, child.children) &&
56+
isLastItemOfArray(child, item.children) &&
57+
(open = false)
58+
"
59+
/>
60+
</li>
61+
</ul>
62+
</template>
63+
64+
<template v-else>
65+
<NavLink
66+
:item="child"
67+
@focusout="
68+
isLastItemOfArray(child, item.children) && (open = false)
69+
"
70+
/>
71+
</template>
72+
</li>
73+
</ul>
74+
</div>
75+
</template>
76+
77+
<script lang="ts">
78+
import { computed, defineComponent, ref, toRefs, watch } from 'vue'
79+
import type { PropType } from 'vue'
80+
import { useRoute } from 'vue-router'
81+
import type { NavGroup, NavItem } from '../../shared'
82+
import NavLink from './_NavLink.vue'
83+
84+
export default defineComponent({
85+
name: 'DropdownLink',
86+
87+
components: {
88+
NavLink,
89+
},
90+
91+
props: {
92+
item: {
93+
type: Object as PropType<NavGroup<NavItem>>,
94+
required: true,
95+
},
96+
},
97+
98+
setup(props) {
99+
const { item } = toRefs(props)
100+
const dropdownAriaLabel = computed(
101+
() => item.value.ariaLabel || item.value.text
102+
)
103+
104+
const open = ref(false)
105+
const route = useRoute()
106+
watch(
107+
() => route.path,
108+
() => {
109+
open.value = false
110+
}
111+
)
112+
113+
/**
114+
* Open the dropdown when user tab and click from keyboard.
115+
*
116+
* Use event.detail to detect tab and click from keyboard.
117+
* The Tab + Click is UIEvent > KeyboardEvent, so the detail is 0.
118+
*
119+
* @see https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail
120+
*/
121+
const handleDropdown = (e): void => {
122+
const isTriggerByTab = e.detail === 0
123+
if (isTriggerByTab) {
124+
open.value = !open.value
125+
} else {
126+
open.value = false
127+
}
128+
}
129+
130+
const isLastItemOfArray = (item: unknown, arr: unknown[]): boolean =>
131+
arr[arr.length - 1] === item
132+
133+
return {
134+
open,
135+
dropdownAriaLabel,
136+
handleDropdown,
137+
isLastItemOfArray,
138+
}
139+
},
140+
})
141+
</script>

‎__old/_DropdownTransition.vue

Copy file name to clipboard
+34Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<template>
2+
<Transition
3+
name="dropdown"
4+
@enter="setHeight"
5+
@after-enter="unsetHeight"
6+
@before-leave="setHeight"
7+
>
8+
<slot />
9+
</Transition>
10+
</template>
11+
12+
<script lang="ts">
13+
import { defineComponent } from 'vue'
14+
15+
export default defineComponent({
16+
name: 'DropdownTransition',
17+
18+
setup() {
19+
const setHeight = (items): void => {
20+
// explicitly set height so that it can be transitioned
21+
items.style.height = items.scrollHeight + 'px'
22+
}
23+
24+
const unsetHeight = (items): void => {
25+
items.style.height = ''
26+
}
27+
28+
return {
29+
setHeight,
30+
unsetHeight,
31+
}
32+
},
33+
})
34+
</script>

‎__old/_NavLink.vue

Copy file name to clipboard
+120Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
<template>
2+
<RouterLink
3+
custom
4+
:to="item.link"
5+
v-slot="{ href, route, navigate, isActive, isExactActive }"
6+
>
7+
<CNavLink :active="isActive" :href="href" @click="navigate">
8+
{{ item.text }}
9+
</CNavLink>
10+
</RouterLink>
11+
<!-- <a
12+
v-else
13+
class="nav-link external"
14+
:href="item.link"
15+
:rel="linkRel"
16+
:target="linkTarget"
17+
:aria-label="linkAriaLabel"
18+
v-bind="$attrs"
19+
>
20+
<slot name="before" />
21+
{{ item.text }}
22+
<OutboundLink v-if="isBlankTarget" />
23+
<slot name="after" />
24+
</a> -->
25+
</template>
26+
27+
<script lang="ts">
28+
import { computed, defineComponent, toRefs } from 'vue'
29+
import type { PropType } from 'vue'
30+
import { useRoute } from 'vue-router'
31+
import { useSiteData } from '@vuepress/client'
32+
import { isLinkHttp, isLinkMailto, isLinkTel } from '@vuepress/shared'
33+
import type { NavLink } from '../../shared'
34+
import { CNavLink } from './../../../../../../src'
35+
36+
export default defineComponent({
37+
name: 'NavLink',
38+
39+
inheritAttrs: false,
40+
41+
props: {
42+
item: {
43+
type: Object as PropType<NavLink>,
44+
required: true,
45+
},
46+
},
47+
48+
setup(props) {
49+
const route = useRoute()
50+
const site = useSiteData()
51+
const { item } = toRefs(props)
52+
53+
// if the link has http protocol
54+
const hasHttpProtocol = computed(() => isLinkHttp(item.value.link))
55+
// if the link has non-http protocol
56+
const hasNonHttpProtocal = computed(
57+
() => isLinkMailto(item.value.link) || isLinkTel(item.value.link),
58+
)
59+
// resolve the `target` attr
60+
const linkTarget = computed(() => {
61+
if (hasNonHttpProtocal.value) return undefined
62+
if (item.value.target) return item.value.target
63+
if (hasHttpProtocol.value) return '_blank'
64+
return undefined
65+
})
66+
// if the `target` attr is '_blank'
67+
const isBlankTarget = computed(() => linkTarget.value === '_blank')
68+
// is `<RouterLink>` or not
69+
const isRouterLink = computed(
70+
() => !hasHttpProtocol.value && !hasNonHttpProtocal.value && !isBlankTarget.value,
71+
)
72+
// resolve the `rel` attr
73+
const linkRel = computed(() => {
74+
if (hasNonHttpProtocal.value) return undefined
75+
if (item.value.rel) return item.value.rel
76+
if (isBlankTarget.value) return 'noopener noreferrer'
77+
return undefined
78+
})
79+
// resolve the `aria-label` attr
80+
const linkAriaLabel = computed(() => item.value.ariaLabel || item.value.text)
81+
82+
// should be active when current route is a subpath of this link
83+
const shouldBeActiveInSubpath = computed(() => {
84+
const localeKeys = Object.keys(site.value.locales)
85+
if (localeKeys.length) {
86+
return !localeKeys.some((key) => key === item.value.link)
87+
}
88+
return item.value.link !== '/'
89+
})
90+
// if this link is active in subpath
91+
const isActiveInSubpath = computed(() => {
92+
if (!shouldBeActiveInSubpath.value) {
93+
return false
94+
}
95+
return route.path.startsWith(item.value.link)
96+
})
97+
98+
// if this link is active
99+
// const isActive = computed(() => {
100+
// if (!isRouterLink.value) {
101+
// return false
102+
// }
103+
// if (item.value.activeMatch) {
104+
// return new RegExp(item.value.activeMatch).test(route.path)
105+
// }
106+
// return isActiveInSubpath.value
107+
// })
108+
109+
return {
110+
CNavLink,
111+
// isActive,
112+
isBlankTarget,
113+
isRouterLink,
114+
linkRel,
115+
linkTarget,
116+
linkAriaLabel,
117+
}
118+
},
119+
})
120+
</script>

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.