feat: add pagination to generated site post list
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
550ebf728a
commit
30884372d6
|
|
@ -5,4 +5,10 @@
|
||||||
|
|
||||||
{{ template "_post_meta.html" . }}
|
{{ template "_post_meta.html" . }}
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
{{ if or .PrevURL .NextURL }}
|
||||||
|
<nav class="pagination">
|
||||||
|
{{ if .PrevURL }}<a href="{{ .PrevURL }}">← Newer posts</a>{{ end }}
|
||||||
|
{{ if .NextURL }}<a href="{{ .NextURL }}">Older posts →</a>{{ end }}
|
||||||
|
</nav>
|
||||||
|
{{ end }}
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,8 @@ func (b *Builder) BuildSite(outDir string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Builder) renderPostListWithCategories(bctx buildContext, ctx context.Context) error {
|
func (b *Builder) renderPostListWithCategories(bctx buildContext, ctx context.Context) error {
|
||||||
var posts []postSingleData
|
// Collect all posts
|
||||||
|
var allPosts []postSingleData
|
||||||
for mp := range b.site.PostIter(ctx) {
|
for mp := range b.site.PostIter(ctx) {
|
||||||
post, err := mp.Get()
|
post, err := mp.Get()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -132,17 +133,70 @@ func (b *Builder) renderPostListWithCategories(bctx buildContext, ctx context.Co
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
posts = append(posts, rp)
|
allPosts = append(allPosts, rp)
|
||||||
}
|
}
|
||||||
|
|
||||||
pl := postListData{
|
postsPerPage := b.site.PostsPerPage
|
||||||
commonData: commonData{Site: b.site},
|
if postsPerPage < 1 {
|
||||||
Posts: posts,
|
postsPerPage = 10
|
||||||
}
|
}
|
||||||
|
|
||||||
return b.createAtPath(bctx, "", func(f io.Writer) error {
|
totalPages := (len(allPosts) + postsPerPage - 1) / postsPerPage
|
||||||
return b.renderTemplate(f, tmplNamePostList, pl)
|
if totalPages < 1 {
|
||||||
})
|
totalPages = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = "/posts/"
|
||||||
|
} else {
|
||||||
|
prevURL = fmt.Sprintf("/posts/page/%d/", page-1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if page < totalPages {
|
||||||
|
nextURL = fmt.Sprintf("/posts/page/%d/", page+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
pl := postListData{
|
||||||
|
commonData: commonData{Site: b.site},
|
||||||
|
Posts: allPosts[start:end],
|
||||||
|
PageInfo: pageInfo,
|
||||||
|
PrevURL: prevURL,
|
||||||
|
NextURL: nextURL,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Page 1 renders at both root and /posts/
|
||||||
|
var paths []string
|
||||||
|
if page == 1 {
|
||||||
|
paths = []string{"", "/posts"}
|
||||||
|
} else {
|
||||||
|
paths = []string{fmt.Sprintf("/posts/page/%d", page)}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, path := range paths {
|
||||||
|
if err := b.createAtPath(bctx, path, func(f io.Writer) error {
|
||||||
|
return b.renderTemplate(f, tmplNamePostList, pl)
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Builder) renderFeeds(ctx buildContext, postIter iter.Seq[models.Maybe[*models.Post]], opts feedOptions) error {
|
func (b *Builder) renderFeeds(ctx buildContext, postIter iter.Seq[models.Maybe[*models.Post]], opts feedOptions) error {
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ func TestBuilder_BuildSite(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
site := pubmodel.Site{
|
site := pubmodel.Site{
|
||||||
|
Site: models.Site{PostsPerPage: 10},
|
||||||
BaseURL: "https://example.com",
|
BaseURL: "https://example.com",
|
||||||
PostIter: func(ctx context.Context) iter.Seq[models.Maybe[*models.Post]] {
|
PostIter: func(ctx context.Context) iter.Seq[models.Maybe[*models.Post]] {
|
||||||
return func(yield func(models.Maybe[*models.Post]) bool) {
|
return func(yield func(models.Maybe[*models.Post]) bool) {
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,10 @@ type postSingleData struct {
|
||||||
|
|
||||||
type postListData struct {
|
type postListData struct {
|
||||||
commonData
|
commonData
|
||||||
Posts []postSingleData
|
Posts []postSingleData
|
||||||
|
PageInfo models.PageInfo
|
||||||
|
PrevURL string
|
||||||
|
NextURL string
|
||||||
}
|
}
|
||||||
|
|
||||||
type layoutData struct {
|
type layoutData struct {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue