From b83e319a345336723be8d95da8b04f4ee809f314 Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Fri, 8 May 2026 20:27:15 -0400 Subject: [PATCH] feat(series): add series browse template, nav link, and clickable badge Create templates/series.templ with: - Library selector dropdown (sticky, same pattern as dashboard) - Loading spinner overlay for AJAX library switching - Series grid with stacked-cascade multi-cover cards - Empty state when no series found - Pagination with Previous/Next links - SeriesCard sub-template linking to filtered bookshelf view Add 'Series' nav link in header between 'All Books' and 'Collections'. Make series badge on book detail page clickable, linking to /bookshelf?series_filter=&sort=series. Add 'Continue Series' option to restore system collection modal. --- templates/book_detail.templ | 11 +- templates/book_detail_templ.go | 721 +++++++++--------- templates/header.templ | 3 + templates/header_templ.go | 4 +- .../restore_system_collection_modal.templ | 1 + .../restore_system_collection_modal_templ.go | 2 +- templates/series.templ | 124 +++ templates/series_templ.go | 395 ++++++++++ 8 files changed, 901 insertions(+), 360 deletions(-) create mode 100644 templates/series.templ create mode 100644 templates/series_templ.go diff --git a/templates/book_detail.templ b/templates/book_detail.templ index 3614b85..0853be0 100644 --- a/templates/book_detail.templ +++ b/templates/book_detail.templ @@ -3,6 +3,8 @@ package templates import ( "bookhoard/internal/handlers" "fmt" + "net/url" + "github.com/microcosm-cc/bluemonday" "strings" ) @@ -119,15 +121,16 @@ templ BookDetail(user User, book handlers.MediaDetail, errorMessage string) { if book.Series.Valid && book.Series.String != "" {
- { book.Series.String } if book.SeriesNumber.Valid && book.SeriesNumber.Int32 > 0 { #{ book.SeriesNumber.Int32 } } - +
} diff --git a/templates/book_detail_templ.go b/templates/book_detail_templ.go index 41f00d7..7c0d2f6 100644 --- a/templates/book_detail_templ.go +++ b/templates/book_detail_templ.go @@ -11,6 +11,8 @@ import templruntime "github.com/a-h/templ/runtime" import ( "bookhoard/internal/handlers" "fmt" + "net/url" + "github.com/microcosm-cc/bluemonday" "strings" ) @@ -43,7 +45,7 @@ func BookDetail(user User, book handlers.MediaDetail, errorMessage string) templ var templ_7745c5c3_Var2 string templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(book.Title) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 16, Col: 22} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 18, Col: 22} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) if templ_7745c5c3_Err != nil { @@ -69,7 +71,7 @@ func BookDetail(user User, book handlers.MediaDetail, errorMessage string) templ var templ_7745c5c3_Var3 string templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(book.CoverImagePath.String) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 29, Col: 40} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 31, Col: 40} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) if templ_7745c5c3_Err != nil { @@ -82,7 +84,7 @@ func BookDetail(user User, book handlers.MediaDetail, errorMessage string) templ var templ_7745c5c3_Var4 string templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(book.Title) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 30, Col: 24} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 32, Col: 24} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) if templ_7745c5c3_Err != nil { @@ -105,7 +107,7 @@ func BookDetail(user User, book handlers.MediaDetail, errorMessage string) templ var templ_7745c5c3_Var5 string templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(book.Title) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 45, Col: 89} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 47, Col: 89} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) if templ_7745c5c3_Err != nil { @@ -123,7 +125,7 @@ func BookDetail(user User, book handlers.MediaDetail, errorMessage string) templ var templ_7745c5c3_Var6 string templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(book.Author.String) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 48, Col: 31} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 50, Col: 31} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) if templ_7745c5c3_Err != nil { @@ -141,7 +143,7 @@ func BookDetail(user User, book handlers.MediaDetail, errorMessage string) templ var templ_7745c5c3_Var7 string templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs("window.location.href = '/readers/" + uuidToString(book.ID) + "'") if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 55, Col: 82} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 57, Col: 82} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) if templ_7745c5c3_Err != nil { @@ -169,7 +171,7 @@ func BookDetail(user User, book handlers.MediaDetail, errorMessage string) templ var templ_7745c5c3_Var8 string templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(book.NotesCount + book.HighlightsCount) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 83, Col: 50} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 85, Col: 50} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) if templ_7745c5c3_Err != nil { @@ -195,7 +197,7 @@ func BookDetail(user User, book handlers.MediaDetail, errorMessage string) templ var templ_7745c5c3_Var9 string templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%.1f", float64(getBookRating(book.Rating))/2.0)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 102, Col: 71} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 104, Col: 71} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) if templ_7745c5c3_Err != nil { @@ -221,7 +223,7 @@ func BookDetail(user User, book handlers.MediaDetail, errorMessage string) templ var templ_7745c5c3_Var10 string templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%.1f / 10", book.CommunityRating.Float64)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 114, Col: 66} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 116, Col: 66} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) if templ_7745c5c3_Err != nil { @@ -237,128 +239,141 @@ func BookDetail(user User, book handlers.MediaDetail, errorMessage string) templ return templ_7745c5c3_Err } if book.Series.Valid && book.Series.String != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var12 string + templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(book.Series.String) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 129, Col: 29} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, " ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if book.SeriesNumber.Valid && book.SeriesNumber.Int32 > 0 { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "#") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "#") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var12 string - templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(book.SeriesNumber.Int32) + var templ_7745c5c3_Var13 string + templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(book.SeriesNumber.Int32) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 128, Col: 36} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 131, Col: 36} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if book.ReadingDirection.Valid && book.ReadingDirection.String != "" && book.ReadingDirection.String != "auto" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "
📖 ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var13 string - templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(strings.ToUpper(book.ReadingDirection.String)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 140, Col: 61} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if book.AgeRating.Valid && book.AgeRating.String != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "
📖 ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var14 string - templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(book.AgeRating.String) + templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(strings.ToUpper(book.ReadingDirection.String)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 152, Col: 32} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 143, Col: 61} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - if book.IsBlackAndWhite.Valid && book.IsBlackAndWhite.Bool { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "B&W") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if book.StoryArc.Valid && book.StoryArc.String != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "📚 ") + if book.AgeRating.Valid && book.AgeRating.String != "" { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var15 string - templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(book.StoryArc.String) + templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(book.AgeRating.String) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 170, Col: 36} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 155, Col: 32} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if book.IsBlackAndWhite.Valid && book.IsBlackAndWhite.Bool { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "B&W") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if book.StoryArc.Valid && book.StoryArc.String != "" { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "📚 ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var16 string + templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(book.StoryArc.String) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 173, Col: 36} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if book.Description.Valid && book.Description.String != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "

Synopsis

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "

Synopsis

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -368,17 +383,17 @@ func BookDetail(user User, book handlers.MediaDetail, errorMessage string) templ if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if book.Summary.Valid && book.Summary.String != "" && book.Summary.String != book.Description.String { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "

Comic Summary

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "

Comic Summary

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -388,741 +403,741 @@ func BookDetail(user User, book handlers.MediaDetail, errorMessage string) templ if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 46, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 46, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if book.MetadataNotes.Valid && book.MetadataNotes.String != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, "

Metadata Notes

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var16 string - templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(book.MetadataNotes.String) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 206, Col: 34} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if book.ReadingProgress != nil { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, "

Reading Progress

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if book.ActiveConflict != nil { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, "

⚠️ Progress conflict detected - Click \"Sync Progress\" to review and resolve

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 52, "

Metadata Notes

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var17 string - templ_7745c5c3_Var17, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues(fmt.Sprintf("width: %.1f%%; background-color: var(--accent);", book.ReadingProgress.Percentage.Float64*100)) + templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(book.MetadataNotes.String) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 232, Col: 124} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 209, Col: 34} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "\">

Progress

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if book.ReadingProgress != nil { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, "

Reading Progress

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if book.ActiveConflict != nil { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 52, "

⚠️ Progress conflict detected - Click \"Sync Progress\" to review and resolve

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 54, "\">

Progress

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var19 string + templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%.1f", book.ReadingProgress.Percentage.Float64*100)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 244, Col: 77} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "%

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if book.ReadingProgress.CurrentPage.Valid && book.ReadingProgress.TotalPages.Valid { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "

Page

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var19 string - templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(book.ReadingProgress.CurrentPage.Int32) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 247, Col: 52} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, " / ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "

Page

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var20 string - templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(book.ReadingProgress.TotalPages.Int32) + templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(book.ReadingProgress.CurrentPage.Int32) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 247, Col: 96} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 250, Col: 52} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, "

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - if book.ReadingProgress.LastReadAt.Valid { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, "

Last Read

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, " / ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var21 string - templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(FormatTimestamptzInTimezone(book.ReadingProgress.LastReadAt, user.Timezone)) + templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(book.ReadingProgress.TotalPages.Int32) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 253, Col: 89} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 250, Col: 96} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - if book.ReadingProgress.LastSyncSource.Valid { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 60, "

Source

") + if book.ReadingProgress.LastReadAt.Valid { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, "

Last Read

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var22 string - templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(book.ReadingProgress.LastSyncSource.String) + templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(FormatTimestamptzInTimezone(book.ReadingProgress.LastReadAt, user.Timezone)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 259, Col: 75} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 256, Col: 89} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 60, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, "
") + if book.ReadingProgress.LastSyncSource.Valid { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, "

Source

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var23 string + templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(book.ReadingProgress.LastSyncSource.String) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 262, Col: 75} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, "

Metadata

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, "

Metadata

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if book.Publisher.Valid && book.Publisher.String != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, "

Publisher

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var23 string - templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(book.Publisher.String) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 276, Col: 34} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 65, "

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - if book.DatePublished.Valid { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 66, "

Published

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 65, "

Publisher

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var24 string - templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(book.DatePublished.Time.Format("01-02-2006")) + templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(book.Publisher.String) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 282, Col: 57} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 279, Col: 34} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 67, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 66, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - if book.Isbn.Valid && book.Isbn.String != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 68, "

Isbn

") + if book.DatePublished.Valid { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 67, "

Published

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var25 string - templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(book.Isbn.String) + templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(book.DatePublished.Time.Format("01-02-2006")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 288, Col: 29} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 285, Col: 57} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 69, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 68, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - if book.Language.Valid && book.Language.String != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 70, "

Language

") + if book.Isbn.Valid && book.Isbn.String != "" { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 69, "

Isbn

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var26 string - templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(book.Language.String) + templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(book.Isbn.String) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 294, Col: 52} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 291, Col: 29} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 70, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - if book.Edition.Valid && book.Edition.String != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 72, "

Edition

") + if book.Language.Valid && book.Language.String != "" { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, "

Language

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var27 string - templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(book.Edition.String) + templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(book.Language.String) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 300, Col: 32} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 297, Col: 52} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 73, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 72, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - if book.PageCount.Valid && book.PageCount.Int32 > 0 { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 74, "

Pages

") + if book.Edition.Valid && book.Edition.String != "" { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 73, "

Edition

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var28 string - templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinStringErrs(book.PageCount.Int32) + templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinStringErrs(book.Edition.String) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 306, Col: 33} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 303, Col: 32} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 75, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 74, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - if book.Genre.Valid && book.Genre.String != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 76, "

Genre

") + if book.PageCount.Valid && book.PageCount.Int32 > 0 { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 75, "

Pages

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var29 string - templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinStringErrs(book.Genre.String) + templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinStringErrs(book.PageCount.Int32) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 312, Col: 30} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 309, Col: 33} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 77, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 76, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 78, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if book.SeriesCount.Valid && book.SeriesCount.Int32 > 0 { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 79, "

Series Count

") + if book.Genre.Valid && book.Genre.String != "" { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 77, "

Genre

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var30 string - templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(book.SeriesCount.Int32) + templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(book.Genre.String) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 319, Col: 35} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 315, Col: 30} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 80, " items

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 78, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - if book.Volume.Valid && book.Volume.Int32 > 0 { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 81, "

Volume

Vol. ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 79, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if book.SeriesCount.Valid && book.SeriesCount.Int32 > 0 { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 80, "

Series Count

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var31 string - templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinStringErrs(book.Volume.Int32) + templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinStringErrs(book.SeriesCount.Int32) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 325, Col: 35} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 322, Col: 35} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 82, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 81, " items

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - if book.Imprint.Valid && book.Imprint.String != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 83, "

Imprint

") + if book.Volume.Valid && book.Volume.Int32 > 0 { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 82, "

Volume

Vol. ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var32 string - templ_7745c5c3_Var32, templ_7745c5c3_Err = templ.JoinStringErrs(book.Imprint.String) + templ_7745c5c3_Var32, templ_7745c5c3_Err = templ.JoinStringErrs(book.Volume.Int32) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 331, Col: 32} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 328, Col: 35} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var32)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 84, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 83, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - if book.CopyrightYear.Valid && book.CopyrightYear.Int32 > 0 { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 85, "

Copyright Year

") + if book.Imprint.Valid && book.Imprint.String != "" { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 84, "

Imprint

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var33 string - templ_7745c5c3_Var33, templ_7745c5c3_Err = templ.JoinStringErrs(book.CopyrightYear.Int32) + templ_7745c5c3_Var33, templ_7745c5c3_Err = templ.JoinStringErrs(book.Imprint.String) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 337, Col: 37} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 334, Col: 32} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var33)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 86, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 85, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 87, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if book.MangaType.Valid && book.MangaType.String != "" && book.MangaType.String != "unknown" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 88, "

Manga Type

") + if book.CopyrightYear.Valid && book.CopyrightYear.Int32 > 0 { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 86, "

Copyright Year

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var34 string - templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.JoinStringErrs(strings.ReplaceAll(book.MangaType.String, "_", " ")) + templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.JoinStringErrs(book.CopyrightYear.Int32) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 344, Col: 83} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 340, Col: 37} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var34)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 89, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 87, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - if book.ScanInformation.Valid && book.ScanInformation.String != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 90, "

Scan Info

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 88, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if book.MangaType.Valid && book.MangaType.String != "" && book.MangaType.String != "unknown" { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 89, "

Manga Type

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var35 string - templ_7745c5c3_Var35, templ_7745c5c3_Err = templ.JoinStringErrs(book.ScanInformation.String) + templ_7745c5c3_Var35, templ_7745c5c3_Err = templ.JoinStringErrs(strings.ReplaceAll(book.MangaType.String, "_", " ")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 350, Col: 94} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 347, Col: 83} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var35)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 91, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 90, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - if len(book.AlternateInfo) > 0 { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 92, "

Alternate Series

") + if book.ScanInformation.Valid && book.ScanInformation.String != "" { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 91, "

Scan Info

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var36 string - templ_7745c5c3_Var36, templ_7745c5c3_Err = templ.JoinStringErrs(string(book.AlternateInfo)) + templ_7745c5c3_Var36, templ_7745c5c3_Err = templ.JoinStringErrs(book.ScanInformation.String) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 356, Col: 55} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 353, Col: 94} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var36)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 93, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 92, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - if altSeries := getAlternateSeries(book.AlternateInfo); altSeries != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 94, "

Alternate Series

") + if len(book.AlternateInfo) > 0 { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 93, "

Alternate Series

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var37 string - templ_7745c5c3_Var37, templ_7745c5c3_Err = templ.JoinStringErrs(altSeries) + templ_7745c5c3_Var37, templ_7745c5c3_Err = templ.JoinStringErrs(string(book.AlternateInfo)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 362, Col: 22} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 359, Col: 55} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var37)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 95, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 94, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 96, "

Format

") + if altSeries := getAlternateSeries(book.AlternateInfo); altSeries != "" { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 95, "

Alternate Series

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var38 string + templ_7745c5c3_Var38, templ_7745c5c3_Err = templ.JoinStringErrs(altSeries) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 365, Col: 22} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var38)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 96, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 97, "

Format

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var38 string - templ_7745c5c3_Var38, templ_7745c5c3_Err = templ.JoinStringErrs(book.MimeType.String) + var templ_7745c5c3_Var39 string + templ_7745c5c3_Var39, templ_7745c5c3_Err = templ.JoinStringErrs(book.MimeType.String) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 368, Col: 32} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 371, Col: 32} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var38)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var39)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 97, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 98, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if book.FileSize.Valid && book.FileSize.Int64 > 0 { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 98, "

File Size

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 99, "

File Size

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var39 string - templ_7745c5c3_Var39, templ_7745c5c3_Err = templ.JoinStringErrs(formatFileSize(book.FileSize.Int64)) + var templ_7745c5c3_Var40 string + templ_7745c5c3_Var40, templ_7745c5c3_Err = templ.JoinStringErrs(formatFileSize(book.FileSize.Int64)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 373, Col: 48} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 376, Col: 48} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var39)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var40)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 99, "

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 100, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 100, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 101, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if book.GoodreadsID.Valid || book.OpenlibraryID.Valid || book.GoogleBooksID.Valid || book.Asin.Valid || book.Isbn.Valid || book.WebUrl.Valid { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 101, "

External Links

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 102, "

External Links

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if book.GoodreadsID.Valid && book.GoodreadsID.String != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 102, "📚 Goodreads ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } else { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 104, "📚 Goodreads ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 104, "\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"text-sm hover:underline flex items-center gap-1\" style=\"color: var(--accent);\">📚 Goodreads ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - } - if book.OpenlibraryID.Valid && book.OpenlibraryID.String != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 106, "📖 Open Library ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 106, "\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"text-sm hover:underline flex items-center gap-1\" style=\"color: var(--accent);\">📚 Goodreads ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - } else { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 108, "📖 Open Library ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 108, "\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"text-sm hover:underline flex items-center gap-1\" style=\"color: var(--accent);\">📖 Open Library ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - } - if book.GoogleBooksID.Valid && book.GoogleBooksID.String != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 110, "🔍 Google Books ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 110, "\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"text-sm hover:underline flex items-center gap-1\" style=\"color: var(--accent);\">📖 Open Library ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - } else { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 112, "🔍 Google Books ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 112, "\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"text-sm hover:underline flex items-center gap-1\" style=\"color: var(--accent);\">🔍 Google Books ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - } - if book.Asin.Valid && book.Asin.String != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 114, "🛒 Amazon ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 114, "\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"text-sm hover:underline flex items-center gap-1\" style=\"color: var(--accent);\">🔍 Google Books ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - } else if book.Isbn.Valid && book.Isbn.String != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 116, "🛒 Amazon ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 116, "\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"text-sm hover:underline flex items-center gap-1\" style=\"color: var(--accent);\">🛒 Amazon ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - } - if book.WebUrl.Valid && book.WebUrl.String != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 118, "🔗 ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 118, "\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"text-sm hover:underline flex items-center gap-1\" style=\"color: var(--accent);\">🛒 Amazon ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var49 string - templ_7745c5c3_Var49, templ_7745c5c3_Err = templ.JoinStringErrs(getDomainName(book.WebUrl.String)) + } + if book.WebUrl.Valid && book.WebUrl.String != "" { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 119, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 120, "\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"text-sm hover:underline flex items-center gap-1\" style=\"color: var(--accent);\">🔗 ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 121, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 122, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if len(book.Collections) > 0 { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 123, "

Collections

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - for _, col := range book.Collections { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 124, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 121, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var51 string - templ_7745c5c3_Var51, templ_7745c5c3_Err = templ.JoinStringErrs(col.Icon.String) + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 122, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 123, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if len(book.Collections) > 0 { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 124, "

Collections

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for _, col := range book.Collections { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 125, " ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 126, "\" class=\"px-3 py-2 rounded-lg border flex items-center gap-2 hover:opacity-80 transition-opacity\" style=\"border-color: { col.Color.String }; background-color: var(--bg-primary); text-decoration: none;\">") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var52 string - templ_7745c5c3_Var52, templ_7745c5c3_Err = templ.JoinStringErrs(col.Name) + templ_7745c5c3_Var52, templ_7745c5c3_Err = templ.JoinStringErrs(col.Icon.String) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/book_detail.templ`, Line: 496, Col: 61} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 498, Col: 69} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var52)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 127, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 127, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var53 string + templ_7745c5c3_Var53, templ_7745c5c3_Err = templ.JoinStringErrs(col.Name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail.templ`, Line: 499, Col: 61} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var53)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 128, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 128, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 129, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 129, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 130, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -1138,7 +1153,7 @@ func BookDetail(user User, book handlers.MediaDetail, errorMessage string) templ if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 130, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 131, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/templates/header.templ b/templates/header.templ index 1bbae1a..4b3a872 100644 --- a/templates/header.templ +++ b/templates/header.templ @@ -21,6 +21,9 @@ templ Header(user User, currentPath string) { > All Books + + Series + Collections diff --git a/templates/header_templ.go b/templates/header_templ.go index bad3391..7b1af40 100644 --- a/templates/header_templ.go +++ b/templates/header_templ.go @@ -29,7 +29,7 @@ func Header(user User, currentPath string) templ.Component { templ_7745c5c3_Var1 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "