Safety backup before Path A fixes - fixing function mismatches and missing functions

This commit is contained in:
2026-03-11 11:01:43 -04:00
parent 0a5042e130
commit 083f152b35
62 changed files with 202 additions and 261 deletions
+1 -2
View File
@@ -97,7 +97,7 @@ templ Admin(user User) {
</div> </div>
<div class="mt-4 flex gap-2"> <div class="mt-4 flex gap-2">
<button <button
@click="window.location.reload()" @click="$store.window.location.reload()"
class="btn-primary px-4 py-2 rounded-lg" class="btn-primary px-4 py-2 rounded-lg"
> >
Refresh to View Books Refresh to View Books
@@ -117,4 +117,3 @@ templ Admin(user User) {
</body> </body>
</html> </html>
} }
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
+2 -2
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
@@ -45,7 +45,7 @@ func Admin(user User) templ.Component {
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<main class=\"flex-1 p-8\"><div class=\"max-w-4xl\"><div class=\"mb-8\"><h1 class=\"text-3xl font-bold mb-2\" style=\"color: var(--text-primary)\">Dashboard</h1><p style=\"color: var(--text-secondary)\">Overview of your Bookhoard library and settings</p></div><div class=\"grid grid-cols-1 md:grid-cols-2 gap-6 mb-8\"><div class=\"card p-6 rounded-lg border\" style=\"background-color: var(--bg-secondary); border-color: var(--border)\"><div class=\"flex items-center space-x-3\"><div class=\"text-3xl\">📖</div><div><h3 class=\"font-semibold\" style=\"color: var(--text-primary)\">Library</h3><p style=\"color: var(--text-secondary)\" class=\"text-sm\">Manage your ebook collection</p></div></div><a href=\"/\" class=\"mt-4 inline-block text-sm btn-secondary px-3 py-1 rounded\">View Library</a></div><div class=\"card p-6 rounded-lg border\" style=\"background-color: var(--bg-secondary); border-color: var(--border)\"><div class=\"flex items-center space-x-3\"><div class=\"text-3xl\">👁️</div><div><h3 class=\"font-semibold\" style=\"color: var(--text-primary)\">Scan Watch Status</h3><p style=\"color: var(--text-secondary)\" class=\"text-sm\">Auto-detecting new files</p></div></div><div id=\"watch-status\" class=\"mt-4 text-sm\" style=\"color: var(--text-secondary)\"><span class=\"inline-block w-2 h-2 rounded-full bg-green-500 mr-2\"></span> Watching <span id=\"watch-count\">0</span> libraries</div></div></div><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-4\" style=\"color: var(--text-primary)\">Quick Actions</h3><div class=\"grid grid-cols-1 sm:grid-cols-2 gap-4\"><button @click=\"scanAllLibraries()\" class=\"btn-primary p-4 rounded-lg text-left\"><div class=\"font-medium\">Rescan Library</div><div style=\"color: var(--text-secondary)\" class=\"text-sm\">Re-scan existing files and fix metadata</div></button> <a href=\"/admin/library\" class=\"btn-secondary p-4 rounded-lg text-left block\"><div class=\"font-medium\">Manage Folders</div><div style=\"color: var(--text-secondary)\" class=\"text-sm\">Add or remove scan directories</div></a></div></div><!-- Scan Progress Section --><div id=\"scan-progress-container\" class=\"hidden mt-6 p-6 rounded-lg border opacity-0 -translate-y-2.5 transition-all duration-300 ease-out\" style=\"background-color: var(--bg-secondary); border-color: var(--border);\"><div class=\"flex justify-between items-center mb-4\"><h3 class=\"text-lg font-semibold\" style=\"color: var(--text-primary)\">📚 Scanning Libraries</h3><button @click=\"hideScanProgress()\" class=\"p-2 hover:bg-gray-700 rounded\">✕</button></div><!-- Overall Progress --><div class=\"mb-4\"><div class=\"flex justify-between text-sm mb-2\"><span style=\"color: var(--text-secondary)\">Overall Progress</span> <span id=\"scan-progress-text\" style=\"color: var(--text-primary)\">0%</span></div><div class=\"w-full bg-gray-700 rounded-full h-3\"><div id=\"scan-progress-bar\" class=\"h-3 rounded-full transition-all duration-500\" style=\"width: 0%; background-color: var(--accent);\"></div></div><div id=\"scan-status\" class=\"text-sm mt-2\" style=\"color: var(--text-secondary)\">Starting scan...</div></div><!-- Per-Library Progress --><div id=\"library-progress-list\" class=\"space-y-3\"><!-- Dynamically populated --></div><!-- Results Summary --><div id=\"scan-results\" class=\"hidden mt-6 p-4 rounded-lg border\" style=\"background-color: var(--bg-primary); border-color: var(--border);\"><h4 class=\"font-semibold mb-2\" style=\"color: var(--text-primary)\">✅ Scan Complete!</h4><div id=\"scan-results-content\" style=\"color: var(--text-secondary)\"><!-- Results populated by JS --></div><div class=\"mt-4 flex gap-2\"><button @click=\"window.location.reload()\" class=\"btn-primary px-4 py-2 rounded-lg\">Refresh to View Books</button> <button @click=\"hideScanProgress()\" class=\"btn-secondary px-4 py-2 rounded-lg\">Dismiss</button></div></div></div></div></main></div></body></html>") templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<main class=\"flex-1 p-8\"><div class=\"max-w-4xl\"><div class=\"mb-8\"><h1 class=\"text-3xl font-bold mb-2\" style=\"color: var(--text-primary)\">Dashboard</h1><p style=\"color: var(--text-secondary)\">Overview of your Bookhoard library and settings</p></div><div class=\"grid grid-cols-1 md:grid-cols-2 gap-6 mb-8\"><div class=\"card p-6 rounded-lg border\" style=\"background-color: var(--bg-secondary); border-color: var(--border)\"><div class=\"flex items-center space-x-3\"><div class=\"text-3xl\">📖</div><div><h3 class=\"font-semibold\" style=\"color: var(--text-primary)\">Library</h3><p style=\"color: var(--text-secondary)\" class=\"text-sm\">Manage your ebook collection</p></div></div><a href=\"/\" class=\"mt-4 inline-block text-sm btn-secondary px-3 py-1 rounded\">View Library</a></div><div class=\"card p-6 rounded-lg border\" style=\"background-color: var(--bg-secondary); border-color: var(--border)\"><div class=\"flex items-center space-x-3\"><div class=\"text-3xl\">👁️</div><div><h3 class=\"font-semibold\" style=\"color: var(--text-primary)\">Scan Watch Status</h3><p style=\"color: var(--text-secondary)\" class=\"text-sm\">Auto-detecting new files</p></div></div><div id=\"watch-status\" class=\"mt-4 text-sm\" style=\"color: var(--text-secondary)\"><span class=\"inline-block w-2 h-2 rounded-full bg-green-500 mr-2\"></span> Watching <span id=\"watch-count\">0</span> libraries</div></div></div><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-4\" style=\"color: var(--text-primary)\">Quick Actions</h3><div class=\"grid grid-cols-1 sm:grid-cols-2 gap-4\"><button @click=\"scanAllLibraries()\" class=\"btn-primary p-4 rounded-lg text-left\"><div class=\"font-medium\">Rescan Library</div><div style=\"color: var(--text-secondary)\" class=\"text-sm\">Re-scan existing files and fix metadata</div></button> <a href=\"/admin/library\" class=\"btn-secondary p-4 rounded-lg text-left block\"><div class=\"font-medium\">Manage Folders</div><div style=\"color: var(--text-secondary)\" class=\"text-sm\">Add or remove scan directories</div></a></div></div><!-- Scan Progress Section --><div id=\"scan-progress-container\" class=\"hidden mt-6 p-6 rounded-lg border opacity-0 -translate-y-2.5 transition-all duration-300 ease-out\" style=\"background-color: var(--bg-secondary); border-color: var(--border);\"><div class=\"flex justify-between items-center mb-4\"><h3 class=\"text-lg font-semibold\" style=\"color: var(--text-primary)\">📚 Scanning Libraries</h3><button @click=\"hideScanProgress()\" class=\"p-2 hover:bg-gray-700 rounded\">✕</button></div><!-- Overall Progress --><div class=\"mb-4\"><div class=\"flex justify-between text-sm mb-2\"><span style=\"color: var(--text-secondary)\">Overall Progress</span> <span id=\"scan-progress-text\" style=\"color: var(--text-primary)\">0%</span></div><div class=\"w-full bg-gray-700 rounded-full h-3\"><div id=\"scan-progress-bar\" class=\"h-3 rounded-full transition-all duration-500\" style=\"width: 0%; background-color: var(--accent);\"></div></div><div id=\"scan-status\" class=\"text-sm mt-2\" style=\"color: var(--text-secondary)\">Starting scan...</div></div><!-- Per-Library Progress --><div id=\"library-progress-list\" class=\"space-y-3\"><!-- Dynamically populated --></div><!-- Results Summary --><div id=\"scan-results\" class=\"hidden mt-6 p-4 rounded-lg border\" style=\"background-color: var(--bg-primary); border-color: var(--border);\"><h4 class=\"font-semibold mb-2\" style=\"color: var(--text-primary)\">✅ Scan Complete!</h4><div id=\"scan-results-content\" style=\"color: var(--text-secondary)\"><!-- Results populated by JS --></div><div class=\"mt-4 flex gap-2\"><button @click=\"$store.window.location.reload()\" class=\"btn-primary px-4 py-2 rounded-lg\">Refresh to View Books</button> <button @click=\"hideScanProgress()\" class=\"btn-secondary px-4 py-2 rounded-lg\">Dismiss</button></div></div></div></div></main></div></body></html>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
+5 -5
View File
@@ -25,16 +25,16 @@ templ APIExplorer(explorer APIExplorerData) {
<pre class="bg-background-primary p-4 rounded-lg overflow-x-auto"><code class="text-text-primary text-sm">{ explorer.Endpoint.Response }</code></pre> <pre class="bg-background-primary p-4 rounded-lg overflow-x-auto"><code class="text-text-primary text-sm">{ explorer.Endpoint.Response }</code></pre>
</div> </div>
<div class="flex gap-2 mt-4"> <div class="flex gap-2 mt-4">
<button @click="copyToClipboard(JSON.stringify({ explorer.Endpoint.RequestBody }, null, 2))" class="px-4 py-2 border border-border rounded bg-background-primary text-text-primary hover:bg-background-secondary cursor-pointer text-sm">Copy Request</button> <button @click="$store.devices.copyToClipboard(JSON.stringify({ explorer.Endpoint.RequestBody }, null, 2))" class="px-4 py-2 border border-border rounded bg-background-primary text-text-primary hover:bg-background-secondary cursor-pointer text-sm">Copy Request</button>
<button @click="copyToClipboard(JSON.stringify({ explorer.Endpoint.Response }, null, 2))" class="px-4 py-2 border border-border rounded bg-background-primary text-text-primary hover:bg-background-secondary cursor-pointer text-sm">Copy Response</button> <button @click="$store.devices.copyToClipboard(JSON.stringify({ explorer.Endpoint.Response }, null, 2))" class="px-4 py-2 border border-border rounded bg-background-primary text-text-primary hover:bg-background-secondary cursor-pointer text-sm">Copy Response</button>
</div> </div>
</div> </div>
} else { } else {
// Show interactive explorer with real execution // Show interactive explorer with real execution
<div class="border border-border rounded-lg p-6 mt-8 bg-background-secondary" x-data="apiExplorerDoc" x-init="initAPIExplorerDoc('{ explorer.Endpoint.Path }', '{ explorer.Endpoint.RequestBody }', '{ explorer.Endpoint.Response }')"> <div class="border border-border rounded-lg p-6 mt-8 bg-background-secondary" x-data="apiExplorerDoc" x-init="initAPIExplorerDoc('{ explorer.Endpoint.Path }', '{ explorer.Endpoint.RequestBody }', '{ explorer.Endpoint.Response }')">
<div class="flex gap-2 mb-4"> <div class="flex gap-2 mb-4">
<button class="mode-btn px-4 py-2 border border-border rounded bg-background-primary text-text-primary cursor-pointer hover:bg-background-secondary text-sm" id="mock-btn" @click="showDocMode('mock')">Mock Data</button> <button class="mode-btn px-4 py-2 border border-border rounded bg-background-primary text-text-primary cursor-pointer hover:bg-background-secondary text-sm" id="mock-btn" @click="$store.apiExplorerDoc.showDocMode('mock')">Mock Data</button>
<button class="mode-btn px-4 py-2 bg-accent text-white rounded cursor-pointer text-sm" id="real-btn" @click="showDocMode('real')">Try It Out</button> <button class="mode-btn px-4 py-2 bg-accent text-white rounded cursor-pointer text-sm" id="real-btn" @click="$store.apiExplorerDoc.showDocMode('real')">Try It Out</button>
</div> </div>
<div class="mb-4"> <div class="mb-4">
<div class="mb-4"> <div class="mb-4">
@@ -67,7 +67,7 @@ templ APIExplorer(explorer APIExplorerData) {
// APIExplorerData holds data for the API explorer component // APIExplorerData holds data for the API explorer component
type APIExplorerData struct { type APIExplorerData struct {
Endpoint EndpointInfo Endpoint EndpointInfo
IsLoggedIn bool IsLoggedIn bool
} }
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
+2 -2
View File
@@ -19,7 +19,7 @@ templ BookShelf(user User, libraries []LibraryData) {
<div class="flex flex-col sm:flex-row gap-4 items-center justify-between"> <div class="flex flex-col sm:flex-row gap-4 items-center justify-between">
<div class="flex-1 w-full"> <div class="flex-1 w-full">
<label class="block text-sm font-medium mb-2" style="color: var(--text-secondary)">Select Library</label> <label class="block text-sm font-medium mb-2" style="color: var(--text-secondary)">Select Library</label>
<select id="library-select" @change="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);"> <select id="library-select" @change="$store.bookshelf.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 len(libraries) == 0 { if len(libraries) == 0 {
<option value="">No libraries available</option> <option value="">No libraries available</option>
} else { } else {
@@ -30,7 +30,7 @@ templ BookShelf(user User, libraries []LibraryData) {
</select> </select>
</div> </div>
<div class="flex gap-2"> <div class="flex gap-2">
<button @click="loadBookshelf()" class="btn-primary px-6 py-3 rounded-lg font-medium"> <button @click="$store.bookshelf.loadBookshelf" class="btn-primary px-6 py-3 rounded-lg font-medium">
Refresh Refresh
</button> </button>
</div> </div>
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
+8 -8
View File
@@ -60,7 +60,7 @@ templ Collection(user User, collections []CollectionData, errorMessage string) {
</div> </div>
} }
for _, col := range collections { for _, col := range collections {
<div @click="navigateToCollection($el)" data-href={ "/collections/" + col.ID } class="block"> <div @click="$store.collections.navigateToCollection($el)" data-href={ "/collections/" + col.ID } class="block">
<div <div
class="card p-6 rounded-lg border-l-4 cursor-pointer hover:shadow-lg transition-shadow" class="card p-6 rounded-lg border-l-4 cursor-pointer hover:shadow-lg transition-shadow"
style="background-color: var(--bg-secondary);" style="background-color: var(--bg-secondary);"
@@ -116,7 +116,7 @@ templ CollectionDetail(user User, collection CollectionData, books []handlers.Bo
@Header(user, "/collections") @Header(user, "/collections")
<div class="w-full px-4 sm:px-6 lg:px-8 py-8"> <div class="w-full px-4 sm:px-6 lg:px-8 py-8">
<div class="mb-6"> <div class="mb-6">
<button @click="backToCollections()" class="btn-secondary px-4 py-2 rounded-lg mb-4"> <button @click="$store.collections.backToCollections" class="btn-secondary px-4 py-2 rounded-lg mb-4">
Back to Collections Back to Collections
</button> </button>
<div class="flex items-center gap-4"> <div class="flex items-center gap-4">
@@ -147,13 +147,13 @@ templ CollectionDetail(user User, collection CollectionData, books []handlers.Bo
</div> </div>
<button <button
id="bulk-remove-btn" id="bulk-remove-btn"
@click="removebooksToAdd()" @click="$store.collections.removebooksToAdd"
disabled disabled
class="btn-danger px-4 py-2 rounded-lg disabled:opacity-50 disabled:cursor-not-allowed" class="btn-danger px-4 py-2 rounded-lg disabled:opacity-50 disabled:cursor-not-allowed"
> >
🗑️ Remove Selected 🗑️ Remove Selected
</button> </button>
<button @click="showAddBooksModal()" class="btn-primary px-4 py-2 rounded-lg"> <button @click="$store.collections.showAddBooksModal" class="btn-primary px-4 py-2 rounded-lg">
Add Books Add Books
</button> </button>
</div> </div>
@@ -213,7 +213,7 @@ templ CollectionDetail(user User, collection CollectionData, books []handlers.Bo
<!-- Remove Button --> <!-- Remove Button -->
<div class="mt-3 pt-3 border-t" style="border-color: var(--border);"> <div class="mt-3 pt-3 border-t" style="border-color: var(--border);">
<button <button
@click="removeBook('{ book.MediaItemID }')" @click="$store.collections.removeBook('{ book.MediaItemID }')"
class="px-3 py-1 text-sm border rounded hover:opacity-80" class="px-3 py-1 text-sm border rounded hover:opacity-80"
style="border-color: var(--border); color: var(--text-secondary);" style="border-color: var(--border); color: var(--text-secondary);"
> >
@@ -228,7 +228,7 @@ templ CollectionDetail(user User, collection CollectionData, books []handlers.Bo
<div class="card rounded-lg p-6 w-full max-w-2xl mx-4" style="background-color: var(--bg-secondary); border-color: var(--border);"> <div class="card rounded-lg p-6 w-full max-w-2xl mx-4" style="background-color: var(--bg-secondary); border-color: var(--border);">
<div class="flex justify-between items-center mb-6"> <div class="flex justify-between items-center mb-6">
<h2 class="text-xl font-bold" style="color: var(--text-primary)">Add Books to Collection</h2> <h2 class="text-xl font-bold" style="color: var(--text-primary)">Add Books to Collection</h2>
<button @click="hideAddBooksModal()" class="p-2 hover:opacity-80 rounded" style="color: var(--text-primary)"></button> <button @click="$store.collections.hideAddBooksModal" class="p-2 hover:opacity-80 rounded" style="color: var(--text-primary)"></button>
</div> </div>
<p class="mb-4" style="color: var(--text-secondary)">Search and select books to add to this collection.</p> <p class="mb-4" style="color: var(--text-secondary)">Search and select books to add to this collection.</p>
<!-- Library filter toggle - hidden by default, shown by JS when library_id present --> <!-- Library filter toggle - hidden by default, shown by JS when library_id present -->
@@ -249,10 +249,10 @@ templ CollectionDetail(user User, collection CollectionData, books []handlers.Bo
</div> </div>
<div id="book-results" class="max-h-64 overflow-y-auto mb-4"></div> <div id="book-results" class="max-h-64 overflow-y-auto mb-4"></div>
<div class="flex justify-end space-x-3"> <div class="flex justify-end space-x-3">
<button type="button" @click="hideAddBooksModal()" class="btn-secondary px-4 py-2 rounded-lg"> <button type="button" @click="$store.collections.hideAddBooksModal" class="btn-secondary px-4 py-2 rounded-lg">
Cancel Cancel
</button> </button>
<button type="button" @click="addSelectedBooks()" class="btn-primary px-4 py-2 rounded-lg"> <button type="button" @click="$store.collections.addSelectedBooks" class="btn-primary px-4 py-2 rounded-lg">
Add Selected Books Add Selected Books
</button> </button>
</div> </div>
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
+8 -8
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
@@ -260,7 +260,7 @@ func CollectionCarousel(section handlers.SectionData) templ.Component {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
} }
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "</div><!-- Carousel --><div class=\"carousel-container relative group\"><button class=\"carousel-nav-left absolute left-0 top-1/2 -translate-y-1/2 z-10\n\t\t\t\t\t\t w-12 h-full bg-gradient-to-r from-gray-900 to-transparent\n\t\t\t\t\t\t flex items-center justify-start opacity-0 group-hover:opacity-100\n\t\t\t\t\t\t transition-opacity duration-200\" data-action=\"scroll-carousel\" data-collection-id=\"") templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "</div><!-- Carousel --><div class=\"carousel-container relative group\"><button class=\"carousel-nav-left absolute left-0 top-1/2 -translate-y-1/2 z-10 w-12 h-full bg-gradient-to-r from-gray-900 to-transparent flex items-center justify-start opacity-0 group-hover:opacity-100 transition-opacity duration-200\" data-action=\"scroll-carousel\" data-collection-id=\"")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@@ -286,7 +286,7 @@ func CollectionCarousel(section handlers.SectionData) templ.Component {
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "\" class=\"carousel-track flex gap-4 overflow-x-auto\n\t\t\t\t\t\t\t scroll-smooth snap-x snap-mandatory\n\t\t\t\t\t\t\t px-12 pb-4\" style=\"scrollbar-width: none; -ms-overflow-style: none;\">") templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "\" class=\"carousel-track flex gap-4 overflow-x-auto scroll-smooth snap-x snap-mandatory px-12 pb-4\" style=\"scrollbar-width: none; -ms-overflow-style: none;\">")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@@ -302,7 +302,7 @@ func CollectionCarousel(section handlers.SectionData) templ.Component {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
} }
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "</div><button class=\"carousel-nav-right absolute right-0 top-1/2 -translate-y-1/2 z-10\n\t\t\t\t\t\t w-12 h-full bg-gradient-to-l from-gray-900 to-transparent\n\t\t\t\t\t\t flex items-center justify-end opacity-0 group-hover:opacity-100\n\t\t\t\t\t\t transition-opacity duration-200\" data-action=\"scroll-carousel\" data-collection-id=\"") templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "</div><button class=\"carousel-nav-right absolute right-0 top-1/2 -translate-y-1/2 z-10 w-12 h-full bg-gradient-to-l from-gray-900 to-transparent flex items-center justify-end opacity-0 group-hover:opacity-100 transition-opacity duration-200\" data-action=\"scroll-carousel\" data-collection-id=\"")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@@ -344,7 +344,7 @@ func BookCard(item handlers.BookInfo) templ.Component {
templ_7745c5c3_Var16 = templ.NopComponent templ_7745c5c3_Var16 = templ.NopComponent
} }
ctx = templ.ClearChildren(ctx) ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "<div class=\"book-card flex-shrink-0 w-36 rounded-lg overflow-hidden snap-start cursor-pointer\n\t\t\t\t\ttransition-transform duration-200 hover:scale-105\" data-action=\"view-book\" data-book-id=\"") templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "<div class=\"book-card flex-shrink-0 w-36 rounded-lg overflow-hidden snap-start cursor-pointer transition-transform duration-200 hover:scale-105\" data-action=\"view-book\" data-book-id=\"")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@@ -370,7 +370,7 @@ func BookCard(item handlers.BookInfo) templ.Component {
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "\"><div class=\"aspect-[2/3] overflow-hidden shadow-lg\n\t\t\t\t\t\tbg-gradient-to-br from-gray-700 to-gray-900\">") templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "\"><div class=\"aspect-[2/3] overflow-hidden shadow-lg bg-gradient-to-br from-gray-700 to-gray-900\">")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@@ -494,7 +494,7 @@ func DashboardSettingsModal(sections []handlers.SectionData, hiddenCollections [
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
for _, section := range sections { for _, section := range sections {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "<div class=\"collection-item flex items-center justify-between p-3 rounded border\n\t\t\t\t\t\t\t\t cursor-move select-none\" data-collection-id=\"") templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "<div class=\"collection-item flex items-center justify-between p-3 rounded border cursor-move select-none\" data-collection-id=\"")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@@ -589,7 +589,7 @@ func DashboardSettingsModal(sections []handlers.SectionData, hiddenCollections [
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
} }
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "><div class=\"w-11 h-6 bg-gray-600 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-800 rounded-full peer\n\t\t\t\t\t\t\t\t\t\t peer-checked:after:translate-x-full peer-checked:after:border-white\n\t\t\t\t\t\t\t\t\t\t after:content-[''] after:absolute after:top-[2px] after:left-[2px]\n\t\t\t\t\t\t\t\t\t\t after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all\n\t\t\t\t\t\t\t\t\t\t peer-checked:bg-blue-600\"></div></label></div></div>") templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "><div class=\"w-11 h-6 bg-gray-600 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-800 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600\"></div></label></div></div>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
+12 -12
View File
@@ -70,7 +70,7 @@ templ Header(user User, currentPath string) {
<h3 class="text-sm font-semibold mb-3" style="color: var(--text-primary)">Select Theme</h3> <h3 class="text-sm font-semibold mb-3" style="color: var(--text-primary)">Select Theme</h3>
<div class="space-y-2"> <div class="space-y-2">
<button <button
@click="header.changeThemeTo('tokyo-night'); themeDropdownOpen = false" @click="$store.theme.changeTheme('tokyo-night'); themeDropdownOpen = false"
class="w-full text-left px-3 py-2 rounded hover:opacity-80 transition-opacity" class="w-full text-left px-3 py-2 rounded hover:opacity-80 transition-opacity"
style="color: var(--text-primary); background-color: var(--bg-primary);" style="color: var(--text-primary); background-color: var(--bg-primary);"
> >
@@ -78,7 +78,7 @@ templ Header(user User, currentPath string) {
Tokyo Night Tokyo Night
</button> </button>
<button <button
@click="header.changeThemeTo('dracula'); themeDropdownOpen = false" @click="$store.theme.changeTheme('dracula'); themeDropdownOpen = false"
class="w-full text-left px-3 py-2 rounded hover:opacity-80 transition-opacity" class="w-full text-left px-3 py-2 rounded hover:opacity-80 transition-opacity"
style="color: var(--text-primary); background-color: var(--bg-primary);" style="color: var(--text-primary); background-color: var(--bg-primary);"
> >
@@ -86,7 +86,7 @@ templ Header(user User, currentPath string) {
Dracula Dracula
</button> </button>
<button <button
@click="header.changeThemeTo('nord'); themeDropdownOpen = false" @click="$store.theme.changeTheme('nord'); themeDropdownOpen = false"
class="w-full text-left px-3 py-2 rounded hover:opacity-80 transition-opacity" class="w-full text-left px-3 py-2 rounded hover:opacity-80 transition-opacity"
style="color: var(--text-primary); background-color: var(--bg-primary);" style="color: var(--text-primary); background-color: var(--bg-primary);"
> >
@@ -94,7 +94,7 @@ templ Header(user User, currentPath string) {
Nord Nord
</button> </button>
<button <button
@click="header.changeThemeTo('solarized-dark'); themeDropdownOpen = false" @click="$store.theme.changeTheme('solarized-dark'); themeDropdownOpen = false"
class="w-full text-left px-3 py-2 rounded hover:opacity-80 transition-opacity" class="w-full text-left px-3 py-2 rounded hover:opacity-80 transition-opacity"
style="color: var(--text-primary); background-color: var(--bg-primary);" style="color: var(--text-primary); background-color: var(--bg-primary);"
> >
@@ -102,7 +102,7 @@ templ Header(user User, currentPath string) {
Solarized Dark Solarized Dark
</button> </button>
<button <button
@click="header.changeThemeTo('monokai'); themeDropdownOpen = false" @click="$store.theme.changeTheme('monokai'); themeDropdownOpen = false"
class="w-full text-left px-3 py-2 rounded hover:opacity-80 transition-opacity" class="w-full text-left px-3 py-2 rounded hover:opacity-80 transition-opacity"
style="color: var(--text-primary); background-color: var(--bg-primary);" style="color: var(--text-primary); background-color: var(--bg-primary);"
> >
@@ -110,7 +110,7 @@ templ Header(user User, currentPath string) {
Monokai Monokai
</button> </button>
<button <button
@click="header.changeThemeTo('one-dark-pro'); themeDropdownOpen = false" @click="$store.theme.changeTheme('one-dark-pro'); themeDropdownOpen = false"
class="w-full text-left px-3 py-2 rounded hover:opacity-80 transition-opacity" class="w-full text-left px-3 py-2 rounded hover:opacity-80 transition-opacity"
style="color: var(--text-primary); background-color: var(--bg-primary);" style="color: var(--text-primary); background-color: var(--bg-primary);"
> >
@@ -118,7 +118,7 @@ templ Header(user User, currentPath string) {
One Dark Pro One Dark Pro
</button> </button>
<button <button
@click="header.changeThemeTo('material-dark'); themeDropdownOpen = false" @click="$store.theme.changeTheme('material-dark'); themeDropdownOpen = false"
class="w-full text-left px-3 py-2 rounded hover:opacity-80 transition-opacity" class="w-full text-left px-3 py-2 rounded hover:opacity-80 transition-opacity"
style="color: var(--text-primary); background-color: var(--bg-primary);" style="color: var(--text-primary); background-color: var(--bg-primary);"
> >
@@ -128,7 +128,7 @@ templ Header(user User, currentPath string) {
<div class="border-t pt-2 mt-2" style="border-color: var(--border);"> <div class="border-t pt-2 mt-2" style="border-color: var(--border);">
<p class="text-xs mb-2" style="color: var(--text-secondary)">Bookshelf Background</p> <p class="text-xs mb-2" style="color: var(--text-secondary)">Bookshelf Background</p>
<button <button
@click="woodPaneling.change('none'); themeDropdownOpen = false" @click="$store.theme.changeWoodPaneling('none'); themeDropdownOpen = false"
class="wood-paneling-btn w-full text-left px-3 py-2 rounded hover:opacity-80 transition-opacity" class="wood-paneling-btn w-full text-left px-3 py-2 rounded hover:opacity-80 transition-opacity"
style="color: var(--text-primary);" style="color: var(--text-primary);"
data-wood="none" data-wood="none"
@@ -136,7 +136,7 @@ templ Header(user User, currentPath string) {
None None
</button> </button>
<button <button
@click="woodPaneling.change('wood-light'); themeDropdownOpen = false" @click="$store.theme.changeWoodPaneling('wood-light'); themeDropdownOpen = false"
class="wood-paneling-btn w-full text-left px-3 py-2 rounded hover:opacity-80 transition-opacity" class="wood-paneling-btn w-full text-left px-3 py-2 rounded hover:opacity-80 transition-opacity"
style="color: var(--text-primary);" style="color: var(--text-primary);"
data-wood="wood-light" data-wood="wood-light"
@@ -148,7 +148,7 @@ templ Header(user User, currentPath string) {
Wood Light Wood Light
</button> </button>
<button <button
@click="woodPaneling.change('wood-dark'); themeDropdownOpen = false" @click="$store.theme.changeWoodPaneling('wood-dark'); themeDropdownOpen = false"
class="wood-paneling-btn w-full text-left px-3 py-2 rounded hover:opacity-80 transition-opacity" class="wood-paneling-btn w-full text-left px-3 py-2 rounded hover:opacity-80 transition-opacity"
style="color: var(--text-primary);" style="color: var(--text-primary);"
data-wood="wood-dark" data-wood="wood-dark"
@@ -160,7 +160,7 @@ templ Header(user User, currentPath string) {
Wood Dark Wood Dark
</button> </button>
<button <button
@click="woodPaneling.change('wood-mahogany'); themeDropdownOpen = false" @click="$store.theme.changeWoodPaneling('wood-mahogany'); themeDropdownOpen = false"
class="wood-paneling-btn w-full text-left px-3 py-2 rounded hover:opacity-80 transition-opacity" class="wood-paneling-btn w-full text-left px-3 py-2 rounded hover:opacity-80 transition-opacity"
style="color: var(--text-primary);" style="color: var(--text-primary);"
data-wood="wood-mahogany" data-wood="wood-mahogany"
@@ -208,7 +208,7 @@ templ Header(user User, currentPath string) {
} }
<div class="border-t my-1" style="border-color: var(--border);"></div> <div class="border-t my-1" style="border-color: var(--border);"></div>
<button <button
@click="header.logout(); userMenuOpen = false" @click="$store.header.logout(); userMenuOpen = false"
class="block w-full text-left px-4 py-2 text-sm hover:opacity-80" class="block w-full text-left px-4 py-2 text-sm hover:opacity-80"
style="color: var(--text-primary); background-color: var(--bg-secondary);" style="color: var(--text-primary); background-color: var(--bg-secondary);"
> >
File diff suppressed because one or more lines are too long
+1 -2
View File
@@ -18,7 +18,7 @@ templ Index(loggedIn bool) {
<div class="relative max-w-7xl mx-auto px-4 py-16 sm:px-6 sm:py-24 lg:py-32 lg:px-8"> <div class="relative max-w-7xl mx-auto px-4 py-16 sm:px-6 sm:py-24 lg:py-32 lg:px-8">
<div class="flex justify-between items-start mb-8"> <div class="flex justify-between items-start mb-8">
<div></div> <div></div>
<select id="theme-select" @change="changeTheme()" class="px-3 py-2 border rounded text-sm" style="background-color: var(--bg-secondary); color: var(--text-primary); border-color: var(--border)"> <select id="theme-select" @change="$store.theme.changeTheme" class="px-3 py-2 border rounded text-sm" style="background-color: var(--bg-secondary); color: var(--text-primary); border-color: var(--border)">
<option value="tokyo-night">Tokyo Night</option> <option value="tokyo-night">Tokyo Night</option>
<option value="dracula">Dracula</option> <option value="dracula">Dracula</option>
<option value="nord">Nord</option> <option value="nord">Nord</option>
@@ -120,4 +120,3 @@ templ Index(loggedIn bool) {
</body> </body>
</html> </html>
} }
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
+1 -2
View File
@@ -15,7 +15,7 @@ templ Login(sessionExpired bool, deleted bool) {
<div class="container mx-auto px-4 py-8 max-w-md"> <div class="container mx-auto px-4 py-8 max-w-md">
<div class="flex justify-between items-center mb-8"> <div class="flex justify-between items-center mb-8">
<h1 class="text-3xl font-bold">Login to Bookhoard</h1> <h1 class="text-3xl font-bold">Login to Bookhoard</h1>
<select id="theme-select" @change="changeTheme()" class="px-3 py-2 border rounded" style="background-color: var(--bg-secondary); color: var(--text-primary); border-color: var(--border)"> <select id="theme-select" @change="$store.login.changeTheme()" class="px-3 py-2 border rounded" style="background-color: var(--bg-secondary); color: var(--text-primary); border-color: var(--border)">
<option value="tokyo-night">Tokyo Night</option> <option value="tokyo-night">Tokyo Night</option>
<option value="dracula">Dracula</option> <option value="dracula">Dracula</option>
<option value="nord">Nord</option> <option value="nord">Nord</option>
@@ -64,4 +64,3 @@ templ Login(sessionExpired bool, deleted bool) {
</body> </body>
</html> </html>
} }
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT. // Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977 // templ: version: v0.3.1001
package templates package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present. //lint:file-ignore SA4006 This context is only used if a nested component is present.
+1 -1
View File
@@ -396,7 +396,7 @@ export {
triggerQuickScan, triggerQuickScan,
}; };
Alpine.global("admin", { Alpine.store("admin", {
hideScanProgress, hideScanProgress,
loadSystemStats, loadSystemStats,
loadWatchStatus, loadWatchStatus,
+5
View File
@@ -1,4 +1,5 @@
import { showToast } from "./toast"; import { showToast } from "./toast";
import { Alpine } from "./alpine";
async function loadAnalytics(): Promise<void> { async function loadAnalytics(): Promise<void> {
const token = localStorage.getItem("token"); const token = localStorage.getItem("token");
@@ -124,3 +125,7 @@ function renderPopularBooks(popular: PopularBooksResponse): void {
document.addEventListener("DOMContentLoaded", loadAnalytics); document.addEventListener("DOMContentLoaded", loadAnalytics);
export { loadAnalytics }; export { loadAnalytics };
Alpine.store("analytics", {
loadAnalytics,
});
+1 -1
View File
@@ -132,7 +132,7 @@ export {
tryDocEndpoint, tryDocEndpoint,
}; };
Alpine.global("apiExplorerDoc", { Alpine.store("apiExplorerDoc", {
copyDocRequest, copyDocRequest,
copyDocResponse, copyDocResponse,
generateDocCURL, generateDocCURL,
+1 -1
View File
@@ -99,7 +99,7 @@ export {
handleError, handleError,
}; };
Alpine.global("api", { Alpine.store("api", {
get: apiGet, get: apiGet,
post: apiPost, post: apiPost,
put: apiPut, put: apiPut,
+1 -1
View File
@@ -196,7 +196,7 @@ export {
viewBook, viewBook,
}; };
Alpine.global("bookshelf", { Alpine.store("bookshelf", {
changePage, changePage,
initBookshelf, initBookshelf,
loadBookshelf, loadBookshelf,
+1 -1
View File
@@ -408,7 +408,7 @@ export {
toggleRule, toggleRule,
}; };
Alpine.global("collectionRules", { Alpine.store("collectionRules", {
backToCollection, backToCollection,
clearForm, clearForm,
deleteRule, deleteRule,
+1 -1
View File
@@ -914,7 +914,7 @@ export {
updateSelectedCount, updateSelectedCount,
}; };
Alpine.global("collections", { Alpine.store("collections", {
addbooksToAdd, addbooksToAdd,
backToCollections, backToCollections,
closeCollectionModal, closeCollectionModal,
+1 -1
View File
@@ -216,7 +216,7 @@ export {
showResolveModal, showResolveModal,
}; };
Alpine.global("conflicts", { Alpine.store("conflicts", {
bulkDismiss, bulkDismiss,
bulkResolve, bulkResolve,
dismissAllResolved, dismissAllResolved,
+1 -1
View File
@@ -556,7 +556,7 @@ export {
showShelfMappings, showShelfMappings,
}; };
Alpine.global("devices", { Alpine.store("devices", {
approveDevice, approveDevice,
clearSyncQueue, clearSyncQueue,
copyToClipboard, copyToClipboard,
+2 -2
View File
@@ -93,14 +93,14 @@ document.addEventListener("DOMContentLoaded", () => {
initializeDocsSearch(); initializeDocsSearch();
}); });
Alpine.global("docs", { Alpine.store("docs", {
toggleSidebar, toggleSidebar,
initializeSearch: initializeDocsSearch, initializeSearch: initializeDocsSearch,
}); });
export { toggleSidebar, initializeDocsSearch }; export { toggleSidebar, initializeDocsSearch };
Alpine.global("docs", { Alpine.store("docs", {
toggleSidebar, toggleSidebar,
initializeSearch: initializeDocsSearch, initializeSearch: initializeDocsSearch,
}); });
+2 -29
View File
@@ -1,28 +1,6 @@
// Header functionality // Header functionality
import { Alpine } from "./alpine"; import { Alpine } from "./alpine";
import { applyTheme } from "./theme";
import { updateThemeIndicators } from "./themeDropdown";
const changeTheme = (theme: string): void => {
// Apply the theme using the consolidated function from theme.ts
applyTheme(theme);
// Save to server if logged in
const token = localStorage.getItem("token");
if (token) {
fetch("/api/auth/theme", {
method: "PUT",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({ theme }),
}).catch((err) => console.log("Theme save failed", err));
}
// Alpine closes dropdown automatically via template state
};
const logout = (): void => { const logout = (): void => {
localStorage.removeItem("token"); localStorage.removeItem("token");
@@ -30,13 +8,8 @@ const logout = (): void => {
window.location.href = "/"; window.location.href = "/";
}; };
export { changeTheme, logout }; export { logout };
Alpine.global("header", { Alpine.store("header", {
logout, logout,
changeThemeTo: (theme: string) => {
console.log("changeThemeTo called with:", theme);
changeTheme(theme);
updateThemeIndicators();
},
}); });
+1 -1
View File
@@ -43,7 +43,7 @@ async function checkAuthRedirect(): Promise<void> {
export { changeTheme, checkAuthRedirect, initIndexTheme }; export { changeTheme, checkAuthRedirect, initIndexTheme };
Alpine.global("index", { Alpine.store("index", {
changeTheme, changeTheme,
checkAuthRedirect, checkAuthRedirect,
initIndexTheme, initIndexTheme,
+1 -1
View File
@@ -680,7 +680,7 @@ export {
confirmDeleteLibrary, confirmDeleteLibrary,
}; };
Alpine.global("library", { Alpine.store("library", {
deleteLibrary, deleteLibrary,
showLibraryFolders, showLibraryFolders,
addLibraryFolder, addLibraryFolder,
+1 -1
View File
@@ -201,7 +201,7 @@ export {
showSuggestionsModal, showSuggestionsModal,
}; };
Alpine.global("linking", { Alpine.store("linking", {
autoLinkBooks, autoLinkBooks,
getSuggestions, getSuggestions,
hideMatchModal, hideMatchModal,
+1 -1
View File
@@ -22,7 +22,7 @@ function changeTheme(): void {
export { changeTheme, initLoginTheme }; export { changeTheme, initLoginTheme };
Alpine.global("login", { Alpine.store("login", {
changeTheme, changeTheme,
initLoginTheme, initLoginTheme,
}); });
+1 -1
View File
@@ -189,6 +189,6 @@ function initPasswordValidation(): void {
// Export for use in template // Export for use in template
export { initPasswordValidation }; export { initPasswordValidation };
Alpine.global("validation", { Alpine.store("validation", {
initPasswordValidation, initPasswordValidation,
}); });
+1 -1
View File
@@ -26,7 +26,7 @@ function setupProfileModal(): void {
export { closeProfileModal, setupProfileModal }; export { closeProfileModal, setupProfileModal };
Alpine.global("profileModal", { Alpine.store("profileModal", {
closeProfileModal, closeProfileModal,
setupProfileModal, setupProfileModal,
}); });
+1 -1
View File
@@ -41,6 +41,6 @@ async function confirmDeleteAccount(): Promise<void> {
export { confirmDeleteAccount }; export { confirmDeleteAccount };
Alpine.global("profile", { Alpine.store("profile", {
confirmDeleteAccount, confirmDeleteAccount,
}); });
+1 -1
View File
@@ -164,7 +164,7 @@ export {
retryQueueItem, retryQueueItem,
}; };
Alpine.global("queue", { Alpine.store("queue", {
clearAllItems, clearAllItems,
clearFailedItems, clearFailedItems,
deleteQueueItem, deleteQueueItem,
+1 -1
View File
@@ -11,6 +11,6 @@ function initRegisterTheme(): void {
export { initRegisterTheme }; export { initRegisterTheme };
Alpine.global("register", { Alpine.store("register", {
initRegisterTheme, initRegisterTheme,
}); });
+1 -1
View File
@@ -307,6 +307,6 @@ document.addEventListener("DOMContentLoaded", initializeSearch);
export { selectLibraryAndBook }; export { selectLibraryAndBook };
Alpine.global("search", { Alpine.store("search", {
selectLibraryAndBook, selectLibraryAndBook,
}); });
+104 -10
View File
@@ -1,3 +1,4 @@
import { Alpine } from "./alpine";
// Theme management functionality // Theme management functionality
type ThemeType = type ThemeType =
@@ -37,14 +38,8 @@ const loadTheme = (): void => {
applyTheme(theme); applyTheme(theme);
}; };
// Handle theme change from user selection // Change: Remove DOM element lookup, accept theme as parameter
const changeTheme = async (): Promise<void> => { const changeTheme = async (theme: string): Promise<void> => {
const themeSelect = document.getElementById(
"theme-select",
) as HTMLSelectElement;
if (!themeSelect) return;
const theme = themeSelect.value as ThemeType;
applyTheme(theme); applyTheme(theme);
// Save to server if logged in // Save to server if logged in
@@ -128,14 +123,113 @@ const setupSmoothScroll = (): void => {
}); });
}; };
// Wood paneling management functionality
type WoodPanelingType = "none" | "wood-light" | "wood-dark" | "wood-mahogany";
const WOOD_STORAGE_KEY = "wood-paneling";
// Apply wood paneling to collections container
const applyWoodPaneling = (paneling: WoodPanelingType): void => {
const container = document.getElementById("collections-container");
const body = document.body;
if (!container || !body) return;
// Remove all wood background classes from container
container.classList.remove(
"bg-wood-light",
"bg-wood-dark",
"bg-wood-mahogany",
);
container.removeAttribute("data-wood");
// Remove from body
body.classList.remove("bg-wood-light", "bg-wood-dark", "bg-wood-mahogany");
if (paneling !== "none") {
// Add selected wood background class to both container and body
const woodClass = `bg-${paneling}`;
container.classList.add(woodClass);
container.setAttribute("data-wood", paneling);
// Add to body for overscroll area
body.classList.add(woodClass);
}
// Save to localStorage
localStorage.setItem(WOOD_STORAGE_KEY, paneling);
};
// Load wood paneling from localStorage on page load
const loadWoodPaneling = (): void => {
const stored = localStorage.getItem(
WOOD_STORAGE_KEY,
) as WoodPanelingType | null;
if (stored) {
applyWoodPaneling(stored);
} else {
// Default to none
applyWoodPaneling("none");
}
};
// Change wood paneling (called from theme dropdown)
const changeWoodPaneling = (paneling: WoodPanelingType): void => {
applyWoodPaneling(paneling);
// Update active indicators
updateWoodPanelingIndicators();
// Alpine closes dropdown automatically via template state
};
// Update visual indicators for wood paneling buttons
const updateWoodPanelingIndicators = (): void => {
const currentWood = localStorage.getItem(WOOD_STORAGE_KEY) || "none";
// Update wood paneling buttons
document.querySelectorAll(".wood-paneling-btn").forEach((btn) => {
const wood = btn.getAttribute("data-wood");
if (wood === currentWood) {
// Active state - use CSS class instead of inline style
btn.classList.add("bg-wood-active");
btn.classList.remove("bg-wood-inactive");
} else {
// Inactive state
btn.classList.remove("bg-wood-active");
btn.classList.add("bg-wood-inactive");
}
});
};
// Auto-initialize when DOM is ready // Auto-initialize when DOM is ready
if (typeof document !== "undefined") { if (typeof document !== "undefined") {
if (document.readyState === "loading") { if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initializeTheme); document.addEventListener("DOMContentLoaded", () => {
initializeTheme();
loadWoodPaneling();
updateWoodPanelingIndicators();
});
} else { } else {
initializeTheme(); initializeTheme();
loadWoodPaneling();
updateWoodPanelingIndicators();
} }
} }
export { applyTheme, changeTheme, initializeTheme, loadTheme, loadUserTheme }; Alpine.store("theme", {
changeTheme,
changeWoodPaneling,
});
export {
applyTheme,
changeTheme,
changeWoodPaneling,
initializeTheme,
loadTheme,
loadUserTheme,
loadWoodPaneling,
updateWoodPanelingIndicators,
};
export type { ThemeType }; export type { ThemeType };
-28
View File
@@ -1,28 +0,0 @@
// Theme dropdown active indicator management
import { Alpine } from "./alpine";
import { updateWoodPanelingIndicators } from "./woodPaneling";
// Update visual indicators for theme buttons
// Note: With Alpine.js, most theme state is handled reactively in the template
// This function primarily ensures wood paneling indicators are updated
const updateThemeIndicators = (): void => {
updateWoodPanelingIndicators();
};
// Auto-initialize when DOM is ready
if (typeof document !== "undefined") {
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", () => {
updateThemeIndicators();
});
} else {
updateThemeIndicators();
}
}
Alpine.global("themeDropdown", {
updateIndicators: updateThemeIndicators,
});
export { updateThemeIndicators };
+1 -1
View File
@@ -30,6 +30,6 @@ function showErrorToast(message: string): void {
export { showErrorToast }; export { showErrorToast };
Alpine.global("toastError", { Alpine.store("toastError", {
showErrorToast, showErrorToast,
}); });
+1 -1
View File
@@ -226,7 +226,7 @@ if (typeof document !== "undefined") {
} }
// Export toast API for manual use // Export toast API for manual use
Alpine.global("showToast", { Alpine.store("showToast", {
error: (message: string, duration?: number) => error: (message: string, duration?: number) =>
showToast(message, "error", duration), showToast(message, "error", duration),
success: (message: string, duration?: number) => success: (message: string, duration?: number) =>
+1 -1
View File
@@ -427,7 +427,7 @@ export {
toggleAllUnlinked, toggleAllUnlinked,
}; };
Alpine.global("unlinkedBooks", { Alpine.store("unlinkedBooks", {
bulkAutoLink, bulkAutoLink,
bulkGetSuggestions, bulkGetSuggestions,
confirmManualLink, confirmManualLink,
-100
View File
@@ -1,100 +0,0 @@
// Wood paneling management functionality
import { Alpine } from "./alpine";
type WoodPanelingType = "none" | "wood-light" | "wood-dark" | "wood-mahogany";
const WOOD_STORAGE_KEY = "wood-paneling";
// Apply wood paneling to collections container
const applyWoodPaneling = (paneling: WoodPanelingType): void => {
const container = document.getElementById("collections-container");
const body = document.body;
if (!container || !body) return;
// Remove all wood background classes from container
container.classList.remove(
"bg-wood-light",
"bg-wood-dark",
"bg-wood-mahogany",
);
container.removeAttribute("data-wood");
// Remove from body
body.classList.remove("bg-wood-light", "bg-wood-dark", "bg-wood-mahogany");
if (paneling !== "none") {
// Add selected wood background class to both container and body
const woodClass = `bg-${paneling}`;
container.classList.add(woodClass);
container.setAttribute("data-wood", paneling);
// Add to body for overscroll area
body.classList.add(woodClass);
}
// Save to localStorage
localStorage.setItem(WOOD_STORAGE_KEY, paneling);
};
// Load wood paneling from localStorage on page load
const loadWoodPaneling = (): void => {
const stored = localStorage.getItem(
WOOD_STORAGE_KEY,
) as WoodPanelingType | null;
if (stored) {
applyWoodPaneling(stored);
} else {
// Default to none
applyWoodPaneling("none");
}
};
// Change wood paneling (called from theme dropdown)
const changeWoodPaneling = (paneling: WoodPanelingType): void => {
applyWoodPaneling(paneling);
// Update active indicators
updateWoodPanelingIndicators();
// Alpine closes dropdown automatically via template state
};
// Update visual indicators for wood paneling buttons
const updateWoodPanelingIndicators = (): void => {
const currentWood = localStorage.getItem(WOOD_STORAGE_KEY) || "none";
// Update wood paneling buttons
document.querySelectorAll(".wood-paneling-btn").forEach((btn) => {
const wood = btn.getAttribute("data-wood");
if (wood === currentWood) {
// Active state - use CSS class instead of inline style
btn.classList.add("bg-wood-active");
btn.classList.remove("bg-wood-inactive");
} else {
// Inactive state
btn.classList.remove("bg-wood-active");
btn.classList.add("bg-wood-inactive");
}
});
};
export { changeWoodPaneling, loadWoodPaneling, updateWoodPanelingIndicators };
// Register with Alpine for template access
Alpine.global("woodPaneling", {
change: changeWoodPaneling,
});
// Auto-initialize when DOM is ready
if (typeof document !== "undefined") {
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", () => {
loadWoodPaneling();
updateWoodPanelingIndicators();
});
} else {
loadWoodPaneling();
updateWoodPanelingIndicators();
}
}