diff --git a/render.go b/render.go index 870accc..e29cb70 100644 --- a/render.go +++ b/render.go @@ -34,22 +34,17 @@ func (a *App) JSON(w http.ResponseWriter, code int, v any) { json.NewEncoder(w).Encode(v) } -func (a *App) HTML(w http.ResponseWriter, code int, layout, page string, td *TemplateData) { +func (a *App) HTML(w http.ResponseWriter, r *http.Request, code int, layout string, page string, td *TemplateData) { w.Header().Set("Content-Type", "text/html; charset=utf-8") w.WriteHeader(code) - err := a.Templates.Template(w, layout, page, td) + + err := a.Templates.Render(w, layout, page, td, r.Header.Get("HX-Request") != "true") if err != nil { - slog.Error("error rendering template", "error", err) + slog.Error("error rendering", "layout", layout, "page", page, "error", err) http.Error(w, err.Error(), http.StatusInternalServerError) - return } } func (a *App) RenderComponent(name string, td *TemplateData) (string, error) { - result, err := a.Templates.RenderComponent(name, td) - if err != nil { - slog.Error("error rendering component", "component", name, "error", err) - return "", err - } - return result, nil + return a.Templates.RenderComponent(name, td) } diff --git a/templates.go b/templates.go index d70c9f9..70a41ec 100644 --- a/templates.go +++ b/templates.go @@ -3,6 +3,7 @@ package goblocks import ( "bytes" "errors" + "fmt" "html/template" "log/slog" "maps" @@ -38,8 +39,9 @@ func defaultHTMLRender() *Render { TemplatesPath: "templates", TemplateData: TemplateData{}, Functions: template.FuncMap{ - "default": defaultIfEmpty, - "dict": Dict, + "default": defaultIfEmpty, + "dict": Dict, + "duration": Duration, }, templateCache: templateCache{}, } @@ -74,18 +76,36 @@ func cloneFuncMap(src template.FuncMap) template.FuncMap { return c } -func (re *Render) Template(w http.ResponseWriter, layoutName, pageName string, td *TemplateData) error { +func (re *Render) Render(w http.ResponseWriter, layoutName, pageName string, td *TemplateData, useLayout bool) error { if td == nil { td = &TemplateData{} } + if !useLayout { + path := filepath.Join(re.TemplatesPath, "pages", pageName) + + funcs := cloneFuncMap(re.Functions) + tmpl, err := template.New(strings.TrimSuffix(pageName, ".gohtml")).Funcs(funcs).ParseFiles(path) + if err != nil { + return err + } + + var buf bytes.Buffer + if err := tmpl.ExecuteTemplate(&buf, strings.TrimSuffix(pageName, ".gohtml"), td); err != nil { + return err + } + + _, err = buf.WriteTo(w) + return err + } + tmpl, err := re.loadTemplateWithLayout(layoutName, pageName) if err != nil { return err } - buf := new(bytes.Buffer) - if err = tmpl.ExecuteTemplate(buf, strings.TrimSuffix(layoutName, ".gohtml"), td); err != nil { + var buf bytes.Buffer + if err := tmpl.ExecuteTemplate(&buf, strings.TrimSuffix(layoutName, ".gohtml"), td); err != nil { return err } @@ -103,6 +123,7 @@ func (re *Render) RenderComponent(name string, td *TemplateData) (string, error) files := []string{path} matches, err := filepath.Glob(filepath.Join(re.TemplatesPath, "components", "*.gohtml")) if err != nil { + slog.Error("error loading component files", "error", err) return "", err } files = append(files, matches...) @@ -110,11 +131,15 @@ func (re *Render) RenderComponent(name string, td *TemplateData) (string, error) funcs := cloneFuncMap(re.Functions) tmpl, err := template.New(name).Funcs(funcs).ParseFiles(files...) if err != nil { + slog.Error("error loading component files", "error", err) return "", err } var buf bytes.Buffer err = tmpl.ExecuteTemplate(&buf, strings.TrimSuffix(name, ".gohtml"), td) + if err != nil { + slog.Error("error executing component template", "error", err) + } return buf.String(), err } @@ -342,3 +367,13 @@ func FormatDateSpanish(date time.Time) string { return dayName + ", " + strconv.Itoa(day) + " de " + month + " de " + strconv.Itoa(year) } + +func Duration(start, end time.Time) string { + if end.IsZero() { + end = time.Now() + } + d := end.Sub(start) + h := int(d.Hours()) + m := int(d.Minutes()) % 60 + return fmt.Sprintf("%d:%02d", h, m) +}