mirror of
https://github.com/Arrowar/StreamingCommunity.git
synced 2025-06-07 12:05:35 +00:00
create component for media details
This commit is contained in:
parent
cbbcf04630
commit
e61c64680f
@ -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)
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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 };
|
||||||
|
},
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
91
frontend/src/views/Details.vue
Normal file
91
frontend/src/views/Details.vue
Normal 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>
|
@ -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>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user