Files
bookhoard/templates/series.templ
T
john-okeefe 668aee4e22 fix(templates): library switcher and bookshelf filter improvements
- bookshelf.templ: Fix form field name from "library" to "library_id"
  to match the handler's QueryParam("library_id"). Add "All Books"
  as the default option in the library filter dropdown. The bookshelf
  uses its own inline filter, NOT the universal library switcher.

- collections.templ: Remove @LibrarySwitcher from the collections list
  page — collections are not library-specific, so the switcher was
  misleading. Fix data-id interpolation bug where {collection.ID} was
  rendered as literal text instead of being interpolated.

- series.templ: Replace inline library selector with the universal
  @LibrarySwitcher component. SeriesCard links no longer include
  library_id since series detail always shows all books.
2026-05-18 17:52:49 -04:00

97 lines
3.4 KiB
Templ

package templates
import (
"fmt"
"net/url"
)
templ Series(user User, seriesList []SeriesCardData, libData []LibraryData, currentLibraryID string, totalPages int, currentPage int, errorMessage string) {
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Series - Bookhoard</title>
<link href="/static/style.css" rel="stylesheet"/>
</head>
<body x-data="seriesPage" x-init="initSeriesPage()" class="theme-{ user.Theme }">
@Header(user, "/series")
@LibrarySwitcher(libData, currentLibraryID)
<!-- Series Grid -->
<div id="series-container">
<main class="w-full px-4 py-8">
<h1 class="text-3xl font-bold mb-6" style="color: var(--text-primary)">Series</h1>
if len(seriesList) == 0 {
<div id="series-empty" class="text-center py-16" style="color: var(--text-secondary)">
<div class="text-6xl mb-4">📚</div>
<h3 class="text-xl font-semibold mb-2" style="color: var(--text-primary)">No Series Found</h3>
<p>Books with series metadata will appear here</p>
</div>
}
<div id="series-grid" class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-6">
for _, series := range seriesList {
@SeriesCard(series)
}
</div>
<!-- Pagination -->
if totalPages > 1 {
<div id="series-pagination" class="flex justify-center items-center gap-4 mt-8">
if currentPage > 1 {
<a
href={ fmt.Sprintf("/series?library_id=%s&page=%d", currentLibraryID, currentPage-1) }
class="px-4 py-2 rounded-lg border"
style="border-color: var(--border); color: var(--text-primary);"
>
Previous
</a>
}
<span class="text-sm" style="color: var(--text-secondary)">
Page { fmt.Sprintf("%d", currentPage) } of { fmt.Sprintf("%d", totalPages) }
</span>
if currentPage < totalPages {
<a
href={ fmt.Sprintf("/series?library_id=%s&page=%d", currentLibraryID, currentPage+1) }
class="px-4 py-2 rounded-lg border"
style="border-color: var(--border); color: var(--text-primary);"
>
Next
</a>
}
</div>
}
</main>
</div>
@ErrorToast(errorMessage)
</body>
</html>
}
templ SeriesCard(series SeriesCardData) {
<a href={ "/series/detail?name=" + url.QueryEscape(series.Name) } class="block">
<div class="series-card rounded-lg overflow-hidden cursor-pointer hover:shadow-lg transition-shadow" style="background-color: var(--bg-secondary);">
<div class={ "stacked-covers cover-count-" + fmt.Sprintf("%d", len(series.CoverPaths)) }>
for i, cover := range series.CoverPaths {
<img
src={ cover }
class={ "cover-img cover-" + fmt.Sprintf("%d", i) }
alt={ series.Name }
loading="lazy"
onerror="this.src='/static/placeholder-book.svg'"
/>
}
if len(series.CoverPaths) == 0 {
<div class="cover-img cover-0 flex items-center justify-center" style="background: var(--bg-primary);">
<span class="text-3xl">📚</span>
</div>
}
</div>
<div class="series-card-info px-3 py-2">
<h3 class="font-semibold text-sm line-clamp-2" style="color: var(--text-primary)">{ series.Name }</h3>
<p class="text-xs mt-1" style="color: var(--text-secondary)">
{ fmt.Sprintf("%d", series.BookCount) } of { fmt.Sprintf("%d", series.TotalInSeries) } books
</p>
</div>
</div>
</a>
}