"Page N of M" now renders as small secondary-color text on the page background rather than an accent chip (user preference; the old TS twin happened to render this way and the chip was only being seen after JS took over). With the twin deleted, this templ markup is the only paginator rendering, so the look is stable.
106 lines
4.0 KiB
Templ
106 lines
4.0 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"/>
|
|
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg"/>
|
|
</head>
|
|
<body x-data="seriesPage" x-init="initSeriesPage()" class={ "theme-" + user.Theme }>
|
|
@Header(user, "/series")
|
|
@LibrarySwitcher(libData, currentLibraryID, "")
|
|
<div id="series-container">
|
|
<main class="mx-auto container px-4 sm:px-6 lg:px-8 py-8">
|
|
<div class="mb-6 flex items-center gap-3">
|
|
<span class="grid place-items-center h-10 w-10 rounded-xl" style="background-color: var(--accent-muted); color: var(--accent);">
|
|
@Icon("layers", "h-5 w-5")
|
|
</span>
|
|
<div>
|
|
<h1 class="text-2xl font-bold tracking-tight" style="color: var(--text-primary)">Series</h1>
|
|
<p class="text-xs font-semibold uppercase tracking-wide" style="color: var(--text-secondary)">Grouped by series metadata</p>
|
|
</div>
|
|
</div>
|
|
if len(seriesList) == 0 {
|
|
<div id="series-empty" class="card text-center py-16 px-6">
|
|
<div class="grid place-items-center h-14 w-14 rounded-2xl mx-auto mb-4" style="background-color: var(--accent-muted); color: var(--accent);">
|
|
@Icon("layers", "h-7 w-7")
|
|
</div>
|
|
<h3 class="text-xl font-semibold mb-2" style="color: var(--text-primary)">No Series Found</h3>
|
|
<p style="color: var(--text-secondary)">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>
|
|
if totalPages > 1 {
|
|
<div id="series-pagination" class="flex justify-center items-center gap-3 mt-10">
|
|
if currentPage > 1 {
|
|
<a
|
|
href={ fmt.Sprintf("/series?library_id=%s&page=%d", currentLibraryID, currentPage-1) }
|
|
class="btn btn-secondary"
|
|
>
|
|
@Icon("chevron-left", "h-4 w-4")
|
|
<span>Previous</span>
|
|
</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="btn btn-secondary"
|
|
>
|
|
<span>Next</span>
|
|
@Icon("chevron-right", "h-4 w-4")
|
|
</a>
|
|
}
|
|
</div>
|
|
}
|
|
</main>
|
|
</div>
|
|
@ErrorToast(errorMessage)
|
|
</body>
|
|
</html>
|
|
}
|
|
|
|
templ SeriesCard(series SeriesCardData) {
|
|
<a href={ "/series/detail?name=" + url.QueryEscape(series.Name) + "&library_id=" + url.QueryEscape(series.LibraryID) } class="block">
|
|
<div class="series-card card rounded-2xl overflow-hidden cursor-pointer" style="box-shadow: var(--shadow-card);">
|
|
<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); color: var(--text-secondary);">
|
|
@Icon("book", "h-8 w-8 opacity-60")
|
|
</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>
|
|
}
|