Skip to content

Instantly share code, notes, and snippets.

@desero
Last active March 19, 2019 08:37
Show Gist options
  • Select an option

  • Save desero/67b3c0a203877256daaf425f1a0f3f67 to your computer and use it in GitHub Desktop.

Select an option

Save desero/67b3c0a203877256daaf425f1a0f3f67 to your computer and use it in GitHub Desktop.
Nested navigation

Folder structure

content
├── _index.md
...
├── dashboard
│   ├── _index.md
|   |   ...
│   ├── site-management
│   │   ├── _index.md
|   |   |   ...
│   │   ├── stats
│   │   │   ├── _index.md
|   |   |   |   ...
│   │   │   ├── page.md
│   │   │   ├── images
|   |   |   |   ...
│   │   │   │   ├── image.png
...

Index file for each folder

There is an _index.md for each folder that contains the following front-matter:

---
title: Site management
description: "..."
categories: ["..."]
keywords: ["..."]
linktitle: Site management
weight: 2
---

Main configuration

For the side menu, the config.toml file has the following configuration:

# ...

[[menu.docs]]
  name = "Dashboard"
  weight = 2
  identifier = "dashboard"

[[menu.docs]]
  name = "Site Management"
  weight = 1
  identifier = "site-management"
  parent = "dashboard"

[[menu.docs]]
  name = "Stats"
  weight = 1
  identifier = "stats"
  parent = "site-management"
# ...

Navigation template

There is a walker template that loops through menu.docs. Its a recursive loop:

{{ $currentPage := . }}
<nav role="navigation">
  <ul class="list">
  {{- range .Site.Menus.docs.ByWeight}}
  {{ $post := printf "%s" .Post }}
  {{- template "section-tree-nav" dict "sect" . "currentpage" $currentPage "post" $post }}
  {{- end}}
  </ul>
</nav>

{{- define "section-tree-nav" }}
{{- $currentPage := .currentpage }}
{{- $post := .post }}
  {{- with .sect}}
    <li
      class="{{ if .HasChildren }}has-children {{ if eq $post "break" }} break{{ end }}{{ else }}list-item{{ end }}"
    >
      {{ $id := printf "%s" .Identifier }}
      <a
        href="{{ if .HasChildren }}javascript:void(0){{ else }}{{ .URL }}{{ end }}"
        class="js-toggle {{if or ($currentPage.IsMenuCurrent "docs" .) ($currentPage.HasMenuCurrent "docs" .)}}active{{end}}"
        data-target=".{{ .Identifier }}"
      >
        {{ .Name }}
      </a>
      {{- if .HasChildren }}
      <ul
        class="{{ .Identifier }} desktopmenu animated fadeIn list pl0 {{if $currentPage.HasMenuCurrent "docs" . }}db{{ else }}dn{{ end }}"
      >
        {{- range .Children }}
        {{- template "section-tree-nav" dict "sect" . "currentpage" $currentPage "post" $post }}
        {{- end}}
      </ul>
      {{- end}}
    </li>
  {{- end}}
{{- end}}

Frontend part of the Navigation

Using breakpoint-sass and a few colors variables.

.side-nav {
  display: none;
  padding: 20px 0;

  @include breakpoint($medium) {
    display: block;
  }

  a {
    display: block;
    padding: 5px 10px;
    color: $silver;
    text-decoration: none;
    font-weight: 400;
    line-height: 20px;
    font-size: 14px;

    &:hover {
      background: $silver-15;
    }
  }

  > ul > li {
    border-top: 1px solid $silver-14;

    &:first-child {
      border-top: 0;
    }
  }

  ul {
    list-style: none;
  }

  .list {
    margin-bottom: 20px;

    .list {
      margin-left: 20px;
    }
  }

  .has-children > a {
    font-weight: 700;
  }

  .active {
    color: $cyan;
  }
}

.dn {
  display: none;
}

.db {
  display: block;
}

.db-l {
  display: inline-block;
}

and the javascript interaction

const toggleClass = function() {
  const content = this.dataset.target.split(' ')
  const mobileCurrentlyOpen = document.querySelector('.mobilemenu:not(.dn)')
  const desktopActive = document.querySelector('.desktopmenu:not(.dn)')

  content.forEach(item => {
    const matches = document.querySelectorAll(item)
    ;[].forEach.call(matches, dom => {
      dom.classList.toggle('dn')
      return false
    })
  })

  content.forEach(item => { // eslint-disable-line
    if (mobileCurrentlyOpen) mobileCurrentlyOpen.classList.add('dn')
    if (desktopActive) desktopActive.classList.remove('db')
  })
}

const toggleBtns = [...document.getElementsByClassName('js-toggle')]
toggleBtns.forEach(toggleBtn => {
  toggleBtn.addEventListener('click', toggleClass, false)
})

Navigation template usage

Directory and templates structure:

layouts/
├── _default
...
│   ├── single.html
│   ├── taxonomy.html
...
├── index.html
├── partials
...
│   ├── nav-links-docs.html
│   ├── pagelayout.html
...

Template usage inside single.html. This is the single page template, the actual .md display:

{{ define "main" }}
<div class="nav side-nav">
  {{ partial "nav-links-docs.html" . }}
</div>
...

{{ end }}

Template usage inside pagelayout.html. This is categories page (listing):

<div class="nav side-nav">
  {{ partial "nav-links-docs.html" .context }}
</div>

and .context is inherited from taxonomy.html:

{{ define "main" }}
  {{ $section_to_display := .Data.Pages }}
  {{ partial "pagelayout.html" (dict "context" . "section_to_display" $section_to_display ) }}
{{ end }}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment