diff --git a/internal/router/frontend.go b/internal/router/frontend.go
index e2f1046..37d5577 100644
--- a/internal/router/frontend.go
+++ b/internal/router/frontend.go
@@ -5,6 +5,7 @@ import (
"context"
"log"
"net/http"
+ "strconv"
"time"
"bookhoard/internal/config"
@@ -160,8 +161,79 @@ func registerFrontendRoutes(cfg *Config) {
}
}
+ // Fetch saved filters for SSR (using existing query)
+ var savedFilters []database.SavedFilters
+ if libraryID != "" && errorMsg == "" {
+ savedFilters, err = cfg.Queries.GetSavedFilters(c.Request().Context(), database.GetSavedFiltersParams{
+ UserID: pgtype.UUID{Bytes: userUUID, Valid: true},
+ ResourceType: "media-items",
+ })
+ if err != nil {
+ log.Printf("GetSavedFilters failed: %v", err)
+ savedFilters = []database.SavedFilters{}
+ }
+ }
+
+ // Fetch first page of books for SSR
+ var books []database.ListMediaItemsFilteredRow
+ var bookInfoList []handlers.BookInfo
+ totalCount := 0
+ limit := 50
+ offset := 0
+
+ if libraryID != "" && errorMsg == "" {
+ libUUID, err := uuid.Parse(libraryID)
+ if err == nil {
+ // Check URL params for pagination
+ if limitStr := c.QueryParam("limit"); limitStr != "" {
+ if l, err := strconv.Atoi(limitStr); err == nil && l > 0 && l <= 100 {
+ limit = l
+ }
+ }
+ if offsetStr := c.QueryParam("offset"); offsetStr != "" {
+ if o, err := strconv.Atoi(offsetStr); err == nil && o >= 0 {
+ offset = o
+ }
+ }
+
+ books, err = cfg.Queries.ListMediaItemsFiltered(c.Request().Context(), database.ListMediaItemsFilteredParams{
+ LibraryID: pgtype.UUID{Bytes: libUUID, Valid: true},
+ UserID: pgtype.UUID{Bytes: userUUID, Valid: true},
+ AuthorFilter: pgtype.Text{String: "", Valid: false},
+ SeriesFilter: pgtype.Text{String: "", Valid: false},
+ GenreFilter: pgtype.Text{String: "", Valid: false},
+ LanguageFilter: pgtype.Text{String: "", Valid: false},
+ YearMin: pgtype.Int4{Valid: false},
+ YearMax: pgtype.Int4{Valid: false},
+ HasCover: pgtype.Bool{Valid: false},
+ Sort: pgtype.Text{String: "created_at DESC", Valid: true},
+ Limit: pgtype.Int4{Int32: int32(limit), Valid: true},
+ Offset: pgtype.Int4{Int32: int32(offset), Valid: true},
+ })
+
+ if err != nil {
+ log.Printf("ListMediaItemsFiltered failed: %v", err)
+ // Continue without books - will show empty state
+ } else {
+ // Convert database rows to BookInfo structs (matching BuildSections pattern)
+ bookInfoList = make([]handlers.BookInfo, len(books))
+ for i, book := range books {
+ bookUUID, _ := uuid.FromBytes(book.ID.Bytes[0:16])
+ bookLibUUID, _ := uuid.FromBytes(book.LibraryID.Bytes[0:16])
+ bookInfoList[i] = handlers.BookInfo{
+ MediaItemID: bookUUID.String(),
+ Title: book.Title,
+ Author: getText(book.Author),
+ CoverImagePath: utils.ResolveMediaURL(pgtype.UUID{Bytes: bookLibUUID, Valid: true}, book.CoverImagePath),
+ }
+ }
+ totalCount = len(bookInfoList)
+ }
+ }
+ }
+
var buf bytes.Buffer
- err = templates.BookShelf(user, libData, libraryID, errorMsg).Render(c.Request().Context(), &buf)
+ err = templates.BookShelf(user, libData, libraryID, errorMsg, savedFilters, bookInfoList, limit, offset, totalCount).Render(c.Request().Context(), &buf)
if err != nil {
return err
}
diff --git a/templates/bookshelf.templ b/templates/bookshelf.templ
index 2594c77..3f3a022 100644
--- a/templates/bookshelf.templ
+++ b/templates/bookshelf.templ
@@ -1,6 +1,21 @@
package templates
-templ BookShelf(user User, libraries []LibraryData, currentLibraryID string, errorMessage string) {
+import (
+ "bookhoard/internal/database"
+ "bookhoard/internal/handlers"
+)
+
+templ BookShelf(
+ user User,
+ libraries []LibraryData,
+ currentLibraryID string,
+ errorMessage string,
+ savedFilters []database.SavedFilters,
+ books []handlers.BookInfo, // NEW
+ limit int, // NEW
+ offset int, // NEW
+ count int, // NEW
+) {
@@ -195,6 +210,53 @@ templ BookShelf(user User, libraries []LibraryData, currentLibraryID string, err
💾 Save Filter
+
+
+
+
+
+
+
+ Saved Filters
+
+
+
+ for _, filter := range savedFilters {
+ filterUUID := string(filter.ID.Bytes[0:16])
+
+
+
+
+ }
+
+
+ if len(savedFilters) == 0 {
+
+ No saved filters yet
+
+ }
+
+
+
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "
Saved Filters
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- if errorMessage != "" {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "
")
+ for _, filter := range savedFilters {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "filterUUID := string(filter.ID.Bytes[0:16])
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "\">
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if len(savedFilters) == 0 {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "
No saved filters yet
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if len(books) > 0 {
+ for _, book := range books {
+ templ_7745c5c3_Err = BookCard(book).Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ }
+ } else {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "
📚 No books found
Try adjusting your filters or add some books to your library.
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ if errorMessage != "" {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var9 string
+ templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(errorMessage)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/bookshelf.templ`, Line: 323, Col: 58}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
+ 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
+ }
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "