package server
import (
"embed"
"fmt"
"html/template"
)
// templateFS holds the rendered admin/login HTML pages. Keeping them as
// separate files (rather than inline raw-string literals in server.go) gives
// them real syntax highlighting and keeps server.go focused on handlers.
//
//go:embed templates/*.html
var templateFS embed.FS
var (
loginTemplate = mustParseTemplate("login.html", "login")
loginResultTemplate = mustParseTemplate("login_result.html", "login-result")
adminTemplate = mustParseTemplateFuncs("admin.html", "admin", template.FuncMap{
"pct": func(f float64) string { return fmt.Sprintf("%.1f%%", f*100) },
"rate": func(cached, prompt int64) string {
if prompt <= 0 {
return "0%"
}
return fmt.Sprintf("%.1f%%", float64(cached)/float64(prompt)*100)
},
"human": humanNum,
})
)
// mustParseTemplate reads a single embedded template file and parses it,
// panicking on error (a malformed template is a build-time mistake).
func mustParseTemplate(filename, name string) *template.Template {
data, err := templateFS.ReadFile("templates/" + filename)
if err != nil {
panic("embed template " + filename + ": " + err.Error())
}
return template.Must(template.New(name).Parse(string(data)))
}
// mustParseTemplateFuncs is mustParseTemplate with a FuncMap registered before
// parsing, so the template body may reference the custom functions.
func mustParseTemplateFuncs(filename, name string, funcs template.FuncMap) *template.Template {
data, err := templateFS.ReadFile("templates/" + filename)
if err != nil {
panic("embed template " + filename + ": " + err.Error())
}
return template.Must(template.New(name).Funcs(funcs).Parse(string(data)))
}