infinite scroll
This commit is contained in:
parent
bd344d56ef
commit
819af8b7b8
5 changed files with 51 additions and 5 deletions
|
|
@ -77,6 +77,15 @@ func GetStories(category string, page int, limit int) []Story {
|
|||
ids := *top
|
||||
start := page * limit
|
||||
end := start + limit
|
||||
|
||||
if start > len(ids) {
|
||||
return make([]Story, 0)
|
||||
}
|
||||
|
||||
if end > len(ids) {
|
||||
end = len(ids)
|
||||
}
|
||||
|
||||
return batch.ParallelProcess[int, Story](
|
||||
ids[start:end],
|
||||
50,
|
||||
|
|
|
|||
11
examples/hackernews/internal/parse/parse.go
Normal file
11
examples/hackernews/internal/parse/parse.go
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
package parse
|
||||
|
||||
import "strconv"
|
||||
|
||||
func MustParseInt(s string, fallback int) int {
|
||||
v, err := strconv.ParseInt(s, 10, 64)
|
||||
if err != nil {
|
||||
return fallback
|
||||
}
|
||||
return int(v)
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/maddalax/htmgo/framework/hx"
|
||||
"hackernews/components"
|
||||
"hackernews/internal/news"
|
||||
"hackernews/internal/parse"
|
||||
"hackernews/internal/timeformat"
|
||||
"time"
|
||||
)
|
||||
|
|
@ -45,10 +46,23 @@ var ScrollJs = `
|
|||
|
||||
func StorySidebar(ctx *h.RequestContext) *h.Partial {
|
||||
category := h.GetQueryParam(ctx, "category")
|
||||
pageRaw := h.GetQueryParam(ctx, "page")
|
||||
mode := h.GetQueryParam(ctx, "mode")
|
||||
|
||||
if pageRaw == "" {
|
||||
pageRaw = "0"
|
||||
}
|
||||
|
||||
if category == "" {
|
||||
category = "topstories"
|
||||
}
|
||||
|
||||
page := parse.MustParseInt(pageRaw, 0)
|
||||
|
||||
fetchMorePath := h.GetPartialPathWithQs(StorySidebar, h.NewQs("mode", "infinite", "page", fmt.Sprintf("%d", page+1), "category", category))
|
||||
|
||||
list := CachedStoryList(category, page, 50, fetchMorePath)
|
||||
|
||||
body := h.Aside(
|
||||
h.Id("story-sidebar"),
|
||||
h.JoinExtensions(h.TriggerChildren()),
|
||||
|
|
@ -56,13 +70,21 @@ func StorySidebar(ctx *h.RequestContext) *h.Partial {
|
|||
h.Div(
|
||||
h.Class("flex flex-col gap-1"),
|
||||
SidebarTitle(category),
|
||||
CachedStoryList(category, 0, 50),
|
||||
h.Id("story-list"),
|
||||
list,
|
||||
),
|
||||
)
|
||||
|
||||
if mode == "infinite" {
|
||||
return h.NewPartial(
|
||||
list,
|
||||
)
|
||||
}
|
||||
|
||||
if ctx.IsHxRequest() {
|
||||
return h.SwapManyPartial(ctx, body)
|
||||
}
|
||||
|
||||
return h.NewPartial(body)
|
||||
}
|
||||
|
||||
|
|
@ -99,7 +121,7 @@ func CategoryBadge(defaultCategory string, category news.Category) *h.Element {
|
|||
)
|
||||
}
|
||||
|
||||
var CachedStoryList = h.CachedPerKeyT3(time.Minute*5, func(category string, page int, limit int) (string, h.GetElementFunc) {
|
||||
var CachedStoryList = h.CachedPerKeyT4(time.Minute*5, func(category string, page int, limit int, fetchMorePath string) (string, h.GetElementFunc) {
|
||||
return fmt.Sprintf("%s-stories-%d-%d", category, page, limit), func() *h.Element {
|
||||
stories := news.GetStories(category, page, limit)
|
||||
return h.List(stories, func(item news.Story, index int) *h.Element {
|
||||
|
|
@ -120,6 +142,12 @@ var CachedStoryList = h.CachedPerKeyT3(time.Minute*5, func(category string, page
|
|||
h.Class("text-sm text-gray-600"),
|
||||
h.UnsafeRaw(fmt.Sprintf("%d upvotes • %d comments", item.Score, item.Descendents)),
|
||||
),
|
||||
h.If(index == len(stories)-1, h.Div(
|
||||
h.Id("load-more"),
|
||||
h.Attribute("hx-swap", "beforeend"),
|
||||
h.HxTarget("#story-list"),
|
||||
h.Get(fetchMorePath, "intersect once"),
|
||||
)),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,7 +75,6 @@ func StoryBody(story *news.Story) *h.Element {
|
|||
h.TextF(" %s", timeformat.RelativeTime(story.Time)),
|
||||
),
|
||||
),
|
||||
h.TriggerChildren(),
|
||||
h.Div(
|
||||
h.Id("comments-loader"),
|
||||
h.Class("flex justify-center items-center h-24"),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package h
|
||||
|
||||
import (
|
||||
"html"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"runtime"
|
||||
|
|
@ -89,5 +88,5 @@ func GetPartialPath(partial PartialFunc) string {
|
|||
}
|
||||
|
||||
func GetPartialPathWithQs(partial func(ctx *RequestContext) *Partial, qs *Qs) string {
|
||||
return html.EscapeString(GetPartialPath(partial) + "?" + qs.ToString())
|
||||
return GetPartialPath(partial) + "?" + qs.ToString()
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue