Integrating documentation markdown into a Zola (SSG) website

william May 23, 2023 #website #Zola

Brief notes on integrating the AVATeR user manual into this website. The manual is maintained separately, so it can be included in a software package. While written for the Zola SSG, most aspects apply to Hugo and other SSGs as well. Discussing who reads manuals is left for another time ;)

Importing markdown files

An easy solution is to import content into an existing SSG page. For one or a few pages, this will suffice. For Zola use load_data() with format="plain" to import plain text (amongst others). Note:

Generating 'frontmatter' metadata for multiple pages

Alternatively, convert or export the source files as a SSG page. As Zola (Hugo, and most blog orientated SSGs) require each page to start with a metadata block ('frontmatter') like:

+++
title = "Integrating documentation into a Zola (SSG) website"
draft = false
date = 2023-01-01
+++

Content here...

this implies such a block must be constructed and prepended to each source page. Scripting and/or a documentation generator that uses templates (i.e. Sphinx) can take care of this.

Templates are responsible for generating navigation menus, which are -generally speaking- derived from the file hierarchy. Each directory with an _index.md will create a section (i.e. a node): it registers the pages and content its directory contains. Sections may 'forward' their pages to its parent section, using the transparancy toggle.

The template used for a section and/or page can thus use section data to generate navigation menus. Navigation implementations in themes can be missing or limited, though extending templates is easy. Some themes focus solely on documentation, like adidoks (Zola) or doks (Hugo).

File layout considerations

Letting posts and documentation content co-exist requires some planning, especially when section indexes are part of the navigation structure - we are (ab)using a blog orientated system after all, be it a flexible one. Two suggested file layouts are detailed.

├──layout1
│   └── software
│       ├── avater
│       │   ├── _index.md
│       │   ├── info.md
│       │   └── manual.md
│       ├── project #2
│       ├── project #3
│       └── _index.md

Above, the software/_index.md section index will list both info.md and manual.md, which we may not want. For Zola an 'exclude_from_index' toggle seems to be in the works. Better is to move manual.md into its own section avater/manuals/ (allowing translations, etc.). This in turn will require a link to it from info.md or another page. A more advanced solution is customizing the navigation in the section and page templates. Shortcuts tend to fall short for this: listing taxonomy pages cannot be done for technical reasons; I'm not sure if the same applies for section pages.

The main projectpage (index) path would ideally be just avater/ without the 'info' part. Putting the content into avater/_index.md solves this, but depending on your theme, a section index may render very differently, requiring changes; using a page template for a section can produce odd results (either its not recommended, or it depends on the template).

When there is just a single projectpage, consider using the index.md instead:

└── layout2
    └── software
        ├── avater
        │   ├── index.md   <--- (former info.md; no _ prefix)
        │   └── manual
        │       ├── _index.md
        │       └── manual.md
        ├── project #2
        ├── project #3
        └── _index.md

An avater/index.md (without the underscore) is treated as a page. Zola does appear to forward the latter for inclusion in the /software/ section index1. Without a section index, the avater/* pages will be reported as 'orphaned': but this is a warning after all.

At some point, (ab)using the post forwarding/accumulation mechanisms will fail - and that also depends on the theme its capabilities-, but at this stage we will often be customizing templates already. For a setup with one info page per project, and zero or more manuals, the last setup works.

Modifying URLs

Image URLs

It's easiest to store images with the post content ('bundling'). If moved to /static/, the URLs may need to be modified. The regex below suffices, but may not cover all situations.

sed -E 's+\!\[(.*)\]\((.\+)\)+![\1](/files/avater/manual/\2)+ somewhere/manual_en.md > manual_en.md 
# Test using sed -En 's+regexhere+p' manual_en.md

With Powershell avoid the default unicode conversion (always something... ;)), if desired.

get-content somewhere/manual_en.md | 
 %{$_ -replace '!\[(.*)\]\((.+)\)' , '![$1](/files/avater/manual/$2)'} | 
 Out-File -Encoding ascii -FilePath manual_en.md

Internal URLs

File layout changes may necessitate changing internal URLs. A quick example using sed with the -s multi-file option (on BSD/MacOS use find -exec instead, etc.):

sed -s -i 's+(@/software/avater/#requirements)+(@/software/avater/index.md#requirements)+' *.md

Be careful after testing with the -n and p (print) options. When not using git, a pre/post directory comparison can be done with diff -r or diff -ru0.


1

Implying transparancy = true

Back to top