Added tag actor editing.

This commit is contained in:
2026-03-04 03:57:04 +01:00
parent f4447b23de
commit 46839b48cf
4 changed files with 130 additions and 64 deletions

View File

@@ -1,35 +1,46 @@
<template> <template>
<div class="tags-sections">
<div
v-for="actorTags in tags"
:key="`tags-${actorTags.actor?.slug || 'scene'}`"
class="tags-section"
>
<ul <ul
class="tags nolist" class="tags nolist"
:class="{ disabled: !editing.has(item.key) }" :class="{ disabled: !editing.has(item.key) }"
> >
<li <li
v-for="tag in [...item.value, ...newTags]" v-if="actorTags.actor"
class="tags-actor"
>{{ actorTags.actor.name }}:</li>
<li
v-for="tag in [...actorTags.tags, ...newTags.filter((newTag) => newTag.actorId === actorTags.actorId)]"
:key="`tag-${tag.id}`" :key="`tag-${tag.id}`"
class="tag" class="tag"
:class="{ deleted: edits.tags && !edits.tags.some((tagId) => tagId === tag.id) }" :class="{ deleted: edits.tags && !edits.tags.some((sceneTag) => sceneTag.id === tag.id && sceneTag.actorId === actorTags.actorId) }"
> >
<span class="tag-name">{{ tag.name }}</span> <span class="tag-name">{{ tag.name }}</span>
<Icon <Icon
v-if="edits.tags && !edits.tags.some((tagId) => tagId === tag.id)" v-if="edits.tags && !edits.tags.some((sceneTag) => sceneTag.id === tag.id && sceneTag.actorId === actorTags.actorId)"
icon="checkmark" icon="checkmark"
class="add" class="add"
@click="emit('tags', edits.tags.concat(tag.id))" @click="emit('tags', edits.tags.concat(tag))"
/> />
<Icon <Icon
v-else v-else
icon="cross2" icon="cross2"
class="remove" class="remove"
@click="emit('tags', edits.tags.filter((tagId) => tagId !== tag.id))" @click="emit('tags', edits.tags.filter((sceneTag) => !(sceneTag.id === tag.id && sceneTag.actorId === actorTags.actorId)))"
/> />
</li> </li>
<li class="new"> <li class="new">
<TagSearch <TagSearch
:disabled="!editing.has(item.key)" :disabled="!editing.has(item.key)"
@tag="addTag" @tag="(tag) => addTag(tag, actorTags.actor)"
> >
<Icon <Icon
icon="plus3" icon="plus3"
@@ -38,6 +49,8 @@
</TagSearch> </TagSearch>
</li> </li>
</ul> </ul>
</div>
</div>
</template> </template>
<script setup> <script setup>
@@ -70,8 +83,23 @@ const props = defineProps({
const emit = defineEmits(['tags']); const emit = defineEmits(['tags']);
function addTag(tag) { const tags = [
if (props.edits.tags.some((tagId) => tagId === tag.id)) { {
tags: props.item.value.filter((tag) => tag.actorId === null),
actor: null,
actorId: null,
},
...props.scene.actors.map((actor) => ({
tags: props.item.value.filter((tag) => tag.actorId === actor.id),
actor,
actorId: actor?.id || null,
})),
];
function addTag(newTag, actor) {
const actorId = actor?.id || null;
if (props.edits.tags.some((sceneTag) => sceneTag.id === newTag.id && sceneTag.actorId === actorId)) {
events.emit('feedback', { events.emit('feedback', {
type: 'error', type: 'error',
message: 'Tag already added', message: 'Tag already added',
@@ -80,9 +108,13 @@ function addTag(tag) {
return; return;
} }
newTags.value = newTags.value.concat(tag); const newTagWithActorId = {
...newTag,
actorId,
};
emit('tags', props.edits.tags.concat(tag.id)); newTags.value = newTags.value.concat(newTagWithActorId);
emit('tags', props.edits.tags.concat(newTagWithActorId));
} }
watch(() => props.scene, () => { newTags.value = []; }); watch(() => props.scene, () => { newTags.value = []; });
@@ -116,7 +148,7 @@ watch(() => props.scene, () => { newTags.value = []; });
align-items: center; align-items: center;
margin-left: .25rem; margin-left: .25rem;
&:hover { &:hover .icon {
box-shadow: 0 0 3px var(--shadow-weak-20); box-shadow: 0 0 3px var(--shadow-weak-20);
} }
@@ -129,6 +161,18 @@ watch(() => props.scene, () => { newTags.value = []; });
} }
} }
.tags-sections {
display: flex;
flex-direction: column;
gap: .75rem;
margin: .5rem 0;
}
.tags-actor {
margin-right: .5rem;
font-weight: bold;
}
.tag { .tag {
display: flex; display: flex;
align-items: stretch; align-items: stretch;
@@ -145,9 +189,11 @@ watch(() => props.scene, () => { newTags.value = []; });
.tag, .tag,
.new { .new {
.remove, .remove,
.add { .add,
.actor {
height: auto; height: auto;
padding: .25rem .3rem; padding: .25rem .3rem;
margin-left: .25rem;
border-radius: .25rem; border-radius: .25rem;
fill: var(--highlight-strong-10); fill: var(--highlight-strong-10);

View File

@@ -140,11 +140,14 @@
</li> </li>
</ul> </ul>
<div class="tags">
<div <div
v-for="actorTags in tags" v-for="(actorTags, index) in tags"
:key="`tags-${actorTags.actor?.name || 'scene'}`" :key="`tags-${actorTags.actor?.slug || 'scene'}`"
class="tags-section"
:class="{ space: index > 1 }"
> >
<ul class="tags nolist"> <ul class="nolist">
<li <li
v-if="actorTags.actor" v-if="actorTags.actor"
class="tags-actor" class="tags-actor"
@@ -161,6 +164,7 @@
</li> </li>
</ul> </ul>
</div> </div>
</div>
<div <div
v-if="scene.movies.length > 0 || scene.series.length > 0" v-if="scene.movies.length > 0 || scene.series.length > 0"
@@ -658,6 +662,20 @@ function copySummary() {
margin-bottom: 1rem; margin-bottom: 1rem;
} }
.tags {
display: flex;
flex-wrap: wrap;
gap: .25rem;
}
.tags-section {
display: inline-flex;
&.space {
margin-left: .5rem;
}
}
.tags-actor { .tags-actor {
margin-right: .5rem; margin-right: .5rem;
font-weight: bold; font-weight: bold;

View File

@@ -261,6 +261,7 @@ const fields = computed(() => [
key: 'tags', key: 'tags',
type: 'tags', type: 'tags',
value: scene.value.tags.toSorted((tagA, tagB) => tagA.name.localeCompare(tagB.name)), value: scene.value.tags.toSorted((tagA, tagB) => tagA.name.localeCompare(tagB.name)),
simplify: false,
}, },
{ {
key: 'movies', key: 'movies',

View File

@@ -785,9 +785,10 @@ async function applySceneTagsDelta(sceneId, delta, trx) {
if (delta.value.length > 0) { if (delta.value.length > 0) {
await knexOwner('releases_tags') await knexOwner('releases_tags')
.insert(delta.value.map((tagId) => ({ .insert(delta.value.map((tag) => ({
release_id: sceneId, release_id: sceneId,
tag_id: tagId, tag_id: tag.id,
actor_id: tag.actorId,
source: 'editor', source: 'editor',
}))) })))
.transacting(trx); .transacting(trx);