| 1 | package theme |
| 2 | |
| 3 | import ( |
| 4 | "embed" |
| 5 | "net/http" |
| 6 | "strings" |
| 7 | ) |
| 8 | |
| 9 | // Onest is Calma's typeface: the Latin subset of the variable font |
| 10 | // (weights 300-800), SIL Open Font License 1.1. Provenance and the |
| 11 | // licence are in credits/notices/onest-*; list them on the app's credits |
| 12 | // page with credits.Onest(). |
| 13 | |
| 14 | //go:embed fonts/onest-latin.woff2 |
| 15 | var fontFS embed.FS |
| 16 | |
| 17 | // FontPrefix is the URL path FontHandler serves under. Its version moves |
| 18 | // whenever either file's bytes do (a new subset, a newer Onest, a changed |
| 19 | // unicode-range): browsers hold both for a year under this path. |
| 20 | const FontPrefix = "/static/estilo/fonts/v1/" |
| 21 | |
| 22 | // fontCSS declares Onest for the Latin range; a character outside it |
| 23 | // falls through to the system face in --rst-font, glyph by glyph. |
| 24 | const fontCSS = `/* Onest, Calma's typeface (estilo theme/fonts.go). */ |
| 25 | @font-face { |
| 26 | font-family: "Onest"; |
| 27 | font-style: normal; |
| 28 | font-weight: 300 800; |
| 29 | font-display: swap; |
| 30 | src: url("` + FontPrefix + `onest-latin.woff2") format("woff2"); |
| 31 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; |
| 32 | } |
| 33 | ` |
| 34 | |
| 35 | // FontCSS is the @font-face stylesheet, served by FontHandler as |
| 36 | // FontPrefix + "fonts.css". Link it before theme.css. Without it the |
| 37 | // theme still works, in the system face. |
| 38 | func FontCSS() []byte { return []byte(fontCSS) } |
| 39 | |
| 40 | // FontHandler serves GET and HEAD for FontPrefix + "fonts.css" and |
| 41 | // FontPrefix + "onest-latin.woff2". Mount it at FontPrefix; anything else |
| 42 | // under it is 404. Public, sessionless, and the bytes never change under |
| 43 | // a name, so both are cached for a year. |
| 44 | func FontHandler() http.Handler { |
| 45 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 46 | name := strings.TrimPrefix(r.URL.Path, FontPrefix) |
| 47 | var body []byte |
| 48 | var kind string |
| 49 | switch { |
| 50 | case !strings.HasPrefix(r.URL.Path, FontPrefix): |
| 51 | case name == "fonts.css": |
| 52 | body, kind = FontCSS(), "text/css; charset=utf-8" |
| 53 | case name == "onest-latin.woff2": |
| 54 | body, _ = fontFS.ReadFile("fonts/onest-latin.woff2") |
| 55 | kind = "font/woff2" |
| 56 | } |
| 57 | if body == nil { |
| 58 | http.NotFound(w, r) |
| 59 | return |
| 60 | } |
| 61 | if r.Method != http.MethodGet && r.Method != http.MethodHead { |
| 62 | w.Header().Set("Allow", "GET, HEAD") |
| 63 | http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed) |
| 64 | return |
| 65 | } |
| 66 | w.Header().Set("Content-Type", kind) |
| 67 | w.Header().Set("Cache-Control", "public, max-age=31536000, immutable") |
| 68 | w.Header().Set("X-Content-Type-Options", "nosniff") |
| 69 | if r.Method == http.MethodHead { |
| 70 | return |
| 71 | } |
| 72 | _, _ = w.Write(body) |
| 73 | }) |
| 74 | } |
| 75 | |