Files
bookhoard/templates/admin_library_templ.go
T
john-okeefe 0c515a277c refactor(templates): add error toast support to page templates
Update all page templates to accept an optional error message parameter
and display it via the ErrorToast component when data loading fails.
2026-02-20 13:25:49 -05:00

54 lines
20 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 AdminLibrary(user User) 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\"><title>Library Management - Bookhoard</title><script src=\"/static/htmx.min.js\"></script><script src=\"/static/toast.js\"></script><link href=\"/static/style.css\" rel=\"stylesheet\"></head><body class=\"theme-tokyo-night\"><nav class=\"border-b\" style=\"border-color: var(--border); background-color: var(--bg-secondary)\"><div class=\"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8\"><div class=\"flex justify-between items-center h-16\"><div class=\"flex items-center\"><h1 class=\"text-xl font-bold\" style=\"color: var(--text-primary)\">📚 Bookhoard</h1></div><div class=\"flex items-center space-x-4\"><a href=\"/\" class=\"px-3 py-2 text-sm hover:opacity-80\" style=\"color: var(--text-secondary)\">Library</a> <span style=\"color: var(--text-secondary)\">Welcome, ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(user.Username)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_library.templ`, Line: 22, Col: 91}
}
_, 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, 2, "!</span> <button onclick=\"logout()\" class=\"btn-primary px-4 py-2 rounded text-sm\">Logout</button></div></div></div></nav><div class=\"flex min-h-screen\" style=\"background-color: var(--bg-primary)\"><aside class=\"w-64 border-r\" style=\"background-color: var(--bg-secondary); border-color: var(--border)\"><div class=\"p-6\"><h2 class=\"text-lg font-semibold mb-6\" style=\"color: var(--text-primary)\">Admin Panel</h2><nav class=\"space-y-2\"><a href=\"/admin\" class=\"block px-4 py-2 rounded-lg hover:opacity-80\" style=\"color: var(--text-primary)\">🏠 Dashboard</a> <a href=\"/admin/profile\" class=\"block px-4 py-2 rounded-lg hover:opacity-80\" style=\"color: var(--text-primary)\">👤 Profile Settings</a> <a href=\"/admin/library\" class=\"block px-4 py-2 rounded-lg bg-accent text-bg-primary\" style=\"color: var(--text-primary)\">📚 Library Management</a></nav></div></aside><main class=\"flex-1 p-8\"><div class=\"max-w-6xl\"><div class=\"mb-8\"><div class=\"flex items-center justify-between mb-4\"><a href=\"/admin\" class=\"btn-secondary px-4 py-2 rounded-lg font-medium\">← Back to Dashboard</a> <button onclick=\"showCreateLibraryModal()\" class=\"btn-primary px-4 py-2 rounded-lg font-medium\">+ Create Library</button></div><h1 class=\"text-3xl font-bold mb-2\" style=\"color: var(--text-primary)\">Library Management</h1><p style=\"color: var(--text-secondary)\">Manage libraries and configure media scanning</p></div><div class=\"grid grid-cols-1 lg:grid-cols-2 gap-8\"><!-- Libraries Section --><div class=\"card p-6 rounded-lg border\" style=\"background-color: var(--bg-secondary); border-color: var(--border)\"><h3 class=\"text-xl font-semibold mb-6\" style=\"color: var(--text-primary)\">Libraries</h3><p style=\"color: var(--text-secondary)\" class=\"mb-4\">Manage media libraries and their folders</p><div id=\"libraries-list\" class=\"space-y-3 mb-6\"><!-- Libraries will be loaded here --></div></div><!-- User Library Visibility Section --><div class=\"card p-6 rounded-lg border\" style=\"background-color: var(--bg-secondary); border-color: var(--border)\"><h3 class=\"text-xl font-semibold mb-6\" style=\"color: var(--text-primary)\">Library Visibility</h3><p style=\"color: var(--text-secondary)\" class=\"mb-4\">Control which libraries are visible to users</p><div id=\"visibility-controls\" class=\"space-y-4\"><!-- Visibility controls will be loaded here --></div></div></div><!-- User Visibility Management --><div class=\"mt-8 card p-6 rounded-lg border\" style=\"background-color: var(--bg-secondary); border-color: var(--border)\"><h3 class=\"text-xl font-semibold mb-6\" style=\"color: var(--text-primary)\">User Library Access</h3><p style=\"color: var(--text-secondary)\" class=\"mb-4\">Manage individual user access to specific libraries</p><div class=\"mb-4\"><select id=\"user-select\" onchange=\"loadUserVisibility()\" class=\"px-3 py-2 border rounded\" style=\"background-color: var(--bg-primary); color: var(--text-primary); border-color: var(--border)\"><option value=\"\">Select a user...</option></select></div><div id=\"user-libraries\" class=\"space-y-3\"><!-- User library checkboxes will be loaded here --></div></div></div></main></div><!-- Create Library Modal --><div id=\"create-library-modal\" class=\"fixed inset-0 bg-black bg-opacity-50 hidden flex items-center justify-center z-50\"><div class=\"card p-6 rounded-lg border max-w-md w-full mx-4\" style=\"background-color: var(--bg-secondary); border-color: var(--border)\"><h3 class=\"text-xl font-semibold mb-4\" style=\"color: var(--text-primary)\">Create Library</h3><form hx-post=\"/api/libraries\" hx-target=\"#create-result\" hx-swap=\"innerHTML\" hx-headers='{\"Authorization\": \"Bearer \" + localStorage.getItem(\"token\")}' onsubmit=\"this.reset();\"><div class=\"mb-4\"><label class=\"block text-sm font-medium mb-2\" style=\"color: var(--text-primary)\">Library Name</label> <input type=\"text\" name=\"name\" placeholder=\"My Ebook Library\" class=\"w-full px-3 py-2 border rounded\" style=\"background-color: var(--bg-primary); color: var(--text-primary); border-color: var(--border)\" required></div><div class=\"mb-4\"><label class=\"block text-sm font-medium mb-2\" style=\"color: var(--text-primary)\">Description</label> <textarea name=\"description\" placeholder=\"Optional description\" rows=\"3\" class=\"w-full px-3 py-2 border rounded\" style=\"background-color: var(--bg-primary); color: var(--text-primary); border-color: var(--border)\"></textarea></div><div class=\"mb-4\"><label class=\"block text-sm font-medium mb-2\" style=\"color: var(--text-primary)\">Library Type</label> <select name=\"type\" class=\"w-full px-3 py-2 border rounded\" style=\"background-color: var(--bg-primary); color: var(--text-primary); border-color: var(--border)\" required><option value=\"ebooks\">📚 Ebooks</option> <option value=\"comics\">📖 Comics</option> <option value=\"manga\">🗾 Manga</option></select></div><div class=\"flex justify-end space-x-3\"><button type=\"button\" onclick=\"hideCreateLibraryModal()\" class=\"btn-secondary px-4 py-2 rounded\">Cancel</button> <button type=\"submit\" class=\"btn-primary px-4 py-2 rounded\">Create</button></div></form><div id=\"create-result\" class=\"mt-2\"></div></div></div><script>\n let libraries = [];\n let users = [];\n let libraryTypes = [];\n\n function loadLibraries() {\n fetch('/api/libraries', {\n headers: { 'Authorization': 'Bearer ' + localStorage.getItem('token') }\n })\n .then(response => response.json())\n .then(data => {\n libraries = data;\n renderLibraries();\n })\n .catch(error => console.error('Error loading libraries:', error));\n }\n\n function renderLibraries() {\n const container = document.getElementById('libraries-list');\n container.innerHTML = libraries.map(library => \n '<div class=\"p-4 border rounded-lg\" style=\"background-color: var(--bg-primary); border-color: var(--border)\">' +\n '<div class=\"flex justify-between items-start mb-2\">' +\n '<div>' +\n '<h4 class=\"font-semibold\" style=\"color: var(--text-primary)\">' + library.name + '</h4>' +\n '<p class=\"text-sm\" style=\"color: var(--text-secondary)\">' + (library.description || '') + '</p>' +\n '<span class=\"inline-block px-2 py-1 text-xs rounded\" style=\"background-color: var(--accent); color: var(--bg-primary)\">' + \n (library.type_name || library.type) + '</span>' +\n '</div>' +\n '<div class=\"flex space-x-2\">' +\n '<button onclick=\"showLibraryFolders(\\'' + library.id + '\\')\" class=\"text-xs px-2 py-1 rounded\" style=\"background-color: var(--bg-secondary); color: var(--text-primary)\">Folders</button>' +\n '<button onclick=\"editLibrary(\\'' + library.id + '\\')\" class=\"text-xs px-2 py-1 rounded\" style=\"background-color: var(--accent); color: var(--bg-primary)\">Edit</button>' +\n '<button onclick=\"deleteLibrary(\\'' + library.id + '\\')\" class=\"text-xs px-2 py-1 rounded text-red-500\">Delete</button>' +\n '</div>' +\n '</div>' +\n '<div id=\"library-folders-' + library.id + '\" class=\"hidden mt-3 space-y-2\"></div>' +\n '</div>'\n ).join('');\n }\n\n function loadUsers() {\n fetch('/api/auth/users', {\n headers: { 'Authorization': 'Bearer ' + localStorage.getItem('token') }\n })\n .then(response => response.json())\n .then(data => {\n users = data;\n renderUserSelect();\n })\n .catch(error => console.error('Error loading users:', error));\n }\n\n function renderUserSelect() {\n const select = document.getElementById('user-select');\n select.innerHTML = '<option value=\"\">Select a user...</option>' + \n users.map(user => '<option value=\"' + user.id + '\">' + user.username + ' (' + user.email + ')</option>').join('');\n }\n\n function loadUserVisibility() {\n const userId = document.getElementById('user-select').value;\n if (!userId) {\n document.getElementById('user-libraries').innerHTML = '<p style=\"color: var(--text-secondary)\">Please select a user</p>';\n return;\n }\n\n // Load user's visible libraries\n fetch('/api/libraries/visible', {\n headers: { 'Authorization': 'Bearer ' + localStorage.getItem('token') }\n })\n .then(response => response.json())\n .then(visibleLibraries => {\n const container = document.getElementById('user-libraries');\n const visibleIds = visibleLibraries.map(lib => lib.id);\n \n container.innerHTML = libraries.map(library => {\n const isVisible = visibleIds.includes(library.id);\n return '<label class=\"flex items-center space-x-3 p-2 rounded\" style=\"background-color: var(--bg-primary);\">' +\n '<input type=\"checkbox\" ' + (isVisible ? 'checked' : '') + \n ' onchange=\"setLibraryVisibility(\\'' + userId + '\\', \\'' + library.id + '\\', this.checked)\" ' +\n 'class=\"w-4 h-4\">' +\n '<span style=\"color: var(--text-primary)\">' + library.name + ' (' + library.type_name + ')</span>' +\n '</label>';\n }).join('');\n })\n .catch(error => console.error('Error loading user libraries:', error));\n }\n\n function setLibraryVisibility(userId, libraryId, isVisible) {\n fetch('/api/libraries/visibility', {\n method: 'POST',\n headers: { \n 'Authorization': 'Bearer ' + localStorage.getItem('token'),\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({\n library_id: libraryId,\n is_visible: isVisible\n })\n })\n .then(response => response.json())\n .then(() => {\n // Refresh visibility controls\n loadUserVisibility();\n })\n .catch(error => console.error('Error setting library visibility:', error));\n }\n\n function showCreateLibraryModal() {\n document.getElementById('create-library-modal').classList.remove('hidden');\n }\n\n function hideCreateLibraryModal() {\n document.getElementById('create-library-modal').classList.add('hidden');\n }\n\n function deleteLibrary(libraryId) {\n const library = libraries.find(l => l.id === libraryId);\n if (!library) return;\n \n if (confirm('Delete library \"' + library.name + '\"? This will permanently remove all associated media and cannot be undone.')) {\n fetch('/api/libraries/' + libraryId, {\n method: 'DELETE',\n headers: { 'Authorization': 'Bearer ' + localStorage.getItem('token') }\n })\n .then(response => {\n if (response.ok) {\n loadLibraries(); // Refresh\n } else {\n alert('Error deleting library');\n }\n })\n .catch(error => console.error('Error deleting library:', error));\n }\n }\n\n function showLibraryFolders(libraryId) {\n const container = document.getElementById('library-folders-' + libraryId);\n const library = libraries.find(l => l.id === libraryId);\n \n if (container.classList.contains('hidden')) {\n // Load folders for this library\n fetch('/api/libraries/' + libraryId + '/folders', {\n headers: { 'Authorization': 'Bearer ' + localStorage.getItem('token') }\n })\n .then(response => response.json())\n .then(folders => {\n container.innerHTML = folders.map(folder => \n '<div class=\"flex justify-between items-center p-2 rounded\" style=\"background-color: var(--bg-secondary); border-color: var(--border)\">' +\n '<span class=\"text-sm\" style=\"color: var(--text-primary)\">' + folder.folder_path + '</span>' +\n '<button onclick=\"removeLibraryFolder(\\'' + libraryId + '\\', \\'' + folder.folder_path + '\\')\" ' +\n 'class=\"text-xs text-red-500\">Remove</button>' +\n '</div>'\n ).join('');\n \n // Add folder input\n container.innerHTML += '<div class=\"mt-2 flex space-x-2\">' +\n '<input type=\"text\" id=\"folder-path-' + libraryId + '\" placeholder=\"Add folder path\" ' +\n 'class=\"flex-1 px-2 py-1 text-sm border rounded\" style=\"background-color: var(--bg-primary); color: var(--text-primary); border-color: var(--border)\">' +\n '<button onclick=\"addLibraryFolder(\\'' + libraryId + '\\')\" ' +\n 'class=\"btn-primary px-2 py-1 text-xs rounded\">Add</button>' +\n '</div>';\n \n container.classList.remove('hidden');\n })\n .catch(error => console.error('Error loading folders:', error));\n } else {\n container.classList.add('hidden');\n }\n }\n\n function addLibraryFolder(libraryId) {\n const input = document.getElementById('folder-path-' + libraryId);\n const folderPath = input.value.trim();\n \n if (!folderPath) return;\n \n fetch('/api/libraries/' + libraryId + '/folders', {\n method: 'POST',\n headers: { \n 'Authorization': 'Bearer ' + localStorage.getItem('token'),\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({ folder_path: folderPath })\n })\n .then(response => response.json())\n .then(() => {\n input.value = '';\n showLibraryFolders(libraryId); // Refresh\n })\n .catch(error => console.error('Error adding folder:', error));\n }\n\n function removeLibraryFolder(libraryId, folderPath) {\n if (confirm('Remove this folder from the library?')) {\n fetch('/api/libraries/' + libraryId + '/folders', {\n method: 'DELETE',\n headers: { \n 'Authorization': 'Bearer ' + localStorage.getItem('token'),\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({ folder_path: folderPath })\n })\n .then(response => response.json())\n .then(() => {\n showLibraryFolders(libraryId); // Refresh\n })\n .catch(error => console.error('Error removing folder:', error));\n }\n }\n\n function logout() {\n localStorage.removeItem('token');\n localStorage.removeItem('user');\n window.location.href = '/';\n }\n\n function loadTheme() {\n // Load saved theme if exists\n const savedTheme = localStorage.getItem('theme');\n if (savedTheme) {\n document.body.className = 'theme-' + savedTheme;\n }\n }\n\n document.addEventListener('DOMContentLoaded', function() {\n loadTheme();\n loadLibraries();\n loadUsers();\n });\n </script></body></html>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
var _ = templruntime.GeneratedTemplate