···
···
avatar config.AvatarConfig
resolver *idresolver.Resolver
templateDir string // Path to templates on disk for dev mode
rctx *markup.RenderContext
func NewPages(config *config.Config, res *idresolver.Resolver) *Pages {
···
t: make(map[string]*template.Template),
templateDir: "appview/pages",
74
+
logger: slog.Default().With("component", "pages"),
// Initial load of all templates
···
82
-
func (p *Pages) loadAllTemplates() {
83
-
templates := make(map[string]*template.Template)
83
+
func (p *Pages) fragmentPaths() ([]string, error) {
var fragmentPaths []string
86
-
// Use embedded FS for initial loading
87
-
// First, collect all fragment paths
err := fs.WalkDir(p.embedFS, "templates", func(path string, d fs.DirEntry, err error) error {
···
if !strings.Contains(path, "fragments/") {
101
-
name := strings.TrimPrefix(path, "templates/")
102
-
name = strings.TrimSuffix(name, ".html")
103
-
tmpl, err := template.New(name).
104
-
Funcs(p.funcMap()).
105
-
ParseFS(p.embedFS, path)
107
-
log.Fatalf("setting up fragment: %v", err)
109
-
templates[name] = tmpl
fragmentPaths = append(fragmentPaths, path)
111
-
log.Printf("loaded fragment: %s", name)
115
-
log.Fatalf("walking template dir for fragments: %v", err)
105
+
return fragmentPaths, nil
108
+
func (p *Pages) loadAllTemplates() {
110
+
p.embedFS = os.DirFS(p.templateDir)
115
+
l := p.logger.With("handler", "loadAllTemplates")
116
+
templates := make(map[string]*template.Template)
117
+
fragmentPaths, err := p.fragmentPaths()
119
+
l.Error("failed to collect fragments", "err", err)
123
+
// parse all fragments together
124
+
allFragments := template.New("").Funcs(p.funcMap())
125
+
for _, f := range fragmentPaths {
126
+
name := strings.TrimPrefix(f, "templates/")
127
+
name = strings.TrimSuffix(name, ".html")
128
+
pf, err := template.New(name).Funcs(p.funcMap()).ParseFS(p.embedFS, f)
130
+
l.Error("failed to parse fragment", "name", name, "path", f)
133
+
allFragments, err = allFragments.AddParseTree(name, pf.Tree)
135
+
l.Error("failed to add parse tree", "name", name, "path", f)
138
+
templates[name] = allFragments.Lookup(name)
// Then walk through and setup the rest of the templates
err = fs.WalkDir(p.embedFS, "templates", func(path string, d fs.DirEntry, err error) error {
···
return fmt.Errorf("setting up template: %w", err)
151
-
log.Printf("loaded template: %s", name)
173
+
l.Debug("loaded all templates")
155
-
log.Fatalf("walking template dir: %v", err)
177
+
l.Error("walking template dir", "err", err)
158
-
log.Printf("total templates loaded: %d", len(templates))
181
+
l.Info("loaded all templates", "total", len(templates))
164
-
// loadTemplateFromDisk loads a template from the filesystem in dev mode
165
-
func (p *Pages) loadTemplateFromDisk(name string) error {
170
-
log.Printf("reloading template from disk: %s", name)
172
-
// Find all fragments first
173
-
var fragmentPaths []string
174
-
err := filepath.WalkDir(filepath.Join(p.templateDir, "templates"), func(path string, d fs.DirEntry, err error) error {
181
-
if !strings.HasSuffix(path, ".html") {
184
-
if !strings.Contains(path, "fragments/") {
187
-
fragmentPaths = append(fragmentPaths, path)
191
-
return fmt.Errorf("walking disk template dir for fragments: %w", err)
194
-
// Find the template path on disk
195
-
templatePath := filepath.Join(p.templateDir, "templates", name+".html")
196
-
if _, err := os.Stat(templatePath); os.IsNotExist(err) {
197
-
return fmt.Errorf("template not found on disk: %s", name)
200
-
// Create a new template
201
-
tmpl := template.New(name).Funcs(p.funcMap())
204
-
layoutGlob := filepath.Join(p.templateDir, "templates", "layouts", "*.html")
205
-
layouts, err := filepath.Glob(layoutGlob)
207
-
return fmt.Errorf("finding layout templates: %w", err)
210
-
// Create paths for parsing
211
-
allFiles := append(layouts, fragmentPaths...)
212
-
allFiles = append(allFiles, templatePath)
214
-
// Parse all templates
215
-
tmpl, err = tmpl.ParseFiles(allFiles...)
217
-
return fmt.Errorf("parsing template files: %w", err)
220
-
// Update the template in the map
222
-
defer p.mu.Unlock()
224
-
log.Printf("template reloaded from disk: %s", name)
func (p *Pages) executeOrReload(templateName string, w io.Writer, base string, params any) error {
229
-
// In dev mode, reload the template from disk before executing
188
+
// In dev mode, reparse templates from disk before executing
231
-
if err := p.loadTemplateFromDisk(templateName); err != nil {
232
-
log.Printf("warning: failed to reload template %s from disk: %v", templateName, err)
233
-
// Continue with the existing template
190
+
p.loadAllTemplates()
···
sub, err := fs.Sub(Files, "static")
1272
-
log.Fatalf("no static dir found? that's crazy: %v", err)
1228
+
p.logger.Error("no static dir found? that's crazy", "err", err)
// Custom handler to apply Cache-Control headers for font files
return Cache(http.StripPrefix("/static/", http.FileServer(http.FS(sub))))
···
func CssContentHash() string {
cssFile, err := Files.Open("static/tw.css")
1295
-
log.Printf("Error opening CSS file: %v", err)
1252
+
slog.Debug("Error opening CSS file", "err", err)
if _, err := io.Copy(hasher, cssFile); err != nil {
1302
-
log.Printf("Error hashing CSS file: %v", err)
1259
+
slog.Debug("Error hashing CSS file", "err", err)