Files
cv-site/internal/templates/template.go
T
juanatsap dab68f34f2 Initial commit: Go + HTMX CV Site
- Minimal, professional CV design with paper-on-gray layout
- Bilingual support (Spanish/English) with HTMX language switching
- JSON-based content management (cv-en.json, cv-es.json)
- Print-optimized CSS for PDF export
- Responsive design for all devices
- Go backend with stdlib net/http
- Clean, maintainable codebase

Features:
- 18+ years professional experience
- SAP CDC expertise
- Complete project history
- Education, certifications, awards
- Multi-language support

Tech stack: Go, HTMX, vanilla CSS
2025-10-20 08:54:21 +01:00

100 lines
2.2 KiB
Go

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
},
}
// 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
}