traxxx-web/components/actors/tile.vue

212 lines
4.0 KiB
Vue

<template>
<div
class="tile"
:class="{
unstashed: !favorited && pageStash && user && pageStash.user.id === user?.id,
}"
>
<span class="name">{{ actor.name }}</span>
<div class="avatar-container">
<Link
:href="`/actor/${actor.id}/${actor.slug}`"
class="avatar-link no-link"
>
<img
v-if="actor.avatar"
:src="actor.avatar.isS3 ? `https://cdndev.traxxx.me/${actor.avatar.thumbnail}` : `/media/${actor.avatar.thumbnail}`"
:style="{ 'background-image': actor.avatar.isS3 ? `url(https://cdndev.traxxx.me/${actor.avatar.lazy})` : `url(/media/${actor.avatar.lazy})` }"
loading="lazy"
class="avatar"
>
<img
v-else
:src="`/img/avatars/${actor.gender || 'female'}.svg`"
loading="lazy"
class="fallback"
>
</Link>
<Heart
domain="actors"
:item="actor"
:show-secondary="false"
class="light tiled"
@stashed="(stash) => { favorited = stash.id === currentStash.id ? true : favorited; }"
@unstashed="(stash) => { favorited = stash.id === currentStash.id ? false : favorited; }"
/>
</div>
<div class="details">
<span class="birth">
<Gender :gender="actor.gender" />
<span
v-if="actor.ageFromBirth"
:title="`Born ${formatDate(actor.dateOfBirth, 'MMMM d, yyyy')}`"
class="age"
>{{ actor.ageFromBirth }}</span>
<span
v-if="actor.ageThen && actor.ageThen < actor.ageFromBirth"
title="Age on date of release"
class="age age-then"
>{{ actor.ageThen }}</span>
</span>
<span
v-if="actor.origin?.country"
:title="`Born in ${actor.origin.country.alias || actor.origin.country.name}`"
class="country"
>
{{ actor.origin.country.alpha2 }}
<img
:src="`/img/flags/${actor.origin.country.alpha2.toLowerCase()}.svg`"
class="flag"
>
</span>
</div>
</div>
</template>
<script setup>
import { ref, inject } from 'vue';
import { formatDate } from '#/utils/format.js';
import Heart from '#/components/stashes/heart.vue';
import Gender from './gender.vue';
const props = defineProps({
actor: {
type: Object,
default: null,
},
});
const pageContext = inject('pageContext');
const { user } = pageContext;
const pageStash = pageContext.pageProps.stash;
const currentStash = pageStash || user?.primaryStash;
const favorited = ref(props.actor.stashes.some((actorStash) => actorStash.id === currentStash.id));
</script>
<style scoped>
.tile {
display: flex;
flex-direction: column;
width: 100%;
aspect-ratio: 2/3;
position: relative;
border-radius: .25rem;
box-shadow: 0 0 3px var(--shadow-weak-30);
overflow: hidden;
&:hover {
box-shadow: 0 0 3px var(--shadow-weak-20);
.name {
color: var(--primary);
}
:deep(.bookmarks) .icon:not(.favorited):not(:hover) {
fill: var(--text-light);
}
}
&.unstashed {
opacity: .5;
}
}
.name {
flex-shrink: 0;
padding: .25rem .5rem;
font-weight: bold;
font-size: .9rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
user-select: all;
}
.avatar-container {
position: relative;
flex-grow: 1;
overflow: hidden;
background: var(--grey-dark-40);
}
.avatar-link {
height: 100%;
display: block;
overflow: hidden;
}
.avatar {
height: 100%;
width: 100%;
object-fit: cover;
object-position: center 0;
background-size: cover;
background-position: center 0;
}
.fallback {
height: 100%;
width: 100%;
display: block;
object-fit: contain;
opacity: .1;
}
.details {
width: 100%;
height: 1.5rem;
display: flex;
justify-content: space-between;
align-items: center;
position: absolute;
bottom: 0;
box-sizing: border-box;
padding: 0 .5rem;
color: var(--text-light);
background: var(--shadow);
font-size: .9rem;
font-weight: bold;
}
.gender {
display: inline-block;
padding: .25rem 0;
margin-right: .25rem;
transform: translateY(1px);
}
.birth {
display: flex;
align-items: center;
}
.age {
margin-right: .25rem;
}
.age-then {
color: var(--grey-light-20);
font-weight: normal;
}
.country {
display: flex;
align-items: center;
}
.flag {
height: .75rem;
margin-left: .25rem;
}
</style>