create component for media details

This commit is contained in:
Francesco Grazioso 2024-05-03 22:20:38 +02:00
parent cbbcf04630
commit e61c64680f
7 changed files with 136 additions and 15 deletions

View File

@ -25,9 +25,9 @@ class SearchView(viewsets.ViewSet):
self.type_search = request.query_params.get("type") self.type_search = request.query_params.get("type")
media_search_manager.media_list = [] media_search_manager.media_list = []
self.site_version, self.domain = get_version_and_domain()
self.len_database = 0 self.len_database = 0
if self.type_search == "film": if self.type_search == "film":
_, self.domain = get_version_and_domain()
self.len_database = search(self.search_query, self.domain) self.len_database = search(self.search_query, self.domain)
elif self.type_search == "anime": elif self.type_search == "anime":
self.len_database = anime_search(self.search_query) self.len_database = anime_search(self.search_query)

View File

@ -45,4 +45,4 @@
"animeunity": "to", "animeunity": "to",
"altadefinizione": "food" "altadefinizione": "food"
} }
} }

View File

@ -17,6 +17,7 @@ export interface MediaItem {
seasons_count: number; seasons_count: number;
images: Image[]; images: Image[];
comment: string; comment: string;
plot: string;
} }
export interface MediaItemResponse { export interface MediaItemResponse {

View File

@ -1,9 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted } from 'vue'; import { ref, onMounted } from 'vue';
import axios from 'axios'; import axios from 'axios';
import type {MediaItem} from "@/api/interfaces";
import {useRouter} from "vue-router";
import router from "@/router";
const props = defineProps<{ const props = defineProps<{
title: string; item: MediaItem;
mediaType: string; mediaType: string;
}>(); }>();
@ -11,13 +14,16 @@ const imageUrl = ref('');
const movieApiUrl = 'https://api.themoviedb.org/3/search/movie?api_key=15d2ea6d0dc1d476efbca3eba2b9bbfb&query='; const movieApiUrl = 'https://api.themoviedb.org/3/search/movie?api_key=15d2ea6d0dc1d476efbca3eba2b9bbfb&query=';
const animeApiUrl = 'https://kitsu.io/api/edge/anime?filter[text]='; const animeApiUrl = 'https://kitsu.io/api/edge/anime?filter[text]=';
const navigateToDetails = () => {
router.push({ name: 'details', params: { item: JSON.stringify(props.item), imageUrl: imageUrl.value } });
};
onMounted(async () => { onMounted(async () => {
const searcTerm = props.title.replace(' ', '-'); imageUrl.value = "https://eapp.org/wp-content/uploads/2018/05/poster_placeholder.jpg";
if (props.mediaType == "film") { if (props.mediaType == "film") {
try { try {
const response = await axios.get(movieApiUrl + props.title); const response = await axios.get(movieApiUrl + props.item.name);
if (response.data.results.length === 0) { if (response.data.results.length === 0) {
imageUrl.value = "https://eapp.org/wp-content/uploads/2018/05/poster_placeholder.jpg";
return; return;
} }
imageUrl.value = "http://image.tmdb.org/t/p/w500/" + response.data.results[0].poster_path; imageUrl.value = "http://image.tmdb.org/t/p/w500/" + response.data.results[0].poster_path;
@ -26,11 +32,10 @@ onMounted(async () => {
} }
} else { } else {
try { try {
const response = await axios.get(animeApiUrl + props.title); const response = await axios.get(animeApiUrl + props.item.name);
// if (response.data.results.length === 0) { if (response.data.data && response.data.data.length === 0) {
// imageUrl.value = "https://eapp.org/wp-content/uploads/2018/05/poster_placeholder.jpg"; return;
// return; }
// }
imageUrl.value = response.data.data[0].attributes.posterImage.small; imageUrl.value = response.data.data[0].attributes.posterImage.small;
} catch (error) { } catch (error) {
console.error('Error fetching anime image:', error); console.error('Error fetching anime image:', error);
@ -41,9 +46,11 @@ onMounted(async () => {
</script> </script>
<template> <template>
<div class="card"> <div class="card" @click="navigateToDetails">
<img :src="imageUrl" :alt="title" class="card-image" /> <img :src="imageUrl" :alt="item.name" class="card-image" />
<div class="card-title">{{ title }}</div> <div class="card-title">
{{ item.name.slice(0, 25) + (item.name.length > 24 ? '...' : '') }}
</div>
</div> </div>
</template> </template>
@ -53,6 +60,13 @@ onMounted(async () => {
border-radius: 4px; border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
overflow: hidden; overflow: hidden;
cursor: pointer;
}
.card:hover {
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
transform: translateY(-2px) scale(1.02);
transition: all 0.3s;
} }
.card-image { .card-image {

View File

@ -1,5 +1,6 @@
import { createRouter, createWebHistory } from 'vue-router' import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue' import HomeView from '../views/HomeView.vue'
import Details from "../views/Details.vue";
const router = createRouter({ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), history: createWebHistory(import.meta.env.BASE_URL),
@ -8,6 +9,20 @@ const router = createRouter({
path: '/', path: '/',
name: 'home', name: 'home',
component: HomeView component: HomeView
},
{
path: '/details:item:imageUrl',
name: 'details',
component: Details,
props: route => {
let item;
try {
item = JSON.parse(<string>route.params.item);
} catch (error) {
item = {}; // or any default value you want to set
}
return { item: item, imageUrl: route.params.imageUrl };
},
} }
] ]
}) })

View File

@ -0,0 +1,91 @@
<template>
<div class="details-container">
<div class="details-card">
<div class="details-header">
<img :src="imageUrl" :alt="item.name" class="details-image" />
<div class="details-title-container">
<h1 class="details-title">{{ item.name }}</h1>
<div class="details-description">
<p>{{ item.plot }}</p>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { useRoute } from 'vue-router'
import type { MediaItem } from "@/api/interfaces";
const route = useRoute()
const item: MediaItem = JSON.parse(<string>route.params.item)
const imageUrl: string = <string>route.params.imageUrl
</script>
<style scoped>
.details-container {
justify-content: center;
align-items: center;
min-height: 100vh;
width: 200%;
color: #fff;
}
.details-card {
width: 100%;
max-width: 1200px;
background-color: #232323;
padding: 2rem;
border-radius: 0.5rem;
}
.details-header {
display: flex;
align-items: flex-start;
margin-bottom: 2rem;
}
.details-image {
max-width: 300px;
margin-right: 2rem;
border-radius: 0.5rem;
}
@media (max-width: 1008px) {
.details-container {
width: 100%;
}
.details-header {
flex-direction: column;
align-items: center;
}
.details-image {
max-width: 100%;
margin-right: 0;
margin-bottom: 1rem;
}
}
.details-title-container {
flex: 1;
}
.details-title {
font-size: 2rem;
margin-bottom: 1rem;
}
.details-info {
display: flex;
gap: 1rem;
font-size: 0.9rem;
color: #999;
}
.details-description {
line-height: 1.5;
}
</style>

View File

@ -36,7 +36,7 @@ function searchTitle() {
</div> </div>
<div class="card-container"> <div class="card-container">
<div v-for="result in searchResults" :key="result.id" class="card-item"> <div v-for="result in searchResults" :key="result.id" class="card-item">
<Card :title="result.name" :media-type="selectedOption" /> <Card :item="result" :media-type="selectedOption" />
</div> </div>
</div> </div>
</template> </template>