- 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.
97 lines
3.4 KiB
Templ
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>
|
|
}
|