Showing avatars on actor tags instead of sections. Slightly sized down scene page actor tiles, shrinking font size on long names.

This commit is contained in:
2026-07-03 17:59:44 +02:00
parent 4636a213b3
commit 930cc52373
2 changed files with 116 additions and 44 deletions

View File

@@ -74,7 +74,10 @@
</div> </div>
<span class="label"> <span class="label">
<span class="name ellipsis">{{ actor.name }}</span> <span
class="name ellipsis"
:style="{ 'font-size': `${Math.max(0.9 + Math.min((17 - actor.name.length), 0) * 0.06, 0.65)}rem` }"
>{{ actor.name }}</span>
<img <img
v-if="actor.entity" v-if="actor.entity"
@@ -155,6 +158,7 @@ const favorited = ref(props.actor.stashes.some((actorStash) => actorStash.id ===
} }
.label { .label {
height: 1.75rem;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
@@ -168,7 +172,7 @@ const favorited = ref(props.actor.stashes.some((actorStash) => actorStash.id ===
} }
.name { .name {
padding: .35rem .25rem .35rem .5rem; padding: 0 .25rem 0 .5rem;
} }
.favicon { .favicon {

View File

@@ -140,30 +140,41 @@
</li> </li>
</ul> </ul>
<div class="tags"> <ul class="tags nolist">
<div <li
v-for="actorTags in tags" v-for="tag in tags"
:key="`tags-${actorTags.actor?.slug || 'scene'}`" :key="`tag-${tag.id}`"
class="tags-section" class="tag"
:class="{ 'has-actors': tag.actors.length > 0 }"
> >
<ul class="nolist"> <Link
<li :href="`/tag/${tag.slug}`"
v-if="actorTags.actor" class="tag-name nolink"
class="tags-actor" >{{ tag.name }}</Link>
>{{ actorTags.actor.name }}:</li>
<li <span
v-for="tag in actorTags.tags" v-for="tagActor in tag.actors"
:key="`tag-${tag.id}`" :key="`tagactor-${tagActor.id}`"
v-tooltip="{
content: `Performed by ${tagActor.name}`,
triggers: ['hover', 'click'],
}"
class="tag-frame"
>
<img
v-if="tagActor.avatar"
class="tag-avatar"
:src="getPath(tagActor.avatar, 'thumbnail')"
> >
<Link
:href="`/tag/${tag.slug}`" <Icon
class="tag nolink" v-else
>{{ tag.name }}</Link> icon="star-full"
</li> class="tag-star"
</ul> />
</div> </span>
</div> </li>
</ul>
<div <div
v-if="scene.movies.length > 0 || scene.series.length > 0" v-if="scene.movies.length > 0 || scene.series.length > 0"
@@ -424,6 +435,7 @@ import Cookies from 'js-cookie';
import { formatDate, formatDuration } from '#/utils/format.js'; import { formatDate, formatDuration } from '#/utils/format.js';
import events from '#/src/events.js'; import events from '#/src/events.js';
import processSummaryTemplate from '#/utils/process-summary-template.js'; import processSummaryTemplate from '#/utils/process-summary-template.js';
import getPath from '#/src/get-path.js';
import Banner from '#/components/media/banner.vue'; import Banner from '#/components/media/banner.vue';
import ActorTile from '#/components/actors/tile.vue'; import ActorTile from '#/components/actors/tile.vue';
@@ -450,23 +462,44 @@ const {
const { scene } = pageProps; const { scene } = pageProps;
const tags = [ /*
{ const tags = scene.tags.map((tag) => ({
tags: scene.tags.filter((tag) => tag.actorId === null), ...tag,
actor: null, actor: scene.actors.find((actor) => actor.id === tag.actorId) || null,
}, }));
...scene.actors.map((actor) => ({ */
actor,
tags: scene.tags.filter((tag) => tag.actorId === actor.id),
})),
]
.filter((actorTags) => actorTags.tags.length > 0)
.toSorted((actorTagsA, actorTagsB) => {
const priorityA = actorTagsA.tags.reduce((acc, tag) => acc + tag.priority, 0) / actorTagsA.tags.length;
const priorityB = actorTagsB.tags.reduce((acc, tag) => acc + tag.priority, 0) / actorTagsB.tags.length;
return priorityB - priorityA; const actorsById = Object.fromEntries(scene.actors.map((actor) => [actor.id, actor]));
});
const tags = Array.from(scene.tags
.reduce((acc, tag) => {
const accTag = acc.get(tag.id);
if (accTag && tag.actorId) {
return acc.set(tag.id, {
...tag,
actors: [...accTag.actors, actorsById[tag.actorId]].toSorted((actorA, actorB) => actorA.name.localeCompare(actorB.name)),
});
}
if (accTag) {
// shouldn't happen, but account for it
return acc;
}
if (tag.actorId) {
return acc.set(tag.id, {
...tag,
actors: [actorsById[tag.actorId]],
});
}
return acc.set(tag.id, {
...tag,
actors: [],
});
}, new Map())
.values());
const showSummaryDialog = ref(false); const showSummaryDialog = ref(false);
@@ -671,7 +704,7 @@ function copySummary() {
.tags { .tags {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: .25rem 1rem; gap: .35rem;
} }
.tags-section { .tags-section {
@@ -691,25 +724,60 @@ function copySummary() {
overflow-x: auto; overflow-x: auto;
.actor { .actor {
width: 10rem; width: 9rem;
flex-shrink: 0; flex-shrink: 0;
} }
} }
.tag { .tag {
padding: .5rem; display: flex;
border-radius: .25rem; border-radius: .25rem;
margin: 0 .25rem .25rem 0;
background: var(--background); background: var(--background);
box-shadow: 0 0 3px var(--shadow-weak-30); box-shadow: 0 0 3px var(--shadow-weak-30);
overflow: hidden;
&:hover {
box-shadow: 0 0 3px var(--shadow-weak-20);
}
}
.tag-name {
display: inline-flex;
align-items: center;
padding: .5rem;
&:hover { &:hover {
color: var(--primary); color: var(--primary);
box-shadow: 0 0 3px var(--shadow-weak-20);
cursor: pointer; cursor: pointer;
} }
} }
.tag-frame {
display: inline-flex;
justify-content: center;
width: 2.25rem;
height: 2.25rem;
position: relative;
overflow: hidden;
&::after {
content: '';
position: absolute;
inset: 0;
box-shadow: inset 0 0 3px var(--shadow-weak-20);
pointer-events: none; /* so it doesn't block hover/click on the image */
}
}
.tag-avatar {
height: 350%;
}
.tag-star {
height: 100%;
fill: var(--primary);
}
.movies, .movies,
.series { .series {
display: grid; display: grid;