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

Ability to collapse sections #423

Open
mike-engel opened this issue Nov 4, 2019 · 10 comments
Open

Ability to collapse sections #423

mike-engel opened this issue Nov 4, 2019 · 10 comments

Comments

@mike-engel
Copy link

It think it would be nice if each section in the main navigation area could be collapsed. This would help with a docs project with many sections and pages, making navigation much easier. This could be a simple state key in the x-section component, with an available prop collapsed to set the default state.

If a PR would be supported for this, I'm happy to create it. Thanks!

@RobbieTheWagner
Copy link
Member

That sounds good to me. @samselikoff are you in favor?

@samselikoff
Copy link
Contributor

Potentially! I'd like to see some examples of the UI/UX first, I think a lot of times this sort of feature goes unused and just clutters up the UI. It also can make it harder to find things (first I have to expand every section to see if it has what I want).

I see a lot of sites like Zeit Next and Svelte etc. that don't have this but again I'm open to it.

I think ideally this would not be configurable, and we'd be able to land on something that works for everyone. For example, maybe sections start out collapsed if there's more than 4 of them or something like that. But I understand folks will want to configure them too.

I think the new Square API docs do a good job. (If you view them on a big screen you'll see the sidebar.) Maybe we could add a single boolean on the nav component that enables or disabled this, and if it's enabled it acts like that one does: clicking on a category navigates to the first guide in that section, and also expands the section. Feels like one less click (don't need to expand/collapse, this is where I feel the UX gets tiresome).

What do you think?

@RobbieTheWagner
Copy link
Member

I was thinking it would be purely opt in. I'm not sure if I would want it enabled by default over 3 items.

@mike-engel
Copy link
Author

Yep, I was thinking purely opt in. I guess that would be two props: collapsible, and startCollapsed (or something).

I'm assuming that by the square docs, you mean these docs?

If so, that's not bad, and could be a good solution for most people if it was opt in :)

@samselikoff
Copy link
Contributor

Whoops meant to link them! Yep those docs. I just like that there's no arrows that kind of clutter up the UI, you just click a section, it opens it + navigates to the first page. Feels like less work to me.

I also would like to see API docs move to a separate top-level nav, I think that would also help the UI situation. (No pressure to work on that but if you feel so inclined I think it would be good for the project!)

Do you have a screenshot/link of the docs you're working with now that are cluttered?

If you want to work on this go for it. If we follow the Square API docs UI pattern strictly, we wouldn't need a startCollapsed, you would just click on the top-level Documentation link and the app would navigate to the first doc of the first section, so the first section would be open. Then all other sections would be closed, and if you click on one of them you'd navigate to the first respective page + that section would open. What do you think?

@mike-engel
Copy link
Author

I like the idea of API docs moving to a separate tab, but I think I'll leave that for another PR. I'm new to Ember so I think this PR is going to be enough for me to handle 😅

I don't have a current screenshot of our docs—this was more in anticipation of all the docs we're going to have at some point. I've included a screenshot of our information architecture, however, which should help illustrate what we're thinking about.

Screenshot 2019-11-05 at 21 43 08

One thing our team brought up when reviewing the comments here is that it could potentially be jarring to click on a section header and go to the first item rather than a section landing page. In that case, I think it might be nice to go to the first item in the section by default, but allow a route parameter to be passed in which will be navigated to when clicked instead. Thoughts?

Agree on removing the startCollapsed and collapse management features. They're no longer needed 😄

@samselikoff
Copy link
Contributor

I personally don't think it's jarring on the Square site, I think it saves you a click as the index page is usually kinda redundant. But I think it will be easy enough for us to support both.

I think we'll need to change the API to use nesting. (I swear this is how I had it originally but I changed it for some reason... can't remember why. Nesting definitely feels right here.)

Current behavior:

{{#docs-viewer as |viewer|}}
  {{#viewer.nav as |nav|}}
    {{#nav.section 'Components' as |section|}}
      {{section.item 'Header' 'docs.components.docs-header'}}
      {{section.item 'Hero' 'docs.components.docs-hero'}}
      {{section.item 'Viewer' 'docs.components.docs-viewer'}}
      {{section.item 'Snippet' 'docs.components.docs-snippet'}}
      {{section.item 'Demo' 'docs.components.docs-demo'}}
      {{section.item 'Logo' 'docs.components.docs-logo'}}
    {{/nav.section}}
  {{/viewer.nav}}
{{/docs-viewer}}

With collapsible flag, sections are collapsed. Sections become links that navigate to first child page. A section is expanded if any of its children are the active page.

{{#docs-viewer as |viewer|}}
  {{#viewer.nav collapsible=true as |nav|}}
    {{#nav.section 'Components' as |section|}}
      {{section.item 'Header' 'docs.components.docs-header'}}
      {{section.item 'Hero' 'docs.components.docs-hero'}}
      {{section.item 'Viewer' 'docs.components.docs-viewer'}}
      {{section.item 'Snippet' 'docs.components.docs-snippet'}}
      {{section.item 'Demo' 'docs.components.docs-demo'}}
      {{section.item 'Logo' 'docs.components.docs-logo'}}
    {{/nav.section}}
  {{/viewer.nav}}
{{/docs-viewer}}

Sections take optional second param, a routeName, which changes the URL of its link. In this case, users could drop a /docs/components/index.hbs file in to add an index page.

{{#docs-viewer as |viewer|}}
  {{#viewer.nav collapsible=true as |nav|}}
    {{#nav.section 'Components' 'docs.components' as |section|}}
      {{section.item 'Header' 'docs.components.docs-header'}}
      {{section.item 'Hero' 'docs.components.docs-hero'}}
      {{section.item 'Viewer' 'docs.components.docs-viewer'}}
      {{section.item 'Snippet' 'docs.components.docs-snippet'}}
      {{section.item 'Demo' 'docs.components.docs-demo'}}
      {{section.item 'Logo' 'docs.components.docs-logo'}}
    {{/nav.section}}
  {{/viewer.nav}}
{{/docs-viewer}}

Watcha think?

@mike-engel
Copy link
Author

Yep, that looks about how I was imagining it! I was already planning to go to a nested structure, so that's perfect.

Excuse my naïveté on this next part, but I'm new to ember (from react), so I may be thinking about this all wrong. What's the best way for the section to know that a child route is active? Does each child item have to be registered with its parent section, or is there a more ember way to do this? If it does, is that something that should be in init?

Thanks for the time to look over this! I think we're nearly on the same page, I just need to get a good chunk of time to work on it 😄

@samselikoff
Copy link
Contributor

@mike-engel no problem man, and keep the questions coming! Not naive at all, this kinda stuff is tough 😄

In React you might be used to setting some props and using clone children, in Ember we don't have that kind of flexibility. Instead we use a global service and have nav-items add themselves to it when they are rendered.

We already have some of this wired up:

this.get('docsRoutes.items').addObject(this);

I would take a look at the state of that docsRoutes service from within a Section component (you'll need to inject it there just like we do in the nav item here) and then write a computed property on the Section that inspects its child routes. You'll also need to inject the router service and use that to find the currentPath.

// something like this...
isActive: computed('router.currentPath', function() {
  let docsRoutes = this.docsRoutes;
  let router = this.router
  // Use docsRoutes to find children, check if any match the currently active route using the router service
})

If the docsRoutes service currently just has a flat list of routes, you'll need to update it to include the nesting. The way I'd do that is with contextual component. If you did something like this

{{! section/template.hbs}}
{{yield (hash
  item=(component 'docs-viewer/x-nav-item' sectionId=this.sectionId)
)}}

then every section.item that was rendered, you could pre-wire it with a sectionId (which you could define on the Section, probably using guidFor), and then in that isActive computed property you could look up child routes that way.

That was a lot and this is complex for an Ember newbie so let me know if you want to go step by step! Happy to walk through it in more detail.

@mike-engel
Copy link
Author

Thanks a ton for that explanation! I think it makes a lot of sense, and also helps me at the same time understand how this pattern would work under ember, which is another plus 😁

No promises on when I'll be able to get to it, but it seems pretty straightforward now, so hopefully soon!

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

No branches or pull requests

3 participants