repos

blog.bythewood.me-rust

mirror archived upstream

Single-binary self-hosted Markdown blog on Rust axum: no database, live search, Typst PDF export, and strong SEO.

axumblogdockermarkdownminijinjarustself-hostedtypstvite

5.3 KB · 106 lines · HTML Raw History
  1{% extends 'base.html' %}
  2
  3
  4{% block extra_head %}
  5{% include "includes/social.html" %}
  6{% endblock %}
  7
  8
  9{% block main %}
 10<div class="container mt-5">
 11  <div class="row">
 12    <div class="col-12 col-md-8 col-lg-6">
 13      <div class="d-flex justify-content-between align-items-center">
 14        <div class="mb-2">
 15          {% for tag in post.tags %}
 16          <a href="{{ url_for('blog_tag', tag=tag) }}" class="btn btn-tag btn-sm rounded-pill">
 17            {{ tag|title }}
 18          </a>
 19          {% endfor %}
 20        </div>
 21        <div class="mb-2 d-flex align-items-center text-muted">
 22          <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-stopwatch me-2" viewBox="0 0 16 16">
 23            <path d="M8.5 5.6a.5.5 0 1 0-1 0v2.9h-3a.5.5 0 0 0 0 1H8a.5.5 0 0 0 .5-.5V5.6z"/>
 24            <path d="M6.5 1A.5.5 0 0 1 7 .5h2a.5.5 0 0 1 0 1v.57c1.36.196 2.594.78 3.584 1.64a.715.715 0 0 1 .012-.013l.354-.354-.354-.353a.5.5 0 0 1 .707-.708l1.414 1.415a.5.5 0 1 1-.707.707l-.353-.354-.354.354a.512.512 0 0 1-.013.012A7 7 0 1 1 7 2.071V1.5a.5.5 0 0 1-.5-.5zM8 3a6 6 0 1 0 .001 12A6 6 0 0 0 8 3z"/>
 25          </svg>
 26          <span>{{ post.read_time }} min read</span>
 27        </div>
 28      </div>
 29      <h1 class="fw-bolder">{{ post.title }}</h1>
 30      <p class="h5 text-muted" style="font-weight: 400;">{{ post.description }}</p>
 31    </div>
 32    <div class="d-none d-md-block col-md-4 col-lg-6 text-end d-print-none">
 33      <a href="{{ url_for('blog_post_md', slug=post.slug) }}" target="_blank" class="btn btn-link btn-sm" aria-label="Download Markdown">
 34        <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="currentColor" class="bi bi-filetype-md" viewBox="0 0 16 16">
 35          <path fill-rule="evenodd" d="M14 4.5V14a2 2 0 0 1-2 2h-1v-1h1a1 1 0 0 0 1-1V4.5h-2A1.5 1.5 0 0 1 9.5 3V1H4a1 1 0 0 0-1 1v9H2V2a2 2 0 0 1 2-2h5.5zM.706 13.189v2.66H0V11.85h.806l1.14 2.596h.026l1.14-2.596h.8v3.999h-.716v-2.66h-.038l-.946 2.159h-.516l-.952-2.16H.706Zm3.919 2.66V11.85h1.459c.406 0 .741.078 1.005.234.264.157.46.382.589.68.13.297.196.655.196 1.075 0 .422-.066.784-.196 1.084a1.45 1.45 0 0 1-.595.689c-.264.158-.597.236-.999.236H4.625Zm.791-3.354v2.707h.563c.186 0 .347-.028.483-.082a.8.8 0 0 0 .334-.252c.088-.114.153-.254.196-.422a2.3 2.3 0 0 0 .068-.592c0-.3-.04-.552-.118-.753a.89.89 0 0 0-.354-.454c-.159-.102-.361-.152-.61-.152h-.562Z"/>
 36        </svg>
 37      </a>
 38      <a href="{{ url_for('blog_post_pdf', slug=post.slug) }}" target="_blank" class="btn btn-link btn-sm" aria-label="Download PDF">
 39        <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="currentColor" class="bi bi-filetype-pdf" viewBox="0 0 16 16">
 40          <path fill-rule="evenodd" d="M14 4.5V14a2 2 0 0 1-2 2h-1v-1h1a1 1 0 0 0 1-1V4.5h-2A1.5 1.5 0 0 1 9.5 3V1H4a1 1 0 0 0-1 1v9H2V2a2 2 0 0 1 2-2h5.5L14 4.5ZM1.6 11.85H0v3.999h.791v-1.342h.803c.287 0 .531-.057.732-.173.203-.117.358-.275.463-.474a1.42 1.42 0 0 0 .161-.677c0-.25-.053-.476-.158-.677a1.176 1.176 0 0 0-.46-.477c-.2-.12-.443-.179-.732-.179Zm.545 1.333a.795.795 0 0 1-.085.38.574.574 0 0 1-.238.241.794.794 0 0 1-.375.082H.788V12.48h.66c.218 0 .389.06.512.181.123.122.185.296.185.522Zm1.217-1.333v3.999h1.46c.401 0 .734-.08.998-.237a1.45 1.45 0 0 0 .595-.689c.13-.3.196-.662.196-1.084 0-.42-.065-.778-.196-1.075a1.426 1.426 0 0 0-.589-.68c-.264-.156-.599-.234-1.005-.234H3.362Zm.791.645h.563c.248 0 .45.05.609.152a.89.89 0 0 1 .354.454c.079.201.118.452.118.753a2.3 2.3 0 0 1-.068.592 1.14 1.14 0 0 1-.196.422.8.8 0 0 1-.334.252 1.298 1.298 0 0 1-.483.082h-.563v-2.707Zm3.743 1.763v1.591h-.79V11.85h2.548v.653H7.896v1.117h1.606v.638H7.896Z"/>
 41        </svg>
 42      </a>
 43    </div>
 44  </div>
 45</div>
 46
 47{% if post.cover_image %}
 48<div class="container mt-5">
 49  <img
 50    src="{{ url_for('content_images', filename=post.cover_image) }}"
 51    class="img-fluid rounded"
 52    alt="{{ post.title }}"
 53  >
 54</div>
 55{% endif %}
 56
 57<div class="container">
 58  <div class="py-3" style="border-bottom: 1px solid rgba(255,255,255,0.06);">
 59    <div class="section-label mb-2">Author</div>
 60    <div class="d-flex justify-content-between">
 61      <div class="d-flex align-items-center">
 62        <img class="rounded-circle me-3"
 63          src="{{ url_for('content_images', filename='avatar.webp') }}"
 64          alt="Isaac Bythewood"
 65          width="40"
 66          height="40">
 67        <strong>
 68          Isaac Bythewood
 69        </strong>
 70      </div>
 71      <div class="d-flex align-items-center justify-content-end text-muted">
 72        <div class="vr me-3 my-1"></div>
 73        {{ post.date }}
 74      </div>
 75    </div>
 76  </div>
 77</div>
 78
 79<div class="container mt-5">
 80  <article>
 81    {{ post.body_html|safe }}
 82    <hr class="mt-5" style="height: 2px; max-width: 600px; margin-left: auto; margin-right: auto; border-color: rgba(255,255,255,0.06);">
 83  </article>
 84</div>
 85
 86{% if related_posts %}
 87<div class="container mt-5 d-print-none">
 88  <div class="row">
 89    <div class="col">
 90      <div class="section-label mb-1">
 91        Related posts
 92      </div>
 93      <p class="text-muted">Some posts in similar tags to this one.</p>
 94    </div>
 95  </div>
 96  <div class="row d-flex flex-nowrap overflow-auto w-100">
 97    {% for blog_post in related_posts %}
 98    <div class="col-10 col-sm-7 col-md-5 col-lg-4">
 99      {% include "includes/blog_post_card.html" %}
100    </div>
101    {% endfor %}
102  </div>
103</div>
104{% endif %}
105{% endblock %}