feat: add search tab

This commit is contained in:
Sergey Krylov 2025-02-10 07:27:06 +03:00
parent 3da3f4769c
commit 47485f941d
6 changed files with 146 additions and 24 deletions

View File

@ -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
View 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>

View File

@ -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
View 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>

View File

@ -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: {

View 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);
}
}
})