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:
@@ -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) }
|
||||
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);" />
|
||||
<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>
|
||||
|
||||
Reference in New Issue
Block a user