Single-binary self-hosted Markdown blog on Rust axum: no database, live search, Typst PDF export, and strong SEO.
axumblogdockermarkdownminijinjarustself-hostedtypstvite
1{% extends 'base.html' %}
2
3
4{% block extra_head %}
5{% include "includes/social.html" %}
6{% endblock %}
7
8
9{% block extra_title %}
10{% if active_tag %}
11- Tag - {{ active_tag.name|title }}
12{% elif active_year %}
13- Year - {{ active_year }}
14{% endif %}
15{% endblock %}
16
17
18{% block extra_description %}
19{% if active_tag %}
20Currently filtered by tag {{ active_tag.name|title }}.
21{% elif active_year %}
22Currently filtered by year {{ active_year }}.
23{% endif %}
24{% endblock %}
25
26
27{% block extra_breadcrumbs %}
28{% if active_tag %}
29<li class="breadcrumb-item active">{{ active_tag.name|title }}</li>
30{% elif active_year %}
31<li class="breadcrumb-item active">{{ active_year }}</li>
32{% else %}
33<li class="breadcrumb-item active">{{ page.title }}</li>
34{% endif %}
35{% endblock %}
36
37
38{% block main %}
39<div class="container mt-5">
40 <div class="row">
41 <div class="col-sm-6">
42 <h1 class="mb-3 fw-bolder">
43 {% if active_tag %}
44 <div class="section-label fs-6 mb-1">{{ active_tag.name|title }}</div>
45 {% elif active_year %}
46 <div class="section-label fs-6 mb-1">{{ active_year }}</div>
47 {% endif %}
48 {{ page.title }}
49 </h1>
50 </div>
51 <div class="col-sm-6">
52 {% include 'includes/search_form.html' %}
53 </div>
54 </div>
55</div>
56
57<div class="container mt-3">
58 <div class="d-flex flex-wrap align-items-center gap-2">
59 <span class="filter-label">tags</span>
60 {% for tag in tags %}
61 <a href="{{ url_for('blog_tag', tag=tag.slug) }}" class="btn btn-sm rounded-pill {% if active_tag and active_tag.slug == tag.slug %}btn-filter-active{% else %}btn-filter{% endif %}">
62 {{ tag.name|title }}
63 </a>
64 {% endfor %}
65 <span class="filter-divider"></span>
66 <span class="filter-label">year</span>
67 {% for year in years %}
68 <a href="{{ url_for('blog_year', year=year) }}" class="btn btn-sm rounded-pill {% if active_year == year %}btn-filter-active{% else %}btn-filter{% endif %}">
69 {{ year }}
70 </a>
71 {% endfor %}
72 {% if active_tag or active_year %}
73 <span class="filter-divider"></span>
74 <a href="{{ url_for('blog_index') }}" class="btn btn-sm rounded-pill btn-filter-clear">clear</a>
75 {% endif %}
76 </div>
77</div>
78
79{% set blog_post = blog_posts[0] if blog_posts else None %}
80{% if blog_post %}
81{% include "includes/blog_post_latest.html" %}
82{% endif %}
83
84<div class="container mt-5">
85 <div class="row">
86 {% for blog_post in blog_posts %}
87 {% if not loop.first %}
88 <div class="col-sm-12 col-md-6 col-lg-4 mb-5">
89 {% include "includes/blog_post_card.html" %}
90 </div>
91 {% endif %}
92 {% endfor %}
93 </div>
94 {% if extra_posts %}
95 <div class="row mb-3">
96 <div class="col">
97 <div class="alert alert-info d-flex align-items-center row g-1">
98 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-info-circle-fill col-2 col-md-1" viewBox="0 0 16 16">
99 <path d="M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16zm.93-9.412-1 4.705c-.07.34.029.533.304.533.194 0 .487-.07.686-.246l-.088.416c-.287.346-.92.598-1.465.598-.703 0-1.002-.422-.808-1.319l.738-3.468c.064-.293.006-.399-.287-.47l-.451-.081.082-.381 2.29-.287zM8 5.5a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/>
100 </svg>
101 <div class="col-10 col-md-11">I don't have any more posts with this filter at
102 the moment but here are some other posts you might like!</div>
103 </div>
104 </div>
105 </div>
106 <div class="row">
107 {% for blog_post in extra_posts %}
108 <div class="col-12 col-md-6 col-lg-4 mb-5">
109 {% include "includes/blog_post_card.html" %}
110 </div>
111 {% endfor %}
112 </div>
113 {% endif %}
114</div>
115{% endblock %}