package templates import ( "encoding/json" "fmt" ) func readerInitExpr(metadata ReaderMetadata, progress ReadingProgress, bookmarks []Bookmark) string { config := map[string]interface{}{ "mediaItemId": metadata.MediaItemID, "fileUrl": metadata.FileURL, "formatGroup": metadata.FormatGroup, "readingDirection": metadata.ReadingDirection, "mangaType": metadata.MangaType, } if progress.Percentage > 0 { config["savedPercentage"] = progress.Percentage / 100 } if progress.EpubCfi != "" { config["savedCfi"] = progress.EpubCfi } // Fixed-layout & comic formats: the page index is the canonical, exact // locator (pages are fixed images). Pass it so the reader restores by page. if (metadata.FormatGroup == "fixed_layout" || metadata.FormatGroup == "comic_archive") && progress.CurrentPage > 0 { config["savedPage"] = progress.CurrentPage if progress.TotalPages > 0 { config["savedTotalPages"] = progress.TotalPages } } if len(bookmarks) > 0 { items := make([]map[string]interface{}, 0, len(bookmarks)) for _, b := range bookmarks { var page any if b.PageNumber != nil { page = *b.PageNumber } items = append(items, map[string]interface{}{ "id": b.ID, "title": b.Title, "positionLabel": b.Position, "cfi": b.CfiPosition, "page": page, }) } config["bookmarks"] = items } jsonBytes, _ := json.Marshal(config) return fmt.Sprintf("initReader(%s)", string(jsonBytes)) } templ Reader(user User, metadata ReaderMetadata, progress ReadingProgress, bookmarks []Bookmark) { { metadata.Title } - Bookhoard Reader
@ReaderChrome(metadata, progress) } templ ReaderChrome(metadata ReaderMetadata, progress ReadingProgress) {
← Back

{ metadata.Title }

if progress.FormatGroup == "reflowable" { if metadata.EstimatedPages > 0 { { fmt.Sprintf("%.0f%% · Page %d/%d", progress.Percentage, progress.CurrentPage, metadata.EstimatedPages) } } else { { fmt.Sprintf("%.0f%%", progress.Percentage) } } } else { { fmt.Sprintf("%d/%d", progress.CurrentPage, progress.TotalPages) } }
if progress.FormatGroup == "reflowable" { { fmt.Sprintf("%.0f%%", progress.Percentage) } } else { { fmt.Sprintf("%d/%d", progress.CurrentPage, progress.TotalPages) } }
0/0
} templ drawerHeader(title string) {

{ title }

} templ ReaderTOCDrawer() { @drawerHeader("Contents")
} templ ReaderAnnotationsDrawer() { @drawerHeader("Annotations")
} templ ReaderSearchDrawer() { @drawerHeader("Search")
Searching… 0 matches No matches Search failed
} templ ReaderSettingsDrawer() { @drawerHeader("Settings")

Behavior

Reading Theme

Typography

Layout

}