Templates#
mdssg ships one theme. Drop a file with the same name into your site's
templates/ directory and yours is used instead — for that file only, so
replacing the page layout does not mean re-implementing the rest.
templates/
base.html the html shell
index.html the home page
page.html a note
seed.html a seed page
graph.html the global graph
search.html static search
404.html the not-found page
_backlinks.html the "mentioned in" panel
_related.html the "related" panel
_local_graph.html immediate graph neighbours
style.css the stylesheet
search.js the dependency-free search client
logo.svg the site mark
The language#
{{ page.title }} a value, HTML-escaped
{{ page.html | raw }} trusted HTML, not escaped again
{{ page.date | date:"%d %B %Y" }}
{{ page.tags | join:" / " }}
{% if page.date %}...{% elif x %}...{% else %}...{% endif %}
{% if not backlinks %}...{% endif %}
{% for note in related %}
<a href="{{ note.url }}">{{ note.title }}</a>
{{ loop.index }} {{ loop.first }} {{ loop.last }}
{% endfor %}
{% include "_related.html" %}
{% extends "base.html" %}
{% block content %}...{% endblock %}
Filters: raw, escape, date, slug, truncate, length, default,
join, upper, lower.
What it cannot do, on purpose#
There is no arithmetic, no comparison, no method call, no indexing, and no way to register a filter of your own. An expression is a dotted path plus filters from a fixed table, and anything else is a parse error:
error: 'a == b' is not a value path. The template grammar has no arithmetic,
comparisons or calls - put the computation in the page context.
This is the whole design, not an unfinished part of it. A template language that can compute grows until the interesting logic lives in HTML, where it cannot be tested and cannot be read. If a template seems to need logic, the value belongs in the context.
Paths also cannot begin with an underscore. Values are looked up with getattr
as well as by key, and allowing _ would put {{ a.__class__.__init__ }} one
step away from a template.
Escaping#
Escaping is on by default. {{ }} escapes unless the value is already marked
as HTML, which only the markdown renderer and the raw filter produce. Getting
this backwards is the standard way a generator grows an injection bug, so it is
the default rather than something to remember.
What a template receives#
Every page:
| name | contents |
|---|---|
site | title, url, description, author, language, repository |
theme, ui | validated visual settings and translated interface strings |
page | title, url, slug, date, tags, html, description, is_post, is_seed, noindex |
related | list of {title, url, seed} |
asset_url, logo_url, feed_url | paths to the stylesheet, logo and feed |
Notes also get backlinks, a list of {title, url, excerpts} where each
excerpt is HTML with the mention wrapped in <mark>. Seed pages get mentions
in the same shape. The home page gets posts and notes. The graph page gets
graph, containing the bounded SVG, grouped page directory and counts. Linked
notes also receive local_graph with incoming and outgoing neighbours.
Styling the graph#
The theme leaves these hooks for you:
.wikilink /* any resolved wikilink */
.wikilink-seed /* points at an unwritten note */
.wikilink-missing /* seeds disabled, nothing there */
.backlinks mark /* the mention inside a quote */
.seed-notice /* the banner on a seed page */
.embed /* transcluded content */
.embed-error /* a cycle or a depth limit */
.graph-map /* the bounded SVG graph */
.graph-node /* a written note */
.graph-seed /* an unwritten seed */
.graph-focus /* current note in a local graph */
.local-graph /* immediate neighbours */
.search-view /* search page */
The bundled theme uses system fonts. Its only JavaScript is the small static
search client; the graphs remain SVG and work without scripts. /graph/ and
/search/ are reserved for their generated pages.