package server import ( "embed" "html/template" "net/http" "path/filepath" ) //go:embed templates/**/*.html var templatesFS embed.FS // Templates holds parsed templates for each page. type Templates struct { pages map[string]*template.Template } // NewTemplates loads and parses all templates from the embedded filesystem. func NewTemplates() (*Templates, error) { pages := make(map[string]*template.Template) // Define custom template functions funcMap := template.FuncMap{ "add": func(a, b int) int { return a + b }, "sub": func(a, b int) int { return a - b }, "supportedEcosystems": supportedEcosystems, "ecosystemBadgeClass": ecosystemBadgeClasses, "ecosystemBadgeLabel": ecosystemBadgeLabel, } // Get all page files pageFiles, err := templatesFS.ReadDir("templates/pages") if err != nil { return nil, err } for _, pageFile := range pageFiles { if pageFile.IsDir() { continue } pageName := pageFile.Name() pageName = pageName[:len(pageName)-len(filepath.Ext(pageName))] // Parse all layout files + components + this page with custom functions tmpl, err := template.New("").Funcs(funcMap).ParseFS(templatesFS, "templates/layout/*.html", "templates/components/*.html", "templates/pages/"+pageFile.Name(), ) if err != nil { return nil, err } pages[pageName] = tmpl } return &Templates{pages: pages}, nil } // Render renders a page template with the given data. func (t *Templates) Render(w http.ResponseWriter, pageName string, data any) error { w.Header().Set("Content-Type", "text/html; charset=utf-8") tmpl, ok := t.pages[pageName] if !ok { return http.ErrAbortHandler } return tmpl.ExecuteTemplate(w, "base", data) }