feat(book-detail): add tags and contributors display, fix series/tag links

- Add clickable tag badges between comic badges and synopsis, linking to
  /tags/detail?name=<tag>&library_id=<id> for browsing books by tag
- Add Contributors as comma-separated row in the metadata grid
- Add data-library-id attribute to body for tag autocomplete API calls
- Fix series badge link: append &library_id= so /series/detail works
  when navigated from book detail page (was returning empty/404)
This commit is contained in:
2026-05-10 16:12:28 -04:00
parent dc07a2f19f
commit a93be75408
2 changed files with 590 additions and 492 deletions
+22 -2
View File
@@ -19,7 +19,7 @@ templ BookDetail(user User, book handlers.MediaDetail, errorMessage string) {
<script src="/static/htmx.min.js"></script>
<link href="/static/style.css" rel="stylesheet"/>
</head>
<body x-data="bookDetail" class="theme-{ user.Theme }" data-format-group={ book.FormatGroup }>
<body x-data="bookDetail" class="theme-{ user.Theme }" data-format-group={ book.FormatGroup } data-library-id={ uuidToString(book.LibraryID) }>
@Header(user, "/media/{ uuidToString(book.ID) }")
<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">
@@ -129,7 +129,7 @@ templ BookDetail(user User, book handlers.MediaDetail, errorMessage string) {
if book.Series.Valid && book.Series.String != "" {
<div class="mb-4">
<a
href={ "/series/detail?name=" + url.QueryEscape(book.Series.String) }
href={ "/series/detail?name=" + url.QueryEscape(book.Series.String) + "&library_id=" + uuidToString(book.LibraryID) }
class="px-3 py-1 rounded-full text-sm font-semibold inline-block hover:opacity-80 transition-opacity"
style="background-color: var(--accent); color: white; text-decoration: none;"
>
@@ -181,6 +181,20 @@ templ BookDetail(user User, book handlers.MediaDetail, errorMessage string) {
</span>
}
</div>
<!-- Tags -->
if len(book.Tags) > 0 {
<div class="flex flex-wrap gap-2 mb-4">
for _, tag := range book.Tags {
<a
href={ "/tags/detail?name=" + url.QueryEscape(tag) + "&library_id=" + uuidToString(book.LibraryID) }
class="px-2 py-1 rounded-full text-xs font-semibold hover:opacity-80 transition-opacity"
style="background-color: var(--bg-primary); border: 1px solid var(--border); color: var(--text-secondary); text-decoration: none;"
>
{ tag }
</a>
}
</div>
}
<!-- Description/Synopsis -->
if book.Description.Valid && book.Description.String != "" {
<div class="mb-6">
@@ -372,6 +386,12 @@ templ BookDetail(user User, book handlers.MediaDetail, errorMessage string) {
<p>{ altSeries }</p>
</div>
}
if len(book.Contributors) > 0 {
<div>
<p style="color: var(--text-secondary)">Contributors</p>
<p>{ strings.Join(book.Contributors, ", ") }</p>
</div>
}
<!-- Technical Info -->
<div>
<p style="color: var(--text-secondary)">Format</p>
File diff suppressed because it is too large Load Diff