feat(tags): fandom-edit UI in tags directory + image modal
CI / lint (push) Successful in 3s
CI / backend-lint-and-test (push) Successful in 13s
CI / frontend-build (push) Successful in 26s
CI / intimp (push) Successful in 3m47s
CI / intapi (push) Successful in 7m52s
CI / intcore (push) Successful in 8m58s

Adds the missing UI to change a character tag's fandom, in both places:

- FandomSetDialog (shared): pick an existing fandom, create a new one, or
  clear it; on a name collision in the target fandom it surfaces a merge
  confirmation and resolves via setFandom(merge:true). Reuses the tags
  store's fandom cache.
- TagCard kebab gains "Set fandom…" for character tags (→ TagsView opens
  the dialog, reloads on success).
- TagPanel chip kebab gains "Set fandom…" for character tags (→ reloads the
  modal's tag list on success).
- tags store: setFandom(tagId, fandomId, {merge}) action + test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-03 23:21:25 -04:00
parent d9ab6e15c6
commit e678d1dfdf
6 changed files with 258 additions and 2 deletions
+21
View File
@@ -28,6 +28,7 @@
v-for="c in store.cards" :key="c.id" :card="c"
@open="openTag" @rename="onRename" @manage="onManage" @read="onRead"
@merge-with="onMergeWith" @delete="onDeleteTag"
@set-fandom="onSetFandom"
/>
</div>
@@ -85,6 +86,13 @@
: ''"
@confirm="onDeleteTagConfirm"
/>
<v-dialog v-model="fandomDialogOpen" max-width="460">
<FandomSetDialog
v-if="fandomTarget" :tag="fandomTarget"
@updated="onFandomUpdated" @cancel="fandomDialogOpen = false"
/>
</v-dialog>
</v-container>
</template>
@@ -98,6 +106,7 @@ import { useInfiniteScroll } from '../composables/useInfiniteScroll.js'
import TagCard from '../components/discovery/TagCard.vue'
import MergeConfirmDialog from '../components/discovery/MergeConfirmDialog.vue'
import DestructiveConfirmModal from '../components/modal/DestructiveConfirmModal.vue'
import FandomSetDialog from '../components/modal/FandomSetDialog.vue'
// Must stay a subset of the backend TagKind enum (character, fandom,
// general, series, archive, post). 'fandom' is this model's
@@ -140,6 +149,18 @@ function openTag(tagId) {
router.push({ name: 'gallery', query: { tag_id: tagId } })
}
// Character fandom editing (dots-menu → FandomSetDialog).
const fandomDialogOpen = ref(false)
const fandomTarget = ref(null)
function onSetFandom(card) {
fandomTarget.value = card
fandomDialogOpen.value = true
}
function onFandomUpdated() {
fandomDialogOpen.value = false
store.reset() // reload so the card reflects the new fandom (or its removal)
}
function onManage(id) {
router.push({ name: 'series-manage', params: { tagId: id } })
}