78 lines
1.9 KiB
Go
78 lines
1.9 KiB
Go
package httpserver
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"html/template"
|
|
"net/http"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
type Renderer struct {
|
|
templates map[string]*template.Template
|
|
}
|
|
|
|
func NewRenderer(templatesDir string) (*Renderer, error) {
|
|
layouts, err := filepath.Glob(filepath.Join(templatesDir, "layouts", "*.gohtml"))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("find layouts: %w", err)
|
|
}
|
|
|
|
if len(layouts) == 0 {
|
|
return nil, fmt.Errorf("no layout templates found in %s", filepath.Join(templatesDir, "layouts"))
|
|
}
|
|
|
|
partials, err := filepath.Glob(filepath.Join(templatesDir, "partials", "*.gohtml"))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("find partials: %w", err)
|
|
}
|
|
|
|
pages, err := filepath.Glob(filepath.Join(templatesDir, "pages", "*.gohtml"))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("find pages: %w", err)
|
|
}
|
|
|
|
if len(pages) == 0 {
|
|
return nil, fmt.Errorf("no page templates found in %s", filepath.Join(templatesDir, "pages"))
|
|
}
|
|
|
|
renderer := &Renderer{templates: make(map[string]*template.Template, len(pages))}
|
|
|
|
for _, page := range pages {
|
|
files := append([]string{}, layouts...)
|
|
files = append(files, partials...)
|
|
files = append(files, page)
|
|
|
|
tmpl, err := template.ParseFiles(files...)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("parse template set for %s: %w", page, err)
|
|
}
|
|
|
|
name := strings.TrimSuffix(filepath.Base(page), filepath.Ext(page))
|
|
renderer.templates[name] = tmpl
|
|
}
|
|
|
|
return renderer, nil
|
|
}
|
|
|
|
func (r *Renderer) Render(w http.ResponseWriter, name string, status int, data any) error {
|
|
tmpl, ok := r.templates[name]
|
|
if !ok {
|
|
return fmt.Errorf("unknown template %q", name)
|
|
}
|
|
|
|
var output bytes.Buffer
|
|
if err := tmpl.ExecuteTemplate(&output, "base", data); err != nil {
|
|
return err
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
|
if status <= 0 {
|
|
status = http.StatusOK
|
|
}
|
|
w.WriteHeader(status)
|
|
|
|
_, err := output.WriteTo(w)
|
|
return err
|
|
}
|