|
| 1 | +<script lang="ts" setup> |
| 2 | +import { NFlex, NSkeleton } from 'naive-ui'; |
| 3 | +import { computed, type PropType, ref, toRefs, Transition } from 'vue'; |
| 4 | +
|
| 5 | +import type { PosterItem } from '~/models/poster.model'; |
| 6 | +import type { ImageQuery, ImageStoreTypes } from '~/stores/data/image.store'; |
| 7 | +
|
| 8 | +import PosterComponent from '~/components/common/poster/PosterComponent.vue'; |
| 9 | +
|
| 10 | +const props = defineProps({ |
| 11 | + tmdb: { |
| 12 | + type: Number, |
| 13 | + required: false, |
| 14 | + }, |
| 15 | + mode: { |
| 16 | + type: String as PropType<ImageStoreTypes>, |
| 17 | + required: true, |
| 18 | + }, |
| 19 | + seasonNumber: { |
| 20 | + type: Number, |
| 21 | + required: false, |
| 22 | + }, |
| 23 | + episodeNumber: { |
| 24 | + type: Number, |
| 25 | + required: false, |
| 26 | + }, |
| 27 | +}); |
| 28 | +
|
| 29 | +const { tmdb, mode, seasonNumber, episodeNumber } = toRefs(props); |
| 30 | +
|
| 31 | +const size = computed(() => window?.innerWidth ?? 800 / 2); |
| 32 | +
|
| 33 | +const posterItem = computed<PosterItem | undefined>(() => { |
| 34 | + const id = tmdb?.value; |
| 35 | + const type = mode?.value; |
| 36 | +
|
| 37 | + if (!id || !type) return; |
| 38 | +
|
| 39 | + const imageQuery: ImageQuery = { |
| 40 | + id, |
| 41 | + type, |
| 42 | + season: seasonNumber?.value, |
| 43 | + episode: episodeNumber?.value, |
| 44 | + }; |
| 45 | +
|
| 46 | + return { |
| 47 | + posterRef: ref(), |
| 48 | + getPosterQuery: () => imageQuery, |
| 49 | + }; |
| 50 | +}); |
| 51 | +
|
| 52 | +const key = computed(() => { |
| 53 | + if (episodeNumber?.value !== undefined && seasonNumber?.value !== undefined) { |
| 54 | + return `episode-${episodeNumber.value}-season-${seasonNumber.value}`; |
| 55 | + } |
| 56 | + if (seasonNumber?.value !== undefined) return `season-${seasonNumber.value}`; |
| 57 | + if (tmdb?.value !== undefined) return `tmdb-${tmdb?.value}`; |
| 58 | + return `placeholder`; |
| 59 | +}); |
| 60 | +</script> |
| 61 | + |
| 62 | +<template> |
| 63 | + <Transition v-if="posterItem" name="scale" mode="out-in"> |
| 64 | + <NFlex :key="key" class="poster-container" :class="{ landscape: mode !== 'season' }"> |
| 65 | + <PosterComponent :item="posterItem" :size="size" backdrop /> |
| 66 | + </NFlex> |
| 67 | + </Transition> |
| 68 | + <NSkeleton |
| 69 | + v-else |
| 70 | + class="poster-container skeleton" |
| 71 | + :class="{ landscape: mode !== 'season' }" |
| 72 | + /> |
| 73 | +</template> |
| 74 | + |
| 75 | +<style lang="scss" scoped> |
| 76 | +@use '~/styles/transition' as transition; |
| 77 | +@include transition.scale; |
| 78 | +
|
| 79 | +.poster-container { |
| 80 | + --poster-height: calc(50dvw * (9 / 16)); |
| 81 | + --poster-width: calc(var(--poster-height) * (2 / 3)); |
| 82 | +
|
| 83 | + &.landscape { |
| 84 | + --poster-width: 50dvw; |
| 85 | + --poster-height: calc(var(--poster-width) * (9 / 16)); |
| 86 | + } |
| 87 | +
|
| 88 | + &.skeleton { |
| 89 | + width: var(--poster-width); |
| 90 | + height: var(--poster-height); |
| 91 | + } |
| 92 | +
|
| 93 | + position: relative; |
| 94 | + margin-bottom: 1rem; |
| 95 | + border: 1px solid var(--border-white); |
| 96 | + box-shadow: var(--image-box-shadow); |
| 97 | +} |
| 98 | +</style> |
0 commit comments