forked from DebaucheryLibrarian/traxxx
				
			
		
			
				
	
	
		
			394 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Vue
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			394 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Vue
		
	
	
		
			Executable File
		
	
	
| <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>
 |