de en

Thorsten Reimers

Lektor Navigation Tree

Aug 18, 2023

I wanted to create a sub navigation tree on the left side in Lektor CMS for a menu item.

It should look and behave similiar to the the documentation menu in Lektor itself: https://www.getlektor.com/docs/

It took me a moment to understand how to achieve that

  1. Specifying a two-column layout to split the navigation tree and contents with CSS
  2. Building an own model and an own template file for the site with its own navigation tree and its subpages
  3. Generation of the navigation tree using Jinja 2 in the template file

Starting with Lektor's Quickstart project as an example I made the necessary adjustments for the project page.

Projects

The whole Lektor project can be downloaded from here.

Two Column Layout

I used a suggestion from W3schools how to divide the various elements such as header, footer, container, navigation tree (left) and content (right): https://www.w3schools.com/css/css_website_layout.asp

Layout

I adjusted the cascading style sheet file accordingly with header, footer, .page, .leftcolumn, .rightcolumn.

styles.css:

* {
    box-sizing: border-box;
}

body {
    font-family: 'Verdana', sans-serif;
    padding: 10px;
    margin: 0 auto;
    width: 80%;
}

header,
footer,
.page {
    padding: 10px;
    background: #daeef3;
    overflow: hidden;
}

footer {
    font-size: x-small;
}

header,
footer,
.center {
    text-align: center;
}

header h1 {
    color: #169bbd;
    margin: 0;
    font-weight: normal;
    font-size: 42px;
}

nav ul {
    list-style: none;
    margin: 0;
    padding: 0;
}

nav a {
    float: left;
    display: block;
    text-align: center;
    padding: 14px 16px;
    text-decoration: none;
    color: #2a99b6;
}

nav a:hover {
    color: #33bbdf;
    text-decoration: underline;
}

/* Create two unequal columns that floats next to each other */
/* Left column */
.leftcolumn {
    font-size: 0.85em;
    float: left;
    width: 16%;
}

/* Right column */
.rightcolumn {
    float: left;
    width: 84%;
    padding-left: 20px;
}

.leftcolumn ul {
    list-style: none;
}

.leftcolumn a {
    text-decoration: none;
    color: #2a99b6;
}

.leftcolumn a:hover {
    color: #33bbdf;
    text-decoration: underline;
}

.leftcolumn .active,
nav .active {
    color: #33bbdf;
}

.rightcolumn p {
    white-space: pre-line;
}

.rightcolumn strong {
    color: #169bbd;
    font-weight: normal;
}

/* Clear floats after the columns */
.page::after {
    content: "";
    display: table;
    clear: both;
}

@media screen and (max-width: 1200px) {
    body {
        width: 90%;
    }
}

@media screen and (max-width: 960px) {
    body {
        width: 100%;
    }
}

/* Responsive layout - when the screen is less than 800px wide, make the two columns stack on top of each other instead of next to each other */
@media screen and (max-width: 800px) {

    .leftcolumn,
    .rightcolumn {
        width: 100%;
        padding: 0;
    }
}

/* Responsive layout - when the screen is less than 400px wide, make the navigation links stack on top of each other instead of next to each other */
@media screen and (max-width: 400px) {
    nav a {
        float: none;
        width: 100%;
    }
}

Model

The new model I created is projects.ini.

projects.ini

[model]
name = Projects
label = {{ this.title }}
hidden = yes

[children]
model = projects
order_by = sort_key, title

[fields.title]
type = string

[fields.body]
type = markdown

[fields.hidden]
type = boolean
default = false

Template File

I created an new template file for the projects. It extends base template layout.html and creates a navigation on the left side (CSS class leftcolumn) and the contents column on the right (CSS class rightcolumn).

The navigation menu for the projects is generated with Jinja 2 (according to the Lektor documentation here).

projects.html

{% extends "layout.html" %}
{% block title %}{{ this.title }}{% endblock %}
{% block body %}

<div class="leftcolumn">
    <ul>
        {% set root = site.get('/projects') %}
        {% for child in root.children recursive %}
                <li>
                    <a href="{{ child|url }}" {% if this.path == child._path %} class="active" {% endif %}>{{ child.title }}
                    </a>
                </li>
        {% endfor %}
    </ul>
</div>
<div class="rightcolumn">
    <h2>{{ this.title }}</h2>
    {{ this.body }}
</div>
{% endblock %}