forked from DebaucheryLibrarian/traxxx
				
			
		
			
				
	
	
		
			386 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Vue
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			386 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Vue
		
	
	
		
			Executable File
		
	
	
| <template>
 | |
| 	<div class="media-container">
 | |
| 		<div
 | |
| 			class="media"
 | |
| 			:class="{ center: (release.photos?.length || 0) + (release.caps?.length || 0) + (release.scenesPhotos?.length || 0) < 2, preview: !me }"
 | |
| 		>
 | |
| 			<div
 | |
| 				v-if="release.trailer || release.teaser"
 | |
| 				class="trailer-container"
 | |
| 			>
 | |
| 				<Player
 | |
| 					v-if="release.trailer"
 | |
| 					:video="release.trailer"
 | |
| 					:poster="poster"
 | |
| 					class="item trailer"
 | |
| 					@play="playing = true; paused = false;"
 | |
| 					@pause="playing = false; paused = true;"
 | |
| 				/>
 | |
| 
 | |
| 				<Player
 | |
| 					v-else-if="release.teaser && /^video\//.test(release.teaser.mime)"
 | |
| 					:video="release.teaser"
 | |
| 					:poster="poster"
 | |
| 					:alt="release.title"
 | |
| 					:class="{ sfw: sfw && paused }"
 | |
| 					class="item trailer"
 | |
| 					@play="playing = true; paused = false;"
 | |
| 					@pause="playing = false; paused = true;"
 | |
| 				/>
 | |
| 
 | |
| 				<img
 | |
| 					v-else-if="release.teaser && /^image\//.test(release.teaser.mime)"
 | |
| 					:src="getPath(release.teaser, 'thumbnail', { original: true })"
 | |
| 					:alt="release.title"
 | |
| 					:width="release.teaser.thumbnailWidth"
 | |
| 					:height="release.teaser.thumbnailHeight"
 | |
| 					loading="lazy"
 | |
| 					class="item trailer"
 | |
| 				>
 | |
| 
 | |
| 				<span
 | |
| 					v-if="release.poster || release.teaser"
 | |
| 					class="poster-links"
 | |
| 				>
 | |
| 					<a
 | |
| 						v-if="release.teaser"
 | |
| 						v-tooltip="'View teaser'"
 | |
| 						:href="getPath(release.teaser)"
 | |
| 						:class="{ playing }"
 | |
| 						target="_blank"
 | |
| 						rel="noopener noreferrer"
 | |
| 						class="poster-link"
 | |
| 					><Icon icon="film4" /></a>
 | |
| 
 | |
| 					<a
 | |
| 						v-if="release.poster"
 | |
| 						v-tooltip="'View poster'"
 | |
| 						:href="getPath(release.poster)"
 | |
| 						:class="{ playing }"
 | |
| 						target="_blank"
 | |
| 						rel="noopener noreferrer"
 | |
| 						class="poster-link"
 | |
| 					><Icon icon="image" /></a>
 | |
| 				</span>
 | |
| 
 | |
| 				<span
 | |
| 					v-if="sfw && !playing"
 | |
| 					class="warning"
 | |
| 				>
 | |
| 					<Icon icon="warning2" />NSFW
 | |
| 				</span>
 | |
| 			</div>
 | |
| 
 | |
| 			<template v-if="release.covers?.length > 0">
 | |
| 				<div
 | |
| 					v-for="cover in release.covers"
 | |
| 					:key="`cover-${cover.id}`"
 | |
| 					class="item-container"
 | |
| 				>
 | |
| 					<a
 | |
| 						:href="getPath(cover)"
 | |
| 						target="_blank"
 | |
| 						rel="noopener noreferrer"
 | |
| 					>
 | |
| 						<img
 | |
| 							:src="getPath(cover, 'thumbnail')"
 | |
| 							:style="{ 'background-image': getBgPath(cover, 'lazy') }"
 | |
| 							:width="cover.thumbnailWidth"
 | |
| 							:height="cover.thumbnailHeight"
 | |
| 							class="item cover"
 | |
| 							loading="lazy"
 | |
| 							@load="$emit('load', $event)"
 | |
| 						>
 | |
| 					</a>
 | |
| 				</div>
 | |
| 			</template>
 | |
| 
 | |
| 			<div
 | |
| 				v-for="photo in photos"
 | |
| 				:key="`media-${photo.id}`"
 | |
| 				class="item-container"
 | |
| 			>
 | |
| 				<a
 | |
| 					:href="getPath(photo)"
 | |
| 					:class="{ sfw }"
 | |
| 					class="item-link"
 | |
| 					target="_blank"
 | |
| 					rel="noopener noreferrer"
 | |
| 				>
 | |
| 					<img
 | |
| 						:src="getPath(photo, 'thumbnail')"
 | |
| 						:style="{ 'background-image': `url('${getPath(photo, 'lazy')}` }"
 | |
| 						:alt="`Photo ${photo.index + 1}`"
 | |
| 						:width="photo.thumbnailWidth"
 | |
| 						:height="photo.thumbnailHeight"
 | |
| 						loading="lazy"
 | |
| 						class="item"
 | |
| 						@load="$emit('load', $event)"
 | |
| 					>
 | |
| 
 | |
| 					<span
 | |
| 						v-if="sfw"
 | |
| 						class="warning"
 | |
| 					>
 | |
| 						<Icon icon="warning2" />NSFW
 | |
| 					</span>
 | |
| 				</a>
 | |
| 			</div>
 | |
| 
 | |
| 			<div
 | |
| 				v-if="!me"
 | |
| 				class="item-container item-more"
 | |
| 			><router-link
 | |
| 				:to="{ name: 'login', query: { ref: $route.path } }"
 | |
| 				class="link"
 | |
| 			>Log in</router-link> for more photos, trailers and features!</div>
 | |
| 		</div>
 | |
| 	</div>
 | |
| </template>
 | |
| 
 | |
| <script>
 | |
| import Player from '../video/player.vue';
 | |
| 
 | |
| function sfw() {
 | |
| 	return this.$store.state.ui.sfw;
 | |
| }
 | |
| 
 | |
| function me() {
 | |
| 	return this.$store.state.auth.user;
 | |
| }
 | |
| 
 | |
| function poster() {
 | |
| 	if (this.release.poster) {
 | |
| 		return this.getPath(this.release.poster, 'thumbnail');
 | |
| 	}
 | |
| 
 | |
| 	if (this.release.covers?.length > 0) {
 | |
| 		return this.getPath(this.release.covers[0], 'thumbnail');
 | |
| 	}
 | |
| 
 | |
| 	if (this.photos?.length > 0) {
 | |
| 		return this.getPath(this.release.photos[0], 'thumbnail');
 | |
| 	}
 | |
| 
 | |
| 	return null;
 | |
| }
 | |
| 
 | |
| function photos() {
 | |
| 	const clips = this.release.clips || [];
 | |
| 	const clipPostersById = clips.reduce((acc, clip) => ({ ...acc, [clip.poster.id]: clip.poster }), {});
 | |
| 	const uniqueClipPosters = Array.from(new Set(clips.map((clip) => clip.poster.id) || [])).map((posterId) => clipPostersById[posterId]);
 | |
| 	const photosWithClipPosters = (this.release.photos || []).concat(this.release.caps || []).concat(this.release.scenesPhotos || []).concat(uniqueClipPosters);
 | |
| 
 | |
| 	if (this.release.trailer || (this.release.teaser && this.release.teaser.mime !== 'image/gif')) {
 | |
| 		// poster will be on trailer video
 | |
| 		return photosWithClipPosters;
 | |
| 	}
 | |
| 
 | |
| 	if (this.release.poster) {
 | |
| 		// no trailer, add poster to photos
 | |
| 		return [this.release.poster].concat(photosWithClipPosters);
 | |
| 	}
 | |
| 
 | |
| 	// no poster available
 | |
| 	return photosWithClipPosters;
 | |
| }
 | |
| 
 | |
| export default {
 | |
| 	components: {
 | |
| 		Player,
 | |
| 	},
 | |
| 	props: {
 | |
| 		release: {
 | |
| 			type: Object,
 | |
| 			default: null,
 | |
| 		},
 | |
| 		expanded: {
 | |
| 			type: Boolean,
 | |
| 			default: false,
 | |
| 		},
 | |
| 		test: {
 | |
| 			type: String,
 | |
| 			default: null,
 | |
| 		},
 | |
| 	},
 | |
| 	emits: ['load'],
 | |
| 	data() {
 | |
| 		return {
 | |
| 			player: null,
 | |
| 			playing: false,
 | |
| 			paused: false,
 | |
| 		};
 | |
| 	},
 | |
| 	computed: {
 | |
| 		me,
 | |
| 		photos,
 | |
| 		poster,
 | |
| 		sfw,
 | |
| 	},
 | |
| };
 | |
| </script>
 | |
| 
 | |
| <style lang="scss" scoped>
 | |
| @import 'breakpoints';
 | |
| 
 | |
| .media {
 | |
|     flex-shrink: 0;
 | |
|     white-space: nowrap;
 | |
|     font-size: 0;
 | |
| }
 | |
| 
 | |
| .media.center {
 | |
| 	width: 1200px;
 | |
| 	max-width: 100%;
 | |
| 	display: flex;
 | |
| 	margin: 0 auto;
 | |
| }
 | |
| 
 | |
| .poster-links {
 | |
| 	display: flex;
 | |
|     position: absolute;
 | |
| 	top: 0;
 | |
| 	right: 0;
 | |
| }
 | |
| 
 | |
| .poster-link {
 | |
|     transition: opacity .1s ease;
 | |
| 	padding: .5rem;
 | |
| 
 | |
|     .icon {
 | |
|         width: 1.5rem;
 | |
|         height: 1.5rem;
 | |
|         fill: var(--lighten-strong);
 | |
|         filter: drop-shadow(0 0 1px var(--darken-weak));
 | |
|     }
 | |
| 
 | |
|     &.playing {
 | |
|         opacity: 0;
 | |
|     }
 | |
| 
 | |
| 	&:first-child {
 | |
| 		padding-left: .75rem;
 | |
| 	}
 | |
| 
 | |
| 	&:last-child {
 | |
| 		padding-right: .75rem;
 | |
| 	}
 | |
| 
 | |
|     &:hover {
 | |
|         cursor: pointer;
 | |
|         opacity: 1;
 | |
| 
 | |
|         .icon {
 | |
|             fill: var(--text-light);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| .item-container,
 | |
| .trailer-container {
 | |
| 	height: 100%;
 | |
| 	max-width: 100%;
 | |
|     position: relative;
 | |
|     display: inline-flex;
 | |
|     align-items: center;
 | |
|     justify-content: center;
 | |
| 	flex-shrink: 0;
 | |
| 
 | |
|     .warning {
 | |
|         display: none;
 | |
|         width: 100%;
 | |
|         height: 100%;
 | |
|         flex-direction: column;
 | |
|         align-items: center;
 | |
|         justify-content: center;
 | |
|         position: absolute;
 | |
|         background: var(--darken-weak);
 | |
|         color: var(--text-light);
 | |
|         font-size: 1.2rem;
 | |
|         font-weight: bold;
 | |
|         text-shadow: 0 0 3px var(--darken-strong);
 | |
|         pointer-events: none;
 | |
|         animation: alert .5s ease infinite .1s;
 | |
| 
 | |
|         .icon {
 | |
|             display: block;
 | |
|             fill: var(--text-light);
 | |
|             width: 3rem;
 | |
|             height: 3rem;
 | |
|             margin: 0 0 .25rem 0;
 | |
|             filter: drop-shadow(0 0 3px var(--darken));
 | |
|             animation: alert .5s ease infinite .1s;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     &:hover .warning {
 | |
|         display: inline-flex;
 | |
|     }
 | |
| }
 | |
| 
 | |
| .item {
 | |
| 	max-width: 100%;
 | |
| 	width: auto;
 | |
| 	height: 18rem;
 | |
| 	box-shadow: 0 0 3px var(--shadow-weak);
 | |
| 	background-size: cover;
 | |
| }
 | |
| 
 | |
| .item-more {
 | |
| 	height: auto;
 | |
| 	flex-grow: 1;
 | |
| 	align-items: center;
 | |
| 	padding: .5rem 2rem;
 | |
| 	color: var(--text-light);
 | |
| 	text-shadow: 0 0 3px var(--darken);
 | |
| 	font-weight: bold;
 | |
| 	font-size: 1rem;
 | |
| 
 | |
| 	.link {
 | |
| 		color: inherit;
 | |
| 		text-decoration: underline;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| .trailer-container {
 | |
| 	width: 32rem;
 | |
|     max-width: 100%;
 | |
| }
 | |
| 
 | |
| .trailer {
 | |
| 	width: 100%;
 | |
| 	max-width: 32rem;
 | |
| 	max-height: 100%;
 | |
| 
 | |
|     &.sfw {
 | |
|         filter: blur(2rem);
 | |
|     }
 | |
| }
 | |
| 
 | |
| @keyframes alert {
 | |
|     0% {
 | |
|         color: var(--text-light);
 | |
|         fill: var(--text-light);
 | |
|     }
 | |
|     50% {
 | |
|         color: var(--alert);
 | |
|         fill: var(--alert);
 | |
|     }
 | |
| }
 | |
| 
 | |
| @media(max-width: $breakpoint-micro) {
 | |
| 	.media.center.preview {
 | |
| 		flex-direction: column;
 | |
| 	}
 | |
| 
 | |
| 	.item-more {
 | |
| 		font-size: .9rem;
 | |
| 	}
 | |
| 
 | |
| 	.media:not(.expanded) .item,
 | |
|     .trailer-container {
 | |
| 		height: 56vw; /* 16:9 ratio for full-width video */
 | |
|     }
 | |
| }
 | |
| </style>
 |