feat: add search tab
This commit is contained in:
parent
3da3f4769c
commit
47485f941d
@ -1,6 +1,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { useMovieStore} from './stores/movie-store';
|
import { useMovieStore} from './stores/movie-store';
|
||||||
import Movie from './components/Movie.vue';
|
import Movie from './components/Movie.vue';
|
||||||
|
import Search from './components/Search.vue';
|
||||||
|
|
||||||
const movieStore = useMovieStore();
|
const movieStore = useMovieStore();
|
||||||
</script>
|
</script>
|
||||||
@ -55,7 +56,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="search" v-if="movieStore.activeTab === 2">
|
<div class="search" v-if="movieStore.activeTab === 2">
|
||||||
Search
|
<Search/>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
48
src/components/Loader.vue
Normal file
48
src/components/Loader.vue
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<template>
|
||||||
|
<div class="lds-facebook">
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.lds-facebook {
|
||||||
|
display: block;
|
||||||
|
margin: auto;
|
||||||
|
position: relative;
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
}
|
||||||
|
.lds-facebook div {
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
left: 8px;
|
||||||
|
width: 16px;
|
||||||
|
background: #cef;
|
||||||
|
animation: lds-facebook 1.2s cubic-bezier(0, 0.5, 0.5, 1) infinite;
|
||||||
|
}
|
||||||
|
.lds-facebook div:nth-child(1) {
|
||||||
|
left: 8px;
|
||||||
|
animation-delay: -0.24s;
|
||||||
|
}
|
||||||
|
.lds-facebook div:nth-child(2) {
|
||||||
|
left: 32px;
|
||||||
|
animation-delay: -0.12s;
|
||||||
|
}
|
||||||
|
.lds-facebook div:nth-child(3) {
|
||||||
|
left: 56px;
|
||||||
|
animation-delay: 0;
|
||||||
|
}
|
||||||
|
@keyframes lds-facebook {
|
||||||
|
0% {
|
||||||
|
top: 8px;
|
||||||
|
height: 64px;
|
||||||
|
}
|
||||||
|
50%,
|
||||||
|
100% {
|
||||||
|
top: 24px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -11,7 +11,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<span class="movie-overview">{{ movie.overview }}</span>
|
<span class="movie-overview">{{ movie.overview }}</span>
|
||||||
|
|
||||||
<div class="movie-buttons">
|
<div class="movie-buttons" v-if="!isSearch">
|
||||||
<button
|
<button
|
||||||
class="btn movie-buttons-watched"
|
class="btn movie-buttons-watched"
|
||||||
@click="$emit('toggle-watched')"
|
@click="$emit('toggle-watched')"
|
||||||
@ -26,17 +26,31 @@
|
|||||||
Delete
|
Delete
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="movie-buttons" v-if="isSearch">
|
||||||
|
<button
|
||||||
|
class="btn btn_green"
|
||||||
|
@click="$emit('add')"
|
||||||
|
>
|
||||||
|
Add
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
defineEmits(['toggle-watched', 'remove'])
|
defineEmits(['toggle-watched', 'remove', 'add'])
|
||||||
defineProps({
|
defineProps({
|
||||||
movie: {
|
movie: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true,
|
required: true,
|
||||||
default: () => ({})
|
default: () => ({})
|
||||||
|
},
|
||||||
|
isSearch: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
41
src/components/Search.vue
Normal file
41
src/components/Search.vue
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<template>
|
||||||
|
<form @submit.prevent="searchStore.getMovies(searchMovie)">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="search-input"
|
||||||
|
placeholder="Input movie"
|
||||||
|
v-model="searchMovie"
|
||||||
|
>
|
||||||
|
</form>
|
||||||
|
<Loader v-if="searchStore.loading" />
|
||||||
|
|
||||||
|
<Movie
|
||||||
|
v-else
|
||||||
|
v-for="movie in searchStore.movies"
|
||||||
|
:movie="movie"
|
||||||
|
:key="movie.id"
|
||||||
|
:isSearch="true"
|
||||||
|
@add="searchStore.addToUserMovies(movie)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { useSearchStore } from '../stores/search-store';
|
||||||
|
import Loader from '../components/Loader.vue';
|
||||||
|
import Movie from '../components/Movie.vue';
|
||||||
|
|
||||||
|
const searchMovie = ref('');
|
||||||
|
const searchStore = useSearchStore();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.search-input {
|
||||||
|
border: 1px solid #e7e7e7;
|
||||||
|
width: 100%;
|
||||||
|
height: 40px;
|
||||||
|
padding: 0 10px 0 30px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -2,26 +2,7 @@ import { defineStore } from 'pinia';
|
|||||||
|
|
||||||
export const useMovieStore = defineStore('movieStore', {
|
export const useMovieStore = defineStore('movieStore', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
movies: [
|
movies: [],
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
original_title: "Spider-Man",
|
|
||||||
overview:
|
|
||||||
"After being bitten by a genetically altered spider at Oscorp, nerdy but endearing high school student Peter Parker is endowed with amazing powers to become the superhero known as Spider-Man.",
|
|
||||||
poster_path: "/gh4cZbhZxyTbgxQPxD0dOudNPTn.jpg",
|
|
||||||
release_date: "2002-05-01",
|
|
||||||
isWatched: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
original_title: "The Batman",
|
|
||||||
overview:
|
|
||||||
"In his second year of fighting crime, Batman uncovers corruption in Gotham City that connects to his own family while facing a serial killer known as the Riddler.",
|
|
||||||
poster_path: "/b0PlSFdDwbyK0cf5RxwDpaOJQvQ.jpg",
|
|
||||||
release_date: "2022-03-01",
|
|
||||||
isWatched: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
activeTab: 1,
|
activeTab: 1,
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
|
|||||||
37
src/stores/search-store.js
Normal file
37
src/stores/search-store.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import { useMovieStore } from './movie-store.js';
|
||||||
|
|
||||||
|
const url = `https:api.themoviedb.org/3/search/movie?api_key=${import.meta.env.VITE_API_KEY}&query=`;
|
||||||
|
|
||||||
|
export const useSearchStore = defineStore('search-store', {
|
||||||
|
state: () => ({
|
||||||
|
movies: [],
|
||||||
|
timer: null,
|
||||||
|
loading: false,
|
||||||
|
}),
|
||||||
|
actions: {
|
||||||
|
async getMovies(search) {
|
||||||
|
const request = async () => {
|
||||||
|
const res = await fetch(url + search);
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
this.movies = data.results
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
clearTimeout(this.timer);
|
||||||
|
this.loading = true;
|
||||||
|
await request();
|
||||||
|
} catch (e) {
|
||||||
|
console.log('error', e);
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addToUserMovies(obj) {
|
||||||
|
const movieStore = useMovieStore();
|
||||||
|
movieStore.movies.push(obj);
|
||||||
|
movieStore.setActiveTab(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
Loading…
x
Reference in New Issue
Block a user