traxxx-web/components/actors/tile.vue

230 lines
4.3 KiB
Vue
Raw Permalink Normal View History

<template>
2024-03-21 01:54:05 +00:00
<div
class="tile"
:class="{
unstashed: !favorited && pageStash && user && pageStash.user.id === user?.id,
2024-03-21 01:54:05 +00:00
}"
>
<div class="avatar-container">
<Link
:href="`/actor/${actor.id}/${actor.slug}`"
class="avatar-link no-link"
>
2024-03-21 01:54:05 +00:00
<img
v-if="actor.avatar"
:src="getPath(actor.avatar, 'thumbnail')"
:style="{ 'background-image': `url(${getPath(actor.avatar, 'lazy')})` }"
2024-03-21 01:54:05 +00:00
loading="lazy"
class="avatar"
>
2024-03-23 21:44:49 +00:00
<img
v-else
:src="`/img/avatars/${actor.gender || 'female'}.svg`"
loading="lazy"
class="fallback"
>
2024-03-21 01:54:05 +00:00
</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; }"
2024-03-21 01:54:05 +00:00
/>
<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>
2024-10-30 01:25:19 +00:00
<span class="label">
<span class="name ellipsis">{{ actor.name }}</span>
<img
v-if="actor.entity"
v-tooltip="actor.entity.name"
:src="`/logos/${actor.entity.slug}/favicon_dark.png`"
class="favicon"
>
</span>
</div>
</template>
<script setup>
2024-03-21 01:54:05 +00:00
import { ref, inject } from 'vue';
import getPath from '#/src/get-path.js';
import { formatDate } from '#/utils/format.js';
import Heart from '#/components/stashes/heart.vue';
import Gender from './gender.vue';
2024-03-21 01:54:05 +00:00
const props = defineProps({
actor: {
type: Object,
default: null,
},
});
2024-03-21 01:54:05 +00:00
const pageContext = inject('pageContext');
const { user } = pageContext;
const pageStash = pageContext.pageProps.stash;
const currentStash = pageStash || pageContext.assets?.primaryStash;
2024-03-21 01:54:05 +00:00
const favorited = ref(props.actor.stashes.some((actorStash) => actorStash.id === currentStash?.id));
</script>
<style scoped>
2024-03-21 01:54:05 +00:00
.tile {
display: flex;
flex-direction: column;
2024-01-04 00:49:16 +00:00
width: 100%;
position: relative;
aspect-ratio: 3/5;
border-radius: .25rem;
box-shadow: 0 0 3px var(--shadow-weak-30);
2024-01-04 00:49:16 +00:00
overflow: hidden;
background: var(--background);
&:hover {
box-shadow: 0 0 3px var(--shadow-weak-20);
:deep(.bookmarks) .icon:not(.favorited):not(:hover) {
fill: var(--text-light);
}
}
2024-03-21 01:54:05 +00:00
&.unstashed {
opacity: .5;
}
}
2024-10-30 01:25:19 +00:00
.label {
display: flex;
justify-content: space-between;
align-items: center;
flex-shrink: 0;
font-weight: bold;
font-size: .9rem;
2024-01-04 00:49:16 +00:00
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
user-select: all;
}
2024-10-30 01:25:19 +00:00
.name {
padding: .35rem .25rem .35rem .5rem;
}
.favicon {
height: 1rem;
padding: .35rem .5rem .35rem .25rem;
}
2024-03-21 01:54:05 +00:00
.avatar-container {
position: relative;
flex-grow: 1;
2024-03-23 21:44:49 +00:00
overflow: hidden;
background: var(--grey-dark-40);
2024-03-21 01:54:05 +00:00
}
.avatar-link {
2024-03-21 01:54:05 +00:00
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;
}
2024-03-23 21:44:49 +00:00
.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>