Update all page templates to accept an optional error message parameter and display it via the ErrorToast component when data loading fails.
169 lines
7.2 KiB
Templ
169 lines
7.2 KiB
Templ
package templates
|
|
|
|
templ CustomSectionBuilder(user User, libraries []LibraryData, errorMessage string) {
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Create Custom Section - Bookhoard</title>
|
|
<script src="/static/htmx.min.js"></script>
|
|
<script src="/static/toast.js"></script>
|
|
<script src="/static/api.js"></script>
|
|
<script src="/static/custom-section-builder.js"></script>
|
|
<link href="/static/style.css" rel="stylesheet">
|
|
</head>
|
|
<body class="theme-{ user.Theme }">
|
|
@Header(user, "/custom-section")
|
|
|
|
<main class="max-w-4xl mx-auto px-4 py-8">
|
|
<h1 class="text-3xl font-bold mb-2" style="color: var(--text-primary)">Create Custom Section</h1>
|
|
<p class="mb-6" style="color: var(--text-secondary)">Build a custom dashboard section by defining filter rules or manually selecting books.</p>
|
|
|
|
<form id="custom-section-form" class="space-y-6">
|
|
<!-- Section Details -->
|
|
<div class="p-4 rounded-lg" style="background-color: var(--bg-secondary);">
|
|
<h2 class="text-xl font-semibold mb-4" style="color: var(--text-primary)">Section Details</h2>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div>
|
|
<label class="block text-sm font-medium mb-2" style="color: var(--text-secondary)">Name *</label>
|
|
<input type="text" id="section-name" name="name" required
|
|
class="w-full px-4 py-2 rounded-lg border focus:ring-2 focus:ring-blue-500"
|
|
style="background-color: var(--bg-primary); color: var(--text-primary); border-color: var(--border);">
|
|
</div>
|
|
|
|
<div>
|
|
<label class="block text-sm font-medium mb-2" style="color: var(--text-secondary)">Icon (emoji)</label>
|
|
<input type="text" id="section-icon" name="icon" maxlength="4"
|
|
class="w-full px-4 py-2 rounded-lg border focus:ring-2 focus:ring-blue-500"
|
|
style="background-color: var(--bg-primary); color: var(--text-primary); border-color: var(--border);"
|
|
placeholder="📚">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-4">
|
|
<label class="block text-sm font-medium mb-2" style="color: var(--text-secondary)">Description</label>
|
|
<textarea id="section-description" name="description" rows="2"
|
|
class="w-full px-4 py-2 rounded-lg border focus:ring-2 focus:ring-blue-500"
|
|
style="background-color: var(--bg-primary); color: var(--text-primary); border-color: var(--border);"></textarea>
|
|
</div>
|
|
|
|
<div class="mt-4">
|
|
<label class="block text-sm font-medium mb-2" style="color: var(--text-secondary)">Library *</label>
|
|
<select id="section-library" name="library_id" required
|
|
class="w-full px-4 py-2 rounded-lg border focus:ring-2 focus:ring-blue-500"
|
|
style="background-color: var(--bg-primary); color: var(--text-primary); border-color: var(--border);">
|
|
<option value="">Select a library...</option>
|
|
for _, lib := range libraries {
|
|
<option value={ lib.ID }>{ lib.Name }</option>
|
|
}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Filter Rules -->
|
|
<div class="p-4 rounded-lg" style="background-color: var(--bg-secondary);">
|
|
<div class="flex items-center justify-between mb-4">
|
|
<h2 class="text-xl font-semibold" style="color: var(--text-primary)">Filter Rules</h2>
|
|
<button type="button" id="add-rule-btn"
|
|
class="px-3 py-1 rounded-lg text-sm font-medium"
|
|
style="background-color: var(--accent);">
|
|
+ Add Rule
|
|
</button>
|
|
</div>
|
|
|
|
<p class="text-sm mb-4" style="color: var(--text-secondary)">
|
|
Books matching these rules will be automatically added to your section. Use AND for all rules, OR for any rule.
|
|
</p>
|
|
|
|
<div id="rules-container" class="space-y-3">
|
|
</div>
|
|
|
|
<div class="mt-4 flex items-center gap-2">
|
|
<label class="text-sm font-medium" style="color: var(--text-secondary)">Match:</label>
|
|
<select id="match-type" name="match_type"
|
|
class="px-3 py-1 rounded border"
|
|
style="background-color: var(--bg-primary); color: var(--text-primary); border-color: var(--border);">
|
|
<option value="all">ALL rules (AND)</option>
|
|
<option value="any">ANY rule (OR)</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Manual Book Selection -->
|
|
<div class="p-4 rounded-lg" style="background-color: var(--bg-secondary);">
|
|
<h2 class="text-xl font-semibold mb-4" style="color: var(--text-primary)">Manual Book Selection</h2>
|
|
<p class="text-sm mb-4" style="color: var(--text-secondary)">
|
|
Add specific books to this section. Use the search to find and select multiple books.
|
|
</p>
|
|
|
|
<div class="mb-4">
|
|
<label class="block text-sm font-medium mb-2" style="color: var(--text-secondary)">Search Books</label>
|
|
<div class="flex gap-2">
|
|
<input type="text" id="book-search" name="book_search"
|
|
class="flex-1 px-4 py-2 rounded-lg border focus:ring-2 focus:ring-blue-500"
|
|
style="background-color: var(--bg-primary); color: var(--text-primary); border-color: var(--border);"
|
|
placeholder="Search by title or author..."
|
|
autocomplete="off">
|
|
<button type="button" id="search-books-btn"
|
|
class="px-4 py-2 rounded-lg font-medium"
|
|
style="background-color: var(--accent);">
|
|
Search
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="search-results" class="hidden mb-4 p-3 rounded-lg max-h-60 overflow-y-auto"
|
|
style="background-color: var(--bg-primary);">
|
|
</div>
|
|
|
|
<div class="mb-4">
|
|
<label class="block text-sm font-medium mb-2" style="color: var(--text-secondary)">Selected Books</label>
|
|
<div id="selected-books" class="min-h-[60px] p-3 rounded-lg border-2 border-dashed"
|
|
style="border-color: var(--border); background-color: var(--bg-primary);">
|
|
<p class="text-sm text-center" style="color: var(--text-secondary);">No books selected</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Live Preview -->
|
|
<div class="p-4 rounded-lg" style="background-color: var(--bg-secondary);">
|
|
<div class="flex items-center justify-between mb-4">
|
|
<h2 class="text-xl font-semibold" style="color: var(--text-primary)">Live Preview</h2>
|
|
<button type="button" id="preview-btn"
|
|
class="px-4 py-2 rounded-lg font-medium"
|
|
style="background-color: var(--accent);">
|
|
Refresh Preview
|
|
</button>
|
|
</div>
|
|
|
|
<div id="preview-container" class="p-4 rounded-lg"
|
|
style="background-color: var(--bg-primary); min-height: 200px;">
|
|
<p class="text-center" style="color: var(--text-secondary);">
|
|
Add filter rules or select books to see a preview of your custom section.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Form Actions -->
|
|
<div class="flex justify-end gap-3">
|
|
<button type="button" id="cancel-btn"
|
|
class="px-6 py-2 rounded-lg font-medium border hover:opacity-80"
|
|
style="border-color: var(--border); color: var(--text-primary); background-color: var(--bg-secondary);">
|
|
Cancel
|
|
</button>
|
|
<button type="submit" id="save-section-btn"
|
|
class="px-6 py-2 rounded-lg font-medium text-white hover:opacity-90"
|
|
style="background-color: var(--accent);">
|
|
Save Section
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</main>
|
|
|
|
@ErrorToast(errorMessage)
|
|
</body>
|
|
</html>
|
|
}
|