Skip to content

Commit 32d2cc1

Browse files
committed
feat: sidebarDepth for sidebar groups
1 parent 876b677 commit 32d2cc1

File tree

7 files changed

+147
-96
lines changed

7 files changed

+147
-96
lines changed

Diff for: packages/@vuepress/theme-default/components/Page.vue

+12-7
Original file line numberDiff line numberDiff line change
@@ -177,20 +177,25 @@ function resolveNext (page, items) {
177177
178178
function find (page, items, offset) {
179179
const res = []
180-
items.forEach(item => {
181-
if (item.type === 'group') {
182-
res.push(...item.children || [])
183-
} else {
184-
res.push(item)
185-
}
186-
})
180+
flatternItems(items, res)
187181
for (let i = 0; i < res.length; i++) {
188182
const cur = res[i]
189183
if (cur.type === 'page' && cur.path === decodeURIComponent(page.path)) {
190184
return res[i + offset]
191185
}
192186
}
193187
}
188+
189+
function flatternItems (items, res) {
190+
for (let i = 0, l = items.length; i < l; i++) {
191+
if (items[i].type === 'group') {
192+
flatternItems(items[i].children, res)
193+
} else {
194+
res.push(items[i])
195+
}
196+
}
197+
}
198+
194199
</script>
195200

196201
<style lang="stylus">

Diff for: packages/@vuepress/theme-default/components/Sidebar.vue

+5-63
Original file line numberDiff line numberDiff line change
@@ -2,79 +2,21 @@
22
<aside class="sidebar">
33
<NavLinks/>
44
<slot name="top"/>
5-
<ul class="sidebar-links" v-if="items.length">
6-
<li v-for="(item, i) in items" :key="i">
7-
<SidebarGroup
8-
v-if="item.type === 'group'"
9-
:item="item"
10-
:first="i === 0"
11-
:open="i === openGroupIndex"
12-
:collapsable="item.collapsable || item.collapsible"
13-
@toggle="toggleGroup(i)"
14-
/>
15-
<SidebarLink v-else :item="item"/>
16-
</li>
17-
</ul>
5+
<SidebarLinks class="sidebar-links" :items="items"/>
186
<slot name="bottom"/>
197
</aside>
208
</template>
219

2210
<script>
23-
import SidebarGroup from './SidebarGroup.vue'
24-
import SidebarLink from './SidebarLink.vue'
11+
import SidebarLinks from './SidebarLinks.vue'
2512
import NavLinks from './NavLinks.vue'
26-
import { isActive } from '../util'
2713
2814
export default {
29-
components: { SidebarGroup, SidebarLink, NavLinks },
15+
name: 'Sidebar',
3016
31-
props: ['items'],
17+
components: { SidebarLinks, NavLinks },
3218
33-
data () {
34-
return {
35-
openGroupIndex: 0
36-
}
37-
},
38-
39-
created () {
40-
this.refreshIndex()
41-
},
42-
43-
watch: {
44-
'$route' () {
45-
this.refreshIndex()
46-
}
47-
},
48-
49-
methods: {
50-
refreshIndex () {
51-
const index = resolveOpenGroupIndex(
52-
this.$route,
53-
this.items
54-
)
55-
if (index > -1) {
56-
this.openGroupIndex = index
57-
}
58-
},
59-
60-
toggleGroup (index) {
61-
this.openGroupIndex = index === this.openGroupIndex ? -1 : index
62-
},
63-
64-
isActive (page) {
65-
return isActive(this.$route, page.regularPath)
66-
}
67-
}
68-
}
69-
70-
function resolveOpenGroupIndex (route, items) {
71-
for (let i = 0; i < items.length; i++) {
72-
const item = items[i]
73-
if (item.type === 'group' && item.children.some(c => isActive(route, c.path))) {
74-
return i
75-
}
76-
}
77-
return -1
19+
props: ['items']
7820
}
7921
</script>
8022

Diff for: packages/@vuepress/theme-default/components/SidebarGroup.vue

+12-12
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
22
<section
33
class="sidebar-group"
4-
:class="{ first, collapsable }"
4+
:class="{ collapsable }"
55
>
66
<router-link
77
class="sidebar-heading clickable"
@@ -36,28 +36,28 @@
3636
</p>
3737

3838
<DropdownTransition>
39-
<ul
40-
ref="items"
39+
<SidebarLinks
4140
class="sidebar-group-items"
41+
:items="item.children"
4242
v-if="open || !collapsable"
43-
>
44-
<li v-for="child in item.children">
45-
<SidebarLink :item="child"/>
46-
</li>
47-
</ul>
43+
:sidebarDepth="item.sidebarDepth"
44+
/>
4845
</DropdownTransition>
4946
</section>
5047
</template>
5148

5249
<script>
5350
import { isActive } from '../util'
54-
import SidebarLink from './SidebarLink.vue'
5551
import DropdownTransition from './DropdownTransition.vue'
5652
5753
export default {
5854
name: 'SidebarGroup',
59-
props: ['item', 'first', 'open', 'collapsable'],
60-
components: { SidebarLink, DropdownTransition },
55+
props: ['item', 'open', 'collapsable'],
56+
components: { DropdownTransition },
57+
// ref: https://vuejs.org/v2/guide/components-edge-cases.html#Circular-References-Between-Components
58+
beforeCreate () {
59+
this.$options.components.SidebarLinks = require('./SidebarLinks.vue').default
60+
},
6161
methods: { isActive }
6262
}
6363
</script>
@@ -78,7 +78,7 @@ export default {
7878
font-size 1.1em
7979
font-weight bold
8080
// text-transform uppercase
81-
padding 0.35rem 1.5rem
81+
padding 0.35rem 1.5rem 0.35rem 1.25rem
8282
width 100%
8383
box-sizing border-box
8484
margin 0

Diff for: packages/@vuepress/theme-default/components/SidebarLink.vue

+14-5
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { isActive, hashRE, groupHeaders } from '../util'
44
export default {
55
functional: true,
66
7-
props: ['item'],
7+
props: ['item', 'sidebarDepth'],
88
99
render (h,
1010
{
@@ -16,7 +16,8 @@ export default {
1616
$themeLocaleConfig
1717
},
1818
props: {
19-
item
19+
item,
20+
sidebarDepth
2021
}
2122
}) {
2223
// use custom active class matching logic
@@ -28,10 +29,18 @@ export default {
2829
? selfActive || item.children.some(c => isActive($route, item.basePath + '#' + c.slug))
2930
: selfActive
3031
const link = renderLink(h, item.path, item.title || item.path, active)
31-
const configDepth = $page.frontmatter.sidebarDepth != null
32-
? $page.frontmatter.sidebarDepth
33-
: ($themeLocaleConfig.sidebarDepth || $themeConfig.sidebarDepth)
32+
33+
let configDepth
34+
if ($page.frontmatter.sidebarDepth != null) {
35+
configDepth = $page.frontmatter.sidebarDepth
36+
} else if (sidebarDepth != null) {
37+
configDepth = sidebarDepth
38+
} else {
39+
configDepth = $themeLocaleConfig.sidebarDepth || $themeConfig.sidebarDepth
40+
}
41+
3442
const maxDepth = configDepth == null ? 1 : configDepth
43+
console.log(maxDepth)
3544
3645
const displayAllHeaders = !!$themeLocaleConfig.displayAllHeaders
3746
if (item.type === 'auto') {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<template>
2+
<ul v-if="items.length">
3+
<li v-for="(item, i) in items" :key="i">
4+
<SidebarGroup
5+
v-if="item.type === 'group'"
6+
:item="item"
7+
:first="i === 0"
8+
:open="i === openGroupIndex"
9+
:collapsable="item.collapsable || item.collapsible"
10+
@toggle="toggleGroup(i)"
11+
/>
12+
<SidebarLink
13+
v-else
14+
:sidebarDepth="sidebarDepth"
15+
:item="item"
16+
/>
17+
</li>
18+
</ul>
19+
</template>
20+
21+
<script>
22+
import SidebarGroup from './SidebarGroup.vue'
23+
import SidebarLink from './SidebarLink.vue'
24+
import { isActive } from '../util'
25+
26+
export default {
27+
name: 'SidebarLinks',
28+
29+
components: { SidebarGroup, SidebarLink },
30+
31+
props: ['items', 'sidebarDepth'],
32+
33+
data () {
34+
return {
35+
openGroupIndex: 0
36+
}
37+
},
38+
39+
created () {
40+
this.refreshIndex()
41+
},
42+
43+
watch: {
44+
'$route' () {
45+
this.refreshIndex()
46+
}
47+
},
48+
49+
methods: {
50+
refreshIndex () {
51+
const index = resolveOpenGroupIndex(
52+
this.$route,
53+
this.items
54+
)
55+
if (index > -1) {
56+
this.openGroupIndex = index
57+
}
58+
},
59+
60+
toggleGroup (index) {
61+
this.openGroupIndex = index === this.openGroupIndex ? -1 : index
62+
},
63+
64+
isActive (page) {
65+
return isActive(this.$route, page.regularPath)
66+
}
67+
}
68+
}
69+
70+
function resolveOpenGroupIndex (route, items) {
71+
for (let i = 0; i < items.length; i++) {
72+
const item = items[i]
73+
if (item.type === 'group' && item.children.some(c => c.type === 'page' && isActive(route, c.path))) {
74+
return i
75+
}
76+
}
77+
return -1
78+
}
79+
</script>

Diff for: packages/@vuepress/theme-default/util/index.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -208,26 +208,26 @@ function ensureEndingSlash (path) {
208208
: path + '/'
209209
}
210210

211-
function resolveItem (item, pages, base, isNested) {
211+
function resolveItem (item, pages, base, groupDepth = 1) {
212212
if (typeof item === 'string') {
213213
return resolvePage(pages, item, base)
214214
} else if (Array.isArray(item)) {
215215
return Object.assign(resolvePage(pages, item[0], base), {
216216
title: item[1]
217217
})
218218
} else {
219-
if (isNested) {
219+
if (groupDepth > 3) {
220220
console.error(
221-
'[vuepress] Nested sidebar groups are not supported. ' +
222-
'Consider using navbar + categories instead.'
221+
'[vuepress] detected a too deep nested sidebar group.'
223222
)
224223
}
225224
const children = item.children || []
226225
return {
227226
type: 'group',
228227
path: item.path,
229228
title: item.title,
230-
children: children.map(child => resolveItem(child, pages, base, true)),
229+
sidebarDepth: item.sidebarDepth,
230+
children: children.map(child => resolveItem(child, pages, base, groupDepth + 1)),
231231
collapsable: item.collapsable !== false
232232
}
233233
}

Diff for: packages/docs/docs/.vuepress/config.js

+20-4
Original file line numberDiff line numberDiff line change
@@ -91,21 +91,37 @@ function getGuideSidebar (groupA, groupB) {
9191
{
9292
title: groupA,
9393
collapsable: false,
94+
sidebarDepth: 2,
9495
children: [
9596
'',
9697
'getting-started',
9798
'directory-structure',
9899
'basic-config',
99100
'assets',
100-
'markdown',
101-
'using-vue',
102-
'i18n',
103-
'deploy',
101+
{
102+
title: groupA,
103+
collapsable: false,
104+
sidebarDepth: 2,
105+
children: [
106+
'markdown',
107+
'deploy',
108+
{
109+
title: groupA,
110+
collapsable: false,
111+
sidebarDepth: 2,
112+
children: [
113+
'using-vue',
114+
'i18n',
115+
]
116+
},
117+
]
118+
},
104119
]
105120
},
106121
{
107122
title: groupB,
108123
collapsable: false,
124+
sidebarDepth: 2,
109125
children: [
110126
'frontmatter',
111127
'permalinks',

0 commit comments

Comments
 (0)