<template> <div v-if="actor" class="actor" > <div 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> <RouterLink :to="hasScrolled ? '' : { name: 'actor', params: { actorId: actor.id, actorSlug: actor.slug } }" class="avatar-container" > <img v-if="actor.avatar" :src="getPath(actor.avatar, 'thumbnail')" :style="{ 'background-image': getBgPath(actor.avatar, 'lazy') }" loading="lazy" draggable="false" class="avatar" > <span v-else class="avatar" ><img :src="`/img/avatar_${actor.gender || 'female'}.svg`" draggable="false" class="avatar-fallback" ></span> <Icon v-show="(!stash || stash.primary) && favorited" icon="heart7" class="stash stashed" @click.stop.native="unstashActor" /> <Icon v-show="(!stash || stash.primary) && favorited === false" icon="heart8" class="stash unstashed" @click.stop.native="stashActor" /> <Icon v-show="stash && !stash.primary" icon="cross2" class="stash unstash" @click.stop.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> </RouterLink> </div> </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, }, hasScrolled: { type: Boolean, default: false, }, }, 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); cursor: pointer; } .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>