- Regenerate all template files after adding header component - Clean up generated session files - Templates now use new header component consistently All templates have been regenerated to include the new header functionality and updated routing.
54 lines
21 KiB
Go
54 lines
21 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 - Bookmann</title><script src=\"/static/htmx.min.js\"></script><script src=\"/static/toast.js\"></script><link href=\"/static/style.css\" rel=\"stylesheet\"><style>\n :root {\n --bg-primary: #1a1b26;\n --bg-secondary: #16161e;\n --text-primary: #a9b1d6;\n --text-secondary: #565f89;\n --accent: #7aa2f7;\n --border: #414868;\n }\n .theme-tokyo-night {\n --bg-primary: #1a1b26;\n --bg-secondary: #16161e;\n --text-primary: #a9b1d6;\n --text-secondary: #565f89;\n --accent: #7aa2f7;\n --border: #414868;\n }\n body {\n background-color: var(--bg-primary);\n color: var(--text-primary);\n }\n .card {\n background-color: var(--bg-secondary);\n border-color: var(--border);\n }\n .btn-primary {\n background-color: var(--accent);\n color: var(--bg-primary);\n }\n .btn-primary:hover {\n opacity: 0.8;\n }\n </style></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)\">📚 Bookmann</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: `admin_library.templ`, Line: 55, 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
|