Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c476c20

Browse files
authored
fix(theme): fix sidebar link concatenation error (#722)
1 parent 1686836 commit c476c20

File tree

3 files changed

+209
-205
lines changed

3 files changed

+209
-205
lines changed

theme/src/client/composables/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export * from './prev-next.js'
2929
export * from './route-query.js'
3030
export * from './scroll-behavior.js'
3131
export * from './scroll-promise.js'
32+
export * from './sidebar-data.js'
3233
export * from './sidebar.js'
3334
export * from './tag-colors.js'
3435
export * from './theme-data.js'
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
import type { InjectionKey, Ref } from 'vue'
2+
import type { ResolvedSidebarItem, ThemeSidebar, ThemeSidebarItem } from '../../shared/index.js'
3+
import { sidebar as sidebarRaw } from '@internal/sidebar'
4+
import {
5+
isArray,
6+
isPlainObject,
7+
isString,
8+
removeLeadingSlash,
9+
} from '@vuepress/helper/client'
10+
import {
11+
computed,
12+
inject,
13+
provide,
14+
ref,
15+
} from 'vue'
16+
import { useRouteLocale } from 'vuepress/client'
17+
import { normalizeLink, normalizePrefix, resolveNavLink } from '../utils/index.js'
18+
import { useData } from './data.js'
19+
20+
export type SidebarData = Record<string, ThemeSidebar>
21+
22+
export type SidebarDataRef = Ref<SidebarData>
23+
export type AutoDirSidebarRef = Ref<ThemeSidebarItem[] | {
24+
link: string
25+
items: ThemeSidebarItem[]
26+
}>
27+
export type AutoHomeDataRef = Ref<Record<string, string>>
28+
29+
const { __auto__, __home__, ...items } = sidebarRaw
30+
31+
export const sidebarData: SidebarDataRef = ref(items)
32+
export const autoDirSidebar: AutoDirSidebarRef = ref(__auto__)
33+
const autoHomeData: AutoHomeDataRef = ref(__home__)
34+
35+
if (__VUEPRESS_DEV__ && (import.meta.webpackHot || import.meta.hot)) {
36+
__VUE_HMR_RUNTIME__.updateSidebar = (data: SidebarData) => {
37+
const { __auto__, __home__, ...items } = data
38+
sidebarData.value = items
39+
autoDirSidebar.value = __auto__ as ThemeSidebarItem[]
40+
autoHomeData.value = __home__ as Record<string, string>
41+
}
42+
}
43+
44+
const sidebarSymbol: InjectionKey<Ref<ResolvedSidebarItem[]>> = Symbol(
45+
__VUEPRESS_DEV__ ? 'sidebar' : '',
46+
)
47+
48+
export function setupSidebar(): void {
49+
const { page, frontmatter } = useData()
50+
51+
const routeLocale = useRouteLocale()
52+
53+
const hasSidebar = computed(() => {
54+
return (
55+
frontmatter.value.pageLayout !== 'home'
56+
&& frontmatter.value.pageLayout !== 'friends'
57+
&& frontmatter.value.sidebar !== false
58+
&& frontmatter.value.layout !== 'NotFound'
59+
)
60+
})
61+
62+
const sidebarData = computed(() => {
63+
return hasSidebar.value
64+
? getSidebar(typeof frontmatter.value.sidebar === 'string'
65+
? frontmatter.value.sidebar
66+
: page.value.path, routeLocale.value)
67+
: []
68+
})
69+
70+
provide(sidebarSymbol, sidebarData)
71+
}
72+
73+
export function useSidebarData(): Ref<ResolvedSidebarItem[]> {
74+
const sidebarData = inject(sidebarSymbol)
75+
if (!sidebarData) {
76+
throw new Error('useSidebarData() is called without provider.')
77+
}
78+
return sidebarData
79+
}
80+
81+
/**
82+
* Get the `Sidebar` from sidebar option. This method will ensure to get correct
83+
* sidebar config from `MultiSideBarConfig` with various path combinations such
84+
* as matching `guide/` and `/guide/`. If no matching config was found, it will
85+
* return empty array.
86+
*/
87+
export function getSidebar(routePath: string, routeLocal: string): ResolvedSidebarItem[] {
88+
const _sidebar = sidebarData.value[routeLocal]
89+
90+
if (_sidebar === 'auto') {
91+
return resolveSidebarItems(autoDirSidebar.value[routeLocal])
92+
}
93+
else if (isArray(_sidebar)) {
94+
return resolveSidebarItems(_sidebar, routeLocal)
95+
}
96+
else if (isPlainObject(_sidebar)) {
97+
routePath = decodeURIComponent(routePath)
98+
const dir
99+
= Object.keys(_sidebar)
100+
.sort((a, b) => b.split('/').length - a.split('/').length)
101+
.find((dir) => {
102+
// make sure the multi sidebar key starts with slash too
103+
return routePath.startsWith(`${routeLocal}${removeLeadingSlash(dir)}`)
104+
}) || ''
105+
const sidebar = dir ? _sidebar[dir] : undefined
106+
107+
if (sidebar === 'auto') {
108+
return resolveSidebarItems(
109+
dir ? autoDirSidebar.value[dir] : [],
110+
routeLocal,
111+
)
112+
}
113+
else if (isArray(sidebar)) {
114+
return resolveSidebarItems(sidebar, dir)
115+
}
116+
else if (isPlainObject(sidebar)) {
117+
const prefix = normalizePrefix(routeLocal, sidebar.prefix)
118+
return resolveSidebarItems(
119+
sidebar.items === 'auto'
120+
? autoDirSidebar.value[prefix]
121+
: sidebar.items,
122+
prefix,
123+
)
124+
}
125+
}
126+
return []
127+
}
128+
129+
function resolveSidebarItems(
130+
sidebarItems: (string | ThemeSidebarItem)[],
131+
_prefix = '',
132+
): ResolvedSidebarItem[] {
133+
const resolved: ResolvedSidebarItem[] = []
134+
sidebarItems.forEach((item) => {
135+
if (isString(item)) {
136+
resolved.push(resolveNavLink(normalizeLink(_prefix, item)))
137+
}
138+
else {
139+
const { link, items, prefix, dir, ...args } = item
140+
const navLink = { ...args } as ResolvedSidebarItem
141+
if (link) {
142+
navLink.link = link.startsWith('---') ? link : normalizeLink(_prefix, link)
143+
const nav = resolveNavLink(navLink.link)
144+
navLink.icon = nav.icon || navLink.icon
145+
navLink.badge = nav.badge || navLink.badge
146+
}
147+
const nextPrefix = normalizePrefix(_prefix, prefix || dir)
148+
if (items === 'auto') {
149+
navLink.items = resolveSidebarItems(autoDirSidebar.value[nextPrefix], nextPrefix)
150+
if (!navLink.link && autoHomeData.value[nextPrefix]) {
151+
navLink.link = normalizeLink(autoHomeData.value[nextPrefix])
152+
const nav = resolveNavLink(navLink.link)
153+
navLink.icon = nav.icon || navLink.icon
154+
navLink.badge = nav.badge || navLink.badge
155+
}
156+
}
157+
else {
158+
navLink.items = items?.length
159+
? resolveSidebarItems(items, nextPrefix)
160+
: undefined
161+
}
162+
resolved.push(navLink)
163+
}
164+
})
165+
return resolved
166+
}
167+
168+
/**
169+
* Get or generate sidebar group from the given sidebar items.
170+
*/
171+
export function getSidebarGroups(sidebar: ResolvedSidebarItem[]): ResolvedSidebarItem[] {
172+
const groups: ResolvedSidebarItem[] = []
173+
174+
let lastGroupIndex = 0
175+
176+
for (const index in sidebar) {
177+
const item = sidebar[index]
178+
179+
if (item.items) {
180+
lastGroupIndex = groups.push(item)
181+
continue
182+
}
183+
184+
if (!groups[lastGroupIndex]) {
185+
groups.push({ items: [] })
186+
}
187+
188+
groups[lastGroupIndex]!.items!.push(item)
189+
}
190+
191+
return groups
192+
}
193+
194+
export function getSidebarFirstLink(sidebar: ResolvedSidebarItem[]): string {
195+
for (const item of sidebar) {
196+
if (item.link)
197+
return item.link
198+
if (item.items)
199+
return getSidebarFirstLink(item.items)
200+
}
201+
return ''
202+
}

0 commit comments

Comments
 (0)