package theme import ( "embed" "net/http" "strings" ) // Onest is Calma's typeface: the Latin subset of the variable font // (weights 300-800), SIL Open Font License 1.1. Provenance and the // licence are in credits/notices/onest-*; list them on the app's credits // page with credits.Onest(). //go:embed fonts/onest-latin.woff2 var fontFS embed.FS // FontPrefix is the URL path FontHandler serves under. Its version moves // whenever either file's bytes do (a new subset, a newer Onest, a changed // unicode-range): browsers hold both for a year under this path. const FontPrefix = "/static/estilo/fonts/v1/" // fontCSS declares Onest for the Latin range; a character outside it // falls through to the system face in --rst-font, glyph by glyph. const fontCSS = `/* Onest, Calma's typeface (estilo theme/fonts.go). */ @font-face { font-family: "Onest"; font-style: normal; font-weight: 300 800; font-display: swap; src: url("` + FontPrefix + `onest-latin.woff2") format("woff2"); 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; } ` // FontCSS is the @font-face stylesheet, served by FontHandler as // FontPrefix + "fonts.css". Link it before theme.css. Without it the // theme still works, in the system face. func FontCSS() []byte { return []byte(fontCSS) } // FontHandler serves GET and HEAD for FontPrefix + "fonts.css" and // FontPrefix + "onest-latin.woff2". Mount it at FontPrefix; anything else // under it is 404. Public, sessionless, and the bytes never change under // a name, so both are cached for a year. func FontHandler() http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { name := strings.TrimPrefix(r.URL.Path, FontPrefix) var body []byte var kind string switch { case !strings.HasPrefix(r.URL.Path, FontPrefix): case name == "fonts.css": body, kind = FontCSS(), "text/css; charset=utf-8" case name == "onest-latin.woff2": body, _ = fontFS.ReadFile("fonts/onest-latin.woff2") kind = "font/woff2" } if body == nil { http.NotFound(w, r) return } if r.Method != http.MethodGet && r.Method != http.MethodHead { w.Header().Set("Allow", "GET, HEAD") http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed) return } w.Header().Set("Content-Type", kind) w.Header().Set("Cache-Control", "public, max-age=31536000, immutable") w.Header().Set("X-Content-Type-Options", "nosniff") if r.Method == http.MethodHead { return } _, _ = w.Write(body) }) }