4

I'm building a static site with Jekyll (no blog), just with pages.
I want to find a way to generate (automatically or with a menu.yml file) a menu (like this website, on the footer).
I define title and chapter properties in the pages' YAML:

---
layout: page
title: Title of the page
chapter: Title of the chapter
permalink: /title-of-the-chapter/title-of-the-chapter/
order: 3250
published: true
---

I want to get a menu like that:

<ul>
    <li>Title of the chapter</li>
        <ul>
            <li><a href="permalink">Title of the page</a></li>
        </ul>
</ul>

By the way my files are organised in folders like that :

01-chapter-one
    01-subchapter-one
        index.md
    02-subchapter-two
        index.md
02-chapter-one
    01-subchapter-one
        index.md

Is there a solution (perhaps with no plugin) to do this automatically (I have a lot of pages) ?

antoinentl
  • 63
  • 1
  • 4

2 Answers2

1

Full automation is possible only with a plugin, i.e. vanilla Jekyll is not able to automatically loop your folder and generate a hierarchical list of your files.

So if you want a solution without plugins, you need to maintain data file with your menu hierarchy: each time you add a page, you need to modify the data file as well.

There are different approaches how to generate the menu out of the data file, depending on the complexity you want:

That should be enough to get you started. If you run into problems, please ask a more specific question.

Community
  • 1
  • 1
Christian Specht
  • 35,843
  • 15
  • 128
  • 182
0

Grouping data is the trick here, to do this you will need a secondary processor. The most convenient place to put this post processing is in javascript, but that means you need to leave yourself some data.

The following code embeds an array of all the pages in your as an array. That can then be post processed by in page javascript.

<script>
let menu = [
  {% for p in site.pages %}
  {
    'chapter':'{{ p.chapter }}',
    'title':'{{ p.title }}',
    'url':'{{ p.url }}',
  }
  {% endfor %}
].filter(function(d){
    return d.title != '';
})
.reduce(function(a,d){
    a[d.chapter] = a[d.chapter] || [];
    a[d.chapter].push(d);
},{});
menu = Object
    .keys(menu)
    .map(function(key){
        let html = menu[key].map(function(d){
              return "<li>"+d.title+"</li>";
            })
            .join('');
        html = '<li>' + key + '<ol>'+html+'</ol></li>';
        return html.join('');
    })
    ;
menu.push('</ol>');
menu.unshift('<ol>');
document.write(menu.join(''));
</script>

I'm fairly certain that sorting is not enforced correctly, but that seems roughly correct.

A nice thing about this solution would be that you could actually embed the "chapters" as folders. You could generate nesting based on common folder structure, and use 'index' pages as markers for the 'chapter' titles.

Jefferey Cave
  • 2,507
  • 1
  • 27
  • 46