hmn/src/templates/templates.go

120 lines
3.1 KiB
Go

package templates
import (
"embed"
"fmt"
"html/template"
"net/url"
"strings"
"time"
"git.handmade.network/hmn/hmn/src/hmnurl"
"git.handmade.network/hmn/hmn/src/logging"
"github.com/Masterminds/sprig"
"github.com/teacat/noire"
)
//go:embed src
var templateFs embed.FS
var Templates map[string]*template.Template
var cachebust string
func Init() {
cachebust = fmt.Sprint(time.Now().Unix())
Templates = make(map[string]*template.Template)
files, _ := templateFs.ReadDir("src")
for _, f := range files {
if strings.HasSuffix(f.Name(), ".html") {
t := template.New(f.Name())
t = t.Funcs(sprig.FuncMap())
t = t.Funcs(HMNTemplateFuncs)
t, err := t.ParseFS(templateFs, "src/layouts/*.html", "src/include/*.html", "src/"+f.Name())
if err != nil {
logging.Fatal().Str("filename", f.Name()).Err(err).Msg("failed to parse template")
}
Templates[f.Name()] = t
} else if strings.HasSuffix(f.Name(), ".css") {
t := template.New(f.Name())
t = t.Funcs(sprig.FuncMap())
t = t.Funcs(HMNTemplateFuncs)
t, err := t.ParseFS(templateFs, "src/"+f.Name())
if err != nil {
logging.Fatal().Str("filename", f.Name()).Err(err).Msg("failed to parse template")
}
Templates[f.Name()] = t
}
}
}
func names(ts []*template.Template) []string {
result := make([]string, len(ts))
for i, t := range ts {
result[i] = t.Name()
}
return result
}
var HMNTemplateFuncs = template.FuncMap{
"brighten": func(hexColor string, amount float64) (string, error) {
if len(hexColor) < 6 {
return "", fmt.Errorf("couldn't brighten invalid hex color: %v", hexColor)
}
return noire.NewHex(hexColor).Tint(amount).Hex(), nil
},
"cachebust": func() string {
return cachebust
},
"darken": func(hexColor string, amount float64) (string, error) {
if len(hexColor) < 6 {
return "", fmt.Errorf("couldn't darken invalid hex color: %v", hexColor)
}
return noire.NewHex(hexColor).Shade(amount).Hex(), nil
},
"projecturl": func(url string) string {
return hmnurl.Url(url, nil) // TODO: Use project subdomain
},
"projecturlq": func(url string, query string) string {
absUrl := hmnurl.Url(url, nil)
return fmt.Sprintf("%s?%s", absUrl, query) // TODO: Use project subdomain
},
"query": func(args ...string) string {
query := url.Values{}
for i := 0; i < len(args); i += 2 {
query.Set(args[i], args[i+1])
}
return query.Encode()
},
"static": func(filepath string) string {
return hmnurl.StaticUrl(filepath, []hmnurl.Q{{"v", cachebust}})
},
"staticnobust": func(filepath string) string {
return hmnurl.StaticUrl(filepath, nil)
},
"statictheme": func(theme string, filepath string) string {
return hmnurl.StaticThemeUrl(filepath, theme, []hmnurl.Q{{"v", cachebust}})
},
"staticthemenobust": func(theme string, filepath string) string {
return hmnurl.StaticThemeUrl(filepath, theme, nil)
},
"url": func(url string) string {
return hmnurl.Url(url, nil)
},
"urlq": func(url string, query string) string {
absUrl := hmnurl.Url(url, nil)
return fmt.Sprintf("%s?%s", absUrl, query)
},
}
type ErrInvalidHexColor struct {
color string
}
func (e ErrInvalidHexColor) Error() string {
return fmt.Sprintf("invalid hex color: %s", e.color)
}