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

2.6 KB · 113 lines · Typst Raw History
  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}