I’ve been a relatively happy user of ikiwiki since 2011 for reasons previously discussed.

However, I recently switched over to Jekyll. The main reason is jekyll-scholar, a bibliography formatter for Jekyll. As a researcher, writing papers is my job, and formatting bibliographic entries is tedious and error prone. Bibtex has existed for 30 years, and although I had custom-written a bibtex-to-HTML converter 20 years ago, it still resulted in a lot of cut-and-pasting.

A second reason is Liquid. Yes, it is limited, but it seems to hit a nice level for in-line templates (with out dropping down to a real language like Perl or Ruby). When it is combined with a little data structured in YAML, it is a very powerful way to script things that would otherwise be tedious repetition.

Adding Ikiwiki-style Navigation to Jekyll

One feature of ikiwiki I liked was the automatic navigation at the top of the page. By default, the top of the page follows the directory tree, so if your website structure follows a directory structure, the link “up” one or more levels are automatic.

This feature is missing from Jekyll, but fairly easy to script in Liquid. My effort was inspired by Alex Ellison’s post about building Jekyll menus that follow the directory tree, something similar in spirit but opposite in detail to what I wanted.

My version is:

  <!-- _includes/base.html -->
  <!-- http://ricostacruz.com/til/relative-paths-in-jekyll.html -->
  {% assign base = '' %}{% assign depth = page.path | prepend: '/' | split: '/' | size | minus: 1 %}{% if depth == 1 %}{% assign base = '.' %}{% elsif depth == 2 %}{% assign base = '..' %}{% elsif depth == 3 %}{% assign base = '../..' %}{% elsif depth == 4 %}{% assign base = '../../..' %}{% endif %}
  {!-- _includes/topbar.html -->
  <section class="topbar">
    {% if page.titleicon %}<img alt="({{ page.title }})" src="{{ page.titleicon }}" />{% endif %}
    <h1>
      {% if page.url != "/" %}<a href="{{ base }}/index.html">{{ site.title }}</a> / {% endif %}
      {% assign topdown = '' %}
      {% assign url_parts = page.url | split: '/' %}
      {% for part in url_parts %}
        {% if part != '' %}
          {% capture topdown %}{{ topdown }}/{{ part }}{% endcapture %}
          {% capture target_url %}{{ topdown }}/index.html{% endcapture %}
          {% for p in site.pages %}
            {% if p.url == target_url and p.url != page.url %}
              <a href="{{ base }}{{ p.url }}">{{ p.title }}</a> / 
            {% endif %}
          {% endfor %}
        {% endif %}
      {% endfor %}
      {{ page.title }}
    </h1>
  </section>

This bit of code illustrates the strength and weakness of Jekyll: it’s possible to get this feature scripted in Liquid alone (good!), but each page iterates over all pages, for O(n^2) performance (bad!). Too bad there is no associative array pages_by_url.