summaryrefslogtreecommitdiff
path: root/templates
diff options
context:
space:
mode:
Diffstat (limited to 'templates')
-rw-r--r--templates/.djlintrc14
-rw-r--r--templates/about.html11
-rw-r--r--templates/base.html167
-rw-r--r--templates/blog-month-index.html54
-rw-r--r--templates/blog-post.html31
-rw-r--r--templates/blog-year-index.html54
-rw-r--r--templates/blog.html15
-rw-r--r--templates/categories.html53
-rw-r--r--templates/category.html51
-rw-r--r--templates/index.html15
-rw-r--r--templates/macros/blog.html100
-rw-r--r--templates/macros/pagination.html221
-rw-r--r--templates/page.html3
-rw-r--r--templates/tag.html59
14 files changed, 848 insertions, 0 deletions
diff --git a/templates/.djlintrc b/templates/.djlintrc
new file mode 100644
index 0000000..5882faa
--- /dev/null
+++ b/templates/.djlintrc
@@ -0,0 +1,14 @@
+{
+"blank_line_before_tag": "macro",
+"blank_line_after_tag": "endmacro,extends,import,from",
+"profile": "jinja",
+"format_css": true,
+"css": {
+"indent_size": 2
+},
+"format_js": true,
+"js": {
+"indent_size": 2
+},
+"indent": "2"
+}
diff --git a/templates/about.html b/templates/about.html
new file mode 100644
index 0000000..55a0778
--- /dev/null
+++ b/templates/about.html
@@ -0,0 +1,11 @@
+{% extends "base.html" %}
+
+{% block meta %}
+ {{ super() }}
+ <meta property="og:type" content="profile">
+ <meta property="profile:first_name" content="Dennis">
+ <meta property="profile:last_name" content="Fink">
+{% endblock %}
+{% block content %}
+ <article>{{ this.body }}</article>
+{% endblock %}
diff --git a/templates/base.html b/templates/base.html
new file mode 100644
index 0000000..1000014
--- /dev/null
+++ b/templates/base.html
@@ -0,0 +1,167 @@
+<!DOCTYPE html>
+<html lang="en"
+ prefix="og: https://ogp.me/ns# article: https://ogp.me/ns/article# profile: https://ogp.me/ns/profile#">
+ <head>
+ {% block head %}
+ {% block meta %}
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <meta name="color-scheme" content="dark light">
+ <meta name="generator" content="lektor">
+ <meta name="description"
+ property="og:description"
+ content="{{ bag('blog.tagline') }}">
+ <meta property="og:site_name" content="dennisfink.me">
+ <meta property="og:title"
+ content="{%- if (this.title or title) -%}{{ (this.title or title) | safe }} — {% endif -%}{{ bag('blog.name') }}">
+ <meta property="og:url"
+ content="{{ this | url(absolute=True, external=True) }}">
+ <meta property="og:image"
+ content="{{ '/static/images/opengraph.png' | url(absolute=True, external=True) }}">
+ <meta property="og:image:type" content="image/png">
+ <meta property="og:image:width" content="32">
+ <meta property="og:image:height" content="32">
+ <meta property="og:image:alt"
+ content="Logo of the site showing a second-order Hilbert curve segment drawn as a continuous right-angled line inside a rounded square, with both colored in muted green">
+ <meta name="fediverse:creator" content="@me@dennisfink.me">
+ {% endblock meta %}
+ {% block styles %}
+ <link rel="stylesheet"
+ type="text/css"
+ href="{{ '/static/css/modern_normalize.css' | asseturl }}">
+ <link rel="stylesheet"
+ type="text/css"
+ href="{{ '/static/css/libre_baskerville.css' | asseturl }}">
+ <link rel="stylesheet"
+ type="text/css"
+ href="{{ '/static/css/style.css' | asseturl }}">
+ {% endblock styles %}
+ {% block meta_links %}
+ <link rel="canonical" href="{{ this|url(absolute=True, external=True) }}">
+ <link rel="alternate"
+ type="application/atom+xml"
+ title="{{ bag('blog.name') }} — Latest posts"
+ href="{{ '/blog@atom/latest'|url(absolute=True) }}">
+ <link rel="alternate"
+ type="application/atom+xml"
+ title="{{ bag('blog.name') }} — All posts"
+ href="{{ '/blog@atom/all'|url(absolute=True) }}">
+ <link rel="shortcut icon"
+ type="image/png"
+ href="{{ '/static/images/favicon.png' | asseturl }}">
+ {% endblock meta_links %}
+ <title>
+ {% block meta_title %}
+ {%- if (this.title or title) -%}{{ (this.title or title) | safe }} —
+ {% endif -%}
+ {{ bag("blog.name") }} — dennisfink.me
+ {% endblock meta_title %}
+ </title>
+ {% endblock head %}
+ </head>
+ <body>
+ {% block body %}
+ <a href="#main" class="skip-link">Skip to main content</a>
+ <header>
+ {% block site_header %}
+ <div>
+ <hgroup>
+ <h1>
+ <a href="/">{{ bag("blog.name") }}</a>
+ </h1>
+ <p>{{ bag("blog.tagline") }}</p>
+ </hgroup>
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 800">
+ <path d="M89.4 0C40.1 0 0 40 0 89.4v621.2C0 759.9 40 800 89.4 800h621.2c49.3 0 89.4-40 89.4-89.4V89.4C800 40.1 760 0 710.6 0zm0 18.9h621.2A70 70 0 0 1 781 89.4v621.2a70 70 0 0 1-70.5 70.5H89.4A70 70 0 0 1 19 710.6V89.4A70 70 0 0 1 89.4 19m147.8 71c-11.9-.1-24.6 0-37.2 0-25.4.4-50.7 1.3-70.1 2.7-9.7.7-18 1.5-24 2.5q-4.5.7-7.5 1.7c-2 .6-3.5 1-4.6 3q-.6 1.4-.7 2.9-.3 1.6-.5 4.2l-.9 13.7c-.5 11.4-1 27-1.3 45.5a8909 8909 0 0 0-.2 267.8 1985 1985 0 0 0 2 59.2l.4 4.2q.1 1.5.7 2.8c1 2 2.5 2.4 4.3 3q2.7 1 6.9 1.8 8.4 1.6 22 2.7a1491 1491 0 0 0 64 3.6c23 1 46.2 1.7 63.8 2.5a614 614 0 0 1 28 2l1.4.2.3 1.2.7 5.6c.5 4.8.9 11.6 1.2 19.5a1632 1632 0 0 1 .1 115.5 390 390 0 0 1-1.8 25.3l-.3 1q-.4.3-1.3.4l-6 .6q-7.7.7-20.5 1.1c-16.8.7-38.9 1.1-60.9 1.4a7900 7900 0 0 1-103 .8l-2 .3c-.4 0-1 0-1.6 1.3q-.5.9-.3.8v1.1L88 700l.2 9.3.3.8c.6 1.4 1.2 1.2 1.5 1.3l.7.2 1.4.1 3.7.2h9.1c2.7 0 51.2 0 99.7-.6 24.3-.4 48.5-.9 67-1.7a485 485 0 0 0 30-2.2l2.2-.5c.7-.3 1.3-.3 2.1-1.2q1-1.1 1-2 .4-1.2.6-2.5.5-2.8.8-7.3.8-9.2 1.3-23.9a2277 2277 0 0 0 .1-140 547 547 0 0 0-2-31.2l-.5-2.4c-.2-.7-.2-1.2-1-2-.8-1-1.4-1-2-1.2q-1-.4-2.3-.6l-6.7-.9q-8.4-.7-21.8-1.5c-17.7-1-40.8-1.7-64-2.7-23-.9-46.2-2-63.8-3.4-8.7-.7-16.2-1.5-21.4-2.4q-4-.7-6.2-1.4-1.2-.4-1.5-.7l-.1-.8-.4-3.5q-.5-4.6-.8-12.3c-.4-8-.6-20.1-1-32.3a4578 4578 0 0 1 1.4-306l.5-4.4 1.3-.6q1.8-.8 5.4-1.4 7.4-1.3 19.4-2.3a1269 1269 0 0 1 115.5-1.8 355 355 0 0 1 25.1 1.8l1.2.3.3 1.4.6 6.3q.8 8.2 1.2 21.6c.7 17.7 1.3 40.8 2 64 .6 23 1.2 46.2 2 63.9a465 465 0 0 0 2.4 28.5q.2 1.3.6 2.3.1.9 1.1 2c1 1.1 1.4.8 2.1 1l2.4.5 7.3.8q9.2.7 23.9 1.2a2305 2305 0 0 0 163.9-1.2 101 101 0 0 0 9.7-1.3c.7-.2 1.2-.2 2-1 1-.8 1-1.4 1.2-2q.4-1 .6-2.3l.9-6.7q.8-8.4 1.4-21.8c.9-17.7 1.5-40.9 2.1-64s1.3-46.2 2-63.9a571 571 0 0 1 1.8-27.9l.3-1.4 1.2-.3 5.6-.7a355 355 0 0 1 19.5-1 1269 1269 0 0 1 115.5 1.7q12.1 1 19.4 2.3 3.5.7 5.4 1.4l1.3.6.2.9.3 3.5q.4 4.5.7 12.3a4578 4578 0 0 1-1 338.3l-.6 4.3q-.3.3-1.5.7-2.1.8-6.2 1.4c-5.2 1-12.7 1.7-21.4 2.4-17.6 1.4-40.7 2.5-63.9 3.4-23 1-46.2 1.8-63.9 2.7a493 493 0 0 0-28.5 2.4q-1.3.2-2.3.6c-.6.2-1.2.3-2 1.1s-.8 1.4-1 2.1l-.5 2.4-.8 7.3q-.7 9.2-1.2 23.9a2277 2277 0 0 0 1.4 163.9 97 97 0 0 0 1.3 9.7q.1 1 1 2.1c.9.9 1.5 1 2.2 1.2l2.3.5 7 .9q8.8.8 22.9 1.3c18.5.8 42.7 1.3 67 1.7 48.5.7 97 .6 99.7.6l14.2-.3.7-.2c.3 0 .9 0 1.5-1.3q.5-.9.3-.8v-1.1l.2-8.2-.2-9.3-.3-.8c-.6-1.4-1.2-1.2-1.5-1.3l-.7-.2-1.3-.1-3.7-.2h-8.7c-2.5 0-46.6 0-90.7-.6-22-.3-44-.7-60.9-1.4a483 483 0 0 1-26.5-1.7l-1.3-.3-.3-1.1-.7-5.7a390 390 0 0 1-1-19.5 1632 1632 0 0 1 1.2-135l1-6.9 1.4-.3 6.4-.6 21.6-1.3c17.6-.8 40.7-1.6 63.9-2.5 23-1 46.2-2 64-3.6q13.4-1.2 22-2.7 4-.7 6.8-1.7c1.8-.7 3.4-1.2 4.3-3.1q.6-1.3.7-2.8l.4-4.2q.5-5.1.8-13.7c.5-11.4.8-27 1.2-45.5a8229 8229 0 0 0-1.5-313.3 331 331 0 0 0-1.4-18q0-1.3-.7-2.7c-1-2-2.7-2.5-4.6-3q-3-1-7.5-1.8c-6-1-14.3-1.8-24-2.5a1786 1786 0 0 0-140-2.2 517 517 0 0 0-31.2 1.8l-2.4.5c-.7.2-1.2.2-2 1-1 .8-1 1.4-1.2 2q-.4 1-.6 2.3l-.9 6.7q-.8 8.4-1.4 21.8c-.9 17.7-1.5 40.9-2.1 64s-1.3 46.2-2 63.9a571 571 0 0 1-1.8 27.9l-.3 1.4-1.2.3-5.6.7c-4.8.5-11.6.9-19.5 1.2a1575 1575 0 0 1-135-1.2l-6.9-1-.3-1.4-.6-6.3q-.7-8.2-1.2-21.6c-.7-17.7-1.3-40.8-2-64-.6-23-1.2-46.2-2-63.9a465 465 0 0 0-2.4-28.5q-.2-1.3-.6-2.3-.1-.8-1.1-2c-1-1.2-1.4-.8-2.1-1l-2.4-.5-7.3-.8q-9.2-.7-23.9-1t-32.8-.6M96 147.4c-3.2 65-3.2 230.9-.4 300.6l-.4-14.3a8224 8224 0 0 1 .2-267.6zm608 0 .6 18.7a8887 8887 0 0 1 .2 267.6l-.4 14.3a5034 5034 0 0 0-.4-300.6m-380.2 157c36.4 2.6 116 2.6 152.4 0-2.3 0-3.7.2-6.3.3a2302 2302 0 0 1-139.8 0zm-19.4 218.7.4 7a2273 2273 0 0 1-.1 139.7c-.1 3.3-.3 5.2-.5 8 3-35.2 3-118.2.2-154.7m191.2 0c-2.8 36.5-2.8 119.5.2 154.8-.2-3-.4-4.8-.5-8.1a2274 2274 0 0 1-.1-139.7z" />
+ </svg>
+ </div>
+ <div>
+ <nav aria-label="Site navigation">
+ {% block site_navigation %}
+ <ul>
+ {% block site_navigation_items %}
+ <li>
+ <a href="{{ '/blog' | url(absolute=True) }}"
+ {% if "/blog@" in this.path %}aria-current="page"{% endif %}>Blog</a>
+ </li>
+ <li>
+ <a href="{{ '/categories' | url(absolute=True) }}"
+ {% if this.path == "/categories" %}aria-current="page"{% endif %}>Categories</a>
+ </li>
+ <li>
+ <a href="{{ '/about' | url(absolute=True) }}"
+ {% if this.path == "/about" %}aria-current="page"{% endif %}>About</a>
+ </li>
+ {% endblock site_navigation_items %}
+ </ul>
+ {% endblock site_navigation %}
+ </nav>
+ <fieldset class="theme-switcher">
+ <legend class="visually-hidden">Color theme</legend>
+ <label title="Light mode">
+ <input type="radio"
+ name="theme-switcher"
+ value="light"
+ id="lightmode"
+ aria-label="Light Mode">
+ <span aria-hidden="true"></span>
+ </label>
+ <label title="Auto mode">
+ <input type="radio"
+ name="theme-switcher"
+ value="light dark"
+ id="automode"
+ aria-label="Auto Mode"
+ checked>
+ <span aria-hidden="true"></span>
+ </label>
+ <label title="Dark mode">
+ <input type="radio"
+ name="theme-switcher"
+ value="dark"
+ id="darkmode"
+ aria-label="Dark Mode">
+ <span aria-hidden="true"></span>
+ </label>
+ </fieldset>
+ </div>
+ {% endblock site_header %}
+ </header>
+ <main>
+ {% block content required %}
+ {% endblock content %}
+ </main>
+ <footer>
+ {% block site_footer %}
+ <section aria-label="Follow me">
+ <h2>Follow me:</h2>
+ <div>
+ <a href="{{ '/blog@atom/latest' | url(absolute=True) }}"
+ id="atom"
+ aria-label="Atom feed — Latest posts"></a>
+ <a rel="nofollow"
+ href="/email/"
+ id="email"
+ aria-label="Mail address: me plus blog at dennisfink.me"></a>
+ <a rel="me"
+ href="https://social.dennisfink.me/@me"
+ id="mastodon"
+ aria-label="Mastodon profile: me on social.dennisfink.me"></a>
+ <a href="xmpp:me@dennisfink.me"
+ id="xmpp"
+ aria-label="XMPP address: me on dennisfink.me"></a>
+ </div>
+ </section>
+ <section>
+ <h2>Blogroll</h2>
+ <ul>
+ <li>
+ <a href="https://blog.janguth.eu/">Broadsheet (Jan Guth)</a>
+ </li>
+ </ul>
+ </section>
+ {% endblock %}
+ </footer>
+ {% endblock body %}
+ </body>
+</html>
diff --git a/templates/blog-month-index.html b/templates/blog-month-index.html
new file mode 100644
index 0000000..d114628
--- /dev/null
+++ b/templates/blog-month-index.html
@@ -0,0 +1,54 @@
+{% extends "base.html" %}
+
+{% from "macros/pagination.html" import render_month_archive_navigation %}
+
+{% block meta %}
+ {{ super() }}
+ <meta property="og:type" content="website">
+{% endblock %}
+{% block styles %}
+ {{ super() }}
+ <link rel="stylesheet"
+ type="text/css"
+ href="{{ '/static/css/category.css'|asseturl }}">
+{% endblock %}
+{% set title = "Monthly archive: " + this.date | dateformat('MMMM y') %}
+{% block content %}
+ {% set post_count = this.children.count() %}
+ <article>
+ <header>
+ <hgroup>
+ <h2>Monthly archive: {{ this.date | dateformat("MMMM y") }}</h2>
+ <p>
+ ({{ post_count }}
+ {% if post_count > 1 %}
+ posts)
+ {% else %}
+ post)
+ {% endif %}
+ </p>
+ </hgroup>
+ </header>
+ <table>
+ <thead class="visually-hidden">
+ <tr>
+ <th scope="col">Date</th>
+ <th scope="col">Title</th>
+ </tr>
+ </thead>
+ <tbody>
+ {% for post in this.children.order_by('-publication_date') %}
+ <tr>
+ <td>
+ <time datetime="{{ post.publication_date }}">{{ post.publication_date }}</time>
+ </td>
+ <td>
+ <a href="{{ post|url }}">{{ post.title }}</a>
+ </td>
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+ {{ render_month_archive_navigation(this) }}
+ </article>
+{% endblock %}
diff --git a/templates/blog-post.html b/templates/blog-post.html
new file mode 100644
index 0000000..6ffb600
--- /dev/null
+++ b/templates/blog-post.html
@@ -0,0 +1,31 @@
+{% extends "base.html" %}
+
+{% from "macros/blog.html" import render_blog_post %}
+
+{% block meta %}
+ {{ super() }}
+ <meta property="og:type" content="article">
+ <meta property="article:author" content="https://dennisfink.me/about">
+ {% if this.publication_date %}
+ <meta property="article:published_time"
+ content="{{ this.publication_date }}T00:00:00Z">
+ {% endif %}
+ {% if this.updated_date %}
+ <meta property="article:modified_time"
+ content="{{ this.updated_date }}T00:00:0Z">
+ {% endif %}
+ {% if this.category %}
+ {% set category = site.get("/categories/" + this.category) %}
+ <meta property="article:section" content="{{ category.name }}">
+ {% endif %}
+ {% for t in this.tags %}
+ <meta property="article:tag" content="{{ t }}">
+ {% endfor %}
+{% endblock %}
+{% block styles %}
+ {{ super() }}
+ <link rel="stylesheet"
+ type="text/css"
+ href="{{ '/static/css/blog.css'|asseturl }}">
+{% endblock %}
+{% block content %}{{ render_blog_post(this) }}{% endblock %}
diff --git a/templates/blog-year-index.html b/templates/blog-year-index.html
new file mode 100644
index 0000000..138cc86
--- /dev/null
+++ b/templates/blog-year-index.html
@@ -0,0 +1,54 @@
+{% extends "base.html" %}
+
+{% from "macros/pagination.html" import render_year_archive_navigation %}
+
+{% block meta %}
+ {{ super() }}
+ <meta property="og:type" content="website">
+{% endblock %}
+{% block styles %}
+ {{ super() }}
+ <link rel="stylesheet"
+ type="text/css"
+ href="{{ '/static/css/category.css'|asseturl }}">
+{% endblock %}
+{% set title = "Yearly archive: " + this.key %}
+{% block content %}
+ {% set post_count = this.children.count() %}
+ <article>
+ <header>
+ <hgroup>
+ <h2>Yearly archive: {{ this.key }}</h2>
+ <p>
+ ({{ post_count }}
+ {% if post_count > 1 %}
+ posts)
+ {% else %}
+ post)
+ {% endif %}
+ </p>
+ </hgroup>
+ </header>
+ <table>
+ <thead class="visually-hidden">
+ <tr>
+ <th scope="col">Date</th>
+ <th scope="col">Title</th>
+ </tr>
+ </thead>
+ <tbody>
+ {% for post in this.children.order_by('-publication_date') %}
+ <tr>
+ <td>
+ <time datetime="{{ post.publication_date }}">{{ post.publication_date }}</time>
+ </td>
+ <td>
+ <a href="{{ post|url }}">{{ post.title }}</a>
+ </td>
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+ {{ render_year_archive_navigation(this) }}
+ </article>
+{% endblock %}
diff --git a/templates/blog.html b/templates/blog.html
new file mode 100644
index 0000000..0ee96c7
--- /dev/null
+++ b/templates/blog.html
@@ -0,0 +1,15 @@
+{% extends "base.html" %}
+
+{% from "macros/blog.html" import render_blog_index %}
+
+{% block meta %}
+ {{ super() }}
+ <meta property="og:type" content="website">
+{% endblock %}
+{% block styles %}
+ {{ super() }}
+ <link rel="stylesheet"
+ type="text/css"
+ href="{{ '/static/css/blog.css'|asseturl }}">
+{% endblock %}
+{% block content %}{{ render_blog_index(this.pagination) }}{% endblock %}
diff --git a/templates/categories.html b/templates/categories.html
new file mode 100644
index 0000000..4dbdf1a
--- /dev/null
+++ b/templates/categories.html
@@ -0,0 +1,53 @@
+{% extends "base.html" %}
+
+{% block meta %}
+ {{ super() }}
+ <meta property="og:type" content="website">
+{% endblock %}
+{% block styles %}
+ {{ super() }}
+ <link rel="stylesheet"
+ type="text/css"
+ href="{{ '/static/css/categories.css'|asseturl }}">
+{% endblock %}
+{% set title = "Categories" %}
+{% block content %}
+ <article>
+ <header>
+ <h2>Categories</h2>
+ </header>
+ <ul>
+ {% set sorted = [] %}
+ {% for category in this.children.order_by('name') %}
+ {% set post_count = category.children.count() %}
+ {% if post_count > 0 %}
+ {% set _ = sorted.append((post_count, category)) %}
+ {% endif %}
+ {% endfor %}
+ {% for post_count, category in sorted|sort(attribute='0', reverse=True) %}
+ {% set last_post = category.children.order_by('-publication_date').first() %}
+ <li>
+ <a href="{{ category|url }}">
+ <h3>{{ category.name }}</h3>
+ <dl>
+ <div>
+ <dt>Posts:</dt>
+ <dd>
+ {{ post_count }}
+ </dd>
+ </div>
+ {% if last_post %}
+ <div>
+ <dt>Last post:</dt>
+ <dd>
+ <time datetime="{{ last_post.publication_date }}">{{ last_post.publication_date }}</time>
+ </dd>
+ </div>
+ {% endif %}
+ </dl>
+ </a>
+ </li>
+ {% endfor %}
+ </ul>
+ </article>
+{% endblock %}
diff --git a/templates/category.html b/templates/category.html
new file mode 100644
index 0000000..9d6b35d
--- /dev/null
+++ b/templates/category.html
@@ -0,0 +1,51 @@
+{% extends "base.html" %}
+
+{% block meta %}
+ {{ super() }}
+ <meta property="og:type" content="website">
+{% endblock %}
+{% block styles %}
+ {{ super() }}
+ <link rel="stylesheet"
+ type="text/css"
+ href="{{ '/static/css/category.css'|asseturl }}">
+{% endblock %}
+{% set title = "Category " + this.name %}
+{% block content %}
+ {% set post_count = this.children.count() %}
+ <article>
+ <header>
+ <hgroup>
+ <h2>Category: {{ this.name }}</h2>
+ <p>
+ ({{ post_count }}
+ {% if post_count > 1 %}
+ posts)
+ {% else %}
+ post)
+ {% endif %}
+ </p>
+ </hgroup>
+ </header>
+ <table>
+ <thead class="visually-hidden">
+ <tr>
+ <th scope="col">Date</th>
+ <th scope="col">Title</th>
+ </tr>
+ </thead>
+ <tbody>
+ {% for post in this.children.order_by('-publication_date') %}
+ <tr>
+ <td>
+ <time datetime="{{ post.publication_date }}">{{ post.publication_date }}</time>
+ </td>
+ <td>
+ <a href="{{ post|url }}">{{ post.title }}</a>
+ </td>
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+ </article>
+{% endblock %}
diff --git a/templates/index.html b/templates/index.html
new file mode 100644
index 0000000..0ee96c7
--- /dev/null
+++ b/templates/index.html
@@ -0,0 +1,15 @@
+{% extends "base.html" %}
+
+{% from "macros/blog.html" import render_blog_index %}
+
+{% block meta %}
+ {{ super() }}
+ <meta property="og:type" content="website">
+{% endblock %}
+{% block styles %}
+ {{ super() }}
+ <link rel="stylesheet"
+ type="text/css"
+ href="{{ '/static/css/blog.css'|asseturl }}">
+{% endblock %}
+{% block content %}{{ render_blog_index(this.pagination) }}{% endblock %}
diff --git a/templates/macros/blog.html b/templates/macros/blog.html
new file mode 100644
index 0000000..b4caafe
--- /dev/null
+++ b/templates/macros/blog.html
@@ -0,0 +1,100 @@
+{% from "macros/pagination.html" import render_pagination %}
+
+{% macro render_toc(toc, maxdepth=2) %}
+ <nav aria-label="Table of contents">
+ <p>Table of contents</p>
+ <ol>
+ {% for item in toc recursive %}
+ <li>
+ <a href="#{{ item.anchor }}">{{ item.title }}</a>
+ {% if item.children and loop.depth < maxdepth %}
+ <ol>
+ {{ loop(item.children) }}
+ </ol>
+ {% endif %}
+ </li>
+ {% endfor %}
+ </ol>
+ </nav>
+{% endmacro %}
+
+{% macro render_blog_post(post, show_toc=True) %}
+ <article>
+ <header>
+ <div>
+ <h2>
+ <a href="{{ post|url }}">{{ post.title }}</a>
+ </h2>
+ <dl>
+ {% if post.publication_date %}
+ <div>
+ <dt>Posted:</dt>
+ <dd>
+ <a href="{{ ('/blog@index-pages/year/{}'.format(post.publication_date.year) ) | url }}">
+ <time datetime="{{ post.publication_date | dateformat('yyyy-MM-dd') }}">{{ post.publication_date | dateformat("d MMMM yyyy") }}</time>
+ </a>
+ </dd>
+ </div>
+ {% else %}
+ <div class="missing-publication-date-warning" role="alert">
+ <dt>⚠</dt>
+ <dd>
+ Missing publication date
+ </dd>
+ </div>
+ {% endif %}
+ {% if post.updated_date and post.publication_date and (post.updated_date > post.publication_date) %}
+ <div>
+ <dt>Last updated:</dt>
+ <dd>
+ <time datetime="{{ post.updated_date | dateformat('yyyy-MM-dd') }}">{{ post.updated_date | dateformat("d MMMM yyyy") }}</time>
+ </dd>
+ </div>
+ {% endif %}
+ {% if post.category %}
+ <div>
+ <dt>Category:</dt>
+ <dd>
+ {% set category = site.get('/categories/'+post.category) %}
+ <a href="{{ category|url }}">{{ category.name }}</a>
+ </dd>
+ </div>
+ {% endif %}
+ </dl>
+ </div>
+ {% if show_toc and post.render_toc %}
+ {% set toc = post.body.toc|default([]) %}
+ {{ render_toc(toc) }}
+ {% endif %}
+ </header>
+ {{ post.body }}
+ {% if post.tags %}
+ <footer>
+ <p>Tagged with</p>
+ <ul aria-label="Tags">
+ {% for tag in post.tags %}
+ <li>
+ {% set tag_slug = tag|trim|lower|replace(" ", "-") %}
+ <a href="{{ ('/blog/tag/' ~ tag_slug ~ '/')|url }}" rel="tag">{{ tag }}</a>
+ {%- if not loop.last -%}, {%- else -%}.{%- endif -%}
+ </li>
+ {% endfor %}
+ </ul>
+ </footer>
+ {% endif %}
+ </article>
+{% endmacro %}
+
+{% macro render_blog_index(pagination) %}
+ {% for post in pagination.items %}
+ {{ render_blog_post(post, False) }}
+ {% if not loop.last %}
+ <hr>
+ {% endif %}
+ {% endfor %}
+ {% if pagination.pages > 1 %}
+ <footer>
+ {{ render_pagination(pagination) }}
+ </footer>
+ {% endif %}
+{% endmacro %}
diff --git a/templates/macros/pagination.html b/templates/macros/pagination.html
new file mode 100644
index 0000000..adb1b5c
--- /dev/null
+++ b/templates/macros/pagination.html
@@ -0,0 +1,221 @@
+{% macro render_pagination(pagination, pagination_window=2) %}
+ {% set current = pagination.page %}
+ {% set total = pagination.pages %}
+ {% set window_start = [current - pagination_window, 1] | max %}
+ {% set window_end = [current + pagination_window, total] | min %}
+ <nav aria-label="Page navigation">
+ <ol>
+ <li>
+ {% if pagination.has_prev %}
+ <a href="{{ pagination.prev | url }}" aria-label="Previous page">❮</a>
+ {% else %}
+ <span aria-disabled="true">❮</span>
+ {% endif %}
+ </li>
+ {% if window_start > 1 %}
+ <li>
+ <a href="{{ pagination.for_page(1) | url }}" aria-label="Page 1">1</a>
+ </li>
+ {% if window_start > 2 %}
+ <li>
+ <span aria-hidden="true">&hellip;</span>
+ </li>
+ {% endif %}
+ {% endif %}
+ {% for page_num in range(window_start, window_end + 1) %}
+ <li>
+ {% if page_num == current %}
+ <a href="{{ pagination.for_page(page_num) | url }}" aria-current="page">{{ page_num }}</a>
+ {% else %}
+ <a href="{{ pagination.for_page(page_num) | url }}"
+ aria-label="Page {{ page_num }}">{{ page_num }}</a>
+ {% endif %}
+ </li>
+ {% endfor %}
+ {% if window_end < total %}
+ {% if window_end < total - 1 %}
+ <li>
+ <span aria-hidden="true">&hellip;</span>
+ </li>
+ {% endif %}
+ <li>
+ <a href="{{ pagination.for_page(total) | url }}"
+ aria-label="Page {{ total }}">{{ total }}</a>
+ </li>
+ {% endif %}
+ <li>
+ {% if pagination.has_next %}
+ <a href="{{ pagination.next | url }}" aria-label="Next page">❯</a>
+ {% else %}
+ <span aria-disabled="true">❯</span>
+ {% endif %}
+ </li>
+ </ol>
+ </nav>
+{% endmacro %}
+
+{% macro render_year_archive_navigation(
+ current_year_page,
+ archive_window=2
+ ) %}
+ {% set current_year = current_year_page.year %}
+ {% set first_year_page = current_year_page.first_year_page %}
+ {% set last_year_page = current_year_page.last_year_page %}
+ {% set previous_year_page = current_year_page.previous_year_page %}
+ {% set next_year_page = current_year_page.next_year_page %}
+ {% set first_year = first_year_page.year %}
+ {% set last_year = last_year_page.year %}
+ {% set window_start = [current_year - archive_window, first_year] | max %}
+ {% set window_end = [current_year + archive_window, last_year] | min %}
+ <nav aria-label="Year archive navigation">
+ <ol>
+ <li>
+ {% if previous_year_page %}
+ <a href="{{ previous_year_page | url }}"
+ rel="prev"
+ aria-label="Previous year: {{ previous_year_page.year }}">❮</a>
+ {% else %}
+ <span aria-disabled="true">❮</span>
+ {% endif %}
+ </li>
+ {% if window_start > first_year %}
+ <li>
+ <a href="{{ first_year_page | url }}" aria-label="Year {{ first_year }}">{{ first_year }}</a>
+ </li>
+ {% if window_start > first_year + 1 %}
+ <li>
+ <span aria-hidden="true">&hellip;</span>
+ </li>
+ {% endif %}
+ {% endif %}
+ {% for year in range(window_start, window_end + 1) %}
+ {% set year_page = site.get(
+ '/blog@index-pages/year/{:04d}'.format(year)
+ ) %}
+ {% if year_page %}
+ <li>
+ {% if year == current_year %}
+ <a href="{{ year_page | url }}" aria-current="page">{{ year }}</a>
+ {% else %}
+ <a href="{{ year_page | url }}" aria-label="Year {{ year }}">{{ year }}</a>
+ {% endif %}
+ </li>
+ {% endif %}
+ {% endfor %}
+ {% if window_end < last_year %}
+ {% if window_end < last_year - 1 %}
+ <li>
+ <span aria-hidden="true">&hellip;</span>
+ </li>
+ {% endif %}
+ <li>
+ <a href="{{ last_year_page | url }}" aria-label="Year {{ last_year }}">{{ last_year }}</a>
+ </li>
+ {% endif %}
+ <li>
+ {% if next_year_page %}
+ <a href="{{ next_year_page | url }}"
+ rel="next"
+ aria-label="Next year: {{ next_year_page.year }}">❯</a>
+ {% else %}
+ <span aria-disabled="true">❯</span>
+ {% endif %}
+ </li>
+ </ol>
+ </nav>
+{% endmacro %}
+
+{% macro render_month_archive_navigation(
+ current_month_page,
+ archive_window=2
+ ) %}
+ {% set year_pages = index_pages('year') | sort(attribute='year') %}
+ {% set ns = namespace(
+ month_pages=[],
+ current_position=none
+ ) %}
+ {% for year_page in year_pages %}
+ {% set ns.month_pages = ns.month_pages + (year_page.subindexes | sort(attribute='month')) %}
+ {% endfor %}
+ {% for month_page in ns.month_pages %}
+ {% if month_page.year == current_month_page.year
+ and month_page.month == current_month_page.month %}
+ {% set ns.current_position = loop.index0 %}
+ {% endif %}
+ {% endfor %}
+ {% set total = ns.month_pages | length %}
+ {% set current_position = ns.current_position %}
+ {% set window_start = [current_position - archive_window, 0] | max %}
+ {% set window_end = [current_position + archive_window, total - 1] | min %}
+ {% set first_month_page = ns.month_pages[0] %}
+ {% set last_month_page = ns.month_pages[total - 1] %}
+ {% set previous_month_page = none %}
+ {% set next_month_page = none %}
+ {% if current_position > 0 %}
+ {% set previous_month_page = ns.month_pages[current_position - 1] %}
+ {% endif %}
+ {% if current_position < total - 1 %}
+ {% set next_month_page = ns.month_pages[current_position + 1] %}
+ {% endif %}
+ <nav aria-label="Monthly archive navigation">
+ <ol>
+ <li>
+ {% if previous_month_page %}
+ <a href="{{ previous_month_page | url }}"
+ rel="prev"
+ aria-label="Previous month: {{ previous_month_page.date | dateformat('yyyy-MM') }}">❮</a>
+ {% else %}
+ <span aria-disabled="true">❮</span>
+ {% endif %}
+ </li>
+ {% if window_start > 0 %}
+ <li>
+ <a href="{{ first_month_page | url }}"
+ aria-label="{{ first_month_page.date | dateformat('yyyy-MM') }}">
+ {{ first_month_page.date | dateformat("MMMM y") }}
+ </a>
+ </li>
+ {% if window_start > 1 %}
+ <li>
+ <span aria-hidden="true">&hellip;</span>
+ </li>
+ {% endif %}
+ {% endif %}
+ {% for position in range(window_start, window_end + 1) %}
+ {% set month_page = ns.month_pages[position] %}
+ <li>
+ {% if position == current_position %}
+ <a href="{{ month_page | url }}" aria-current="page">{{ month_page.date | dateformat("MMMM y") }}</a>
+ {% else %}
+ <a href="{{ month_page | url }}"
+ aria-label="{{ month_page.date | dateformat('yyyy-MM') }}">
+ {{ month_page.date | dateformat("MMMM y") }}
+ </a>
+ {% endif %}
+ </li>
+ {% endfor %}
+ {% if window_end < total - 1 %}
+ {% if window_end < total - 2 %}
+ <li>
+ <span aria-hidden="true">&hellip;</span>
+ </li>
+ {% endif %}
+ <li>
+ <a href="{{ last_month_page | url }}"
+ aria-label="{{ last_month_page.date | dateformat('yyyy-MM') }}">
+ {{ last_month_page.date | dateformat("MMMM y") }}
+ </a>
+ </li>
+ {% endif %}
+ <li>
+ {% if next_month_page %}
+ <a href="{{ next_month_page | url }}"
+ rel="next"
+ aria-label="Next month: {{ next_month_page.date | dateformat('yyyy-MM') }}">❯</a>
+ {% else %}
+ <span aria-disabled="true">❯</span>
+ {% endif %}
+ </li>
+ </ol>
+ </nav>
+{% endmacro %}
diff --git a/templates/page.html b/templates/page.html
new file mode 100644
index 0000000..dd20955
--- /dev/null
+++ b/templates/page.html
@@ -0,0 +1,3 @@
+{% extends "base.html" %}
+
+{% block content %}<article>{{ this.body }}</article>{% endblock %}
diff --git a/templates/tag.html b/templates/tag.html
new file mode 100644
index 0000000..b433616
--- /dev/null
+++ b/templates/tag.html
@@ -0,0 +1,59 @@
+{% extends "base.html" %}
+
+{% block meta %}
+ {{ super() }}
+ <meta property="og:type" content="website">
+{% endblock %}
+{% block styles %}
+ {{ super() }}
+ <link rel="stylesheet"
+ type="text/css"
+ href="{{ '/static/css/category.css'|asseturl }}">
+{% endblock %}
+{% set title = "Tag " + this.tag %}
+{% block content %}
+ {% set post_count = this.items.count() %}
+ <article>
+ <header>
+ <hgroup>
+ <h2>Tag: {{ this.tag }}</h2>
+ <p>
+ ({{ post_count }}
+ {% if post_count > 1 %}
+ posts)
+ {% else %}
+ post)
+ {% endif %}
+ </p>
+ </hgroup>
+ </header>
+ <table>
+ <thead class="visually-hidden">
+ <tr>
+ <th scope="col">Date</th>
+ <th scope="col">Title</th>
+ </tr>
+ </thead>
+ <tbody>
+ {% for post in this.items %}
+ <tr>
+ <td>
+ {% if post.publication_date %}
+ <time datetime="{{ post.publication_date }}">{{ post.publication_date }}</time>
+ {% endif %}
+ </td>
+ <td>
+ <a href="{{ post|url }}">{{ post.title }}</a>
+ </td>
+ </tr>
+ {% else %}
+ <tr>
+ <td colspan="2">
+ <em>No posts for this tag.</em>
+ </td>
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+ </article>
+{% endblock %}