package templates import ( "fmt" "html/template" "log" "path/filepath" "sync" "github.com/juanatsap/cv-site/internal/config" ) // Manager handles template parsing and rendering type Manager struct { templates *template.Template config *config.TemplateConfig mu sync.RWMutex } // NewManager creates a new template manager func NewManager(cfg *config.TemplateConfig) (*Manager, error) { m := &Manager{ config: cfg, } if err := m.loadTemplates(); err != nil { return nil, fmt.Errorf("failed to load templates: %w", err) } return m, nil } // loadTemplates parses all templates from the configured directory func (m *Manager) loadTemplates() error { m.mu.Lock() defer m.mu.Unlock() // Create template with custom functions funcMap := template.FuncMap{ "iterate": func(count int) []int { var result []int for i := 0; i < count; i++ { result = append(result, i) } return result }, "eq": func(a, b string) bool { return a == b }, "safeHTML": func(s string) template.HTML { return template.HTML(s) }, } // Parse main templates pattern := filepath.Join(m.config.Dir, "*.html") tmpl, err := template.New("").Funcs(funcMap).ParseGlob(pattern) if err != nil { return fmt.Errorf("error parsing templates from %s: %w", pattern, err) } // Try to parse partials if they exist partialsPattern := filepath.Join(m.config.PartialsDir, "*.html") partials, _ := filepath.Glob(partialsPattern) if len(partials) > 0 { tmpl, err = tmpl.ParseGlob(partialsPattern) if err != nil { log.Printf("Warning: error parsing partials: %v", err) } } m.templates = tmpl log.Printf("✓ Templates loaded successfully from %s", m.config.Dir) return nil } // Reload reloads all templates (useful for hot-reload in development) func (m *Manager) Reload() error { return m.loadTemplates() } // Render executes a template with the given data func (m *Manager) Render(name string) (*template.Template, error) { // Hot reload in development mode if m.config.HotReload { if err := m.Reload(); err != nil { log.Printf("Warning: template reload failed: %v", err) // Continue with cached templates } } m.mu.RLock() defer m.mu.RUnlock() tmpl := m.templates.Lookup(name) if tmpl == nil { return nil, fmt.Errorf("template %q not found", name) } return tmpl, nil }