feat(metadata-editor): replace tags text input with badge picker + autocomplete

Replace the comma-separated text input for tags in the metadata editor
with a badge-based tag picker:
- Current tags shown as removable pill badges (✕ button per tag)
- Autocomplete input queries existing tags via shared tag-dropdown module
- Results shown as inline dropdown (not absolute, avoids overflow clipping
  from the modal's overflow-y-auto content area)
- Keyboard navigation: ArrowUp/Down, Enter to select, comma to add new,
  Escape to close
- Supports adding new tags not in the database (type + Enter/comma)
- Hidden data-editor-tag spans seed initial tags from server-side render
- collectFormData() now accepts editorTags array, skips the removed
  tags text input
This commit is contained in:
2026-05-10 16:13:07 -04:00
parent 46e0744802
commit 504f145f64
3 changed files with 440 additions and 312 deletions
+42 -2
View File
@@ -267,10 +267,50 @@ templ MetadataEditorModal(book handlers.MediaDetail) {
>{ textToString(book.Summary) }</textarea>
</div>
<div>
<label class="block text-sm font-medium mb-1" style="color: var(--text-secondary);">Tags (comma-separated)</label>
<input type="text" name="tags" value={ tagSliceToString(book.Tags) }
<label class="block text-sm font-medium mb-1" style="color: var(--text-secondary);">Tags</label>
<div class="flex flex-wrap gap-1.5 mb-2">
<template x-for="(tag, idx) in editorTags" :key="idx">
<span
class="inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium"
style="background-color: var(--accent); color: white;"
>
<span x-text="tag"></span>
<button type="button" class="hover:opacity-70 leading-none" @click="removeEditorTag(idx)"></button>
</span>
</template>
</div>
for _, tag := range book.Tags {
<span data-editor-tag={ tag } class="hidden"></span>
}
<div>
<input type="text"
x-model="tagSearch"
@input.debounce.300ms="searchEditorTags()"
@keydown="onTagKeydown($event)"
@blur="hideEditorTagDropdown()"
placeholder="Add tag..."
class="w-full px-3 py-2 rounded-lg border text-sm"
style="background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);" />
<div
x-show="showTagDropdown"
x-transition
class="mt-1 w-full rounded-lg shadow-lg border max-h-48 overflow-y-auto"
style="background-color: var(--bg-primary); border-color: var(--border);"
>
<template x-for="sug in tagSuggestions" :key="sug.value">
<button
type="button"
class="w-full text-left px-3 py-2 text-sm flex justify-between items-center"
:class="highlightedTagIndex === tagSuggestions.indexOf(sug) ? 'opacity-80' : ''"
:style="highlightedTagIndex === tagSuggestions.indexOf(sug) ? 'background-color: var(--bg-secondary); color: var(--text-primary);' : 'color: var(--text-primary);'"
@click="selectEditorTagSuggestion(sug.value)"
>
<span x-text="sug.value"></span>
<span class="text-xs" style="color: var(--text-secondary);" x-text="sug.count + ' books'"></span>
</button>
</template>
</div>
</div>
</div>
<div>
<label class="block text-sm font-medium mb-1" style="color: var(--text-secondary);">Community Rating (0-10)</label>
+153 -143
View File
@@ -1,6 +1,6 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.1001
// templ: version: v0.3.1020
package templates
//lint:file-ignore SA4006 This context is only used if a nested component is present.
@@ -354,11 +354,11 @@ func MetadataEditorModal(book handlers.MediaDetail) templ.Component {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var19 string
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(book.CoverImagePath.String)
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.ResolveAttributeValue(book.CoverImagePath.String)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 184, Col: 40}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var19)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -367,11 +367,11 @@ func MetadataEditorModal(book handlers.MediaDetail) templ.Component {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var20 string
templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(book.Title)
templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.ResolveAttributeValue(book.Title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 185, Col: 24}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var20)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -385,11 +385,11 @@ func MetadataEditorModal(book handlers.MediaDetail) templ.Component {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var21 string
templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(book.Title)
templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.ResolveAttributeValue(book.Title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 191, Col: 24}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var21)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -403,11 +403,11 @@ func MetadataEditorModal(book handlers.MediaDetail) templ.Component {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var22 string
templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(book.Title)
templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.ResolveAttributeValue(book.Title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 245, Col: 58}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var22)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -416,11 +416,11 @@ func MetadataEditorModal(book handlers.MediaDetail) templ.Component {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var23 string
templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(textToString(book.Author))
templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.ResolveAttributeValue(textToString(book.Author))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 251, Col: 74}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var23)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -450,448 +450,458 @@ func MetadataEditorModal(book handlers.MediaDetail) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "</textarea></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Tags (comma-separated)</label> <input type=\"text\" name=\"tags\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "</textarea></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Tags</label><div class=\"flex flex-wrap gap-1.5 mb-2\"><template x-for=\"(tag, idx) in editorTags\" :key=\"idx\"><span class=\"inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium\" style=\"background-color: var(--accent); color: white;\"><span x-text=\"tag\"></span> <button type=\"button\" class=\"hover:opacity-70 leading-none\" @click=\"removeEditorTag(idx)\">✕</button></span></template></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, tag := range book.Tags {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "<span data-editor-tag=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var26 string
templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(tagSliceToString(book.Tags))
templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.ResolveAttributeValue(tag)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 271, Col: 74}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 283, Col: 36}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var26)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Community Rating (0-10)</label> <input type=\"number\" name=\"community_rating\" min=\"0\" max=\"10\" step=\"0.1\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "\" class=\"hidden\"></span>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "<div><input type=\"text\" x-model=\"tagSearch\" @input.debounce.300ms=\"searchEditorTags()\" @keydown=\"onTagKeydown($event)\" @blur=\"hideEditorTagDropdown()\" placeholder=\"Add tag...\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"><div x-show=\"showTagDropdown\" x-transition class=\"mt-1 w-full rounded-lg shadow-lg border max-h-48 overflow-y-auto\" style=\"background-color: var(--bg-primary); border-color: var(--border);\"><template x-for=\"sug in tagSuggestions\" :key=\"sug.value\"><button type=\"button\" class=\"w-full text-left px-3 py-2 text-sm flex justify-between items-center\" :class=\"highlightedTagIndex === tagSuggestions.indexOf(sug) ? 'opacity-80' : ''\" :style=\"highlightedTagIndex === tagSuggestions.indexOf(sug) ? 'background-color: var(--bg-secondary); color: var(--text-primary);' : 'color: var(--text-primary);'\" @click=\"selectEditorTagSuggestion(sug.value)\"><span x-text=\"sug.value\"></span> <span class=\"text-xs\" style=\"color: var(--text-secondary);\" x-text=\"sug.count + ' books'\"></span></button></template></div></div></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Community Rating (0-10)</label> <input type=\"number\" name=\"community_rating\" min=\"0\" max=\"10\" step=\"0.1\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var27 string
templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%.1f", book.CommunityRating.Float64))
templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.ResolveAttributeValue(fmt.Sprintf("%.1f", book.CommunityRating.Float64))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 278, Col: 66}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 318, Col: 66}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var27)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div></div></div><!-- Publication --><div class=\"border rounded-lg\" style=\"border-color: var(--border);\"><button type=\"button\" class=\"w-full px-4 py-3 flex justify-between items-center\" style=\"color: var(--text-primary); background-color: var(--bg-primary);\" @click=\"toggleSection('publication')\"><span class=\"font-semibold\">Publication</span> <span x-text=\"openSections.publication ? '▾' : '▸'\">▸</span></button><div x-show=\"openSections.publication\" x-transition class=\"p-4 space-y-3\" style=\"background-color: var(--bg-primary);\"><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Publisher</label> <input type=\"text\" name=\"publisher\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div></div></div><!-- Publication --><div class=\"border rounded-lg\" style=\"border-color: var(--border);\"><button type=\"button\" class=\"w-full px-4 py-3 flex justify-between items-center\" style=\"color: var(--text-primary); background-color: var(--bg-primary);\" @click=\"toggleSection('publication')\"><span class=\"font-semibold\">Publication</span> <span x-text=\"openSections.publication ? '▾' : '▸'\">▸</span></button><div x-show=\"openSections.publication\" x-transition class=\"p-4 space-y-3\" style=\"background-color: var(--bg-primary);\"><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Publisher</label> <input type=\"text\" name=\"publisher\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var28 string
templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinStringErrs(textToString(book.Publisher))
templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.ResolveAttributeValue(textToString(book.Publisher))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 295, Col: 80}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 335, Col: 80}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var28)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Date Published</label> <input type=\"date\" name=\"date_published\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Date Published</label> <input type=\"date\" name=\"date_published\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var29 string
templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinStringErrs(formatDateForInput(book.DatePublished))
templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.ResolveAttributeValue(formatDateForInput(book.DatePublished))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 302, Col: 55}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 342, Col: 55}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var29)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Edition</label> <input type=\"text\" name=\"edition\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Edition</label> <input type=\"text\" name=\"edition\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var30 string
templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(textToString(book.Edition))
templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.ResolveAttributeValue(textToString(book.Edition))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 308, Col: 76}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 348, Col: 76}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var30)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Language</label> <input type=\"text\" name=\"language\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 46, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Language</label> <input type=\"text\" name=\"language\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var31 string
templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinStringErrs(textToString(book.Language))
templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.ResolveAttributeValue(textToString(book.Language))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 314, Col: 78}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 354, Col: 78}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var31)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Genre</label> <input type=\"text\" name=\"genre\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Genre</label> <input type=\"text\" name=\"genre\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var32 string
templ_7745c5c3_Var32, templ_7745c5c3_Err = templ.JoinStringErrs(textToString(book.Genre))
templ_7745c5c3_Var32, templ_7745c5c3_Err = templ.ResolveAttributeValue(textToString(book.Genre))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 320, Col: 72}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 360, Col: 72}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var32))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var32)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 46, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Copyright Year</label> <input type=\"number\" name=\"copyright_year\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Copyright Year</label> <input type=\"number\" name=\"copyright_year\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var33 string
templ_7745c5c3_Var33, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", book.CopyrightYear.Int32))
templ_7745c5c3_Var33, templ_7745c5c3_Err = templ.ResolveAttributeValue(fmt.Sprintf("%d", book.CopyrightYear.Int32))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 327, Col: 60}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 367, Col: 60}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var33))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var33)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div></div></div><!-- Series --><div class=\"border rounded-lg\" style=\"border-color: var(--border);\"><button type=\"button\" class=\"w-full px-4 py-3 flex justify-between items-center\" style=\"color: var(--text-primary); background-color: var(--bg-primary);\" @click=\"toggleSection('series')\"><span class=\"font-semibold\">Series</span> <span x-text=\"openSections.series ? '▾' : '▸'\">▸</span></button><div x-show=\"openSections.series\" x-transition class=\"p-4 space-y-3\" style=\"background-color: var(--bg-primary);\"><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Series</label> <input type=\"text\" name=\"series\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div></div></div><!-- Series --><div class=\"border rounded-lg\" style=\"border-color: var(--border);\"><button type=\"button\" class=\"w-full px-4 py-3 flex justify-between items-center\" style=\"color: var(--text-primary); background-color: var(--bg-primary);\" @click=\"toggleSection('series')\"><span class=\"font-semibold\">Series</span> <span x-text=\"openSections.series ? '▾' : '▸'\">▸</span></button><div x-show=\"openSections.series\" x-transition class=\"p-4 space-y-3\" style=\"background-color: var(--bg-primary);\"><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Series</label> <input type=\"text\" name=\"series\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var34 string
templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.JoinStringErrs(textToString(book.Series))
templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.ResolveAttributeValue(textToString(book.Series))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 344, Col: 74}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 384, Col: 74}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var34))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var34)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div class=\"grid grid-cols-3 gap-3\"><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Number</label> <input type=\"number\" name=\"series_number\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div class=\"grid grid-cols-3 gap-3\"><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Number</label> <input type=\"number\" name=\"series_number\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var35 string
templ_7745c5c3_Var35, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", book.SeriesNumber.Int32))
templ_7745c5c3_Var35, templ_7745c5c3_Err = templ.ResolveAttributeValue(fmt.Sprintf("%d", book.SeriesNumber.Int32))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 352, Col: 60}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 392, Col: 60}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var35))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var35)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Count</label> <input type=\"number\" name=\"series_count\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Count</label> <input type=\"number\" name=\"series_count\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var36 string
templ_7745c5c3_Var36, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", book.SeriesCount.Int32))
templ_7745c5c3_Var36, templ_7745c5c3_Err = templ.ResolveAttributeValue(fmt.Sprintf("%d", book.SeriesCount.Int32))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 359, Col: 59}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 399, Col: 59}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var36))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var36)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Volume</label> <input type=\"number\" name=\"volume\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 52, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Volume</label> <input type=\"number\" name=\"volume\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var37 string
templ_7745c5c3_Var37, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", book.Volume.Int32))
templ_7745c5c3_Var37, templ_7745c5c3_Err = templ.ResolveAttributeValue(fmt.Sprintf("%d", book.Volume.Int32))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 366, Col: 54}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 406, Col: 54}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var37))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var37)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div></div></div></div><!-- Identifiers --><div class=\"border rounded-lg\" style=\"border-color: var(--border);\"><button type=\"button\" class=\"w-full px-4 py-3 flex justify-between items-center\" style=\"color: var(--text-primary); background-color: var(--bg-primary);\" @click=\"toggleSection('identifiers')\"><span class=\"font-semibold\">Identifiers</span> <span x-text=\"openSections.identifiers ? '▾' : '▸'\">▸</span></button><div x-show=\"openSections.identifiers\" x-transition class=\"p-4 space-y-3\" style=\"background-color: var(--bg-primary);\"><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">ISBN</label> <input type=\"text\" name=\"isbn\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div></div></div></div><!-- Identifiers --><div class=\"border rounded-lg\" style=\"border-color: var(--border);\"><button type=\"button\" class=\"w-full px-4 py-3 flex justify-between items-center\" style=\"color: var(--text-primary); background-color: var(--bg-primary);\" @click=\"toggleSection('identifiers')\"><span class=\"font-semibold\">Identifiers</span> <span x-text=\"openSections.identifiers ? '▾' : '▸'\">▸</span></button><div x-show=\"openSections.identifiers\" x-transition class=\"p-4 space-y-3\" style=\"background-color: var(--bg-primary);\"><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">ISBN</label> <input type=\"text\" name=\"isbn\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var38 string
templ_7745c5c3_Var38, templ_7745c5c3_Err = templ.JoinStringErrs(textToString(book.Isbn))
templ_7745c5c3_Var38, templ_7745c5c3_Err = templ.ResolveAttributeValue(textToString(book.Isbn))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 384, Col: 70}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 424, Col: 70}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var38))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var38)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 52, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">ASIN</label> <input type=\"text\" name=\"asin\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 54, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">ASIN</label> <input type=\"text\" name=\"asin\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var39 string
templ_7745c5c3_Var39, templ_7745c5c3_Err = templ.JoinStringErrs(textToString(book.Asin))
templ_7745c5c3_Var39, templ_7745c5c3_Err = templ.ResolveAttributeValue(textToString(book.Asin))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 390, Col: 70}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 430, Col: 70}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var39))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var39)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Goodreads ID</label> <input type=\"text\" name=\"goodreads_id\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Goodreads ID</label> <input type=\"text\" name=\"goodreads_id\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var40 string
templ_7745c5c3_Var40, templ_7745c5c3_Err = templ.JoinStringErrs(textToString(book.GoodreadsID))
templ_7745c5c3_Var40, templ_7745c5c3_Err = templ.ResolveAttributeValue(textToString(book.GoodreadsID))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 396, Col: 85}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 436, Col: 85}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var40))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var40)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 54, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">OpenLibrary ID</label> <input type=\"text\" name=\"openlibrary_id\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">OpenLibrary ID</label> <input type=\"text\" name=\"openlibrary_id\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var41 string
templ_7745c5c3_Var41, templ_7745c5c3_Err = templ.JoinStringErrs(textToString(book.OpenlibraryID))
templ_7745c5c3_Var41, templ_7745c5c3_Err = templ.ResolveAttributeValue(textToString(book.OpenlibraryID))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 402, Col: 89}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 442, Col: 89}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var41))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var41)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Google Books ID</label> <input type=\"text\" name=\"google_books_id\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Google Books ID</label> <input type=\"text\" name=\"google_books_id\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var42 string
templ_7745c5c3_Var42, templ_7745c5c3_Err = templ.JoinStringErrs(textToString(book.GoogleBooksID))
templ_7745c5c3_Var42, templ_7745c5c3_Err = templ.ResolveAttributeValue(textToString(book.GoogleBooksID))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 408, Col: 90}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 448, Col: 90}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var42))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var42)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Web URL</label> <input type=\"url\" name=\"web_url\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Web URL</label> <input type=\"url\" name=\"web_url\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var43 string
templ_7745c5c3_Var43, templ_7745c5c3_Err = templ.JoinStringErrs(textToString(book.WebUrl))
templ_7745c5c3_Var43, templ_7745c5c3_Err = templ.ResolveAttributeValue(textToString(book.WebUrl))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 414, Col: 74}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 454, Col: 74}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var43))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var43)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div></div></div><!-- Comic/Manga --><div class=\"border rounded-lg\" style=\"border-color: var(--border);\"><button type=\"button\" class=\"w-full px-4 py-3 flex justify-between items-center\" style=\"color: var(--text-primary); background-color: var(--bg-primary);\" @click=\"toggleSection('comic')\"><span class=\"font-semibold\">Comic/Manga</span> <span x-text=\"openSections.comic ? '▾' : '▸'\">▸</span></button><div x-show=\"openSections.comic\" x-transition class=\"p-4 space-y-3\" style=\"background-color: var(--bg-primary);\"><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Manga Type</label> <select name=\"manga_type\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"><option value=\"unknown\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div></div></div><!-- Comic/Manga --><div class=\"border rounded-lg\" style=\"border-color: var(--border);\"><button type=\"button\" class=\"w-full px-4 py-3 flex justify-between items-center\" style=\"color: var(--text-primary); background-color: var(--bg-primary);\" @click=\"toggleSection('comic')\"><span class=\"font-semibold\">Comic/Manga</span> <span x-text=\"openSections.comic ? '▾' : '▸'\">▸</span></button><div x-show=\"openSections.comic\" x-transition class=\"p-4 space-y-3\" style=\"background-color: var(--bg-primary);\"><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Manga Type</label> <select name=\"manga_type\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"><option value=\"unknown\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if textToString(book.MangaType) == "unknown" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, " selected")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, ">Unknown</option> <option value=\"no\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if textToString(book.MangaType) == "no" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 60, " selected")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, ">No</option> <option value=\"yes\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, ">Unknown</option> <option value=\"no\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if textToString(book.MangaType) == "yes" {
if textToString(book.MangaType) == "no" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, " selected")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, ">Yes</option> <option value=\"yes_and_right_to_left\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, ">No</option> <option value=\"yes\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if textToString(book.MangaType) == "yes_and_right_to_left" {
if textToString(book.MangaType) == "yes" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, " selected")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 65, ">Yes (Right to Left)</option></select></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Reading Direction</label> <select name=\"reading_direction\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"><option value=\"auto\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 65, ">Yes</option> <option value=\"yes_and_right_to_left\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if textToString(book.ReadingDirection) == "auto" {
if textToString(book.MangaType) == "yes_and_right_to_left" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 66, " selected")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 67, ">Auto</option> <option value=\"ltr\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 67, ">Yes (Right to Left)</option></select></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Reading Direction</label> <select name=\"reading_direction\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"><option value=\"auto\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if textToString(book.ReadingDirection) == "ltr" {
if textToString(book.ReadingDirection) == "auto" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 68, " selected")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 69, ">Left to Right</option> <option value=\"rtl\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 69, ">Auto</option> <option value=\"ltr\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if textToString(book.ReadingDirection) == "rtl" {
if textToString(book.ReadingDirection) == "ltr" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 70, " selected")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, ">Right to Left</option> <option value=\"vertical\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, ">Left to Right</option> <option value=\"rtl\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if textToString(book.ReadingDirection) == "vertical" {
if textToString(book.ReadingDirection) == "rtl" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 72, " selected")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 73, ">Vertical</option></select></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Age Rating</label> <input type=\"text\" name=\"age_rating\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 73, ">Right to Left</option> <option value=\"vertical\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if textToString(book.ReadingDirection) == "vertical" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 74, " selected")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 75, ">Vertical</option></select></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Age Rating</label> <input type=\"text\" name=\"age_rating\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var44 string
templ_7745c5c3_Var44, templ_7745c5c3_Err = templ.JoinStringErrs(textToString(book.AgeRating))
templ_7745c5c3_Var44, templ_7745c5c3_Err = templ.ResolveAttributeValue(textToString(book.AgeRating))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 453, Col: 81}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 493, Col: 81}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var44))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var44)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 74, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Story Arc</label> <input type=\"text\" name=\"story_arc\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 76, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Story Arc</label> <input type=\"text\" name=\"story_arc\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var45 string
templ_7745c5c3_Var45, templ_7745c5c3_Err = templ.JoinStringErrs(textToString(book.StoryArc))
templ_7745c5c3_Var45, templ_7745c5c3_Err = templ.ResolveAttributeValue(textToString(book.StoryArc))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 459, Col: 79}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 499, Col: 79}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var45))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var45)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 75, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Imprint</label> <input type=\"text\" name=\"imprint\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 77, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Imprint</label> <input type=\"text\" name=\"imprint\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var46 string
templ_7745c5c3_Var46, templ_7745c5c3_Err = templ.JoinStringErrs(textToString(book.Imprint))
templ_7745c5c3_Var46, templ_7745c5c3_Err = templ.ResolveAttributeValue(textToString(book.Imprint))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 465, Col: 76}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 505, Col: 76}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var46))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var46)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 76, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Scan Information</label> <input type=\"text\" name=\"scan_information\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 78, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Scan Information</label> <input type=\"text\" name=\"scan_information\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var47 string
templ_7745c5c3_Var47, templ_7745c5c3_Err = templ.JoinStringErrs(textToString(book.ScanInformation))
templ_7745c5c3_Var47, templ_7745c5c3_Err = templ.ResolveAttributeValue(textToString(book.ScanInformation))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 471, Col: 93}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 511, Col: 93}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var47))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var47)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 77, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Metadata Notes</label> <textarea name=\"metadata_notes\" rows=\"2\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\">")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 79, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Metadata Notes</label> <textarea name=\"metadata_notes\" rows=\"2\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var48 string
templ_7745c5c3_Var48, templ_7745c5c3_Err = templ.JoinStringErrs(textToString(book.MetadataNotes))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 480, Col: 43}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 520, Col: 43}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var48))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 78, "</textarea></div><div class=\"flex items-center gap-2\"><input type=\"checkbox\" name=\"is_black_and_white\" id=\"is_black_and_white\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 80, "</textarea></div><div class=\"flex items-center gap-2\"><input type=\"checkbox\" name=\"is_black_and_white\" id=\"is_black_and_white\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if book.IsBlackAndWhite.Bool {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 79, " checked")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 81, " checked")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 80, " class=\"rounded\"> <label for=\"is_black_and_white\" class=\"text-sm\" style=\"color: var(--text-secondary);\">Black & White</label></div></div></div><!-- Technical --><div class=\"border rounded-lg\" style=\"border-color: var(--border);\"><button type=\"button\" class=\"w-full px-4 py-3 flex justify-between items-center\" style=\"color: var(--text-primary); background-color: var(--bg-primary);\" @click=\"toggleSection('technical')\"><span class=\"font-semibold\">Technical</span> <span x-text=\"openSections.technical ? '▾' : '▸'\">▸</span></button><div x-show=\"openSections.technical\" x-transition class=\"p-4 space-y-3\" style=\"background-color: var(--bg-primary);\"><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Page Count</label> <input type=\"number\" name=\"page_count\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 82, " class=\"rounded\"> <label for=\"is_black_and_white\" class=\"text-sm\" style=\"color: var(--text-secondary);\">Black & White</label></div></div></div><!-- Technical --><div class=\"border rounded-lg\" style=\"border-color: var(--border);\"><button type=\"button\" class=\"w-full px-4 py-3 flex justify-between items-center\" style=\"color: var(--text-primary); background-color: var(--bg-primary);\" @click=\"toggleSection('technical')\"><span class=\"font-semibold\">Technical</span> <span x-text=\"openSections.technical ? '▾' : '▸'\">▸</span></button><div x-show=\"openSections.technical\" x-transition class=\"p-4 space-y-3\" style=\"background-color: var(--bg-primary);\"><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Page Count</label> <input type=\"number\" name=\"page_count\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var49 string
templ_7745c5c3_Var49, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", book.PageCount.Int32))
templ_7745c5c3_Var49, templ_7745c5c3_Err = templ.ResolveAttributeValue(fmt.Sprintf("%d", book.PageCount.Int32))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 502, Col: 56}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 542, Col: 56}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var49))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var49)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 81, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Contributors (comma-separated)</label> <input type=\"text\" name=\"contributors\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 83, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Contributors (comma-separated)</label> <input type=\"text\" name=\"contributors\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var50 string
templ_7745c5c3_Var50, templ_7745c5c3_Err = templ.JoinStringErrs(stringSliceToString(book.Contributors))
templ_7745c5c3_Var50, templ_7745c5c3_Err = templ.ResolveAttributeValue(stringSliceToString(book.Contributors))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 508, Col: 93}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 548, Col: 93}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var50))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var50)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 82, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div class=\"grid grid-cols-2 gap-3\"><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Format</label> <input type=\"text\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 84, "\" class=\"w-full px-3 py-2 rounded-lg border text-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div class=\"grid grid-cols-2 gap-3\"><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">Format</label> <input type=\"text\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var51 string
templ_7745c5c3_Var51, templ_7745c5c3_Err = templ.JoinStringErrs(textToString(book.MimeType))
templ_7745c5c3_Var51, templ_7745c5c3_Err = templ.ResolveAttributeValue(textToString(book.MimeType))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 515, Col: 63}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 555, Col: 63}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var51))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var51)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 83, "\" readonly class=\"w-full px-3 py-2 rounded-lg border text-sm opacity-60\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">File Size</label> <input type=\"text\" value=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 85, "\" readonly class=\"w-full px-3 py-2 rounded-lg border text-sm opacity-60\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div><div><label class=\"block text-sm font-medium mb-1\" style=\"color: var(--text-secondary);\">File Size</label> <input type=\"text\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var52 string
templ_7745c5c3_Var52, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%.1f MB", float64(book.FileSize.Int64)/1024/1024))
templ_7745c5c3_Var52, templ_7745c5c3_Err = templ.ResolveAttributeValue(fmt.Sprintf("%.1f MB", float64(book.FileSize.Int64)/1024/1024))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 521, Col: 98}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `book_detail_modals.templ`, Line: 561, Col: 98}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var52))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var52)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 84, "\" readonly class=\"w-full px-3 py-2 rounded-lg border text-sm opacity-60\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div></div></div></div></div></div><div class=\"flex justify-end space-x-3 p-6 border-t flex-shrink-0\" style=\"border-color: var(--border);\"><button @click=\"hideMetadataEditor()\" class=\"px-4 py-2 rounded-lg\" style=\"background-color: var(--bg-primary); color: var(--text-primary); border: 1px solid var(--border);\">Cancel</button> <button @click=\"saveMetadata()\" class=\"px-6 py-2 rounded-lg font-semibold\" style=\"background-color: var(--accent); color: white;\">Save</button></div></div></div>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 86, "\" readonly class=\"w-full px-3 py-2 rounded-lg border text-sm opacity-60\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text-primary);\"></div></div></div></div></div></div><div class=\"flex justify-end space-x-3 p-6 border-t flex-shrink-0\" style=\"border-color: var(--border);\"><button @click=\"hideMetadataEditor()\" class=\"px-4 py-2 rounded-lg\" style=\"background-color: var(--bg-primary); color: var(--text-primary); border: 1px solid var(--border);\">Cancel</button> <button @click=\"saveMetadata()\" class=\"px-6 py-2 rounded-lg font-semibold\" style=\"background-color: var(--accent); color: white;\">Save</button></div></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
+87 -9
View File
@@ -1,6 +1,7 @@
import { Alpine } from "./alpine";
import { showToast } from "./toast";
import { generateCoverBlob } from "./cover-generator";
import { searchTagSuggestions, type TagSuggestion } from "./tag-dropdown";
function getMediaId(): string {
const parts = window.location.pathname.split("/");
@@ -46,7 +47,7 @@ function hideMetadataEditor(): void {
if (modal) modal.classList.add("hidden");
}
function collectFormData(): Record<string, unknown> {
function collectFormData(editorTags: string[]): Record<string, unknown> {
const modal = document.getElementById("metadata-editor-modal");
if (!modal) return {};
@@ -55,6 +56,7 @@ function collectFormData(): Record<string, unknown> {
"input[name], textarea[name], select[name]",
);
for (const el of inputs) {
if (el.name === "tags") continue;
if (el.type === "number") {
const val = parseFloat(el.value);
data[el.name] = isNaN(val) ? 0 : val;
@@ -65,13 +67,7 @@ function collectFormData(): Record<string, unknown> {
}
}
const tagsStr = data.tags as string;
if (typeof tagsStr === "string") {
data.tags = tagsStr
.split(",")
.map((t: string) => t.trim())
.filter(Boolean);
}
data.tags = editorTags;
const contribStr = data.contributors as string;
if (typeof contribStr === "string") {
@@ -124,6 +120,13 @@ Alpine.data("bookDetail", () => {
const coverSrc = coverPreviewEl?.src || "";
const fileUrl = coverSrc && !coverSrc.includes("placeholder") ? coverSrc : "";
const initialTags: string[] = [];
const tagBadges = document.querySelectorAll("#metadata-editor-modal [data-editor-tag]");
tagBadges.forEach((el) => {
const tag = el.getAttribute("data-editor-tag");
if (tag) initialTags.push(tag);
});
return {
openSections: { basic: true } as Record<string, boolean>,
coverGenerating: false,
@@ -132,6 +135,11 @@ Alpine.data("bookDetail", () => {
coverFile: null as Blob | null,
coverAction: "keep",
saving: false,
editorTags: initialTags,
tagSearch: "",
tagSuggestions: [] as TagSuggestion[],
showTagDropdown: false,
highlightedTagIndex: -1,
showReaderPlaceholder,
showMetadataEditor,
@@ -237,7 +245,7 @@ Alpine.data("bookDetail", () => {
try {
const mediaId = getMediaId();
const formData = collectFormData();
const formData = collectFormData(this.editorTags);
formData.cover_action = this.coverAction;
if (this.coverFile) {
@@ -291,5 +299,75 @@ Alpine.data("bookDetail", () => {
this.saving = false;
}
},
async searchEditorTags() {
const libraryId = document.body.getAttribute("data-library-id") || "";
if (!this.tagSearch || this.tagSearch.length < 2 || !libraryId) {
this.tagSuggestions = [];
this.showTagDropdown = false;
return;
}
const results = await searchTagSuggestions(this.tagSearch, libraryId);
const current = this.editorTags.map((t: string) => t.toLowerCase());
this.tagSuggestions = results.filter((r: TagSuggestion) => !current.includes(r.value.toLowerCase()));
this.showTagDropdown = this.tagSuggestions.length > 0;
this.highlightedTagIndex = -1;
},
addEditorTag(tag: string) {
const trimmed = tag.trim();
if (!trimmed) return;
const lower = trimmed.toLowerCase();
if (this.editorTags.some((t: string) => t.toLowerCase() === lower)) return;
this.editorTags.push(trimmed);
this.tagSearch = "";
this.showTagDropdown = false;
this.tagSuggestions = [];
this.highlightedTagIndex = -1;
},
removeEditorTag(index: number) {
this.editorTags.splice(index, 1);
},
selectEditorTagSuggestion(tag: string) {
this.addEditorTag(tag);
},
hideEditorTagDropdown() {
setTimeout(() => { this.showTagDropdown = false; }, 200);
},
onTagKeydown(event: KeyboardEvent) {
if (event.key === "ArrowDown") {
event.preventDefault();
if (this.showTagDropdown && this.tagSuggestions.length > 0) {
this.highlightedTagIndex = (this.highlightedTagIndex + 1) % this.tagSuggestions.length;
}
} else if (event.key === "ArrowUp") {
event.preventDefault();
if (this.showTagDropdown && this.tagSuggestions.length > 0) {
this.highlightedTagIndex = this.highlightedTagIndex <= 0
? this.tagSuggestions.length - 1
: this.highlightedTagIndex - 1;
}
} else if (event.key === "Enter") {
event.preventDefault();
if (this.highlightedTagIndex >= 0 && this.showTagDropdown) {
this.addEditorTag(this.tagSuggestions[this.highlightedTagIndex].value);
} else if (this.tagSearch.trim()) {
this.addEditorTag(this.tagSearch);
}
} else if (event.key === ",") {
event.preventDefault();
if (this.tagSearch.trim()) {
this.addEditorTag(this.tagSearch);
}
} else if (event.key === "Escape") {
this.showTagDropdown = false;
this.tagSuggestions = [];
this.highlightedTagIndex = -1;
}
},
} as MetadataEditorState;
});