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

7.3 KB · 164 lines · HTML Raw History
  1{{/*
  2  The mark: one commit.
  3
  4  It took three drafts to get here and the first two failed the same way. A
  5  branch shape (a stem with something forking off it) reads as a lowercase "h"
  6  next to a wordmark, and a three-node graph collapses into a solid triangle
  7  once the nodes and edges are only two pixels apart. Both were too much drawing
  8  for twenty pixels.
  9
 10  So: a single filled node, which is what every one of those drawings was made
 11  of anyway. It cannot be misread at any size, it holds up as a favicon, and the
 12  serif wordmark beside it is doing the identifying regardless. Inline so it
 13  inherits currentColor and costs no request.
 14*/}}
 15{{define "mark"}}<svg viewBox="0 0 32 32" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="4" stroke-linecap="round"><path d="M9 9v14"/><path d="M9 14h9a5 5 0 0 1 5 5v2"/><circle cx="9" cy="6" r="4.5" fill="currentColor" stroke="none"/><circle cx="9" cy="26" r="4.5" fill="currentColor" stroke="none"/><circle cx="23" cy="26" r="4.5" fill="currentColor" stroke="none"/></svg>{{end}}
 16
 17{{define "icon-dir"}}<svg viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><path d="M1.5 3.25A1.75 1.75 0 0 1 3.25 1.5h2.94c.46 0 .9.18 1.23.51l.87.87h4.46c.97 0 1.75.78 1.75 1.75v7.62a1.75 1.75 0 0 1-1.75 1.75H3.25a1.75 1.75 0 0 1-1.75-1.75V3.25Z"/></svg>{{end}}
 18{{define "icon-file"}}<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" aria-hidden="true"><path d="M9.2 1.8H4.4a1.6 1.6 0 0 0-1.6 1.6v9.2a1.6 1.6 0 0 0 1.6 1.6h7.2a1.6 1.6 0 0 0 1.6-1.6V5.8Z"/><path d="M9.2 1.8v4h4"/></svg>{{end}}
 19{{define "icon-sub"}}<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" aria-hidden="true"><circle cx="4.5" cy="4" r="2"/><circle cx="4.5" cy="12" r="2"/><circle cx="11.5" cy="8" r="2"/><path d="M4.5 6v4M6.4 4h1.7a1.8 1.8 0 0 1 1.8 1.8v.6"/></svg>{{end}}
 20{{define "icon-up"}}<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" aria-hidden="true"><path d="M8 12.5V4M4.5 7.5 8 4l3.5 3.5"/></svg>{{end}}
 21
 22{{define "repohead"}}
 23{{$c := .Ctx}}{{$tab := .Tab}}
 24<div class="repohead">
 25  <div class="titlerow">
 26    <h1><a href="/{{$c.Repo.Name}}">{{$c.Repo.Name}}</a></h1>
 27    {{if $c.Meta.Mirror}}<span class="badge mirror" title="Pulled from {{$c.Meta.Upstream}}, read only">mirror</span>{{end}}
 28    {{if $c.Meta.Archived}}<span class="badge archived">archived upstream</span>{{end}}
 29    {{if $c.Meta.UpstreamGone}}<span class="badge gone" title="No longer on GitHub. This is the only copy.">only copy</span>{{end}}
 30    {{if $c.Empty}}<span class="badge empty">empty</span>{{end}}
 31  </div>
 32
 33  {{if $c.Meta.Description}}<p class="desc">{{$c.Meta.Description}}</p>{{end}}
 34  {{if $c.Meta.Topics}}
 35    <p class="topics">{{range $c.Meta.Topics}}<span class="topic">{{.}}</span>{{end}}</p>
 36  {{end}}
 37
 38  {{/*
 39    aria-current marks the active tab for assistive tech and is also what the
 40    stylesheet hangs the underline on, so the two cannot drift apart.
 41  */}}
 42  <nav class="repotabs">
 43    <a href="/{{$c.Repo.Name}}"{{if eq $tab "files"}} aria-current="page"{{end}}>Files</a>
 44    <a href="/{{$c.Repo.Name}}/log/{{$c.Rev}}"{{if eq $tab "log"}} aria-current="page"{{end}}>Commits</a>
 45    <a href="/{{$c.Repo.Name}}/branches"{{if eq $tab "branches"}} aria-current="page"{{end}}>Branches{{if $c.Branches}} <span class="count">{{len $c.Branches}}</span>{{end}}</a>
 46    <a href="/{{$c.Repo.Name}}/tags"{{if eq $tab "tags"}} aria-current="page"{{end}}>Tags{{if $c.Tags}} <span class="count">{{len $c.Tags}}</span>{{end}}</a>
 47    <a href="/{{$c.Repo.Name}}/atom.xml">Feed</a>
 48  </nav>
 49</div>
 50{{end}}
 51
 52
 53{{define "refswitcher"}}
 54{{$c := .Ctx}}
 55{{if or $c.Branches $c.Tags}}
 56<details class="refswitch">
 57  <summary><span class="reflabel">{{$c.Rev}}</span></summary>
 58  <div class="refmenu">
 59    {{if $c.Branches}}<h4>Branches</h4>
 60      <ul>{{range $c.Branches}}<li><a href="/{{$c.Repo.Name}}/tree/{{.Name}}">{{.Name}}</a></li>{{end}}</ul>
 61    {{end}}
 62    {{if $c.Tags}}<h4>Tags</h4>
 63      <ul>{{range $c.Tags}}<li><a href="/{{$c.Repo.Name}}/tree/{{.Name}}">{{.Name}}</a></li>{{end}}</ul>
 64    {{end}}
 65  </div>
 66</details>
 67{{end}}
 68{{end}}
 69
 70
 71{{define "clonebox"}}
 72{{$c := .Ctx}}
 73<div class="clonebox">
 74  <h3>Clone</h3>
 75  <input type="text" readonly value="git clone {{$c.CloneURL}}" onclick="this.select()">
 76
 77  {{if $c.Meta.Mirror}}
 78    <p class="hint">
 79      This is a mirror of <a href="{{$c.Meta.Upstream}}">upstream</a> and does not
 80      accept pushes. Cloning from it is how a copy is recovered.
 81    </p>
 82  {{else if $.LoggedIn}}
 83    {{/*
 84      Push instructions, the size meter and the limit guidance are all for the
 85      one person who can push, and the guidance names internal container
 86      topology. A visitor gets the clone URL and nothing about how the inside
 87      of this is wired.
 88    */}}
 89    <h3>Push</h3>
 90    <p class="hint">Username is ignored; the password is a push token.</p>
 91    <input type="text" readonly value="git push {{$c.CloneURL}} main" onclick="this.select()">
 92
 93    {{/*
 94      The meter is shown for every repository rather than only oversized ones,
 95      because "how close am I" is the useful question and it can only be asked
 96      before the limit is hit. The oversized case gets a sentence about what it
 97      means from here rather than a warning about a push that has evidently
 98      already happened.
 99    */}}
100    <p class="meter{{if $c.OverLimit}} over{{else if ge $c.PushPercent 75}} warn{{end}}"
101       title="{{humanBytes $c.Size}} against the 100 MB Cloudflare allows in one request">
102      <span class="bar"><span style="width: {{$c.PushPercent}}%"></span></span>
103      {{humanBytes $c.Size}} &middot; {{$c.PushPercent}}% of what one request can carry
104    </p>
105
106    {{if $c.OverLimit}}
107      <p class="warn">
108        A full copy of this repository no longer fits in one request, so
109        <strong>re-seeding it from scratch</strong> (a fresh clone pushed to a new
110        name, or restoring it elsewhere) needs the bridge or a sliced push.
111        Ordinary pushes here are unaffected: they carry new objects only.
112      </p>
113      {{template "pushlimit" (dict "Bridge" $c.BridgeContainer "Name" $c.Repo.Name)}}
114    {{end}}
115  {{end}}
116</div>
117{{end}}
118
119
120{{define "commitrow"}}
121<li class="commit">
122  <a class="subject" href="/{{.Repo}}/commit/{{.Commit.SHA}}">{{.Commit.Subject}}</a>
123  <span class="meta">
124    <code>{{shortSHA .Commit.SHA}}</code>
125    {{.Commit.Author}}
126    <time datetime="{{.Commit.When.Format "2006-01-02T15:04:05Z07:00"}}"
127          title="{{.Commit.When.Format "2006-01-02 15:04:05 MST"}}">{{humanTime .Commit.When}}</time>
128  </span>
129</li>
130{{end}}
131
132
133{{define "difffile"}}
134{{$f := .File}}
135<div class="difffile">
136  <div class="diffhead">
137    <span class="status {{$f.Status}}">{{$f.Status}}</span>
138    {{if eq (printf "%s" $f.Status) "renamed"}}
139      <code>{{$f.OldPath}} &rarr; {{$f.NewPath}}</code>
140    {{else}}
141      <code>{{$f.Path}}</code>
142    {{end}}
143    <span class="counts"><ins>+{{$f.Additions}}</ins> <del>-{{$f.Deletions}}</del></span>
144  </div>
145
146  {{if $f.Binary}}
147    <p class="binary">Binary file not shown.</p>
148  {{else}}
149    {{range $f.Hunks}}
150    <table class="hunk">
151      <tr class="hunkhead"><td colspan="3">{{.Header}}</td></tr>
152      {{range .Lines}}
153      <tr class="{{.Kind}}">
154        <td class="num">{{if .OldNum}}{{.OldNum}}{{end}}</td>
155        <td class="num">{{if .NewNum}}{{.NewNum}}{{end}}</td>
156        <td class="code">{{.Text}}</td>
157      </tr>
158      {{end}}
159    </table>
160    {{end}}
161  {{end}}
162</div>
163{{end}}