repos
/ orchard main

orchard

mirror

Every site I host, in one repo, along with the Cloudflare Tunnel and Caddy that front them. It's all Go, Vite, and SQLite, and it runs on a desktop at home with nothing listening on an inbound port.

blogbuncaddycloudflare-tunneldockergogolanghomelabhtml-templatemonorepoself-hostedseosqlitestatic-sitetypstuptime-monitoringviteweb-analytics

4.9 KB · 115 lines · HTML Raw History
  1{{/* Shared fragments. Each takes exactly what it needs as the dot, so a card
  2     does not have to know which page it is on. */}}
  3
  4{{ define "search_form" }}
  5<form method="GET" action="/search/" class="position-relative search-form">
  6  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="search-icon" viewBox="0 0 16 16">
  7    <path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"/>
  8  </svg>
  9  <input type="text" class="form-control search-input" id="id_search" name="q" value="{{ . }}" placeholder="search posts..." autofocus>
 10</form>
 11{{ end }}
 12
 13{{/* One post as a card in a grid. The dot is a *Post. */}}
 14{{ define "post_card" }}
 15<div class="card rounded border-0 h-100 bg-surface">
 16  <div class="mb-3 pt-3 px-3">
 17    {{- range .TagLinks }}
 18    <a href="{{ .URL }}" class="btn btn-tag btn-sm rounded-pill">{{ .Display }}</a>
 19    {{- end }}
 20  </div>
 21  {{- if .CoverImage }}
 22  <a href="{{ .URL }}">
 23    <img src="{{ .CoverURL }}" class="card-img-top rounded img-fluid px-3" alt="{{ .Title }}" loading="lazy" decoding="async">
 24  </a>
 25  {{- end }}
 26  <div class="card-body d-flex flex-column">
 27    <a href="{{ .URL }}" class="text-decoration-none" style="color: #f0f0f5;">
 28      <div class="h5 card-title fw-bold">{{ .Title }}</div>
 29    </a>
 30    <div class="card-text flex-grow-1" style="color: #a09890;">{{ .Description }}</div>
 31    <div class="row g-0 mt-3">
 32      <div class="col-12 col-xl-8 d-flex align-items-center">
 33        <img class="rounded-circle me-2" src="/content/images/avatar.webp" alt="Isaac Bythewood" width="25" height="25" loading="lazy" decoding="async">
 34        <strong class="me-2" style="font-size: 0.9em;">Isaac Bythewood</strong>
 35      </div>
 36      <div class="col-12 col-xl-4 d-flex justify-content-start justify-content-xl-end text-muted" style="font-size: 0.85em;">
 37        {{ .Date }}
 38      </div>
 39    </div>
 40  </div>
 41</div>
 42{{ end }}
 43
 44{{/* The wide hero treatment for the newest post. The dot is a *Post. */}}
 45{{ define "post_latest" }}
 46<div class="container mt-5">
 47  <div class="row">
 48    <div class="col">
 49      <div class="section-label mb-2">Latest post</div>
 50    </div>
 51  </div>
 52  <div class="row">
 53    <div class="col-12 col-md-6 col-lg-5 pb-5" style="border-bottom: 1px solid rgba(255,255,255,0.06);">
 54      <a href="{{ .URL }}" class="text-decoration-none" style="color: #f0f0f5;">
 55        <h2 class="fw-bolder">{{ .Title }}</h2>
 56      </a>
 57      <div class="mb-3">
 58        {{- range .TagLinks }}
 59        <a href="{{ .URL }}" class="btn btn-tag btn-sm rounded-pill">{{ .Display }}</a>
 60        {{- end }}
 61      </div>
 62      <p class="h5 text-muted mb-3" style="font-weight: 400;">{{ .Description }}</p>
 63      <div class="d-flex align-items-center">
 64        <img class="rounded-circle me-3" src="/content/images/avatar.webp" alt="Isaac Bythewood" width="35" height="35">
 65        <strong class="me-2">Isaac Bythewood</strong>
 66        <div class="d-inline text-muted">{{ .Date }}</div>
 67      </div>
 68    </div>
 69    {{- if .CoverImage }}
 70    <div class="col-12 col-md-6 col-lg-7 pb-5" style="border-bottom: 1px solid rgba(255,255,255,0.06);">
 71      <a href="{{ .URL }}">
 72        <img src="{{ .CoverURL }}" class="img-fluid rounded" alt="{{ .Title }}">
 73      </a>
 74    </div>
 75    {{- end }}
 76  </div>
 77</div>
 78{{ end }}
 79
 80{{/* A horizontally scrolling strip of cards, used for "random" and "related".
 81     The dot is a struct of Label, Blurb and Posts. */}}
 82{{ define "post_strip" }}
 83<div class="container mt-5 d-print-none">
 84  <div class="row">
 85    <div class="col">
 86      <div class="section-label mb-1">{{ .Label }}</div>
 87      <p class="text-muted">{{ .Blurb }}</p>
 88    </div>
 89  </div>
 90  <div class="row d-flex flex-nowrap overflow-auto w-100">
 91    {{- range .Posts }}
 92    <div class="col-10 col-sm-7 col-md-5 col-lg-4">
 93      {{- template "post_card" . }}
 94    </div>
 95    {{- end }}
 96  </div>
 97</div>
 98{{ end }}
 99
100{{/* Bootstrap alert with an icon. The dot is a struct of Kind and Message. */}}
101{{ define "alert" }}
102<div class="alert alert-{{ .Kind }} d-flex align-items-center row g-1">
103  {{- if eq .Kind "warning" }}
104  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="col-2 col-md-1" viewBox="0 0 16 16">
105    <path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8 4a.905.905 0 0 0-.9.995l.35 3.507a.552.552 0 0 0 1.1 0l.35-3.507A.905.905 0 0 0 8 4zm.002 6a1 1 0 1 0 0 2 1 1 0 0 0 0-2z"/>
106  </svg>
107  {{- else }}
108  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="col-2 col-md-1" viewBox="0 0 16 16">
109    <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"/>
110  </svg>
111  {{- end }}
112  <div class="col-10 col-md-11">{{ .Message }}</div>
113</div>
114{{ end }}