fix: fix cellar-go templates 5196f668
Steve · 2026-05-16 20:59 5 file(s) · +56 −14
apps/cellar-go/app.go +1 −1
15 15
type App struct {
16 16
	DB              *sql.DB
17 17
	Log             *slog.Logger
18 -
	Templates       *template.Template
18 +
	Templates       map[string]*template.Template
19 19
	Sessions        *auth.Store
20 20
	AppPassword     string
21 21
	CookieSecure    bool
apps/cellar-go/handlers_admin.go +6 −6
11 11
12 12
func (a *App) loginGet(w http.ResponseWriter, r *http.Request) {
13 13
	q := r.URL.Query()
14 -
	web.Render(a.Templates, w, "login.html", loginPageData{Error: q.Get("error"), Next: q.Get("next")}, a.Log)
14 +
	a.renderPage(w, "login.html", loginPageData{Error: q.Get("error"), Next: q.Get("next")})
15 15
}
16 16
17 17
func (a *App) loginPost(w http.ResponseWriter, r *http.Request) {
57 57
		http.Error(w, "Server error", http.StatusInternalServerError)
58 58
		return
59 59
	}
60 -
	web.Render(a.Templates, w, "admin.html", adminPageData{Wines: wines}, a.Log)
60 +
	a.renderPage(w, "admin.html", adminPageData{Wines: wines})
61 61
}
62 62
63 63
func (a *App) newWineGet(w http.ResponseWriter, r *http.Request) {
64 -
	web.Render(a.Templates, w, "wine_form.html", wineFormPageData{Error: r.URL.Query().Get("error"), HasAnthropicKey: a.AnthropicAPIKey != ""}, a.Log)
64 +
	a.renderPage(w, "wine_form.html", wineFormPageData{Error: r.URL.Query().Get("error"), HasAnthropicKey: a.AnthropicAPIKey != ""})
65 65
}
66 66
67 67
func (a *App) editWineGet(w http.ResponseWriter, r *http.Request) {
75 75
		http.Error(w, "Wine not found", http.StatusNotFound)
76 76
		return
77 77
	}
78 -
	web.Render(a.Templates, w, "wine_form.html", wineFormPageData{Wine: wine, Error: r.URL.Query().Get("error"), HasAnthropicKey: a.AnthropicAPIKey != ""}, a.Log)
78 +
	a.renderPage(w, "wine_form.html", wineFormPageData{Wine: wine, Error: r.URL.Query().Get("error"), HasAnthropicKey: a.AnthropicAPIKey != ""})
79 79
}
80 80
81 81
func (a *App) newWinePost(w http.ResponseWriter, r *http.Request) {
129 129
}
130 130
131 131
func (a *App) newWishlistGet(w http.ResponseWriter, r *http.Request) {
132 -
	web.Render(a.Templates, w, "wishlist_form.html", wineFormPageData{Error: r.URL.Query().Get("error"), HasAnthropicKey: a.AnthropicAPIKey != ""}, a.Log)
132 +
	a.renderPage(w, "wishlist_form.html", wineFormPageData{Error: r.URL.Query().Get("error"), HasAnthropicKey: a.AnthropicAPIKey != ""})
133 133
}
134 134
135 135
func (a *App) editWishlistGet(w http.ResponseWriter, r *http.Request) {
142 142
		http.Error(w, "Wine not found", http.StatusNotFound)
143 143
		return
144 144
	}
145 -
	web.Render(a.Templates, w, "wishlist_form.html", wineFormPageData{Wine: wine, Error: r.URL.Query().Get("error"), HasAnthropicKey: a.AnthropicAPIKey != ""}, a.Log)
145 +
	a.renderPage(w, "wishlist_form.html", wineFormPageData{Wine: wine, Error: r.URL.Query().Get("error"), HasAnthropicKey: a.AnthropicAPIKey != ""})
146 146
}
147 147
148 148
func (a *App) newWishlistPost(w http.ResponseWriter, r *http.Request) {
apps/cellar-go/handlers_public.go +3 −5
5 5
	"net/http"
6 6
	"strings"
7 7
	"time"
8 -
9 -
	"github.com/stevedylandev/andromeda/crates-go/web"
10 8
)
11 9
12 10
func (a *App) indexHandler(w http.ResponseWriter, r *http.Request) {
21 19
		svg := buildPentagonSVG(wine.Sweetness, wine.Acidity, wine.Tannin, wine.Alcohol, wine.Body, 80.0, false)
22 20
		out = append(out, wineWithSVG{Wine: wine, PentagonSVG: template.HTML(svg)})
23 21
	}
24 -
	web.Render(a.Templates, w, "index.html", indexPageData{Wines: out}, a.Log)
22 +
	a.renderPage(w, "index.html", indexPageData{Wines: out})
25 23
}
26 24
27 25
func (a *App) wineDetail(w http.ResponseWriter, r *http.Request) {
36 34
	}
37 35
	pentagon := buildPentagonSVG(wine.Sweetness, wine.Acidity, wine.Tannin, wine.Alcohol, wine.Body, 250.0, true)
38 36
	bars := buildBarsSVG(wine.Clarity, wine.ColorIntensity, wine.AromaIntensity, wine.NoseComplexity, 250.0)
39 -
	web.Render(a.Templates, w, "wine.html", wineDetailPageData{Wine: *wine, PentagonSVG: template.HTML(pentagon), BarsSVG: template.HTML(bars)}, a.Log)
37 +
	a.renderPage(w, "wine.html", wineDetailPageData{Wine: *wine, PentagonSVG: template.HTML(pentagon), BarsSVG: template.HTML(bars)})
40 38
}
41 39
42 40
func (a *App) wineImage(w http.ResponseWriter, r *http.Request) {
62 60
		http.Error(w, "Server error", http.StatusInternalServerError)
63 61
		return
64 62
	}
65 -
	web.Render(a.Templates, w, "wishlist.html", wishlistPageData{Wines: wines, IsAdmin: a.Sessions.HasValid(r)}, a.Log)
63 +
	a.renderPage(w, "wishlist.html", wishlistPageData{Wines: wines, IsAdmin: a.Sessions.HasValid(r)})
66 64
}
67 65
68 66
func xmlEscape(s string) string {
apps/cellar-go/main.go +4 −2
1 1
package main
2 2
3 3
import (
4 -
	"html/template"
5 4
	"log"
6 5
	"log/slog"
7 6
	"net/http"
36 35
	}
37 36
	sessions.PruneExpired()
38 37
39 -
	tmpl := template.Must(template.ParseFS(appFS, "templates/*.html"))
38 +
	tmpl, err := buildTemplates()
39 +
	if err != nil {
40 +
		log.Fatal(err)
41 +
	}
40 42
	app := &App{
41 43
		DB:              db,
42 44
		Log:             logger,
apps/cellar-go/render.go (added) +42 −0
1 +
package main
2 +
3 +
import (
4 +
	"fmt"
5 +
	"html/template"
6 +
	"io/fs"
7 +
	"net/http"
8 +
	"path"
9 +
	"strings"
10 +
11 +
	"github.com/stevedylandev/andromeda/crates-go/web"
12 +
)
13 +
14 +
func buildTemplates() (map[string]*template.Template, error) {
15 +
	pages, err := fs.Glob(appFS, "templates/*.html")
16 +
	if err != nil {
17 +
		return nil, err
18 +
	}
19 +
20 +
	out := make(map[string]*template.Template, len(pages))
21 +
	for _, page := range pages {
22 +
		if strings.HasSuffix(page, "/base.html") {
23 +
			continue
24 +
		}
25 +
		tmpl, err := template.ParseFS(appFS, "templates/base.html", page)
26 +
		if err != nil {
27 +
			return nil, fmt.Errorf("parse %s: %w", page, err)
28 +
		}
29 +
		out[path.Base(page)] = tmpl
30 +
	}
31 +
	return out, nil
32 +
}
33 +
34 +
func (a *App) renderPage(w http.ResponseWriter, name string, data any) {
35 +
	tmpl, ok := a.Templates[name]
36 +
	if !ok {
37 +
		a.Log.Error("template missing", "name", name)
38 +
		http.Error(w, "template missing", http.StatusInternalServerError)
39 +
		return
40 +
	}
41 +
	web.Render(tmpl, w, name, data, a.Log)
42 +
}