Skip to content

Commit 94bb32f

Browse files
committed
feat: refine group
- isolate a group's open status with `isolated: true` - config a isolated group's initial open status with `initialIsolatedOpen: true` - config a group's sidebarDepth with `sidebarDepth: 2` - nested sidebar groups
1 parent 9b602f2 commit 94bb32f

File tree

7 files changed

+111
-68
lines changed

7 files changed

+111
-68
lines changed

docs/default-theme-config/README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,12 @@ module.exports = {
199199

200200
Sidebar groups are collapsable by default. You can force a group to be always open with `collapsable: false`.
201201

202+
When a group is open, other groups at the same level will be automatically closed. You can isolate a group's open status with `isolated: true`. And then you can config its initial open status with `initialIsolatedOpen: true`.
203+
204+
You can config a group's sidebarDepth with `sidebarDepth: 2`.
205+
206+
You can nest sidebar groups.
207+
202208
### Multiple Sidebars
203209

204210
If you wish to display different sidebars for different sections of content, first organize your pages into directories for each desired section:
@@ -333,7 +339,7 @@ module.exports = {
333339
```
334340

335341
::: warning Note
336-
Unlike the [built-in search](#built-in-search) engine which works out of the box, [Algolia DocSearch](https://community.algolia.com/docsearch/) requires you to submit your site to them for indexing before it starts working.
342+
Unlike the [built-in search](#built-in-search) engine which works out of the box, [Algolia DocSearch](https://community.algolia.com/docsearch/) requires you to submit your site to them for indexing before it starts working.
337343
:::
338344

339345
For more options, refer to [Algolia DocSearch's documentation](https://github.com/algolia/docsearch#docsearch-options).

docs/zh/default-theme-config/README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ module.exports = {
164164
}
165165
```
166166

167-
::: tip
167+
::: tip
168168
值得一提的是,当你禁用此选项时,此功能的相应脚本将不会被加载,这是我们性能优化的一个小点。
169169
:::
170170

@@ -196,6 +196,12 @@ module.exports = {
196196

197197
侧边栏的每个子组默认是可折叠的,你可以设置 `collapsable: false` 来让一个组永远都是展开状态。
198198

199+
当一个子组被展开时,跟它同级的其他子组会被折叠。你可以设置 `isolated: true` 来隔离一个组的展开状态。然后你可以设置 `initialIsolatedOpen: true` 来让一个被隔离的组在一开始就处于展开状态。
200+
201+
你可以通过 `sidebarDepth: 2` 来设置一个组的 sidebarDepth。
202+
203+
你可以嵌套组。
204+
199205
### 多个侧边栏
200206

201207
如果你想为不同的页面组来显示不同的侧边栏,首先,将你的页面文件组织成下述的目录结构:

lib/default-theme/Page.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ function find (page, items, offset) {
142142
const res = []
143143
items.forEach(item => {
144144
if (item.type === 'group') {
145-
res.push(...item.children || [])
145+
res.push(...(item.descendants || item.children))
146146
} else {
147147
res.push(item)
148148
}

lib/default-theme/Sidebar.vue

Lines changed: 2 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77
<SidebarGroup v-if="item.type === 'group'"
88
:item="item"
99
:first="i === 0"
10-
:open="i === openGroupIndex"
11-
:collapsable="item.collapsable"
12-
@toggle="toggleGroup(i)"/>
10+
:collapsable="item.collapsable"/>
1311
<SidebarLink v-else :item="item"/>
1412
</li>
1513
</ul>
@@ -21,51 +19,10 @@
2119
import SidebarGroup from './SidebarGroup.vue'
2220
import SidebarLink from './SidebarLink.vue'
2321
import NavLinks from './NavLinks.vue'
24-
import { isActive } from './util'
2522
2623
export default {
2724
components: { SidebarGroup, SidebarLink, NavLinks },
28-
props: ['items'],
29-
data () {
30-
return {
31-
openGroupIndex: 0
32-
}
33-
},
34-
created () {
35-
this.refreshIndex()
36-
},
37-
watch: {
38-
'$route' () {
39-
this.refreshIndex()
40-
}
41-
},
42-
methods: {
43-
refreshIndex () {
44-
const index = resolveOpenGroupIndex(
45-
this.$route,
46-
this.items
47-
)
48-
if (index > -1) {
49-
this.openGroupIndex = index
50-
}
51-
},
52-
toggleGroup (index) {
53-
this.openGroupIndex = index === this.openGroupIndex ? -1 : index
54-
},
55-
isActive (page) {
56-
return isActive(this.$route, page.path)
57-
}
58-
}
59-
}
60-
61-
function resolveOpenGroupIndex (route, items) {
62-
for (let i = 0; i < items.length; i++) {
63-
const item = items[i]
64-
if (item.type === 'group' && item.children.some(c => isActive(route, c.path))) {
65-
return i
66-
}
67-
}
68-
return -1
25+
props: ['items']
6926
}
7027
</script>
7128

lib/default-theme/SidebarGroup.vue

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22
<div class="sidebar-group" :class="{ first, collapsable }">
3-
<p class="sidebar-heading" :class="{ open }" @click="$emit('toggle')">
3+
<p class="sidebar-heading" :class="{ open }" @click="handleClickToggle">
44
<span>{{ item.title }}</span>
55
<span class="arrow"
66
v-if="collapsable"
@@ -9,21 +9,77 @@
99
<DropdownTransition>
1010
<ul class="sidebar-group-items" ref="items" v-if="open || !collapsable">
1111
<li v-for="child in item.children">
12-
<SidebarLink :item="child"/>
12+
<SidebarGroup v-if="child.type === 'group'"
13+
:item="child"
14+
:collapsable="child.collapsable"/>
15+
<SidebarLink v-else :item="child" :sidebarDepth="item.sidebarDepth"/>
1316
</li>
1417
</ul>
1518
</DropdownTransition>
1619
</div>
1720
</template>
1821

1922
<script>
23+
import Vue from 'vue'
2024
import SidebarLink from './SidebarLink.vue'
2125
import DropdownTransition from './DropdownTransition.vue'
26+
import { isActive } from './util'
27+
28+
const hub = new Vue()
2229
2330
export default {
2431
name: 'SidebarGroup',
25-
props: ['item', 'first', 'open', 'collapsable'],
26-
components: { SidebarLink, DropdownTransition }
32+
components: { SidebarLink, DropdownTransition },
33+
props: [
34+
'item',
35+
'first',
36+
'collapsable'
37+
],
38+
data () {
39+
return {
40+
open: this.item.isolated && this.item.initialIsolatedOpen || false
41+
}
42+
},
43+
created () {
44+
this.initToggleEvent()
45+
this.refreshOpen()
46+
},
47+
watch: {
48+
'$route' () {
49+
this.refreshOpen()
50+
}
51+
},
52+
methods: {
53+
initToggleEvent () {
54+
const onToggle = this.onToggle.bind(this)
55+
hub.$on('toggle', onToggle)
56+
this.$on('hook:destroyed', () => {
57+
hub.$off('toggle', onToggle)
58+
})
59+
},
60+
refreshOpen () {
61+
const arr = this.item.descendants || this.item.children
62+
if (arr.some(c => isActive(this.$route, c.path))) {
63+
this.open = true
64+
}
65+
},
66+
handleClickToggle () {
67+
this.open = !this.open
68+
if (this.open && !this.item.isolated) {
69+
hub.$emit('toggle', { depth: this.item.depth, target: this })
70+
}
71+
},
72+
onToggle ({ depth, target }) {
73+
if (
74+
target.$parent === this.$parent &&
75+
depth === this.item.depth &&
76+
!this.item.isolated &&
77+
target !== this
78+
) {
79+
this.open = false
80+
}
81+
}
82+
}
2783
}
2884
</script>
2985

@@ -34,7 +90,7 @@ export default {
3490
.sidebar-group
3591
padding-left 0.5em
3692
&:not(.collapsable)
37-
.sidebar-heading
93+
> .sidebar-heading
3894
cursor auto
3995
color inherit
4096

lib/default-theme/SidebarLink.vue

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,14 @@ import { isActive, hashRE, groupHeaders } from './util'
33
44
export default {
55
functional: true,
6-
props: ['item'],
7-
render (h, { parent: { $page, $site, $route }, props: { item }}) {
6+
props: ['item', 'sidebarDepth'],
7+
render (
8+
h,
9+
{
10+
parent: { $page, $site, $route },
11+
props: { item, sidebarDepth: groupSidebarDepth }
12+
}
13+
) {
814
// use custom active class matching logic
915
// due to edge case of paths ending with / + hash
1016
const selfActive = isActive($route, item.path)
@@ -14,10 +20,17 @@ export default {
1420
? selfActive || item.children.some(c => isActive($route, item.basePath + '#' + c.slug))
1521
: selfActive
1622
const link = renderLink(h, item.path, item.title || item.path, active)
17-
const configDepth = $page.frontmatter.sidebarDepth != null
18-
? $page.frontmatter.sidebarDepth
19-
: $site.themeConfig.sidebarDepth
23+
24+
let configDepth
25+
if ($page.frontmatter.sidebarDepth != null) {
26+
configDepth = $page.frontmatter.sidebarDepth
27+
} else if (groupSidebarDepth != null) {
28+
configDepth = groupSidebarDepth
29+
} else {
30+
$site.themeConfig.sidebarDepth
31+
}
2032
const maxDepth = configDepth == null ? 1 : configDepth
33+
2134
const displayAllHeaders = !!$site.themeConfig.displayAllHeaders
2235
if (item.type === 'auto') {
2336
return [link, renderChildren(h, item.children, item.basePath, $route, maxDepth)]

lib/default-theme/util.js

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -191,26 +191,31 @@ function ensureEndingSlash (path) {
191191
: path + '/'
192192
}
193193

194-
function resolveItem (item, pages, base, isNested) {
194+
function resolveItem (item, pages, base, depth = 0) {
195195
if (typeof item === 'string') {
196196
return resolvePage(pages, item, base)
197197
} else if (Array.isArray(item)) {
198198
return Object.assign(resolvePage(pages, item[0], base), {
199199
title: item[1]
200200
})
201201
} else {
202-
if (isNested) {
203-
console.error(
204-
'[vuepress] Nested sidebar groups are not supported. ' +
205-
'Consider using navbar + categories instead.'
206-
)
207-
}
208-
const children = item.children || []
202+
depth++
203+
const descendants = item.descendants || []
204+
const children = (item.children || []).map(child => {
205+
const resolvedItem = resolveItem(child, pages, base, depth)
206+
;[].push.apply(descendants, resolvedItem.descendants || [resolvedItem])
207+
return resolvedItem
208+
})
209209
return {
210210
type: 'group',
211211
title: item.title,
212-
children: children.map(child => resolveItem(child, pages, base, true)),
213-
collapsable: item.collapsable !== false
212+
children,
213+
descendants,
214+
collapsable: item.collapsable !== false,
215+
isolated: item.isolated === true,
216+
initialIsolatedOpen: item.initialIsolatedOpen === true,
217+
sidebarDepth: item.sidebarDepth,
218+
depth
214219
}
215220
}
216221
}

0 commit comments

Comments
 (0)