<template> <div class="page"> <div class="content"> <Banner :release="movie" /> <div class="meta"> <div class="entity"> <Link v-if="movie.channel" :href="`/${movie.channel.type}/${movie.channel.slug}`" class="channel-link entity-link" > <img v-if="movie.channel.hasLogo" :src="movie.channel.isIndependent || !movie.network ? `/logos/${movie.channel.slug}/network.png` : `/logos/${movie.network.slug}/${movie.channel.slug}.png`" class="channel-logo entity-logo" > </Link> <span v-if="!movie.channel.isIndependent && movie.network" class="network-container" > by <Link :href="`/${movie.network.type}/${movie.network.slug}`" class="network-link entity-link" > <img v-if="movie.network.hasLogo" :src="`/logos/${movie.network.slug}/network.png`" class="network-logo entity-logo" > </Link> </span> </div> <time :datetime="movie.effectiveDate.toISOString()" class="date ellipsis" >{{ formatDate(movie.effectiveDate, { month: 'MMMM y', year: 'y', }[movie.datePrecision] || 'MMMM d, y') }}</time> </div> <div class="header"> <h2 v-if="movie.title" :title="movie.title" class="title" >{{ movie.title }}</h2> <h2 v-else-if="movie.actors.length > 0" class="title notitle" >movie featuring {{ movie.actors.map((actor) => actor.name).join(', ') }}</h2> <h2 v-else class="title notitle" >No title</h2> <div class="actions"> <Heart domain="movies" :item="movie" /> <div class="view"> <button v-if="movie.photos.length > 0" class="button view nolink" >View photos</button> <a v-if="movie.url" :href="movie.url" target="_blank" class="button watch nolink" :data-umami-event="movie.affiliate ? 'watch-click-aff' : 'watch-click'" :data-umami-event-movie-id="`${(movie.channel || movie.network).slug}:movie:${movie.id}`" :data-umami-event-aff-id="movie.affiliate && `aff:${movie.affiliate.id}`" :data-umami-event-channel="movie.channel?.slug" :data-umami-event-network="movie.network?.slug" >Watch full movie</a> </div> </div> </div> <div class="info"> <ul class="actors nolist"> <li v-for="actor in movie.actors" :key="`actor-${actor.id}`" class="actor" > <ActorTile :actor="actor" /> </li> </ul> <ul class="tags nolist"> <li v-for="tag in movie.tags" :key="`tag-${tag.id}`" > <Link :href="`/tag/${tag.slug}`" class="tag nolink" >{{ tag.name }}</Link> </li> </ul> <div v-if="scenes.length > 0" class="section" > <h3 class="heading">Scenes</h3> <ul class="scenes nolist"> <li v-for="scene in scenes" :key="`scene-${scene.id}`" > <SceneTile :scene="scene" /> </li> </ul> </div> <div v-if="movie.description" class="section" > <h3 class="heading">Description</h3> <p class="description">{{ movie.description }}</p> </div> <div class="section details"> <div v-if="movie.duration" class="detail" > <h3 class="heading">Duration</h3> {{ formatDuration(movie.duration) }} </div> <div v-if="movie.directors.length > 0" class="detail" > <h3 class="heading">Director</h3> {{ movie.directors.map((director) => director.name).join(', ') }} </div> <div v-if="movie.shootId" class="detail" > <h3 class="heading">Shoot</h3> {{ movie.shootId }} </div> </div> <div class="section details"> <div class="detail"> <h3 class="heading">Added</h3> <span class="added-date">{{ formatDate(movie.createdAt, 'yyyy-MM-dd') }}</span> <span :title="`Batch ${movie.createdBatchId}`" class="added-batch" >#{{ movie.createdBatchId }}</span> </div> <div v-if="movie.comment" class="detail" > <h3 class="heading">Comment</h3> {{ movie.comment }} </div> </div> </div> </div> </div> </template> <script setup> import { inject } from 'vue'; import { formatDate, formatDuration } from '#/utils/format.js'; import Banner from '#/components/media/banner.vue'; import ActorTile from '#/components/actors/tile.vue'; import SceneTile from '#/components/scenes/tile.vue'; import Heart from '#/components/stashes/heart.vue'; const pageContext = inject('pageContext'); const movie = pageContext.pageProps.movie; const scenes = pageContext.pageProps.scenes; </script> <style scoped> .page { display: flex; flex-grow: 1; justify-content: center; background: var(--background-base-10); } .content { width: 100%; max-width: 1200px; margin: 0 .5rem; display: flex; flex-direction: column; } .meta { display: flex; justify-content: space-between; align-items: center; background: var(--grey-dark-40); border-radius: 0 0 .5rem .5rem; color: var(--text-light); } .entity { display: flex; align-items: center; font-weight: bold; color: var(--highlight); } .entity-link { padding: .5rem 1rem; } .entity-logo { width: 10rem; max-height: 100%; object-fit: contain; } .network-container { display: flex; align-items: center; } .date { padding: 1rem; font-weight: bold; } .info, .header { border-top: none; border-bottom: none; } .info { padding: 0; } .header { display: flex; align-items: flex-start; justify-content: space-between; padding: 1rem .5rem .5rem .5rem; } .title { margin: 0 .5rem 1rem 0; line-height: 1.25; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; } .notitle { color: var(--grey-dark-10); } .actions { display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; .icon { width: 1.5rem; height: 1.5rem; fill: var(--glass); } .button { flex-shrink: 0; padding: .75rem; } .button:not(:last-child) { margin-right: .5rem; } } .bookmarks { margin-right: .75rem; } .view { display: flex; } .watch { padding: .75rem 2rem; margin-left: .25rem; font-size: 1rem; background: var(--primary); color: var(--text-light); } .actors, .tags { margin-bottom: 1rem; } .section { margin-bottom: 1rem; } .heading { color: var(--primary); margin: 0 0 .5rem 0; font-size: .9rem; } .details { display: flex; gap: 1rem; } .description { font-size: 1rem; line-height: 1.5; text-align: justify; margin: 0; } .added-batch { color: var(--glass-weak-10); margin-left: .25rem; } .actors { display: grid; flex-grow: 1; grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr)); gap: .25rem; } .tag { padding: .5rem; border-radius: .25rem; margin: 0 .25rem .25rem 0; background: var(--background); box-shadow: 0 0 3px var(--shadow-weak-30); &:hover { color: var(--primary); box-shadow: 0 0 3px var(--shadow-weak-20); cursor: pointer; } } .scenes { display: grid; grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr)); gap: .5rem; margin-bottom: 1rem; } @media(--small) { .content { margin: 0; } .info { margin: 0 .5rem; } .network-container { display: none; } .header { flex-direction: column-reverse; } .actions { width: 100%; justify-content: space-between; margin-bottom: 1.5rem; } .title { width: 100%; margin-left: .5rem; white-space: wrap; } .meta { border-radius: 0; } .entity-logo { width: 7.5rem; } } @media(--small-10) { .header { padding: 1rem .5rem 1.5rem .5rem; } .info { padding: 0 .5rem; } .actors { grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr)); } } @media(--small-60) { .actors { grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr)); } } </style>