package root import ( "embed" "fmt" "html/template" "io/fs" "log" "path/filepath" "time" ) //go:embed templates static/* var webAssetsFS embed.FS var WebTemplates *template.Template // Custom helper functions for templates var funcMap = template.FuncMap{ "pageContent": func(name string) string { // This allows us to reference specific content blocks return "{{template \"" + name + "-content\" .}}" }, "add": func(a, b int) int { return a + b }, "subtract": func(a, b int) int { return a - b }, "div": func(a int64, b float64) float64 { return float64(a) / b }, "sequence": func(start, end int) []int { if start > end { return []int{} } result := make([]int, end-start+1) for i := range result { result[i] = start + i } return result }, "formatDuration": func(d time.Duration) string { seconds := d.Seconds() if seconds < 60 { return fmt.Sprintf("%.2fs", seconds) } else if seconds < 3600 { minutes := int(seconds) / 60 remainingSeconds := seconds - float64(minutes*60) return fmt.Sprintf("%dm %.2fs", minutes, remainingSeconds) } else { hours := int(seconds) / 3600 remainingMinutes := int(seconds) % 3600 / 60 remainingSeconds := seconds - float64(hours*3600) - float64(remainingMinutes*60) return fmt.Sprintf("%dh %dm %.2fs", hours, remainingMinutes, remainingSeconds) } }, } // InitializeWebTemplates parses all HTML templates in the embedded filesystem func InitializeWebTemplates() error { var err error WebTemplates, err = parseWebTemplates() return err } func parseWebTemplates() (*template.Template, error) { tmpl := template.New("").Funcs(funcMap) // First collect all template paths var templatePaths []string err := fs.WalkDir(webAssetsFS, "templates", func(path string, d fs.DirEntry, err error) error { if err != nil { return err } if d.IsDir() { return nil } if filepath.Ext(path) != ".html" { return nil } templatePaths = append(templatePaths, path) return nil }) if err != nil { return nil, err } // Process each template for _, path := range templatePaths { log.Printf("Parsing template: %s", path) content, err := webAssetsFS.ReadFile(path) if err != nil { return nil, err } filename := filepath.Base(path) name := filename _, err = tmpl.New(name).Parse(string(content)) if err != nil { return nil, err } } return tmpl, nil } // GetStaticFS provides access to the static assets filesystem for serving CSS and other static files func GetStaticFS() (fs.FS, error) { return fs.Sub(webAssetsFS, "static") }