Skip to content

Commit

Permalink
feat: refine group
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
zyy7259 committed Dec 4, 2018
1 parent 1e28e92 commit 24fea8a
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 75 deletions.
2 changes: 1 addition & 1 deletion packages/@vuepress/theme-default/components/Page.vue
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ function find (page, items, offset) {
const res = []
items.forEach(item => {
if (item.type === 'group') {
res.push(...item.children || [])
res.push(...item.descendants || [])
} else {
res.push(item)
}
Expand Down
54 changes: 2 additions & 52 deletions packages/@vuepress/theme-default/components/Sidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@
v-if="item.type === 'group'"
:item="item"
:first="i === 0"
:open="i === openGroupIndex"
:collapsable="item.collapsable || item.collapsible"
@toggle="toggleGroup(i)"
/>
:collapsable="item.collapsable || item.collapsible"/>
<SidebarLink v-else :item="item"/>
</li>
</ul>
Expand All @@ -23,58 +20,11 @@
import SidebarGroup from './SidebarGroup.vue'
import SidebarLink from './SidebarLink.vue'
import NavLinks from './NavLinks.vue'
import { isActive } from '../util'
export default {
components: { SidebarGroup, SidebarLink, NavLinks },
props: ['items'],
data () {
return {
openGroupIndex: 0
}
},
created () {
this.refreshIndex()
},
watch: {
'$route' () {
this.refreshIndex()
}
},
methods: {
refreshIndex () {
const index = resolveOpenGroupIndex(
this.$route,
this.items
)
if (index > -1) {
this.openGroupIndex = index
}
},
toggleGroup (index) {
this.openGroupIndex = index === this.openGroupIndex ? -1 : index
},
isActive (page) {
return isActive(this.$route, page.regularPath)
}
}
}
function resolveOpenGroupIndex (route, items) {
for (let i = 0; i < items.length; i++) {
const item = items[i]
if (item.type === 'group' && item.children.some(c => isActive(route, c.path))) {
return i
}
}
return -1
props: ['items']
}
</script>

Expand Down
72 changes: 67 additions & 5 deletions packages/@vuepress/theme-default/components/SidebarGroup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<p
class="sidebar-heading"
:class="{ open }"
@click="$emit('toggle')"
@click="handleClick"
>
<span>{{ item.title }}</span>
<span
Expand All @@ -23,21 +23,83 @@
v-if="open || !collapsable"
>
<li v-for="child in item.children">
<SidebarLink :item="child"/>
<SidebarGroup v-if="child.type === 'group'"
:item="child"
:collapsable="child.collapsable"/>
<SidebarLink v-else :item="child" :sidebarDepth="item.sidebarDepth"/>
</li>
</ul>
</DropdownTransition>
</div>
</template>

<script>
import Vue from 'vue'
import SidebarLink from './SidebarLink.vue'
import DropdownTransition from './DropdownTransition.vue'
import { isActive } from '../util'
const bus = new Vue()
export default {
name: 'SidebarGroup',
props: ['item', 'first', 'open', 'collapsable'],
components: { SidebarLink, DropdownTransition }
components: { SidebarLink, DropdownTransition },
props: [
'item',
'first',
'collapsable'
],
data () {
return {
open: this.item.isolated && this.item.initialIsolatedOpen || false
}
},
created () {
this.initBusEvent()
this.refreshOpen()
},
watch: {
'$route' () {
this.refreshOpen()
}
},
methods: {
initBusEvent () {
const onRequestClose = this.onRequestClose.bind(this)
bus.$on('requestClose', onRequestClose)
this.$on('hook:destroyed', () => {
bus.$off('requestClose', onRequestClose)
})
},
refreshOpen () {
const arr = this.item.descendants || []
if (arr.some(c => isActive(this.$route, c.path))) {
this.open = true
}
},
handleClick () {
this.open = !this.open
if (this.open && !this.item.isolated) {
bus.$emit('requestClose', { groupDepth: this.item.groupDepth, target: this })
}
},
onRequestClose ({ groupDepth, target }) {
if (
target.$parent === this.$parent &&
groupDepth === this.item.groupDepth &&
!this.item.isolated &&
target !== this
) {
this.open = false
}
}
}
}
</script>

Expand All @@ -48,7 +110,7 @@ export default {
.sidebar-group
padding-left 0.5em
&:not(.collapsable)
.sidebar-heading
> .sidebar-heading
cursor auto
color inherit
Expand Down
23 changes: 18 additions & 5 deletions packages/@vuepress/theme-default/components/SidebarLink.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@ import { isActive, hashRE, groupHeaders } from '../util'
export default {
functional: true,
props: ['item'],
props: ['item', 'sidebarDepth'],
render (h, { parent: { $page, $site, $route }, props: { item }}) {
render (
h,
{
parent: { $page, $site, $route },
props: { item, sidebarDepth }
}
) {
// use custom active class matching logic
// due to edge case of paths ending with / + hash
const selfActive = isActive($route, item.path)
Expand All @@ -16,10 +22,17 @@ export default {
? selfActive || item.children.some(c => isActive($route, item.basePath + '#' + c.slug))
: selfActive
const link = renderLink(h, item.path, item.title || item.path, active)
const configDepth = $page.frontmatter.sidebarDepth != null
? $page.frontmatter.sidebarDepth
: $site.themeConfig.sidebarDepth
let configDepth
if ($page.frontmatter.sidebarDepth != null) {
configDepth = $page.frontmatter.sidebarDepth
} else if (sidebarDepth != null) {
configDepth = sidebarDepth
} else {
configDepth = $site.themeConfig.sidebarDepth
}
const maxDepth = configDepth == null ? 1 : configDepth
const displayAllHeaders = !!$site.themeConfig.displayAllHeaders
if (item.type === 'auto') {
return [link, renderChildren(h, item.children, item.basePath, $route, maxDepth)]
Expand Down
26 changes: 15 additions & 11 deletions packages/@vuepress/theme-default/util/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,26 +207,30 @@ function ensureEndingSlash (path) {
: path + '/'
}

function resolveItem (item, pages, base, isNested) {
function resolveItem (item, pages, base, groupDepth = 1) {
if (typeof item === 'string') {
return resolvePage(pages, item, base)
} else if (Array.isArray(item)) {
return Object.assign(resolvePage(pages, item[0], base), {
title: item[1]
})
} else {
if (isNested) {
console.error(
'[vuepress] Nested sidebar groups are not supported. ' +
'Consider using navbar + categories instead.'
)
}
const children = item.children || []
} else if (Array.isArray(item.children)) {
const descendants = []
const children = item.children.map(child => {
const resolvedItem = resolveItem(child, pages, base, groupDepth + 1)
;[].push.apply(descendants, resolvedItem.descendants || [resolvedItem])
return resolvedItem
})
return {
type: 'group',
title: item.title,
children: children.map(child => resolveItem(child, pages, base, true)),
collapsable: item.collapsable !== false
children,
descendants,
collapsable: item.collapsable !== false,
isolated: item.isolated === true,
initialIsolatedOpen: item.initialIsolatedOpen === true,
sidebarDepth: item.sidebarDepth,
groupDepth
}
}
}
8 changes: 7 additions & 1 deletion packages/docs/docs/theme/default-theme-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,12 @@ module.exports = {

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

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`.

You can config a group's sidebarDepth with `sidebarDepth: 2`.

You can nest sidebar groups.

### Multiple Sidebars

If you wish to display different sidebars for different sections of content, first organize your pages into directories for each desired section:
Expand Down Expand Up @@ -329,7 +335,7 @@ module.exports = {
```

::: warning Note
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.
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.
:::

For more options, refer to [Algolia DocSearch's documentation](https://github.com/algolia/docsearch#docsearch-options).
Expand Down
6 changes: 6 additions & 0 deletions packages/docs/docs/zh/theme/default-theme-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,12 @@ module.exports = {

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

当一个子组被展开时,跟它同级的其他子组会被折叠。你可以设置 `isolated: true` 来隔离一个组的展开状态。然后你可以设置 `initialIsolatedOpen: true` 来让一个被隔离的组在一开始就处于展开状态。

你可以通过 `sidebarDepth: 2` 来设置一个组的 sidebarDepth。

你可以嵌套组。

### 多个侧边栏

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

0 comments on commit 24fea8a

Please sign in to comment.