htmgo/examples/hackernews/partials/sidebar.go

165 lines
4.2 KiB
Go
Raw Normal View History

2024-10-10 22:00:20 +00:00
package partials
import (
"fmt"
"github.com/maddalax/htmgo/framework/h"
"hackernews/components"
"hackernews/internal/news"
2024-10-11 01:17:31 +00:00
"hackernews/internal/parse"
2024-10-10 22:00:20 +00:00
"hackernews/internal/timeformat"
"time"
)
var ScrollJs = `
const scrollContainer = self;
let isDown = false;
let startX;
let scrollLeft;
scrollContainer.addEventListener("mousedown", (e) => {
isDown = true;
scrollContainer.classList.add("active");
startX = e.pageX - scrollContainer.offsetLeft;
scrollLeft = scrollContainer.scrollLeft;
});
scrollContainer.addEventListener("mouseleave", () => {
isDown = false;
scrollContainer.classList.remove("active");
});
scrollContainer.addEventListener("mouseup", () => {
isDown = false;
scrollContainer.classList.remove("active");
});
scrollContainer.addEventListener("mousemove", (e) => {
if (!isDown) return;
e.preventDefault();
const x = e.pageX - scrollContainer.offsetLeft;
const walk = (x - startX) * 3; // Adjust scroll speed here
scrollContainer.scrollLeft = scrollLeft - walk;
});
`
func StorySidebar(ctx *h.RequestContext) *h.Partial {
category := h.GetQueryParam(ctx, "category")
2024-10-11 01:17:31 +00:00
pageRaw := h.GetQueryParam(ctx, "page")
mode := h.GetQueryParam(ctx, "mode")
if pageRaw == "" {
pageRaw = "0"
}
2024-10-10 22:00:20 +00:00
if category == "" {
category = "topstories"
}
2024-10-11 01:17:31 +00:00
page := parse.MustParseInt(pageRaw, 0)
fetchMorePath := h.GetPartialPathWithQs(
StorySidebar,
h.NewQs("mode", "infinite", "page", fmt.Sprintf("%d", page+1), "category", category),
)
2024-10-11 01:17:31 +00:00
list := CachedStoryList(category, page, 50, fetchMorePath)
2024-10-10 22:00:20 +00:00
body := h.Aside(
h.Id("story-sidebar"),
h.JoinExtensions(
h.TriggerChildren(),
),
2024-10-10 22:00:20 +00:00
h.Class("sticky top-0 h-screen p-1 bg-gray-100 overflow-y-auto max-w-80 min-w-80"),
h.Div(
h.Class("flex flex-col gap-1"),
SidebarTitle(category),
2024-10-11 01:17:31 +00:00
h.Id("story-list"),
list,
2024-10-10 22:00:20 +00:00
),
)
2024-10-11 01:17:31 +00:00
if mode == "infinite" {
return h.NewPartial(
list,
)
}
2024-10-10 22:00:20 +00:00
if ctx.IsHxRequest() {
return h.SwapManyPartial(ctx, body)
}
2024-10-11 01:17:31 +00:00
2024-10-10 22:00:20 +00:00
return h.NewPartial(body)
}
func SidebarTitle(defaultCategory string) *h.Element {
today := time.Now().Format("Mon, 02 Jan 2006")
return h.Div(
h.Class("flex flex-col px-2 pt-4 pb-2"),
h.Div(
h.Class("text-sm text-gray-600"),
h.Text(today),
),
h.Div(
h.Class("font-bold text-xl"),
h.Text("Hacker News"),
),
h.Div(
h.OnLoad(
h.EvalJs(ScrollJs),
),
2024-10-10 22:00:20 +00:00
h.Class("scroll-container mt-2 flex gap-1 no-scrollbar overflow-y-hidden whitespace-nowrap overflow-x-auto"),
h.List(news.Categories, func(item news.Category, index int) *h.Element {
return CategoryBadge(defaultCategory, item)
}),
),
)
}
func CategoryBadge(defaultCategory string, category news.Category) *h.Element {
selected := category.Path == defaultCategory
return components.Badge(
category.Name,
selected,
h.Attribute("hx-swap", "none"),
h.If(
!selected,
h.PostPartialOnClickQs(
StorySidebar,
h.NewQs("category", category.Path),
),
),
2024-10-10 22:00:20 +00:00
)
}
2024-10-11 01:17:31 +00:00
var CachedStoryList = h.CachedPerKeyT4(time.Minute*5, func(category string, page int, limit int, fetchMorePath string) (string, h.GetElementFunc) {
2024-10-10 22:00:20 +00:00
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 {
return h.Div(
h.Attribute("hx-swap", "none"),
h.PostPartialOnClickQs(Story, h.NewQs("item", fmt.Sprintf("%d", item.Id))),
h.A(h.Href(item.Url)),
h.Class("block p-2 bg-white rounded-md shadow cursor-pointer"),
h.Div(
h.Class("font-bold"),
h.UnsafeRaw(item.Title),
),
h.Div(
h.Class("text-sm text-gray-600"),
h.Div(h.TextF("%s ", item.By), h.UnsafeRaw("•"), h.TextF(" %s", timeformat.RelativeTime(item.Time))),
),
h.Div(
h.Class("text-sm text-gray-600"),
h.UnsafeRaw(fmt.Sprintf("%d upvotes • %d comments", item.Score, item.Descendents)),
),
2024-10-11 01:17:31 +00:00
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"),
)),
2024-10-10 22:00:20 +00:00
)
})
}
})