- Header: sticky app-wide, active nav highlighting, data-driven theme picker with active swatch, unified SVG icons, deduped login fragment (was duplicated verbatim for desktop + mobile), removed stray console.log - LibrarySwitcher: cleaner sticky bar, SVG action icons, theme-aware - BookCard: the atomic unit now has a real surface (was floating text when wood-paneling was off due to an undefined --wood-border), with cohesive shadow + hover lift; reused across dashboard/bookshelf/series - Dashboard: calmer section headers, snap carousels with SVG chevrons - Bookshelf: recompose the filter wall into a search toolbar + collapsible Filters panel (all 9 filters + save/load/clear preserved), redesigned empty state and pagination - Book detail, series, collections, browse: cohesive cards, SVG action icons, uppercase muted labels, theme-aware badges/links
53 lines
2.0 KiB
Templ
53 lines
2.0 KiB
Templ
package templates
|
|
|
|
import (
|
|
"bookhoard/internal/handlers"
|
|
"fmt"
|
|
)
|
|
|
|
templ BrowseDetail(user User, badgeIcon string, badgeLabel string, title string, pageTitle string, backUrl string, backLabel string, emptyIcon string, emptyMessage string, books []handlers.BookInfo, errorMessage string) {
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8"/>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
|
<title>{ pageTitle } - Bookhoard</title>
|
|
<link href="/static/style.css" rel="stylesheet"/>
|
|
</head>
|
|
<body class="theme-{ user.Theme }">
|
|
@Header(user, backUrl)
|
|
<div class="sticky top-16 z-30 border-b border-line bg-surface/95 backdrop-blur">
|
|
<div class="w-full px-4 sm:px-6 lg:px-8 py-2.5">
|
|
<a href={ backUrl } class="inline-flex items-center gap-1.5 text-sm font-medium text-content-muted transition-colors hover:text-content">
|
|
@Icon("arrow-left", "h-4 w-4")
|
|
{ backLabel }
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<div class="w-full px-4 sm:px-6 lg:px-8 py-8">
|
|
<div class="mb-6 flex flex-wrap items-center gap-3">
|
|
<span class="chip">{ badgeIcon } { badgeLabel }</span>
|
|
<h1 class="text-2xl font-bold tracking-tight text-content">{ title }</h1>
|
|
<span class="text-sm text-content-muted">{ fmt.Sprintf("%d", len(books)) } books</span>
|
|
</div>
|
|
if len(books) > 0 {
|
|
<div class="grid grid-cols-2 gap-4 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6">
|
|
for _, book := range books {
|
|
@BookCard(book)
|
|
}
|
|
</div>
|
|
} else {
|
|
<div class="flex flex-col items-center justify-center rounded-2xl border border-dashed border-line py-20 text-center">
|
|
<div class="mb-3 flex h-14 w-14 items-center justify-center rounded-full bg-surface-hover text-content-muted">
|
|
@Icon("book", "h-7 w-7")
|
|
</div>
|
|
<h3 class="text-lg font-semibold text-content">No Books Found</h3>
|
|
<p class="mt-1 text-sm text-content-muted">{ emptyMessage }</p>
|
|
</div>
|
|
}
|
|
</div>
|
|
@ErrorToast(errorMessage)
|
|
</body>
|
|
</html>
|
|
}
|