Safety backup before Path A fixes - fixing function mismatches and missing functions
This commit is contained in:
@@ -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,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,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,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.
|
||||||
|
|||||||
@@ -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,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.
|
||||||
|
|||||||
@@ -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,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,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.
|
||||||
|
|||||||
@@ -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,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,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.
|
||||||
@@ -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,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,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
@@ -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
@@ -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,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.
|
||||||
|
|||||||
@@ -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,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,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,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,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,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
@@ -396,7 +396,7 @@ export {
|
|||||||
triggerQuickScan,
|
triggerQuickScan,
|
||||||
};
|
};
|
||||||
|
|
||||||
Alpine.global("admin", {
|
Alpine.store("admin", {
|
||||||
hideScanProgress,
|
hideScanProgress,
|
||||||
loadSystemStats,
|
loadSystemStats,
|
||||||
loadWatchStatus,
|
loadWatchStatus,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
});
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ export {
|
|||||||
tryDocEndpoint,
|
tryDocEndpoint,
|
||||||
};
|
};
|
||||||
|
|
||||||
Alpine.global("apiExplorerDoc", {
|
Alpine.store("apiExplorerDoc", {
|
||||||
copyDocRequest,
|
copyDocRequest,
|
||||||
copyDocResponse,
|
copyDocResponse,
|
||||||
generateDocCURL,
|
generateDocCURL,
|
||||||
|
|||||||
+1
-1
@@ -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,
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ export {
|
|||||||
viewBook,
|
viewBook,
|
||||||
};
|
};
|
||||||
|
|
||||||
Alpine.global("bookshelf", {
|
Alpine.store("bookshelf", {
|
||||||
changePage,
|
changePage,
|
||||||
initBookshelf,
|
initBookshelf,
|
||||||
loadBookshelf,
|
loadBookshelf,
|
||||||
|
|||||||
@@ -408,7 +408,7 @@ export {
|
|||||||
toggleRule,
|
toggleRule,
|
||||||
};
|
};
|
||||||
|
|
||||||
Alpine.global("collectionRules", {
|
Alpine.store("collectionRules", {
|
||||||
backToCollection,
|
backToCollection,
|
||||||
clearForm,
|
clearForm,
|
||||||
deleteRule,
|
deleteRule,
|
||||||
|
|||||||
@@ -914,7 +914,7 @@ export {
|
|||||||
updateSelectedCount,
|
updateSelectedCount,
|
||||||
};
|
};
|
||||||
|
|
||||||
Alpine.global("collections", {
|
Alpine.store("collections", {
|
||||||
addbooksToAdd,
|
addbooksToAdd,
|
||||||
backToCollections,
|
backToCollections,
|
||||||
closeCollectionModal,
|
closeCollectionModal,
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ export {
|
|||||||
showResolveModal,
|
showResolveModal,
|
||||||
};
|
};
|
||||||
|
|
||||||
Alpine.global("conflicts", {
|
Alpine.store("conflicts", {
|
||||||
bulkDismiss,
|
bulkDismiss,
|
||||||
bulkResolve,
|
bulkResolve,
|
||||||
dismissAllResolved,
|
dismissAllResolved,
|
||||||
|
|||||||
@@ -556,7 +556,7 @@ export {
|
|||||||
showShelfMappings,
|
showShelfMappings,
|
||||||
};
|
};
|
||||||
|
|
||||||
Alpine.global("devices", {
|
Alpine.store("devices", {
|
||||||
approveDevice,
|
approveDevice,
|
||||||
clearSyncQueue,
|
clearSyncQueue,
|
||||||
copyToClipboard,
|
copyToClipboard,
|
||||||
|
|||||||
+2
-2
@@ -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
@@ -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
@@ -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
@@ -680,7 +680,7 @@ export {
|
|||||||
confirmDeleteLibrary,
|
confirmDeleteLibrary,
|
||||||
};
|
};
|
||||||
|
|
||||||
Alpine.global("library", {
|
Alpine.store("library", {
|
||||||
deleteLibrary,
|
deleteLibrary,
|
||||||
showLibraryFolders,
|
showLibraryFolders,
|
||||||
addLibraryFolder,
|
addLibraryFolder,
|
||||||
|
|||||||
+1
-1
@@ -201,7 +201,7 @@ export {
|
|||||||
showSuggestionsModal,
|
showSuggestionsModal,
|
||||||
};
|
};
|
||||||
|
|
||||||
Alpine.global("linking", {
|
Alpine.store("linking", {
|
||||||
autoLinkBooks,
|
autoLinkBooks,
|
||||||
getSuggestions,
|
getSuggestions,
|
||||||
hideMatchModal,
|
hideMatchModal,
|
||||||
|
|||||||
+1
-1
@@ -22,7 +22,7 @@ function changeTheme(): void {
|
|||||||
|
|
||||||
export { changeTheme, initLoginTheme };
|
export { changeTheme, initLoginTheme };
|
||||||
|
|
||||||
Alpine.global("login", {
|
Alpine.store("login", {
|
||||||
changeTheme,
|
changeTheme,
|
||||||
initLoginTheme,
|
initLoginTheme,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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
@@ -41,6 +41,6 @@ async function confirmDeleteAccount(): Promise<void> {
|
|||||||
|
|
||||||
export { confirmDeleteAccount };
|
export { confirmDeleteAccount };
|
||||||
|
|
||||||
Alpine.global("profile", {
|
Alpine.store("profile", {
|
||||||
confirmDeleteAccount,
|
confirmDeleteAccount,
|
||||||
});
|
});
|
||||||
|
|||||||
+1
-1
@@ -164,7 +164,7 @@ export {
|
|||||||
retryQueueItem,
|
retryQueueItem,
|
||||||
};
|
};
|
||||||
|
|
||||||
Alpine.global("queue", {
|
Alpine.store("queue", {
|
||||||
clearAllItems,
|
clearAllItems,
|
||||||
clearFailedItems,
|
clearFailedItems,
|
||||||
deleteQueueItem,
|
deleteQueueItem,
|
||||||
|
|||||||
+1
-1
@@ -11,6 +11,6 @@ function initRegisterTheme(): void {
|
|||||||
|
|
||||||
export { initRegisterTheme };
|
export { initRegisterTheme };
|
||||||
|
|
||||||
Alpine.global("register", {
|
Alpine.store("register", {
|
||||||
initRegisterTheme,
|
initRegisterTheme,
|
||||||
});
|
});
|
||||||
|
|||||||
+1
-1
@@ -307,6 +307,6 @@ document.addEventListener("DOMContentLoaded", initializeSearch);
|
|||||||
|
|
||||||
export { selectLibraryAndBook };
|
export { selectLibraryAndBook };
|
||||||
|
|
||||||
Alpine.global("search", {
|
Alpine.store("search", {
|
||||||
selectLibraryAndBook,
|
selectLibraryAndBook,
|
||||||
});
|
});
|
||||||
|
|||||||
+104
-10
@@ -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 };
|
||||||
|
|||||||
@@ -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 };
|
|
||||||
@@ -30,6 +30,6 @@ function showErrorToast(message: string): void {
|
|||||||
|
|
||||||
export { showErrorToast };
|
export { showErrorToast };
|
||||||
|
|
||||||
Alpine.global("toastError", {
|
Alpine.store("toastError", {
|
||||||
showErrorToast,
|
showErrorToast,
|
||||||
});
|
});
|
||||||
|
|||||||
+1
-1
@@ -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) =>
|
||||||
|
|||||||
@@ -427,7 +427,7 @@ export {
|
|||||||
toggleAllUnlinked,
|
toggleAllUnlinked,
|
||||||
};
|
};
|
||||||
|
|
||||||
Alpine.global("unlinkedBooks", {
|
Alpine.store("unlinkedBooks", {
|
||||||
bulkAutoLink,
|
bulkAutoLink,
|
||||||
bulkGetSuggestions,
|
bulkGetSuggestions,
|
||||||
confirmManualLink,
|
confirmManualLink,
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user