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

1.5 KB · 80 lines · Go Raw History
 1package main
 2
 3import (
 4	"fmt"
 5	"html/template"
 6	"strconv"
 7	"strings"
 8)
 9
10var templateFuncs = template.FuncMap{
11	"dict":      dict,
12	"json":      jsonBlock,
13	"pct":       pct,
14	"num":       formatNum,
15	"add":       func(a, b int) int { return a + b },
16	"hasPrefix": strings.HasPrefix,
17}
18
19// dict lets a partial take more than one value, since a Go template has a
20// single dot.
21func dict(pairs ...any) (map[string]any, error) {
22	if len(pairs)%2 != 0 {
23		return nil, fmt.Errorf("dict: odd number of arguments (%d)", len(pairs))
24	}
25	out := make(map[string]any, len(pairs)/2)
26	for i := 0; i < len(pairs); i += 2 {
27		key, ok := pairs[i].(string)
28		if !ok {
29			return nil, fmt.Errorf("dict: key %d is %T, want string", i, pairs[i])
30		}
31		out[key] = pairs[i+1]
32	}
33	return out, nil
34}
35
36// pct renders count as a whole-number percentage of total, and returns 0 rather
37// than dividing by zero.
38func pct(count, total int64) int64 {
39	if total <= 0 {
40		return 0
41	}
42	return count * 100 / total
43}
44
45// formatNum groups thousands with commas.
46func formatNum(v any) string {
47	var n int64
48	switch t := v.(type) {
49	case int:
50		n = int64(t)
51	case int64:
52		n = t
53	case *int64:
54		if t == nil {
55			return "0"
56		}
57		n = *t
58	case float64:
59		n = int64(t)
60	default:
61		return fmt.Sprint(v)
62	}
63
64	s := strconv.FormatInt(n, 10)
65	negative := strings.HasPrefix(s, "-")
66	s = strings.TrimPrefix(s, "-")
67
68	var b strings.Builder
69	for i, digit := range s {
70		if i > 0 && (len(s)-i)%3 == 0 {
71			b.WriteByte(',')
72		}
73		b.WriteRune(digit)
74	}
75	if negative {
76		return "-" + b.String()
77	}
78	return b.String()
79}