/
template.go
108 lines (87 loc) · 1.96 KB
/
template.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package main
import (
"bytes"
"embed"
"errors"
"html/template"
"io"
"io/fs"
"path"
"strings"
)
type Template struct {
pages map[string]func(io.Writer, any) error
partials map[string]func(io.Writer, any) error
}
func NewTemplate(templateFS embed.FS) (*Template, error) {
tmpl := &Template{
pages: make(map[string]func(io.Writer, any) error),
partials: make(map[string]func(io.Writer, any) error),
}
pagePaths, err := fs.Glob(templateFS, "templates/*.tmpl")
if err != nil {
return nil, err
}
for _, pagePath := range pagePaths {
t, err := template.ParseFS(templateFS, "templates/root.html.tmpl", pagePath)
if err != nil {
return nil, err
}
k := key(pagePath)
tmpl.pages[k] = rexecute(t)
}
partialPaths, err := fs.Glob(templateFS, "templates/partials/*.tmpl")
if err != nil {
return nil, err
}
for _, partialPath := range partialPaths {
t, err := template.ParseFS(templateFS, partialPath)
if err != nil {
return nil, err
}
k := key(partialPath)
tmpl.partials[k] = t.Execute
}
return tmpl, nil
}
var ErrNotFound = errors.New("template not found")
func (t *Template) RenderPage(w io.Writer, name string, data any) error {
render, ok := t.pages[name]
if !ok {
return ErrNotFound
}
var buf bytes.Buffer
err := render(&buf, data)
if err != nil {
return err
}
if _, err := w.Write(buf.Bytes()); err != nil {
return err
}
return nil
}
func (t *Template) RenderPartial(w io.Writer, name string, data any) error {
render, ok := t.partials[name]
if !ok {
return ErrNotFound
}
var buf bytes.Buffer
err := render(&buf, data)
if err != nil {
return err
}
if _, err := w.Write(buf.Bytes()); err != nil {
return err
}
return nil
}
func rexecute(t *template.Template) func(io.Writer, any) error {
return func(w io.Writer, data any) error {
return t.ExecuteTemplate(w, "root", data)
}
}
func key(p string) string {
_, file := path.Split(p)
name, _ := strings.CutSuffix(file, ".html.tmpl")
return name
}