<template> <div class="media-container"> <div class="media" :class="{ center: (release.photos?.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.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>