package templates import ( "bookhoard/internal/handlers" "fmt" ) templ Dashboard(user User, sections []handlers.SectionData, allSections []handlers.SectionData, libData []LibraryData, currentLibraryID string, hiddenCollections []string, itemsPerSection int, week *WeekStatsData, errorMessage string) { Dashboard - Bookhoard @Header(user, "/dashboard") @LibrarySwitcher(libData, currentLibraryID, DashboardActions())

Your Library

Pick up where you left off, or explore something new.

if week != nil { @DashboardWeekWidget(*week) } for _, section := range sections { @CollectionCarousel(section) }
@DashboardSettingsModal(allSections, hiddenCollections, itemsPerSection) @ErrorToast(errorMessage) } templ CollectionCarousel(section handlers.SectionData) {
{ section.Icon }

{ section.Title }

if section.Description != "" {

{ section.Description }

}
if section.ViewAllURL != "" { View All @Icon("arrow-right", "h-4 w-4") }
} templ BookCard(item handlers.BookInfo) {
if item.CoverImagePath != "" { { } else { { }

{ item.Title }

if item.Author != "" {

{ item.Author }

}
if item.HasConflict { @Icon("book-open", "h-5 w-5") } else { @Icon("book-open", "h-5 w-5") }
} templ DashboardSettingsModal(sections []handlers.SectionData, hiddenCollections []string, itemsPerSection int) { } // WeekStatsData is the dashboard's "this week" widget payload // (server-rendered from the statistics service; nil = suppressed). // Times rendered in the user's timezone at the server, per convention. type WeekStatsData struct { WeekMinutes int WeekPages int WeekSessions int WeekBooks int PrevMinutes int ActiveToday bool CurrentStreak int } // BookStatsData is the per-book reading-stats card on the book detail // page (nil = the viewer has no sessions on this book → hide it). type BookStatsData struct { TotalMinutes int TotalPages int SessionCount int MaxProgress float64 // 0..1 Finished bool LastSession string FirstSession string } templ DashboardWeekWidget(week WeekStatsData) {
@Icon("chart", "h-5 w-5")

This Week

Synced from your reading devices

Full stats →

{ fmt.Sprintf("%d min", week.WeekMinutes) }

{ readingTimeSuffix(week.WeekMinutes, week.PrevMinutes) }

{ fmt.Sprintf("%d", week.WeekPages) }

pages read

{ fmt.Sprintf("%d", week.WeekSessions) }

reading sessions

{ fmt.Sprintf("%d", week.WeekBooks) }

books touched

if week.CurrentStreak > 0 { if week.ActiveToday { { fmt.Sprintf("🔥 %d-day streak — keep it going today", week.CurrentStreak) } } else { { fmt.Sprintf("🔥 %d-day streak — read today to keep it", week.CurrentStreak) } } } else { { "A reading day today starts your streak." } }

} func readingTimeSuffix(minutes, prevMinutes int) string { if prevMinutes <= 0 { if minutes > 0 { return "reading time" } return "no reading yet this week" } percent := float64(minutes-prevMinutes) / float64(prevMinutes) * 100 return fmt.Sprintf("%+.0f%% vs last week", percent) }