From f68bac809ffb500765d6f4e81f68edb05bd48e05 Mon Sep 17 00:00:00 2001 From: Leon Mika Date: Sun, 22 Mar 2026 14:38:39 +1100 Subject: [PATCH] feat: add pagination to generated site category pages Co-Authored-By: Claude Opus 4.6 --- .../templates/categories_single.html | 8 +- providers/sitebuilder/builder.go | 75 +++++++++++++++---- providers/sitebuilder/tmpls.go | 3 + 3 files changed, 71 insertions(+), 15 deletions(-) diff --git a/layouts/simplecss/templates/categories_single.html b/layouts/simplecss/templates/categories_single.html index deaeb02..e9e7116 100644 --- a/layouts/simplecss/templates/categories_single.html +++ b/layouts/simplecss/templates/categories_single.html @@ -8,4 +8,10 @@ {{ .HTML }} {{ template "_post_meta.html" . }} -{{ end }} \ No newline at end of file +{{ end }} +{{ if or .PrevURL .NextURL }} + +{{ end }} diff --git a/providers/sitebuilder/builder.go b/providers/sitebuilder/builder.go index 601db41..f18e00d 100644 --- a/providers/sitebuilder/builder.go +++ b/providers/sitebuilder/builder.go @@ -372,7 +372,8 @@ func (b *Builder) renderCategoryPages(ctx buildContext, goCtx context.Context) e continue } - var posts []postSingleData + // Collect all posts for this category + var allPosts []postSingleData for mp := range b.site.PostIterByCategory(goCtx, cwc.ID) { post, err := mp.Get() if err != nil { @@ -382,7 +383,7 @@ func (b *Builder) renderCategoryPages(ctx buildContext, goCtx context.Context) e if err != nil { return err } - posts = append(posts, rp) + allPosts = append(allPosts, rp) } var descHTML bytes.Buffer @@ -392,22 +393,68 @@ func (b *Builder) renderCategoryPages(ctx buildContext, goCtx context.Context) e } } - data := categorySingleData{ - commonData: commonData{Site: b.site}, - Category: &cwc.Category, - DescriptionHTML: template.HTML(descHTML.String()), - Posts: posts, - Path: fmt.Sprintf("/categories/%s", cwc.Slug), + postsPerPage := b.site.PostsPerPage + if postsPerPage < 1 { + postsPerPage = 10 } - if err := b.createAtPath(ctx, data.Path, func(f io.Writer) error { - return b.renderTemplate(f, tmplNameCategorySingle, data) - }); err != nil { - return err + totalPages := (len(allPosts) + postsPerPage - 1) / postsPerPage + if totalPages < 1 { + totalPages = 1 } - // Per-category feeds - if err := b.renderCategoryFeed(ctx, cwc, posts); err != nil { + basePath := fmt.Sprintf("/categories/%s", cwc.Slug) + + for page := 1; page <= totalPages; page++ { + start := (page - 1) * postsPerPage + end := start + postsPerPage + if end > len(allPosts) { + end = len(allPosts) + } + + pageInfo := models.PageInfo{ + CurrentPage: page, + TotalPages: totalPages, + PostsPerPage: postsPerPage, + } + + var prevURL, nextURL string + if page > 1 { + if page == 2 { + prevURL = basePath + "/" + } else { + prevURL = fmt.Sprintf("%s/page/%d/", basePath, page-1) + } + } + if page < totalPages { + nextURL = fmt.Sprintf("%s/page/%d/", basePath, page+1) + } + + path := basePath + if page > 1 { + path = fmt.Sprintf("%s/page/%d", basePath, page) + } + + data := categorySingleData{ + commonData: commonData{Site: b.site}, + Category: &cwc.Category, + DescriptionHTML: template.HTML(descHTML.String()), + Posts: allPosts[start:end], + Path: path, + PageInfo: pageInfo, + PrevURL: prevURL, + NextURL: nextURL, + } + + if err := b.createAtPath(ctx, path, func(f io.Writer) error { + return b.renderTemplate(f, tmplNameCategorySingle, data) + }); err != nil { + return err + } + } + + // Per-category feeds (use all posts, not paginated) + if err := b.renderCategoryFeed(ctx, cwc, allPosts); err != nil { return err } } diff --git a/providers/sitebuilder/tmpls.go b/providers/sitebuilder/tmpls.go index 2ba1c74..e0ece37 100644 --- a/providers/sitebuilder/tmpls.go +++ b/providers/sitebuilder/tmpls.go @@ -88,4 +88,7 @@ type categorySingleData struct { DescriptionHTML template.HTML Posts []postSingleData Path string + PageInfo models.PageInfo + PrevURL string + NextURL string }