feat(pages): render pages in site builder after all other content

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Leon Mika 2026-03-22 19:11:12 +11:00
parent d464821a8c
commit ef038172ac
5 changed files with 53 additions and 1 deletions

View file

@ -0,0 +1,2 @@
{{ if .Page.Title }}<h2>{{ .Page.Title }}</h2>{{ end }}
{{ .HTML }}

View file

@ -118,7 +118,12 @@ func (b *Builder) BuildSite(outDir string) error {
// Build static assets // Build static assets
eg.Go(func() error { return b.writeStaticAssets(buildCtx) }) eg.Go(func() error { return b.writeStaticAssets(buildCtx) })
return eg.Wait() if err := eg.Wait(); err != nil {
return err
}
// Render pages last so they can override auto-generated content
return b.renderPages(buildCtx)
} }
func (b *Builder) renderPostListWithCategories(bctx buildContext, ctx context.Context) error { func (b *Builder) renderPostListWithCategories(bctx buildContext, ctx context.Context) error {

View file

@ -22,6 +22,7 @@ func TestBuilder_BuildSite(t *testing.T) {
"layout_main.html": {Data: []byte(`{{ .Body }}`)}, "layout_main.html": {Data: []byte(`{{ .Body }}`)},
"categories_list.html": {Data: []byte(`{{ range .Categories}}<a href="{{url_abs .Path}}">{{.Name}}</a>,{{ end }}`)}, "categories_list.html": {Data: []byte(`{{ range .Categories}}<a href="{{url_abs .Path}}">{{.Name}}</a>,{{ end }}`)},
"categories_single.html": {Data: []byte(`<h2>{{.Category.Name}}</h2>`)}, "categories_single.html": {Data: []byte(`<h2>{{.Category.Name}}</h2>`)},
"pages_single.html": {Data: []byte(`{{ if .Page.Title }}<h2>{{ .Page.Title }}</h2>{{ end }}{{ .HTML }}`)},
} }
posts := []*models.Post{ posts := []*models.Post{
@ -49,11 +50,15 @@ func TestBuilder_BuildSite(t *testing.T) {
} }
} }
}, },
Pages: []*models.Page{
{Title: "About", Slug: "about", Body: "About this site"},
},
} }
wantFiles := map[string]string{ wantFiles := map[string]string{
"2026/02/18/test-post/index.html": "<p>This is a test post</p>\n", "2026/02/18/test-post/index.html": "<p>This is a test post</p>\n",
"2026/02/20/another-post/index.html": "<p>This is <strong>another</strong> test post</p>\n", "2026/02/20/another-post/index.html": "<p>This is <strong>another</strong> test post</p>\n",
"index.html": "<a href=\"https://example.com/2026/02/18/test-post\">Test Post</a>,<a href=\"https://example.com/2026/02/20/another-post\">Another Post</a>,", "index.html": "<a href=\"https://example.com/2026/02/18/test-post\">Test Post</a>,<a href=\"https://example.com/2026/02/20/another-post\">Another Post</a>,",
"about/index.html": "<h2>About</h2><p>About this site</p>\n",
} }
outDir := t.TempDir() outDir := t.TempDir()

View file

@ -0,0 +1,31 @@
package sitebuilder
import (
"bytes"
"context"
"html/template"
"io"
)
func (b *Builder) renderPages(bctx buildContext) error {
for _, page := range b.site.Pages {
var md bytes.Buffer
if err := b.mdRenderer.RenderTo(context.Background(), &md, page.Body); err != nil {
return err
}
data := pageSingleData{
commonData: commonData{Site: b.site},
Page: page,
HTML: template.HTML(md.String()),
}
path := "/" + page.Slug
if err := b.createAtPath(bctx, path, func(f io.Writer) error {
return b.renderTemplate(f, tmplNamePageSingle, data)
}); err != nil {
return err
}
}
return nil
}

View file

@ -26,6 +26,9 @@ const (
// tmplNameCategorySingle is the template for a single category page // tmplNameCategorySingle is the template for a single category page
tmplNameCategorySingle = "categories_single.html" tmplNameCategorySingle = "categories_single.html"
// tmplNamePageSingle is the template for a single page (pageSingleData)
tmplNamePageSingle = "pages_single.html"
) )
type Options struct { type Options struct {
@ -92,3 +95,9 @@ type categorySingleData struct {
PrevURL string PrevURL string
NextURL string NextURL string
} }
type pageSingleData struct {
commonData
Page *models.Page
HTML template.HTML
}