Replace the single-purpose SeriesDetail template with a parameterized BrowseDetail component that accepts badge icon/label, title, page title, back URL/label, empty state icon/message, and book list. Both series detail and new tag detail pages use the same template with different params, eliminating duplication. Series detail: 📚 Series, back to /series, "All Series" Tag detail: 🏷️ Tag, back to /bookshelf, "Bookshelf" Deleted series_detail.templ and series_detail_templ.go. Updated frontend.go series route to call BrowseDetail with series params. Added /tags/detail route calling BrowseDetail with tag params.
52 lines
1.9 KiB
Templ
52 lines
1.9 KiB
Templ
package templates
|
|
|
|
import (
|
|
"bookhoard/internal/handlers"
|
|
"fmt"
|
|
)
|
|
|
|
templ BrowseDetail(user User, badgeIcon string, badgeLabel string, title string, pageTitle string, backUrl string, backLabel string, emptyIcon string, emptyMessage string, books []handlers.BookInfo, errorMessage string) {
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8"/>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
|
<title>{ pageTitle } - Bookhoard</title>
|
|
<link href="/static/style.css" rel="stylesheet"/>
|
|
</head>
|
|
<body class="theme-{ user.Theme }">
|
|
@Header(user, backUrl)
|
|
<div class="sticky top-0 z-40 bg-opacity-95 backdrop-blur border-b" style="background-color: var(--bg-primary);">
|
|
<div class="w-full px-4 py-3 flex items-center gap-4">
|
|
<a href={ backUrl } class="text-sm hover:opacity-80 transition-opacity" style="color: var(--text-secondary); text-decoration: none;">
|
|
← { backLabel }
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<div class="w-full px-4 py-8">
|
|
<div class="flex items-center gap-4 mb-6">
|
|
<span class="px-3 py-1 rounded-full text-sm font-semibold" style="background-color: var(--accent); color: white;">
|
|
{ badgeIcon } { badgeLabel }
|
|
</span>
|
|
<h1 class="text-3xl font-bold" style="color: var(--text-primary)">{ title }</h1>
|
|
<span class="text-sm" style="color: var(--text-secondary)">{ fmt.Sprintf("%d", len(books)) } books</span>
|
|
</div>
|
|
if len(books) > 0 {
|
|
<div class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 xl:grid-cols-8 gap-4">
|
|
for _, book := range books {
|
|
@BookCard(book)
|
|
}
|
|
</div>
|
|
} else {
|
|
<div class="text-center py-16" style="color: var(--text-secondary)">
|
|
<div class="text-6xl mb-4">{ emptyIcon }</div>
|
|
<h3 class="text-xl font-semibold mb-2" style="color: var(--text-primary)">No Books Found</h3>
|
|
<p>{ emptyMessage }</p>
|
|
</div>
|
|
}
|
|
</div>
|
|
@ErrorToast(errorMessage)
|
|
</body>
|
|
</html>
|
|
}
|