package render import ( "fmt" "html/template" "path/filepath" "sync" "github.com/russross/blackfriday/v2" ) type TemplateData struct { Name string FileNameSet []string } type TemplateManager struct { templates map[string]*template.Template mu sync.RWMutex basePath string devMode bool } func NewTemplateManager(basePath string, devMode bool) *TemplateManager { return &TemplateManager{ templates: make(map[string]*template.Template), basePath: basePath, devMode: devMode, } } func (tm *TemplateManager) buildTemplatePath(name string) string { return filepath.Join(tm.basePath, name+".tmpl") } func (tm *TemplateManager) GetTemplate(td *TemplateData) (*template.Template, error) { // Skip cache in dev mode if !tm.devMode { tm.mu.RLock() if tmpl, exists := tm.templates[td.Name]; exists { tm.mu.RUnlock() return tmpl, nil } tm.mu.RUnlock() } // Build file paths var files []string for _, file := range td.FileNameSet { files = append(files, tm.buildTemplatePath(file)) } // Parse template tmpl, err := template.ParseFiles(files...) if err != nil { return nil, fmt.Errorf("parse template %s: %w", td.Name, err) } // Cache it (unless in dev mode) if !tm.devMode { tm.mu.Lock() tm.templates[td.Name] = tmpl tm.mu.Unlock() } return tmpl, nil } // Render markdown to HTML with target="_blank" on links func RenderMarkdown(content []byte) (template.HTML, error) { renderer := blackfriday.NewHTMLRenderer(blackfriday.HTMLRendererParameters{ Flags: blackfriday.CommonHTMLFlags | blackfriday.HrefTargetBlank, }) html := blackfriday.Run(content, blackfriday.WithRenderer(renderer)) return template.HTML(html), nil }