387 lines
6.8 KiB
Vue
Executable File
387 lines
6.8 KiB
Vue
Executable File
<template>
|
|
<div
|
|
v-if="actor"
|
|
class="actor"
|
|
>
|
|
<RouterLink
|
|
:to="{ name: 'actor', params: { actorId: actor.id, actorSlug: actor.slug } }"
|
|
class="link"
|
|
>
|
|
<span
|
|
class="handle"
|
|
>
|
|
<span
|
|
v-tooltip.top="actor.name"
|
|
class="name"
|
|
>{{ actor.name }}</span>
|
|
|
|
<RouterLink
|
|
v-if="actor.entity"
|
|
v-tooltip="actor.entity.name"
|
|
:to="{ name: actor.entity.type, params: { entitySlug: actor.entity.slug, range: 'new', pageNumber: 1 } }"
|
|
class="favicon"
|
|
>
|
|
<img
|
|
:src="`/img/logos/${actor.entity.slug}/favicon_light.png`"
|
|
class="favicon-icon"
|
|
>
|
|
</RouterLink>
|
|
|
|
<Icon
|
|
v-if="alias"
|
|
v-tooltip="`Alias of ${alias.name}`"
|
|
icon="users3"
|
|
class="favicon alias"
|
|
/>
|
|
|
|
<Icon
|
|
v-if="actor.dateOfDeath"
|
|
v-tooltip="`Died ${formatDate(actor.dateOfDeath, 'MMMM D, YYYY')}`"
|
|
icon="tombstone"
|
|
class="favicon died"
|
|
/>
|
|
</span>
|
|
|
|
<div class="avatar-container">
|
|
<img
|
|
v-if="actor.avatar"
|
|
:src="getPath(actor.avatar, 'thumbnail')"
|
|
:style="{ 'background-image': getBgPath(actor.avatar, 'lazy') }"
|
|
loading="lazy"
|
|
class="avatar"
|
|
>
|
|
|
|
<span
|
|
v-else
|
|
class="avatar"
|
|
><img
|
|
:src="`/img/avatar_${actor.gender || 'female'}.svg`"
|
|
class="avatar-fallback"
|
|
></span>
|
|
|
|
<Icon
|
|
v-show="(!stash || stash.primary) && favorited"
|
|
icon="heart7"
|
|
class="stash stashed"
|
|
@click.prevent.native="unstashActor"
|
|
/>
|
|
|
|
<Icon
|
|
v-show="(!stash || stash.primary) && favorited === false"
|
|
icon="heart8"
|
|
class="stash unstashed"
|
|
@click.prevent.native="stashActor"
|
|
/>
|
|
|
|
<Icon
|
|
v-show="stash && !stash.primary"
|
|
icon="cross2"
|
|
class="stash unstash"
|
|
@click.prevent.native="unstashActor"
|
|
/>
|
|
|
|
<span
|
|
class="details"
|
|
>
|
|
<span class="gender-age">
|
|
<Gender :gender="actor.gender" />
|
|
|
|
<span
|
|
v-if="actor.ageAtDeath"
|
|
v-tooltip="`Born ${formatDate(actor.dateOfBirth, 'MMMM D, YYYY')}<br>Died ${formatDate(actor.dateOfDeath, 'MMMM D, YYYY')}`"
|
|
class="age-death"
|
|
>{{ actor.ageAtDeath }}</span>
|
|
|
|
<span
|
|
v-else-if="actor.ageFromBirth"
|
|
v-tooltip="`Born on ${formatDate(actor.dateOfBirth, 'MMMM D, YYYY')}`"
|
|
class="age-now"
|
|
>{{ actor.ageFromBirth }}</span>
|
|
|
|
<span
|
|
v-else-if="actor.age"
|
|
v-tooltip="`At least ${actor.age}`"
|
|
class="age-now"
|
|
>{{ actor.age }}</span>
|
|
|
|
<span
|
|
v-if="actor.ageThen && actor.ageThen < actor.ageFromBirth"
|
|
v-tooltip="`${actor.ageThen} years old on release date`"
|
|
class="age-then"
|
|
>{{ actor.ageThen }}</span>
|
|
</span>
|
|
|
|
<span
|
|
v-if="actor.origin"
|
|
v-tooltip="`Born in ${actor.origin.country.alias || actor.origin.country.name}`"
|
|
class="country"
|
|
>
|
|
{{ actor.origin.country.alpha2 }}
|
|
<img
|
|
class="flag"
|
|
:src="`/img/flags/${actor.origin.country.alpha2.toLowerCase()}.svg`"
|
|
>
|
|
</span>
|
|
|
|
<span
|
|
v-else
|
|
class="country"
|
|
/>
|
|
</span>
|
|
</div>
|
|
</RouterLink>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import Gender from './gender.vue';
|
|
|
|
async function stashActor() {
|
|
this.favorited = true;
|
|
|
|
try {
|
|
await this.$store.dispatch('stashActor', {
|
|
actorId: this.actor.id,
|
|
stashId: this.$store.getters.favorites.id,
|
|
});
|
|
|
|
this.$emit('stash', true);
|
|
} catch (error) {
|
|
this.favorited = false;
|
|
}
|
|
}
|
|
|
|
async function unstashActor() {
|
|
if (!this.stash || this.stash.primary) {
|
|
this.favorited = false;
|
|
}
|
|
|
|
try {
|
|
await this.$store.dispatch('unstashActor', {
|
|
actorId: this.actor.id,
|
|
stashId: this.stash?.id || this.$store.getters.favorites.id,
|
|
});
|
|
|
|
this.$emit('stash', false);
|
|
} catch (error) {
|
|
this.favorited = true;
|
|
}
|
|
}
|
|
|
|
function sfw() {
|
|
return this.$store.state.ui.sfw;
|
|
}
|
|
|
|
export default {
|
|
components: {
|
|
Gender,
|
|
},
|
|
props: {
|
|
actor: {
|
|
type: Object,
|
|
default: null,
|
|
},
|
|
alias: {
|
|
type: Object,
|
|
default: null,
|
|
},
|
|
stash: {
|
|
type: Object,
|
|
default: null,
|
|
},
|
|
},
|
|
emits: ['stash'],
|
|
data() {
|
|
return {
|
|
favorited: this.actor.isFavorited,
|
|
};
|
|
},
|
|
computed: {
|
|
sfw,
|
|
},
|
|
methods: {
|
|
stashActor,
|
|
unstashActor,
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
@import 'theme';
|
|
|
|
.actor {
|
|
width: 100%;
|
|
display: inline-block;
|
|
position: relative;
|
|
box-shadow: 0 0 3px var(--darken-weak);
|
|
background: var(--info);
|
|
overflow: hidden;
|
|
|
|
&::before {
|
|
content: '';
|
|
display: inline-block;
|
|
padding-bottom: 150%;
|
|
}
|
|
|
|
&:hover .unstashed,
|
|
&:hover .unstash {
|
|
fill: var(--lighten);
|
|
}
|
|
}
|
|
|
|
.link {
|
|
width: 100%;
|
|
height: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
color: var(--text-light);
|
|
text-decoration: none;
|
|
}
|
|
|
|
.handle {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-weight: bold;
|
|
box-shadow: 0 0 3px var(--shadow);
|
|
|
|
.name {
|
|
padding: .25rem .5rem;
|
|
font-size: .9rem;
|
|
}
|
|
|
|
.alias {
|
|
fill: var(--shadow);
|
|
}
|
|
}
|
|
|
|
.favicon {
|
|
font-size: 0;
|
|
padding: .5rem .25rem;
|
|
|
|
&:last-child {
|
|
padding: .5rem;
|
|
}
|
|
|
|
&.died {
|
|
fill: var(--shadow);
|
|
}
|
|
}
|
|
|
|
.favicon-icon {
|
|
width: 1rem;
|
|
height: 1rem;
|
|
}
|
|
|
|
.name {
|
|
flex-grow: 1;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.avatar-container {
|
|
display: flex;
|
|
flex-grow: 1;
|
|
position: relative;
|
|
overflow: hidden;
|
|
background: var(--profile);
|
|
}
|
|
|
|
.avatar {
|
|
color: var(--darken-weak);
|
|
background: var(--darken-hint);
|
|
width: 100%;
|
|
height: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
object-fit: cover;
|
|
object-position: center 0;
|
|
background-size: cover;
|
|
background-position: center 0;
|
|
}
|
|
|
|
.avatar-fallback {
|
|
max-height: 100%;
|
|
max-width: 100%;
|
|
opacity: .1;
|
|
}
|
|
|
|
.stash {
|
|
width: 1.5rem;
|
|
height: 1.5rem;
|
|
padding: .25rem .25rem .5rem .5rem;
|
|
position: absolute;
|
|
top: 0;
|
|
right: 0;
|
|
fill: var(--lighten-weak);
|
|
filter: drop-shadow(0 0 2px var(--darken));
|
|
|
|
&:hover.unstashed,
|
|
&.stashed {
|
|
fill: var(--primary);
|
|
}
|
|
|
|
&:hover.unstash {
|
|
fill: var(--text-light);
|
|
filter: drop-shadow(0 0 2px var(--darken-weak));
|
|
}
|
|
}
|
|
|
|
.details {
|
|
background: var(--darken);
|
|
color: var(--text-light);
|
|
width: 100%;
|
|
height: 1.75rem;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
box-sizing: border-box;
|
|
padding: .5rem;
|
|
position: absolute;
|
|
bottom: 0;
|
|
font-size: .9rem;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.gender-age {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.gender {
|
|
margin: .25rem .25rem 0 0;
|
|
}
|
|
|
|
.country {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
align-items: center;
|
|
}
|
|
|
|
.flag {
|
|
height: .75rem;
|
|
margin: 0 0 0 .5rem;
|
|
}
|
|
|
|
.age-now,
|
|
.age-death {
|
|
margin: 0 .25rem 0 0;
|
|
}
|
|
|
|
.age-then {
|
|
color: var(--lighten);
|
|
}
|
|
|
|
@media(max-width: $breakpoint) {
|
|
.name {
|
|
font-size: .9rem;
|
|
}
|
|
}
|
|
</style>
|