<template> <div class="tile"> <Details :release="movie" /> <div class="movie"> <RouterLink :to="{ name: 'movie', params: { releaseId: movie.id, releaseSlug: movie.slug } }" class="cover" > <img v-if="movie.covers[0]" :src="getPath(movie.covers[0], 'thumbnail')" :style="{ 'background-image': getBgPath(movie.covers[0], 'lazy') }" loading="lazy" > <div v-else :title="movie.title" class="unavailable" ><Icon icon="blocked" /></div> <Icon v-show="(!stash || stash.primary) && favorited" icon="heart7" class="stash stashed" @click.prevent.native="unstashMovie" /> <Icon v-show="(!stash || stash.primary) && favorited === false" icon="heart8" class="stash unstashed" @click.prevent.native="stashMovie" /> <Icon v-show="stash && !stash.primary" icon="cross2" class="stash unstash" @click.prevent.native="unstashMovie" /> </RouterLink> <div class="info"> <RouterLink :to="{ name: 'movie', params: { releaseId: movie.id, releaseSlug: movie.slug } }" class="title-link" > <h3 class="title">{{ movie.title }}</h3> </RouterLink> <ul class="actors nolist" :title="movie.actors.map(actor => actor.name).join(', ')" > <li v-for="actor in movie.actors" :key="`tag-${movie.id}-${actor.id}`" class="actor" ><RouterLink :to="`/actor/${actor.id}/${actor.slug}`" class="actor-link" >{{ actor.name }}</RouterLink></li> </ul> <ul class="tags nolist" :title="movie.tags.map(tag => tag.name).join(', ')" > <li v-for="tag in movie.tags" :key="`tag-${movie.id}-${tag.id}`" class="tag" ><RouterLink :to="`/tag/${tag.slug}`" class="tag-link" >{{ tag.name }}</RouterLink></li> </ul> </div> </div> </div> </template> <script> import Details from './tile-details.vue'; async function stashMovie() { this.favorited = true; try { await this.$store.dispatch('stashMovie', { movieId: this.movie.id, stashId: this.$store.getters.favorites.id, }); this.$emit('stash', true); } catch (error) { this.favorited = false; } } async function unstashMovie() { if (!this.stash || this.stash.primary) { this.favorited = false; } try { await this.$store.dispatch('unstashMovie', { movieId: this.movie.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: { Details, }, props: { movie: { type: Object, default: null, }, stash: { type: Object, default: null, }, }, data() { return { favorited: this.movie.isFavorited, }; }, computed: { sfw, }, methods: { stashMovie, unstashMovie, }, }; </script> <style lang="scss" scoped> @import 'breakpoints'; .tile { display: flex; flex-direction: column; background: var(--background); box-shadow: 0 0 3px var(--darken-weak); font-size: 0; &:hover .unstashed, &:hover .unstash { fill: var(--lighten); } } .movie { display: flex; } .title-link { color: var(--text); text-decoration: none; } .cover { height: 16rem; width: 11.25rem; display: flex; align-items: center; justify-content: center; flex-shrink: 0; position: relative; box-shadow: 0 0 3px var(--darken-weak); background-color: var(--shadow-hint); img { height: 100%; width: 100%; background-position: center; background-size: cover; object-fit: cover; object-position: center; } .unavailable .icon { width: 2rem; height: 2rem; fill: var(--shadow-hint); } } .info { display: flex; flex-direction: column; flex-grow: 1; overflow: hidden; } .title { box-sizing: border-box; padding: 1rem; margin: 0; font-size: 1rem; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; } .actors { height: 0; flex-grow: 1; padding: 0 1rem; line-height: 1.5; overflow: hidden; } .actor:not(:last-child)::after { content: ','; margin: 0 .25rem 0 0; font-size: 1rem; } .actor-link { font-size: 1rem; color: var(--link); text-decoration: none; &:hover { color: var(--primary); } } .tags { padding: .25rem 1rem; height: 1.75rem; line-height: 2; overflow: hidden; } .tag { margin: 0 0 .5rem 0; } .tag-link { background: var(--background); font-size: .75rem; padding: .25rem .5rem; color: var(--shadow); font-weight: bold; text-decoration: none; box-shadow: 0 0 3px var(--shadow-weak); &:hover { color: var(--primary); } } .stash { width: 1.5rem; height: 1.5rem; padding: .25rem .5rem .5rem .5rem; position: absolute; top: 0; left: 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)); } } @media(max-width: $breakpoint-kilo) { .cover { height: 12rem; width: 8.25rem; } /* ensure no half actor names show */ .actors { margin: 0 0 1rem 0; } } </style>