Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

can support nested sidebar? #287

Closed
shaodahong opened this issue Apr 28, 2018 · 9 comments
Closed

can support nested sidebar? #287

shaodahong opened this issue Apr 28, 2018 · 9 comments
Labels
contribution welcome Contributions welcome

Comments

@shaodahong
Copy link
Contributor

shaodahong commented Apr 28, 2018

current sidebar only support

.
├─ README.md
├─ contact.md
├─ about.md
├─ foo/
│  ├─ README.md
│  ├─ one.md
│  └─ two.md
└─ bar/
   ├─ README.md
   ├─ three.md
   └─ four.md

but can support this?

├─ README.md
├─ contact.md
├─ about.md
├─ foo/
|  ├─foo1/
|  |    ├─ README.md
|  ├─foo2/
|  |    ├─ README.md
│  ├─ README.md
│  ├─ one.md
│  └─ two.md
└─ bar/
   ├─ README.md
   ├─ three.md
   └─ four.md

I find vuepress/lib/default-theme/util.js

if (isNested) {
  console.error(
    '[vuepress] Nested sidebar groups are not supported. ' +
    'Consider using navbar + categories instead.'
  )
}
@hustjiangtao
Copy link

The answer is Yes!

I made it possible with the document structure such as

./docs/foo/foo1/example.md

And it works well by now, but the only problem is 404 was got when refreshing or opening the link directly.

image

@MikePadge
Copy link

MikePadge commented May 4, 2018

I have this working.
It might be a better idea to separate out the sidebar into its own file and import it into the config, as it looks like nesting sidebars will get out of control quickly all in one place.

@hustjiangtao the key to stopping those 404's is to make sure that the nested sidebars are called before their root directory in the config.js. If /docs/ executes first here, it will break the sidebars for /docs/foo/ and /docs/bar/

But if you notice at the bottom, I actually link to those nested sidebars from the "parent" sidebar. The only thing that's missing now is a back button inside of the nested sidebar.

Because once you reach the nested page, the only way to get back to the previous sidebar page, is the browser back button, or circling back around through Nav links.

  '/docs/foo/': [
        '',
        [ '/docs/foo/failover', 'Failover'],
        'VPNs'
      ],
      '/docs/bar/': [
        '',
        'bar'
      ],
      '/docs/': [
        '',
        'one',
        'two',
        'three',
        'four',
        [ '/docs/foo/', 'Foo'],
        [ '/docs/bar/', 'Bar']
      ],

Edit: Confirmed working at least three levels deep, looks like you can just nest inception with this pattern.

      '/docs/foo/nestor/': [
        '',
        [ '/docs/foo/nestor/testor', 'Testor']
      ],
      '/docs/foo/': [
        '',
        [ '/docs/foo/failover', 'Failover'],
        'VPNs',
        [ '/docs/foo/nestor/', 'Nestor']
      ],
     '/docs/: [
...

It looks like setting yml

---
sidebar: auto
---

In any md files breaks this behavior though. Probably however the frontmatter is parsed?

@ulivz
Copy link
Member

ulivz commented May 21, 2018

We're closing this issue as stale as it's more than 20 days without activity, and without an associated Pull Request. Please feel free to continue discussion. We'll reopen this issue if anything actionable is posted.

@ulivz ulivz closed this as completed May 21, 2018
@j0e1in
Copy link

j0e1in commented Jul 3, 2018

Is it possible to have nested collapsible sidebar? Currently I can only get top-level-collapsible sidebar to work.

Directory structure:

docs
├── foo
│   ├── bar.md
│   └── README.md
└── README.md

With only top-level-collapsible sidebar: (working)

themeConfig: {
  sidebar: {
    '/docs/': [{
      title: 'Docs',
      collapasble: true,
      children: [
        '',
        'foo/'
      ]
    }]
  }
}

With nested-collapsible sidebar: (expected)

themeConfig: {
  sidebar: {
    '/docs/': [{
      title: 'Docs',
      collapsable: true,
      children: [
        '',
        ['foo/', {
          title: 'Foo',
          collapsable: true,
          children: [
            '',
            'bar'
          ]
        }]
      ]
    }]
  }
}

@davestewart
Copy link

davestewart commented Aug 13, 2018

Hey @ulivz, I've been looking at this and would be happy to get involved and submit a PR.

I've got a multi-level sidebar working with the default theme (ejected) and would be happy to jump in and give all the various edge cases a go, update the theme, write tests, update docs, etc.

I've also built some helpers which make it much easier to build sidebar structures, as follows:

image

Have also made some investigation into adding "meta" information so sidebars like the following (additional page types, icons, or such like) could be easily built by users or theme extenders...

image

...just by supplying their own helpers:

demo (path, title) {
  return { path, title, meta: { type: 'demo', icon: 'code' } }
}
const sidebar = group('pages', [
  'intro',
  demo('getting-started'),
  group('demos', [
    // add more demos
  ])
])

This meta information would be additional to the front matter from pages.

I've had a good dig around the source and understand how the pages are resolved, but I imagine that there are various use cases or design decisions to be taken into account if a multi-level sidebar is to be supported.

What would be the best way for me to continue working on this, and getting a knowledge of the various use cases?

@zyy7259
Copy link

zyy7259 commented Aug 17, 2018

I have submitted a pull request to implement this feature~

@Seraf
Copy link

Seraf commented Jan 24, 2019

@davestewart Hi, is it possible to share somewhere those helpers/themes (like a gist) please ?
I'm trying to achieve exactly the same thing, I'd like to understand exactly the definition of the group helper.

Thanks !

ulivz added a commit that referenced this issue Feb 3, 2019
@Sandstedt
Copy link

Sandstedt commented Apr 7, 2019

EDIT: Doesn't seem to work on build.

@Seraf:
Not sure id this is as smart solution, but you only need to change one file. I tried to add a SidebarGroup inside another SidebarGroup, so it will reference itself. My (ejected) SidebarGroup.vue looks like this now:

<template>
  <div
    class="sidebar-group"
    :class="{ first, collapsable }"
  >
    <p
      class="sidebar-heading"
      :class="{ open }"
      @click="$emit('toggle')"
    >
      <span>{{ item.title }}</span>
      <span
        class="arrow"
        v-if="collapsable"
        :class="open ? 'down' : 'right'">
      </span>
    </p>

    <DropdownTransition>
      <ul
        ref="items"
        class="sidebar-group-items"
        v-if="open || !collapsable"
      >
        <li v-for="(child, i) in item.children">
          <SidebarGroup
            v-if="child.type === 'group'"
            :item="child"
            :first="i === 0"
            :open="i === openGroupIndex"
            :collapsable="child.collapsable || child.collapsible"
            @toggle="toggleGroup(i)"
          />
          <SidebarLink v-else :item="child"/>
        </li>
      </ul>
    </DropdownTransition>
  </div>
</template>

<script>
import SidebarLink from './SidebarLink.vue'
import DropdownTransition from './DropdownTransition.vue'

export default {
  name: 'SidebarGroup',
  props: ['item', 'first', 'open', 'collapsable'],
  components: { SidebarLink, DropdownTransition },
  
  data () {
    return {
      openGroupIndex: 0
    }
  },

  methods: {
    toggleGroup (index) {
      this.openGroupIndex = index === this.openGroupIndex ? -1 : index
    },
  }
}
</script>

<style lang="stylus">
.sidebar-group
  &:not(.first)
    margin-top 1em
  .sidebar-group
    padding-left 0.5em
  &:not(.collapsable)
    .sidebar-heading
      cursor auto
      color inherit

.sidebar-heading
  color #999
  transition color .15s ease
  cursor pointer
  font-size 1.1em
  font-weight bold
  // text-transform uppercase
  padding 0 1.5rem
  margin-top 0
  margin-bottom 0.5rem
  &.open, &:hover
    color inherit
  .arrow
    position relative
    top -0.12em
    left 0.5em
  &:.open .arrow
    top -0.18em

.sidebar-group-items
  transition height .1s ease-out
  overflow hidden
</style>

And I'm using it like you could imagine in config.js:

module.exports = {
  themeConfig: {
    sidebar: [
      {
        title: 'API',
        collapsable: true,
        children: [
          '/api/',
          {
            title: 'Modules',
            collapsable: true,
            children: [
              '/api/page-1/',
              '/api/page-2/',
            ]
          },
          {
            title: 'Components',
            collapsable: false,
            children: [
              '/api/page-1/',
              '/api/page-2/',
            ]
          },
        ]
      },
      {
        title: 'Learn more',
        children: [
          '/page-1/',
          '/page-2',
        ]
      }
    ]
  }
}

@davestewart
Copy link

davestewart commented Apr 8, 2019

@davestewart Hi, is it possible to share somewhere those helpers/themes (like a gist) please ?

Hey @Seraf, sorry - I missed this!

It's been ages since I worked on this, so not sure where the code is now, but group is just a wrapper. It works like this:

function page (link, title) {
	return { type: 'page', link, title }
}

function group (title, children) {
	return { type: 'group', title, children }
}

var sidebar = [
	page ('foo', 'Foo'),
	page ('bar', 'Bar'),
	group('Children 1', [
		page ('baz', 'Baz'),
		page ('qux', 'Qux'),
		group('Children 2', [
			page ('abc', 'ABC'),
			page ('def', 'DEF'),
		])
	])
]
console.log(JSON.stringify(sidebar, null, 2))
[
  {
    "type": "page",
    "link": "foo",
    "title": "Foo"
  },
  {
    "type": "page",
    "link": "bar",
    "title": "Bar"
  },
  {
    "type": "group",
    "title": "Children 1",
    "children": [
      {
        "type": "page",
        "link": "baz",
        "title": "Baz"
      },
      {
        "type": "page",
        "link": "qux",
        "title": "Qux"
      },
      {
        "type": "group",
        "title": "Children 2",
        "children": [
          {
            "type": "page",
            "link": "abc",
            "title": "ABC"
          },
          {
            "type": "page",
            "link": "def",
            "title": "DEF"
          }
        ]
      }
    ]
  }
]

I use a similar approach to clean up my routes files:

Hope that helps :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contribution welcome Contributions welcome
Projects
None yet
Development

No branches or pull requests

9 participants