Browse Source

Added MoviePoster component that always maintains a proper aspect ratio

master
David Ludwig 4 years ago
parent
commit
45ecf810dc
3 changed files with 73 additions and 15 deletions
  1. +53
    -0
      src/app/components/MoviePoster.vue
  2. +12
    -11
      src/app/components/modals/MovieModal.vue
  3. +8
    -4
      src/app/views/Search.vue

+ 53
- 0
src/app/components/MoviePoster.vue View File

@ -0,0 +1,53 @@
<template>
<div class="poster">
<div class="poster-padding"></div>
<img v-if="src" class="poster-content w-full h-full object-cover" loading="lazy" ref="poster"
:src="`/api/tmdb/image/${size}${src}`" @load="onPosterLoad">
<div v-else class="poster-content bg-gray-300 text-gray-500">
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="image" class="svg-inline--fa fa-image fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M464 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h416c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48zM112 120c-30.928 0-56 25.072-56 56s25.072 56 56 56 56-25.072 56-56-25.072-56-56-56zM64 384h384V272l-87.515-87.515c-4.686-4.686-12.284-4.686-16.971 0L208 320l-55.515-55.515c-4.686-4.686-12.284-4.686-16.971 0L64 336v48z"></path></svg>
<!-- <img v-else class="w-full h-full object-cover" loading="lazy" :ref="`poster-${index}`"
:src="`/api/tmdb/image/w185${movie.poster_path}`"> -->
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
data() {
return {
isLoaded: false
}
},
methods: {
onPosterLoad() {
this.isLoaded = true;
this.$emit("onLoad", this.$refs["poster"]);
}
},
props: {
size: {
type: String,
default: "w342"
},
src: String
}
});
</script>
<style lang="postcss">
.poster {
@apply relative overflow-hidden;
}
.poster > .poster-padding {
padding-top: 143.885%;
}
.poster > .poster-content {
@apply absolute inset-0 flex justify-center items-center;
}
.poster > .poster-content > svg {
width: 35%;
}
</style>

+ 12
- 11
src/app/components/modals/MovieModal.vue View File

@ -2,16 +2,13 @@
<transition appear name="fade">
<div class="modal p-8 overflow-auto items-center" @click.self="close">
<transition name="slide">
<div v-if="movie !== undefined" class="relative w-full max-w-6xl bg-white overflow-hidden rounded-xl flex-col flex-shrink-0 shadow-xl">
<div v-if="movie !== undefined" class="relative w-full max-w-6xl bg-white md:bg-none overflow-hidden rounded-xl flex-col flex-shrink-0 shadow-xl">
<div class="bg-center bg-cover" :class="{ 'text-white': isDark }"
:style="movie.backdrop_path ? `background: url('/api/tmdb/image/w1280${movie.backdrop_path}')` : ''">
<div class="movie-modal-content z-10" :style="backdropOverlayStyle">
<div class="flex p-4">
<div class="w-24 h-40 flex-shrink-0 md:h-auto md:w-72 rounded-lg md:rounded-xl overflow-hidden shadow-md mdshadow-xl">
<i v-if="!movie.poster_path" class="fas fa-image mx-auto my-auto"></i>
<img v-else class="w-full h-full object-cover" ref="poster"
:src="`/api/tmdb/image/w342${movie.poster_path}`" @load="onPosterLoad">
</div>
<div class="flex p-4 items-center">
<movie-poster v-if="movie.poster_path" :src="movie.poster_path"
class="w-3/12 flex-shrink-0 rounded-xl shadow-md md:shadow-xl" @onLoad="onPosterLoad"/>
<div class="p-4 flex flex-col justify-center">
<h2 class="text-lg md:text-4xl">
<span class="font-bold">{{ movie.title }}</span>
@ -58,8 +55,12 @@ import { IApiMovieDetailsResponse, IApiMovieDetails } from "@common/api_schema";
import { authFetch } from "../../routes";
import { getAverageRgb } from "../../util";
import { useStore, Mutation, Action } from "../../store";
import MoviePoster from "../MoviePoster.vue";
export default defineComponent({
components: {
MoviePoster
},
computed: {
backdropOverlayStyle(): string {
let { r, g, b } = this.rgb;
@ -119,15 +120,15 @@ export default defineComponent({
}
this.close();
},
onPosterLoad() {
onPosterLoad(img: HTMLImageElement) {
this.isPosterLoaded = true;
this.computeBackdropColor();
this.computeBackdropColor(img);
},
computeBackdropColor() {
computeBackdropColor(img: HTMLImageElement) {
// This is being weird and this is the only way I can fix it...
let rgb: {[k: string]: number} = {r: 0, g: 0, b: 0};
try {
rgb = getAverageRgb(<HTMLImageElement>this.$refs["poster"]);
rgb = getAverageRgb(img);
} catch(e) {
return { r: 0, g: 0, b: 0 };
}


+ 8
- 4
src/app/views/Search.vue View File

@ -9,11 +9,13 @@
<ul class="w-full grid gap-8 grid-cols-2 sm:grid-cols-4 md:grid-cols-5 lg:grid-cols-6 xl:grid-cols-8 2xl:grid-cols-10 self-center ">
<li class="inline-block" v-for="(movie, index) in movies">
<router-link :to="{ name: 'Lookup', params: { movieId: movie.id }, query: $route.query }">
<div class="w-full h-full flex shadow-md hover:shadow-lg bg-gray-300 text-gray-500 text-4xl overflow-hidden rounded-xl cursor-pointer motion-safe:transform hover:scale-105 transition-transform ease-out">
<movie-poster class="shadow-md hover:shadow-lg rounded-xl motion-safe:transform hover:scale-105 transition-transform ease-out"
:src="movie.poster_path ?? undefined" size="w185"/>
<!-- <div class="w-full h-full flex shadow-md hover:shadow-lg bg-gray-300 text-gray-500 text-4xl overflow-hidden rounded-xl cursor-pointer motion-safe:transform hover:scale-105 transition-transform ease-out">
<i v-if="!movie.poster_path" class="fas fa-image mx-auto my-auto"></i>
<img v-else class="w-full h-full object-cover" loading="lazy" :ref="`poster-${index}`"
:src="`/api/tmdb/image/w185${movie.poster_path}`">
</div>
</div> -->
</router-link>
</li>
</ul>
@ -25,14 +27,16 @@
import { defineComponent } from "vue";
import { IApiDataResponse } from "@common/api_schema";
import { IMovieSearchResult, IPaginatedResponse } from "@lib/tmdb/schema";
import MovieModal from "../components/modals/MovieModal.vue";
import { authFetch } from "../routes";
import MovieModal from "../components/modals/MovieModal.vue";
import MoviePoster from "../components/MoviePoster.vue";
type MovieResults = IApiDataResponse<IPaginatedResponse<IMovieSearchResult>>;
export default defineComponent({
components: {
MovieModal
MovieModal,
MoviePoster
},
data() {
return {


Loading…
Cancel
Save