Show the recent strip only where it is not a duplicate

The strip is the head of the same updated_at DESC reading list the All tab
renders, and app.html put it on every tab: on a small library it repeated the
list immediately below it while eating ~230px of the first phone screen, and on
Archived and Finished it showed reading series above the opposite bucket.

buildListView now fills Recent only for tab=all with more reading series than
the strip holds. Because the strip lives outside the htmx-swapped #list, an
in-page tab switch cannot re-render it, so applyFilter also decides its
visibility from the active tab; setActiveTab pokes it after a swap.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-30 19:10:42 +07:00
parent aacf57170c
commit 264cf21960
3 changed files with 64 additions and 20 deletions
+44 -10
View File
@@ -1,6 +1,7 @@
package main
import (
"fmt"
"net/http"
"net/http/httptest"
"net/url"
@@ -578,25 +579,58 @@ func TestTabsShowOnlyTheirBucket(t *testing.T) {
}
}
func TestRecentStripExcludesArchivedAndFinished(t *testing.T) {
// stripOf returns everything above the list, which is where the recent section
// renders.
func stripOf(t *testing.T, srv http.Handler, cfg Config, tab string) string {
t.Helper()
req := httptest.NewRequest(http.MethodGet, "/?tab="+tab, nil)
req.AddCookie(sessionCookie(t, cfg))
rr := httptest.NewRecorder()
srv.ServeHTTP(rr, req)
body := rr.Body.String()
if i := strings.Index(body, `id="list"`); i >= 0 {
body = body[:i]
}
return body
}
// The strip is the head of the same list the All tab renders, so it only shows
// where it is not a pure duplicate: on All, with more reading series than it
// holds.
func TestRecentStripOnlyOnAllAndOnlyWhenItAddsSomething(t *testing.T) {
cfg := webConfig()
srv, store := newWebTestServer(t, cfg)
seedStatusRows(t, store)
req := httptest.NewRequest(http.MethodGet, "/?tab=archived", nil)
req.AddCookie(sessionCookie(t, cfg))
rr := httptest.NewRecorder()
srv.ServeHTTP(rr, req)
for _, tab := range []string{"all", "new", "fav", "archived", "finished"} {
if strings.Contains(stripOf(t, srv, cfg, tab), `class="recent"`) {
t.Fatalf("tab %s rendered the strip for a library of one reading series", tab)
}
}
strip := rr.Body.String()
if i := strings.Index(strip, `id="list"`); i >= 0 {
strip = strip[:i] // everything above the list is the recent section
// Past recentCount the strip stops repeating the whole list.
for i := 0; i <= recentCount; i++ {
b := Bookmark{
Key: fmt.Sprintf("asura:more%d", i), Site: "asura",
SeriesID: fmt.Sprintf("more%d", i), Title: fmt.Sprintf("MoreReading%d", i),
Status: statusReading, LastChapterNum: 1, UpdatedAt: time.Now().UnixMilli(),
}
if _, err := store.Upsert(b); err != nil {
t.Fatalf("seed %s: %v", b.Key, err)
}
}
strip := stripOf(t, srv, cfg, "all")
if !strings.Contains(strip, `class="recent"`) {
t.Fatal("strip missing on All with more reading series than it shows")
}
if strings.Contains(strip, "ArchivedOne") || strings.Contains(strip, "FinishedOne") {
t.Fatal("recent strip included an archived or finished series")
}
if !strings.Contains(strip, "ReadingOne") {
t.Fatal("recent strip dropped the reading series")
for _, tab := range []string{"new", "fav", "archived", "finished"} {
if strings.Contains(stripOf(t, srv, cfg, tab), `class="recent"`) {
t.Fatalf("tab %s rendered the strip", tab)
}
}
}