diff --git a/template.go b/template.go index b7af212..110c433 100644 --- a/template.go +++ b/template.go @@ -4,17 +4,22 @@ import ( "fmt" "html/template" "io" + "io/ioutil" "net/url" + "os" "github.com/labstack/echo/v4" ) -type tmpl struct { - // TODO: add support for multiple themes - t *template.Template +const themesDir = "public/themes" + +type renderer struct { + base *template.Template + themes map[string]*template.Template + defaultTheme string } -func (t *tmpl) Render(w io.Writer, name string, data interface{}, ectx echo.Context) error { +func (r *renderer) Render(w io.Writer, name string, data interface{}, ectx echo.Context) error { // ectx is the raw *echo.context, not our own *context ctx := ectx.Get("context").(*context) @@ -24,10 +29,29 @@ func (t *tmpl) Render(w io.Writer, name string, data interface{}, ectx echo.Cont } } - return t.t.ExecuteTemplate(w, name, data) + // TODO: per-user theme selection + t := r.base + if r.defaultTheme != "" { + t = r.themes[r.defaultTheme] + } + return t.ExecuteTemplate(w, name, data) } -func loadTemplates(logger echo.Logger, themeName string, plugins []Plugin) (*tmpl, error) { +func loadTheme(name string, base *template.Template) (*template.Template, error) { + theme, err := base.Clone() + if err != nil { + return nil, err + } + + theme, err = theme.ParseGlob("public/themes/" + name + "/*.html") + if err != nil { + return nil, err + } + + return theme, nil +} + +func loadTemplates(logger echo.Logger, defaultTheme string, plugins []Plugin) (*renderer, error) { base := template.New("").Funcs(template.FuncMap{ "tuple": func(values ...interface{}) []interface{} { return values @@ -45,17 +69,34 @@ func loadTemplates(logger echo.Logger, themeName string, plugins []Plugin) (*tmp return nil, err } - theme, err := base.Clone() - if err != nil { + themes := make(map[string]*template.Template) + + files, err := ioutil.ReadDir(themesDir) + if err != nil && !os.IsNotExist(err) { return nil, err } - if themeName != "" { - logger.Printf("Loading theme \"%s\"", themeName) - if _, err := theme.ParseGlob("public/themes/" + themeName + "/*.html"); err != nil { - return nil, err + for _, fi := range files { + if !fi.IsDir() { + continue + } + + logger.Printf("Loading theme '%v'", fi.Name()) + var err error + if themes[fi.Name()], err = loadTheme(fi.Name(), base); err != nil { + return nil, fmt.Errorf("failed to load theme '%v': %v", fi.Name(), err) + } + } + + if defaultTheme != "" { + if _, ok := themes[defaultTheme]; !ok { + return nil, fmt.Errorf("failed to find default theme '%v'", defaultTheme) } } - return &tmpl{theme}, err + return &renderer{ + base: base, + themes: themes, + defaultTheme: defaultTheme, + }, nil }