- Regenerate admin_library_templ.go with admin sidebar integration - Regenerate admin_users_templ.go with sidebar layout and theme fixes - Regenerate bookshelf_templ.go with dynamic theme rendering - Regenerate index_templ.go with progressive enhancement script - Regenerate login_templ.go with progressive enhancement script - Regenerate register_templ.go with progressive enhancement script - Compile header.js with consolidated theme logic
92 lines
14 KiB
Go
92 lines
14 KiB
Go
// Code generated by templ - DO NOT EDIT.
|
|
|
|
// templ: version: v0.3.977
|
|
package templates
|
|
|
|
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
|
|
|
import "github.com/a-h/templ"
|
|
import templruntime "github.com/a-h/templ/runtime"
|
|
|
|
func BookShelf(user User, libraries []LibraryData) templ.Component {
|
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
|
return templ_7745c5c3_CtxErr
|
|
}
|
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
|
if !templ_7745c5c3_IsBuffer {
|
|
defer func() {
|
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
|
if templ_7745c5c3_Err == nil {
|
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
|
}
|
|
}()
|
|
}
|
|
ctx = templ.InitializeContext(ctx)
|
|
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
|
if templ_7745c5c3_Var1 == nil {
|
|
templ_7745c5c3_Var1 = templ.NopComponent
|
|
}
|
|
ctx = templ.ClearChildren(ctx)
|
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<!doctype html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>Library - Bookhoard</title><script src=\"/static/htmx.min.js\"></script><script src=\"/static/toast.js\"></script><script src=\"/static/search.js\"></script><link href=\"/static/style.css\" rel=\"stylesheet\"></head><body class=\"theme-{ user.Theme }\">")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
templ_7745c5c3_Err = Header(user, "/bookshelf").Render(ctx, templ_7745c5c3_Buffer)
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<div class=\"max-w-7xl mx-auto px-4 sm:px-6 lg:8 py-8\"><!-- Library Selector --><div class=\"mb-8\"><div class=\"flex flex-col sm:flex-row gap-4 items-center justify-between\"><div class=\"flex-1 w-full\"><label class=\"block text-sm font-medium mb-2\" style=\"color: var(--text-secondary)\">Select Library</label> <select id=\"library-select\" onchange=\"selectLibrary()\" class=\"w-full px-4 py-3 border rounded-lg text-lg\" style=\"background-color: var(--bg-secondary); color: var(--text-primary); border-color: var(--border);\">")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
if len(libraries) == 0 {
|
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<option value=\"\">No libraries available</option>")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
} else {
|
|
for _, lib := range libraries {
|
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<option value=\"")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
var templ_7745c5c3_Var2 string
|
|
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(lib.ID)
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `bookshelf.templ`, Line: 28, Col: 58}
|
|
}
|
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\">")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
var templ_7745c5c3_Var3 string
|
|
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(lib.Name)
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `bookshelf.templ`, Line: 28, Col: 71}
|
|
}
|
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</option>")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
}
|
|
}
|
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</select></div><div class=\"flex gap-2\"><button onclick=\"loadBookshelf()\" class=\"btn-primary px-6 py-3 rounded-lg font-medium\">Refresh</button></div></div></div><!-- Bookshelf Container --><div id=\"bookshelf-container\"><!-- Loading state --><div id=\"loading\" class=\"text-center py-16\" style=\"color: var(--text-secondary)\"><div class=\"loading-spinner mx-auto mb-4\"></div><p>Loading your library...</p></div><!-- Empty state --><div id=\"empty-state\" class=\"hidden text-center py-16\" style=\"color: var(--text-secondary)\"><div class=\"text-6xl mb-4\">📚</div><h3 class=\"text-xl font-semibold mb-2\" style=\"color: var(--text-primary)\">No Books Yet</h3><p>Select a library to view your collection</p></div><!-- Books Grid --><div id=\"books-grid\" class=\"hidden\"><!-- Books will be loaded here on shelves --></div></div></div><script src=\"/static/theme.js\"></script><script>\n // Libraries already loaded server-side\n const libraries = [\n if len(libraries) > 0 {\n for _, lib := range libraries {\n {\n id: \"{ lib.ID }\",\n name: \"{ lib.Name }\",\n description: \"{ lib.Description }\",\n type_name: \"{ lib.TypeName }\"\n },\n }\n }\n ];\n let currentLibrary = null;\n let mediaItems = [];\n\n function selectLibrary() {\n const librarySelect = document.getElementById('library-select');\n const selectedId = librarySelect.value;\n currentLibrary = libraries.find(lib => lib.id === selectedId);\n if (currentLibrary) {\n loadBookshelf();\n }\n }\n\n // Auto-select first library if available\n document.addEventListener('DOMContentLoaded', function() {\n loadTheme();\n if (libraries.length > 0) {\n const librarySelect = document.getElementById('library-select');\n currentLibrary = libraries[0];\n librarySelect.value = currentLibrary.id;\n loadBookshelf();\n } else {\n showEmptyState();\n }\n });\n })\n .then(response => response.json())\n .then(data => {\n loading.style.display = 'none';\n libraries = data;\n populateLibrarySelect();\n \n // Auto-select first library if available\n if (libraries.length > 0 && !currentLibrary) {\n currentLibrary = libraries[0];\n librarySelect.value = currentLibrary.id;\n loadBookshelf();\n }\n })\n .catch(error => {\n loading.style.display = 'none';\n console.error('Error loading libraries:', error);\n showToast('Error loading libraries', 'error');\n });\n }\n\n function populateLibrarySelect() {\n const librarySelect = document.getElementById('library-select');\n \n if (libraries.length === 0) {\n librarySelect.innerHTML = '<option value=\"\">No libraries available</option>';\n return;\n }\n\n librarySelect.innerHTML = '<option value=\"\">Select a library...</option>' +\n libraries.map(library => {\n const icon = getLibraryIcon(library.type_name);\n return `<option value=\"${library.id}\">${icon} ${library.name}</option>`;\n }).join('');\n }\n\n function getLibraryIcon(typeName) {\n switch (typeName) {\n case 'ebooks': return '📚';\n case 'comics': return '📖';\n case 'manga': return '🗾';\n default: return '📁';\n }\n }\n\n function selectLibrary() {\n const librarySelect = document.getElementById('library-select');\n const libraryId = librarySelect.value;\n \n currentLibrary = libraries.find(l => l.id === libraryId);\n loadBookshelf();\n }\n\n function loadBookshelf() {\n if (!currentLibrary) {\n showEmptyState();\n return;\n }\n\n const loading = document.getElementById('loading');\n const booksGrid = document.getElementById('books-grid');\n const emptyState = document.getElementById('empty-state');\n\n loading.style.display = 'block';\n booksGrid.classList.add('hidden');\n emptyState.classList.add('hidden');\n\n fetch(`/api/media-items?library_id=${currentLibrary.id}&limit=100&offset=0`, {\n headers: {\n 'Authorization': 'Bearer ' + localStorage.getItem('token'),\n 'Content-Type': 'application/json'\n }\n })\n .then(response => response.json())\n .then(data => {\n loading.style.display = 'none';\n mediaItems = data;\n \n if (mediaItems.length === 0) {\n showEmptyState();\n } else {\n renderBookshelf();\n }\n })\n .catch(error => {\n loading.style.display = 'none';\n console.error('Error loading bookshelf:', error);\n showToast('Error loading books', 'error');\n });\n }\n\n function showEmptyState() {\n const booksGrid = document.getElementById('books-grid');\n const emptyState = document.getElementById('empty-state');\n const loading = document.getElementById('loading');\n \n loading.style.display = 'none';\n booksGrid.classList.add('hidden');\n emptyState.classList.remove('hidden');\n }\n\n function renderBookshelf() {\n const booksGrid = document.getElementById('books-grid');\n const emptyState = document.getElementById('empty-state');\n const loading = document.getElementById('loading');\n \n loading.style.display = 'none';\n emptyState.classList.add('hidden');\n booksGrid.classList.remove('hidden');\n\n // Group books into shelves (6 books per shelf for better display)\n const booksPerShelf = 6;\n const shelves = [];\n \n for (let i = 0; i < mediaItems.length; i += booksPerShelf) {\n shelves.push(mediaItems.slice(i, i + booksPerShelf));\n }\n\n let html = '';\n shelves.forEach((shelfBooks, index) => {\n html += `<div class=\"relative bg-gradient-to-b from-transparent to-black/10 p-8 mb-4 rounded-lg\" style=\"padding-bottom: 3rem;\">\n <div class=\"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4\">\n ${shelfBooks.map(book => renderBookCard(book)).join('')}\n </div>\n <div class=\"absolute bottom-0 left-0 right-0 h-3 rounded-b-lg\" style=\"background: linear-gradient(to bottom, rgba(107, 68, 35, 0.3) 0%, rgba(107, 68, 35, 0.5) 50%, rgba(107, 68, 35, 0.3) 100%); box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\"></div>\n </div>`;\n });\n\n booksGrid.innerHTML = html;\n }\n\n function renderBookCard(book) {\n const coverUrl = book.cover_image_path || '/static/placeholder-book.svg';\n const authorHtml = book.author ? `<p class=\"text-xs\" style=\"color: var(--text-secondary)\">${book.author}</p>` : '';\n\n return `<div class=\"relative transition-all duration-200 ease hover:-translate-y-2 hover:-rotate-2 hover:shadow-2xl hover:z-10 cursor-pointer\" onclick=\"viewBook('${book.id}')\">\n <div class=\"aspect-[2/3] overflow-hidden rounded shadow-[2px_2px_4px_rgba(0,0,0,0.2),-1px_-1px_2px_rgba(255,255,255,0.1)_inset] relative\">\n <div class=\"absolute left-0 top-0 bottom-0 w-1\" style=\"background: linear-gradient(to right, rgba(0, 0, 0, 0.3) 0%, rgba(255, 255, 255, 0.1) 50%, transparent 100%);\"></div>\n <img src=\"${coverUrl}\"\n alt=\"${book.title}\"\n class=\"w-full h-full object-cover\"\n onerror=\"this.src='/static/placeholder-book.svg'\"\n >\n </div>\n <div class=\"mt-2\">\n <h3 class=\"text-sm font-semibold line-clamp-2\" style=\"color: var(--text-primary)\">${book.title}</h3>\n ${authorHtml}\n </div>\n </div>`;\n }\n\n function viewBook(bookId) {\n // TODO: Navigate to book detail view\n showToast('Book viewer coming soon!', 'info');\n }\n\n // Initialize\n document.addEventListener('DOMContentLoaded', function() {\n loadTheme();\n loadLibraries();\n });\n </script></body></html>")
|
|
if templ_7745c5c3_Err != nil {
|
|
return templ_7745c5c3_Err
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
var _ = templruntime.GeneratedTemplate
|