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
1#let render(
2 title: "",
3 date: "",
4 read_time: 0,
5 tags: (),
6 description: "",
7 cover_image: none,
8 body: [],
9) = {
10 set page(
11 paper: "a4",
12 margin: (top: 2cm, bottom: 2.5cm, left: 2cm, right: 2cm),
13 header: context {
14 let page_num = counter(page).get().first()
15 if page_num > 1 {
16 set text(size: 7pt, fill: rgb("#999999"))
17 grid(
18 columns: (1fr, 1fr),
19 align(left)[#title],
20 align(right)[blog.bythewood.me],
21 )
22 }
23 },
24 footer: context {
25 set align(center)
26 set text(size: 7pt, fill: rgb("#999999"))
27 [#counter(page).display() / #counter(page).final().first()]
28 },
29 )
30
31 set text(
32 font: ("Geist", "DejaVu Sans", "Liberation Sans", "Arial"),
33 size: 10pt,
34 fill: rgb("#1a1a1a"),
35 )
36 set par(leading: 0.65em, justify: false)
37
38 show raw: set text(
39 font: ("JetBrains Mono", "DejaVu Sans Mono", "Liberation Mono"),
40 size: 8.5pt,
41 )
42 show raw.where(block: true): it => block(
43 fill: rgb("#f5f5f5"),
44 inset: 8pt,
45 radius: 4pt,
46 width: 100%,
47 breakable: true,
48 it,
49 )
50 show raw.where(block: false): it => box(
51 fill: rgb("#f0f0f0"),
52 inset: (x: 3pt, y: 1pt),
53 radius: 3pt,
54 outset: (y: 2pt),
55 it,
56 )
57
58 show link: set text(fill: rgb("#0e3ff4"))
59 show link: underline
60
61 show heading: set block(above: 1.4em, below: 0.6em)
62 show heading.where(level: 1): set text(size: 1.8em, weight: "bold")
63 show heading.where(level: 2): set text(size: 1.4em, weight: "bold")
64 show heading.where(level: 3): set text(size: 1.15em, weight: "bold")
65 show heading.where(level: 4): set text(size: 1.0em, weight: "bold")
66
67 show quote.where(block: true): it => block(
68 inset: (left: 1em),
69 stroke: (left: 3pt + rgb("#dddddd")),
70 )[#set text(fill: rgb("#555555")); #it.body]
71
72 // Title
73 text(size: 1.8em, weight: "bold")[#title]
74
75 // Meta line + tags + bottom border
76 block(
77 above: 0.4em,
78 below: 1.5em,
79 stroke: (bottom: 2pt + rgb("#eeeeee")),
80 inset: (bottom: 0.8em),
81 width: 100%,
82 )[
83 #set text(size: 0.9em, fill: rgb("#666666"))
84 Isaac Bythewood · #date · #read_time min read
85 #if tags.len() > 0 {
86 v(0.4em)
87 for tag in tags {
88 box(
89 fill: rgb("#eeeeee"),
90 inset: (x: 0.5em, y: 0.1em),
91 radius: 3pt,
92 outset: (y: 1pt),
93 )[#text(size: 0.85em)[#tag]]
94 h(0.3em)
95 }
96 }
97 ]
98
99 if cover_image != none {
100 align(center)[#image(cover_image, width: 100%)]
101 v(1.5em)
102 }
103
104 if description != "" {
105 block(below: 1.5em)[
106 #set text(size: 1.1em, fill: rgb("#555555"))
107 #description
108 ]
109 }
110
111 body
112}