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))) }