New design for Person popup

This commit is contained in:
2022-03-05 18:23:38 +01:00
parent dc98f9ced2
commit b5c56a62de

View File

@@ -1,105 +1,272 @@
<template> <template>
<li class="card"> <section class="person">
<a :href="tmdbLink"> <header ref="header">
<img class="persons--image" :src="pictureUrl" /> <div class="info">
<p class="name">{{ person.name }}</p> <h1 v-if="person">
<p class="meta">{{ person.character }}</p> {{ person.title || person.name }}
<!-- <p class="meta">{{ person.type }}</p> --> </h1>
</a> <loading-placeholder v-else :count="1" />
</li>
<span class="known-for" v-if="person && person['known_for_department']">
{{
person.known_for_department === "Acting"
? "Actor"
: person.known_for_department
}}
</span>
</div>
<figure class="person__poster">
<img
class="person-item__img is-loaded"
ref="poster-image"
src="/assets/placeholder.png"
/>
</figure>
</header>
<div v-if="person">
<MovieDetail v-if="age" title="Age" :detail="age" />
<MovieDetail
v-if="person"
title="Born"
:detail="person.place_of_birth ? person.place_of_birth : '(Not found)'"
/>
<MovieDetail v-if="person.biography" title="Biography">
<MovieDescription :description="person.biography" />
</MovieDetail>
<MovieDetail title="Starred in movies" v-if="credits">
<Cast :cast="movieCredits" />
</MovieDetail>
<MovieDetail title="Starred in shows" v-if="credits">
<Cast :cast="showCredits" />
</MovieDetail>
</div>
</section>
</template> </template>
<script> <script>
import img from "@/directives/v-image";
import Cast from "./Cast";
import MovieDetail from "./ui/MovieDetail";
import MovieDescription from "./ui/MovieDescription";
import LoadingPlaceholder from "./ui/LoadingPlaceholder";
import { getPerson, getPersonCredits } from "@/api";
export default { export default {
name: "Person",
props: { props: {
person: { id: {
type: Object, required: true,
required: true type: Number
},
type: {
required: false,
type: String,
default: "person"
}
},
components: {
MovieDetail,
MovieDescription,
Cast,
LoadingPlaceholder
},
directives: { img: img }, // TODO decide to remove or use
data() {
return {
ASSET_URL: "https://image.tmdb.org/t/p/",
ASSET_SIZES: ["w500", "w780", "original"],
person: undefined,
loading: true,
credits: undefined
};
},
watch: {
id: function (val) {
if (this.type === "person") {
this.fetchperson(val);
} else {
this.fetchShow(val);
}
},
backdrop: function (backdrop) {
if (backdrop != null) {
const style = {
backgroundImage:
"url(" + this.ASSET_URL + this.ASSET_SIZES[1] + backdrop + ")"
};
Object.assign(this.$refs.header.style, style);
}
} }
}, },
computed: { computed: {
tmdbLink() { age: function () {
const { id } = this.person; if (!this.person || !this.person.birthday) {
if (id) return `https://www.themoviedb.org/person/${id}`; return;
}, }
pictureUrl() {
const { profile_path } = this.person;
if (profile_path) return "https://image.tmdb.org/t/p/w185" + profile_path;
return ""; const today = new Date().getFullYear();
const birthYear = new Date(this.person.birthday).getFullYear();
return `${today - birthYear} years old`;
},
movieCredits: function () {
const { cast } = this.credits;
if (!cast) return;
return cast
.filter(l => l.media_type === "movie")
.filter((item, pos, self) => self.indexOf(item) == pos)
.sort((a, b) => a.popularity < b.popularity);
},
showCredits: function () {
const { cast } = this.credits;
if (!cast) return;
const alreadyExists = (item, pos, self) => {
const names = self.map(item => item.name);
return names.indexOf(item.name) == pos;
};
return cast
.filter(item => item.media_type === "tv")
.filter(alreadyExists)
.sort((a, b) => a.popularity < b.popularity);
} }
},
methods: {
parseResponse(person) {
this.loading = false;
this.person = { ...person };
this.title = person.title;
this.poster = person.poster;
this.setPosterSrc();
},
setPosterSrc() {
const poster = this.$refs["poster-image"];
if (this.poster == null) {
poster.src = "/assets/no-image.svg";
return;
}
poster.src = `${this.ASSET_URL}${this.ASSET_SIZES[0]}${this.poster}`;
}
},
created() {
getPerson(this.id, true)
.then(this.parseResponse)
.catch(error => {
console.error(error);
this.$router.push({ name: "404" });
});
getPersonCredits(this.id, true)
.then(credits => (this.credits = credits))
.catch(error => {
console.error(error);
this.$router.push({ name: "404" });
});
} }
}; };
</script> </script>
<style lang="scss"> <style lang="scss" scoped>
li a p:first-of-type { @import "src/scss/loading-placeholder";
padding-top: 10px; @import "src/scss/variables";
} @import "src/scss/media-queries";
@import "src/scss/main";
li p { section.person {
font-size: 1em;
padding: 0 10px;
margin: 0;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; position: relative;
} padding: 40px;
background-color: var(--background-color);
li.card { @include mobile {
margin: 10px; padding: 50px 20px 10px;
margin-right: 4px;
padding-bottom: 10px;
border-radius: 8px;
overflow: hidden;
min-width: 140px;
width: 140px;
background-color: var(--background-color-secondary);
color: var(--text-color);
transition: all 0.3s ease;
transform: scale(0.97) translateZ(0);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
&:first-of-type {
margin-left: 0;
} }
&:hover { &:before {
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3); content: "";
transform: scale(1.03);
}
.name {
font-weight: 500;
}
.character {
font-size: 0.9em;
}
.meta {
font-size: 0.9em;
color: var(--text-color-70);
display: -webkit-box;
overflow: hidden;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
}
a {
display: block; display: block;
text-decoration: none; position: absolute;
top: -130px;
left: -100px;
z-index: 1;
width: 1000px;
height: 500px;
transform: rotate(21deg);
background-color: #062541;
@include mobile {
// top: -52vw;
top: -215px;
}
}
}
header {
$duration: 0.2s;
transition: height $duration ease;
position: relative;
background-color: transparent;
display: grid;
grid-template-columns: 1fr 1fr;
height: 350px;
z-index: 2;
@include mobile {
height: 180px;
} }
img { .info {
display: flex;
flex-direction: column;
padding: 30px;
padding-left: 0;
text-align: left;
@include mobile {
padding: 0;
}
}
h1 {
color: $green;
width: 100%; width: 100%;
height: 100%; font-weight: 500;
min-width: 140px; line-height: 1.4;
min-height: 210px; font-size: 30px;
background-color: var(--text-color-90); margin-top: 0;
@include mobile {
font-size: 24px;
margin: 10px 0;
// padding: 30px 30px 30px 40px;
}
}
.known-for {
color: white;
}
}
.person__poster {
display: block;
> img {
border-radius: 10px;
width: 100%;
@include mobile {
max-width: 225px;
}
} }
} }
</style> </style>