Lego2012
9/26/2016 - 9:09 PM

Complex Menu Design

Complex Menu Design

<!--
When designing this website, the need for a statically generated menu-bar arose. This menu bar would need to:

- List all pages without maintaining a separate list of individual items while being able to order items.
- Highlight the current page
- If the current page is part of either "projects" or "blog", highlight the appropriate header.
- Toggle showing a link to the index page.

The last is easily achieved using unless tags:
-->

{% unless include.hidehome %}
  <li><a href="/">Home</a></li>
{% endunless %}

<!-- As is the first: -->
{% assign sorted_pages = site.pages | sort:"innavbar-order" %}
{% for navpage in sorted_pages %}
  {% if navpage.innavbar %}
    <li><a href="{{ navpage.url }}">{{ navpage.title }}</a></li>
  {% endif %}
{% endfor %}

<!--
Note the use of the custom page attributes innavbar and innavbar-order. The defaults are set in _config.yml as:
-->

defaults:
  -
    scope:
    path: "" # an empty string here means all files in the project
    values:
    innavbar: false
    innavbar-order: 101

<!--
In pages that need to appear in the navigation bar, adding innavbar: true to the frontmatter is sufficient. If the order of pages needs to be changed, setting the value of innavbar-order allows for arbitrary rearrangement. The higher the value, the later in the generated list the item appears.

Highlighting the current page requires only testing each nav bar element for equality with the current page. This can be done by changing the line inside the loop:
-->

<li {% if (navpage.path == page.path) %} class="navbar-current" {%endif%} ><a href="{{ navpage.url }}">{{ navpage.title }}</a></li>

<!--
Since the == operator doesn't check for object equality, we use the unique .path field (which is a string) to see if each item in the navigation bar matches the current page.

We meet the third requirement in a similar manner; this time by testing to see if the current page and the nav bar element are in the same category. We set default values for the category in _config.yml, and extend the condition with:
-->

or (navpage.postcategory and (page.categories contains navpage.postcategory))

<!--
.postcategory is set in the frontmatter of the blog and project list page. If it appears in page.categories, the title is highlighted. The initial test is to skip the page if .postcategory is not set.
-->

<!-- Putting it all together, we have: -->

{% unless include.hidehome %}
  <li><a href="/">Home</a></li>
{% endunless %}
{% assign sorted_pages = site.pages | sort:"innavbar-order" %}
{% for navpage in sorted_pages %}
  {% if navpage.innavbar %}
    <li {% if (navpage.path == page.path) or (navpage.postcategory and (page.categories contains navpage.postcategory)) %} class="navbar-current" {%endif%} ><a href="{{ navpage.url }}">{{ navpage.title }}</a></li>
  {% endif %}
{% endfor %}