From e0dc4678b3321970eb042eb54888aaea025a4ea9 Mon Sep 17 00:00:00 2001 From: Admin Date: Sun, 1 Mar 2026 17:22:42 +0500 Subject: [PATCH] feat: replace load-more with page-number pagination and fix progress dot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace 'Load more chapters' append pattern with discrete page-number pagination bar (« 1 2 3 … N ») on /books/{slug} - Clicking a page number swaps #chapter-list via HTMX (innerHTML replace) and updates the OOB #chapter-pagination bar; URL is pushed via hx-push-url - applyProgress() is called after each swap to re-highlight saved chapter - Fix empty bullet bug: progress-dot span no longer contains the '●' character; replaced with a small amber circle via Tailwind (w-2 h-2 rounded-full bg-amber-400) so hidden spans are truly space-free - Add template FuncMap (pages/prev/next helpers) to both handleBook and handleBookChaptersPage; remove HasMore/NextPage from template data structs --- scraper/internal/server/ui.go | 175 +++++++++++++++++++++++----------- 1 file changed, 121 insertions(+), 54 deletions(-) diff --git a/scraper/internal/server/ui.go b/scraper/internal/server/ui.go index a56df51..403c7e7 100644 --- a/scraper/internal/server/ui.go +++ b/scraper/internal/server/ui.go @@ -593,7 +593,7 @@ const bookTmpl = ` {{.Title}} {{if .Date}}{{.Date}}{{end}} - + {{else}} @@ -601,16 +601,36 @@ const bookTmpl = ` {{end}} - {{if .HasMore}} -
- + {{if gt .TotalPages 1}} +
+ {{if gt .CurrentPage 1}} + « + {{end}} + {{range pages .TotalPages}} + {{if eq . $.CurrentPage}} + {{.}} + {{else}} + {{.}} + {{end}} + {{end}} + {{if lt .CurrentPage .TotalPages}} + » + {{end}}
{{end}}
@@ -677,29 +697,45 @@ func (s *Server) handleBook(w http.ResponseWriter, r *http.Request) { } total := len(chapters) - page := chapters - hasMore := false - if total > chapterPageSize { - page = chapters[:chapterPageSize] - hasMore = true + totalPages := (total + chapterPageSize - 1) / chapterPageSize + if totalPages < 1 { + totalPages = 1 } - t := template.Must(template.New("book").Parse(bookTmpl)) + currentPage := 1 + page := chapters + if total > chapterPageSize { + page = chapters[:chapterPageSize] + } + + funcMap := template.FuncMap{ + "pages": func(n int) []int { + out := make([]int, n) + for i := range out { + out[i] = i + 1 + } + return out + }, + "prev": func(n int) int { return n - 1 }, + "next": func(n int) int { return n + 1 }, + } + + t := template.Must(template.New("book").Funcs(funcMap).Parse(bookTmpl)) var buf bytes.Buffer _ = t.Execute(&buf, struct { Slug string Meta interface{} Chapters interface{} TotalDownloaded int - HasMore bool - NextPage int + TotalPages int + CurrentPage int }{ Slug: slug, Meta: meta, Chapters: page, TotalDownloaded: total, - HasMore: hasMore, - NextPage: 2, + TotalPages: totalPages, + CurrentPage: currentPage, }) s.respond(w, r, meta.Title, buf.String()) @@ -721,33 +757,47 @@ const chapterPageTmpl = `{{range .Chapters}} {{.Title}} {{if .Date}}{{.Date}}{{end}} - + {{end}} -{{if .HasMore}} -
  • -
    - -
    -
  • -{{else}} -
  • -{{end}}` +
    + {{if gt .CurrentPage 1}} + « + {{end}} + {{range pages .TotalPages}} + {{if eq . $.CurrentPage}} + {{.}} + {{else}} + {{.}} + {{end}} + {{end}} + {{if lt .CurrentPage .TotalPages}} + » + {{end}} +
    ` func (s *Server) handleBookChaptersPage(w http.ResponseWriter, r *http.Request) { slug := r.PathValue("slug") - page := 1 + currentPage := 1 if p := r.URL.Query().Get("page"); p != "" { if n, err := strconv.Atoi(p); err == nil && n > 0 { - page = n + currentPage = n } } @@ -757,29 +807,46 @@ func (s *Server) handleBookChaptersPage(w http.ResponseWriter, r *http.Request) return } - start := (page - 1) * chapterPageSize - if start >= len(chapters) { + total := len(chapters) + totalPages := (total + chapterPageSize - 1) / chapterPageSize + if totalPages < 1 { + totalPages = 1 + } + + start := (currentPage - 1) * chapterPageSize + if start >= total { w.WriteHeader(http.StatusNoContent) return } end := start + chapterPageSize - hasMore := end < len(chapters) - if end > len(chapters) { - end = len(chapters) + if end > total { + end = total } - t := template.Must(template.New("chapterPage").Parse(chapterPageTmpl)) + funcMap := template.FuncMap{ + "pages": func(n int) []int { + out := make([]int, n) + for i := range out { + out[i] = i + 1 + } + return out + }, + "prev": func(n int) int { return n - 1 }, + "next": func(n int) int { return n + 1 }, + } + + t := template.Must(template.New("chapterPage").Funcs(funcMap).Parse(chapterPageTmpl)) var buf bytes.Buffer _ = t.Execute(&buf, struct { - Slug string - Chapters interface{} - HasMore bool - NextPage int + Slug string + Chapters interface{} + TotalPages int + CurrentPage int }{ - Slug: slug, - Chapters: chapters[start:end], - HasMore: hasMore, - NextPage: page + 1, + Slug: slug, + Chapters: chapters[start:end], + TotalPages: totalPages, + CurrentPage: currentPage, }) w.Header().Set("Content-Type", "text/html; charset=utf-8")