orchard
mirrorEvery 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
1package main
2
3import "html/template"
4
5var templateFuncs = template.FuncMap{
6 // The sparkline paths are computed in spark.go and go straight into a d
7 // attribute, so they need the type that says a template may write them
8 // without escaping. Everything else on this page is text and stays escaped.
9 "path": func(d string) template.HTMLAttr { return template.HTMLAttr(d) },
10
11 // range gives a zero based index and the feed ranks read from one.
12 "inc": func(i int) int { return i + 1 },
13
14 // dict builds a map inline, which is the only way a template can pass a
15 // named set of values to a shared define. Three gauges with six fields each
16 // is the point at which repeating the markup three times stops being the
17 // simpler option.
18 "dict": func(pairs ...any) map[string]any {
19 out := make(map[string]any, len(pairs)/2)
20 for i := 0; i+1 < len(pairs); i += 2 {
21 key, ok := pairs[i].(string)
22 if !ok {
23 continue
24 }
25 out[key] = pairs[i+1]
26 }
27 return out
28 },
29
30 // Valve's own review bands, so the colour on a rating matches the word the
31 // store puts next to the same number.
32 "band": func(pct int) string {
33 switch {
34 case pct >= 80:
35 return "good"
36 case pct >= 70:
37 return "mixed"
38 case pct >= 40:
39 return "poor"
40 default:
41 return "bad"
42 }
43 },
44}