Choose table of content position

I’m migrating a site (in Pelican) which was telling the table of content position with a [TOC] tag in the Markdown. Is there a way to insert the table of content at a custom place in the content with Zola?

If not, I think I’ll be forced to use a tiny bit of javascript to move it to the right place in user’s browser (people who do not want javascript can pay the price of having the table of content before the content itself).

This can be achieved in templates. Slightly simplified excerpts from my site templates:

macros.html:

{%- macro toc(toc, depth, heading=true) %}
{%- if heading %}
<h3>Table of contents</h3>
{%- endif %}
<ol class=toc>
{%- for heading in toc %}
	<li>
		<a href="{{ heading.permalink | safe }}">{{ heading.title }}</a>
		{% if heading.children and depth > 1 -%}
			{{ self::toc(toc=heading.children, depth=depth - 1, heading=false) }}
		{%- endif %}
	</li>
{%- endfor %}
</ol>
{%- endmacro %}
{%- macro format_content(resource) %}
	{%- set content = resource.content %}
	{%- if content is containing("<!-- toc -->") %}
		{%- set content = content | replace(from="<!-- toc -->", to=self::toc(toc=resource.toc, depth=resource.extra.toc_depth | default(value=2))) %}
	{%- endif -%}
	{{ content }}
{%- endmacro %}

page.html:

{% import "macros.html" as macros %}
…
{{ macros::format_content(resource=page) }}
2 Likes

Very nice thanks! I did not know that macros had such advanced features :slight_smile:

Just thinking:

Why not taking an existing interpreted language instead of re-coding one? Even the codebase is smaller, I guess it’s a lot of effort to document and maintain. And even if it were Turing-complete, it would still be less convenient than let’s say Python or Julia. An other option would be to let the user pass serialized content to a custom binary or executable, allowing to build macros and plugins in any language.

I modified a bit the code to

  • allow easier css styling
  • not display level 1 header
  • mark the content as safe

here:


{# ========================= #}
{# === table of contents === #}
{# ========================= #}
{%- macro toc(toc, level, depth) %}
{%- if level == 1 %}
<div class="toc">
<h3>Table des matières</h3>
{%- endif %}
{%- if level != 1 %}
<ol class="h{{ level }}">
{%- endif %}
{%- for h in toc %}
    {%- if level != 1 %}
    <li>
        <a href="{{ h.permalink | safe }}">{{ h.title }}</a>
        {%- endif %}
        {% if h.children and level <= depth -%}
            {{ self::toc(toc=h.children, level=level+1, depth=depth, heading=false) }}
        {%- endif %}
    {%- if level != 1 %}
    </li>
    {%- endif %}
    {%- endfor %}
{%- if level != 1 %}
</ol>
{%- endif %}
{%- if level == 1 %}
</div>
{%- endif %}
{%- endmacro %}


{# =================== #}
{# === replace toc === #}
{# =================== #}
{%- macro replace_toc(resource) %}
	{%- set content = resource.content %}
	{%- if content is containing("[TOC]") %}
		{%- set content = content | replace(from="[TOC]", to=self::toc(toc=resource.toc, level=1, depth=resource.extra.toc_depth | default(value=6))) %}
	{%- endif -%}
	{{ content | safe }}
{%- endmacro %}

It is not as readable, but it produce code like this:

<div class="toc">
<h3>Table des matières</h3>
<ol class="h2">
    <li><a href="/wiki/blockchain/#un-systeme-de-crypto-monnaie">Un système de crypto-monnaie</a></li>
    <li> <a href="/wiki/blockchain/#l-asymetrie-spatio-temporelle-dans-les-monnaies-non-libres">L'asymétrie spatio-temporelle dans les monnaies non libres</a> 
        <ol class="h3">
            <li><a href="/wiki/blockchain/#l-asymetrie-spatiale-dans-le-bitcoin">L'asymétrie spatiale dans le Bitcoin</a> </li>
            <li><a href="/wiki/blockchain/#l-asymetrie-temporelle-dans-le-bitcoin">L'asymétrie temporelle dans le Bitcoin</a></li>
        </ol>
    </li>
    <li><a href="/wiki/blockchain/#comment-s-inspirer-du-bitcoin-pour-faire-une-monnaie-libre">Comment s'inspirer du Bitcoin pour faire une monnaie libre</a></li>
    <li><a href="/wiki/blockchain/#en-quoi-la-blockchain-duniter-differe-de-celle-du-bitcoin">En quoi la blockchain Duniter diffère de celle du Bitcoin</a>
        <ol class="h3">
            <li><a href="/wiki/blockchain/#la-toile-de-confiance-wot">La toile de confiance (WoT)</a></li>
            <li><a href="/wiki/blockchain/#les-transactions">Les transactions</a></li>
            <li><a href="/wiki/blockchain/#une-preuve-de-travail-a-difficulte-personnalite">Une preuve de travail à difficulté personnalité</a></li>
            <li><a href="/wiki/blockchain/#pour-resumer">Pour résumer</a></li>
        </ol>
    </li>
    <li><a href="/wiki/blockchain/#une-economie-libre">Une économie libre</a></li>
</ol>
</div>

Allowing with some css to change the list marker according to heading depth:

image

An example with more levels: