package handlers import ( "html/template" "log/slog" "net/http" "path/filepath" "qbank/internal/auth" ) var tmplFuncs = template.FuncMap{ "inc": func(i int) int { return i + 1 }, } // Renderer parses and executes HTML templates from a directory. type Renderer struct { dir string } func NewRenderer(dir string) *Renderer { return &Renderer{dir: dir} } // Render executes layout.html + .html, passing data to the "layout" template. func (r *Renderer) Render(w http.ResponseWriter, status int, name string, data any) { t, err := template.New("").Funcs(tmplFuncs).ParseFiles( filepath.Join(r.dir, "layout.html"), filepath.Join(r.dir, name+".html"), ) if err != nil { slog.Error("parse template", "name", name, "err", err) http.Error(w, "internal error", http.StatusInternalServerError) return } w.Header().Set("Content-Type", "text/html; charset=utf-8") w.WriteHeader(status) if err := t.ExecuteTemplate(w, "layout", data); err != nil { slog.Error("execute template", "name", name, "err", err) } } // HTTPError writes a plain-text HTTP error. func HTTPError(w http.ResponseWriter, status int) { http.Error(w, http.StatusText(status), status) } // BaseData builds the common template map (User, CSRFToken, Flash). func BaseData(a *auth.Manager, r *http.Request) map[string]any { return map[string]any{ "User": auth.UserFromCtx(r.Context()), "CSRFToken": a.CSRFToken(r), "Flash": a.PopFlash(r), } }