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.3 KB · 108 lines · HTML Raw History
  1{{/* Go requires every {{template}} target to exist, so the optional ones are
  2     defined empty here and overridden by whichever page wants them: layouts are
  3     parsed before the page, and a later definition of the same name wins. */}}
  4
  5{{ define "form" }}{{ end }}
  6
  7{{ define "logo" }}
  8<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
  9  <g stroke="#6b9e78" stroke-width="1.6" opacity="0.55" stroke-linecap="round">
 10    <path d="M46 15 L34 28"/>
 11    <path d="M18 47 L29 36"/>
 12    <path d="M46 15 L52 40"/>
 13  </g>
 14  <path d="M32 4 L36.4 26.2 L58 32 L36.4 37.8 L32 60 L27.6 37.8 L6 32 L27.6 26.2 Z"
 15        fill="#6b9e78"/>
 16  <circle cx="46" cy="15" r="3.4" fill="#c9d9cb"/>
 17  <circle cx="18" cy="47" r="2.6" fill="#7eaab8"/>
 18  <circle cx="52" cy="40" r="2.2" fill="#c9a84c"/>
 19</svg>
 20{{ end }}
 21
 22{{ define "nav" }}
 23<nav class="navbar navbar-dark navbar-expand-md">
 24  <div class="container-fluid px-4">
 25    <a class="navbar-brand" href="{{ if .Authenticated }}/account{{ else }}/{{ end }}">
 26      <span class="logo" aria-hidden="true">{{ template "logo" . }}</span>
 27      <span class="brand-text">{{ .SiteName }}</span>
 28      <span class="brand-dot" aria-hidden="true"></span>
 29    </a>
 30    {{ if .Authenticated }}
 31    <button class="navbar-toggler border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navMain" aria-controls="navMain" aria-expanded="false" aria-label="Toggle navigation">
 32      <span class="navbar-toggler-icon"></span>
 33    </button>
 34    <div class="collapse navbar-collapse" id="navMain">
 35      <ul class="navbar-nav ms-3">
 36        <li class="nav-item"><a class="nav-link {{ if eq .Path "/account" }}active{{ end }}" href="/account">Account</a></li>
 37        <li class="nav-item"><a class="nav-link {{ if eq .Path "/sessions" }}active{{ end }}" href="/sessions">Sessions</a></li>
 38        <li class="nav-item"><a class="nav-link {{ if eq .Path "/security" }}active{{ end }}" href="/security">Security</a></li>
 39        <li class="nav-item"><a class="nav-link {{ if eq .Path "/activity" }}active{{ end }}" href="/activity">Activity</a></li>
 40      </ul>
 41      <ul class="navbar-nav ms-auto">
 42        <li class="nav-item d-flex align-items-center">
 43          <form method="post" action="/logout" class="d-inline">
 44            <button type="submit" class="btn btn-sm btn-outline-light">Sign out</button>
 45          </form>
 46        </li>
 47      </ul>
 48    </div>
 49    {{ end }}
 50  </div>
 51</nav>
 52{{ end }}
 53
 54{{/* One of the other sites. The whole card is the link, so the hit area is the
 55     card rather than the word inside it. */}}
 56{{ define "siteCard" }}
 57<a class="site-card" href="https://{{ .host }}/">
 58  <span class="site-card-name">
 59    <span class="site-card-dot" aria-hidden="true"></span>
 60    {{ .name }}
 61    <span class="site-card-go" aria-hidden="true"></span>
 62  </span>
 63  <span class="site-card-desc d-block">{{ .desc }}</span>
 64  <span class="site-card-host d-block">{{ .host }}</span>
 65</a>
 66{{ end }}
 67
 68{{ define "alerts" }}
 69{{ if .Error }}<div class="auth-alert is-error" role="alert">{{ .Error }}</div>{{ end }}
 70{{ if .Notice }}<div class="auth-alert is-notice" role="status">{{ .Notice }}</div>{{ end }}
 71{{ end }}
 72
 73{{/* The shell every signed-out page uses, so the four of them cannot drift.
 74     Everything in the right hand half is decoration and carries aria-hidden:
 75     it is a star field, and there is nothing in it to read. */}}
 76{{ define "authShell" }}
 77<div class="auth-stage">
 78  <div class="auth-sky" aria-hidden="true">
 79    <div class="auth-nebula"></div>
 80    <canvas class="auth-stars" data-starfield></canvas>
 81    <div class="auth-orbits"></div>
 82    <div class="auth-vignette"></div>
 83  </div>
 84
 85  <div class="auth-panel">
 86    <div class="auth-form">
 87      <div class="auth-mark" aria-hidden="true">{{ template "logo" . }}</div>
 88      {{ template "form" . }}
 89    </div>
 90  </div>
 91</div>
 92{{ end }}
 93
 94{{ define "footer" }}
 95<div class="footer-bar">
 96  <div class="container-fluid px-4">
 97    <div class="row align-items-center">
 98      <div class="col-sm-6 d-flex align-items-center justify-content-center justify-content-sm-start order-1 order-sm-0">
 99        <small>&copy; {{ .Year }} {{ .AuthorName }} · All times UTC</small>
100      </div>
101      <div class="col-sm-6 d-flex justify-content-center justify-content-sm-end py-3 py-sm-0">
102        <a href="{{ .SourceURL }}" target="_blank" rel="noopener" class="footer-bar-link">Source</a>
103      </div>
104    </div>
105  </div>
106</div>
107{{ end }}