package templates import ( "embed" "io" "io/fs" "log/slog" "strings" "text/template" "time" "github.com/labstack/echo/v4" "github.com/mentos1386/zdravko/pkg/script" ) //go:embed * var templates embed.FS const base = "components/base.tmpl" type Templates struct { logger *slog.Logger templates map[string]*template.Template } func load(files ...string) *template.Template { files = append(files, base) t := template.New("default").Funcs( template.FuncMap{ "MathDivide": func(a, b int) float64 { if b == 0 { return 0 } return float64(a) / float64(b) }, "DurationRoundSecond": func(d time.Duration) time.Duration { return d.Round(time.Second) }, "DurationRoundMillisecond": func(d time.Duration) time.Duration { return d.Round(time.Millisecond) }, "StringsJoin": strings.Join, "Now": time.Now, "ScriptUnescapeString": script.UnescapeString, "ScriptEscapeString": script.EscapeString, }) return template.Must(t.ParseFS(templates, files...)) } func loadSettings(files ...string) *template.Template { files = append(files, "components/settings.tmpl") return load(files...) } func NewTemplates(logger *slog.Logger) (*Templates, error) { t := Templates{ logger: logger, templates: map[string]*template.Template{}, } err := fs.WalkDir(templates, "pages", func(path string, d fs.DirEntry, err error) error { if err != nil { return err } if strings.Contains(path, ".tmpl") { t.logger.Debug("Loading template", "path", path) pathWithoutPrefix := strings.TrimPrefix(path, "pages/") if strings.Contains(path, "settings") { t.templates[pathWithoutPrefix] = loadSettings(path) } else { t.templates[pathWithoutPrefix] = load(path) } } return nil }) return &t, err } func (t *Templates) Render(w io.Writer, name string, data interface{}, c echo.Context) error { if t.templates[name] == nil { t.logger.Error("template not found", "template", name) return echo.ErrNotFound } err := t.templates[name].ExecuteTemplate(w, "base", data) if err != nil { t.logger.Error("error rendering template", "template", err) } return err }