Movie search done
This commit is contained in:
1
src/lib/constants.ts
Normal file
1
src/lib/constants.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const TMDB_IMAGES = 'https://www.themoviedb.org/t/p/original';
|
||||
@@ -179,3 +179,28 @@ export interface Poster {
|
||||
vote_count: number;
|
||||
width: number;
|
||||
}
|
||||
|
||||
export interface MultiSearchResponse {
|
||||
page: number;
|
||||
results: MultiSearchResult[];
|
||||
total_pages: number;
|
||||
total_results: number;
|
||||
}
|
||||
|
||||
export interface MultiSearchResult {
|
||||
adult: boolean;
|
||||
backdrop_path?: string;
|
||||
id: number;
|
||||
title: string;
|
||||
original_language: string;
|
||||
original_title: string;
|
||||
overview: string;
|
||||
poster_path?: string;
|
||||
media_type: string;
|
||||
genre_ids: number[];
|
||||
popularity: number;
|
||||
release_date: string;
|
||||
video: boolean;
|
||||
vote_average: number;
|
||||
vote_count: number;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import '../app.css';
|
||||
import { setClient } from 'svelte-apollo';
|
||||
import Navbar from './components/Navbar.svelte';
|
||||
import Navbar from './components/Navbar/Navbar.svelte';
|
||||
</script>
|
||||
|
||||
<div class="app">
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import type { PageData } from './$types';
|
||||
import ResourceDetails from './components/ResourceDetails/ResourceDetails.svelte';
|
||||
import ResourceDetailsControls from './ResourceDetailsControls.svelte';
|
||||
import { TMDB_IMAGES } from '$lib/constants';
|
||||
|
||||
export let data: PageData;
|
||||
let movies = data.showcases;
|
||||
@@ -18,9 +19,7 @@
|
||||
{:else}
|
||||
<div
|
||||
class="bg-cover bg-center"
|
||||
style={"background-image: url('https://www.themoviedb.org/t/p/original/" +
|
||||
movie.backdrop_path +
|
||||
"')"}
|
||||
style={"background-image: url('" + TMDB_IMAGES + movie.backdrop_path + "')"}
|
||||
>
|
||||
<div class="p-8 flex flex-col gap-6 backdrop-blur-xl bg-[#000000dd]">
|
||||
<h1 class="uppercase tracking-widest font-bold">Continue Watching</h1>
|
||||
|
||||
3
src/routes/components/IconButton.svelte
Normal file
3
src/routes/components/IconButton.svelte
Normal file
@@ -0,0 +1,3 @@
|
||||
<div class="text-zinc-300 hover:text-zinc-50 cursor-pointer p-1" on:click>
|
||||
<slot />
|
||||
</div>
|
||||
19
src/routes/components/Modal/Modal.svelte
Normal file
19
src/routes/components/Modal/Modal.svelte
Normal file
@@ -0,0 +1,19 @@
|
||||
<script lang="ts">
|
||||
import classNames from 'classnames';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
|
||||
const dispatcher = createEventDispatcher();
|
||||
|
||||
export let visible = false;
|
||||
export let close: () => void;
|
||||
</script>
|
||||
|
||||
<div
|
||||
class={classNames('fixed inset-0 bg-[#00000088] justify-center items-center z-20', {
|
||||
hidden: !visible,
|
||||
flex: visible
|
||||
})}
|
||||
on:click|self={close}
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
9
src/routes/components/Modal/ModalContent.svelte
Normal file
9
src/routes/components/Modal/ModalContent.svelte
Normal file
@@ -0,0 +1,9 @@
|
||||
<!--<script lang="ts">-->
|
||||
<!-- export let close: () => void;-->
|
||||
<!--</script>-->
|
||||
|
||||
<div
|
||||
class="max-w-3xl self-start mt-[10vh] bg-[#33333388] backdrop-blur-xl rounded overflow-hidden flex flex-col flex-1 mx-4 sm:mx-16 lg:mx-24 drop-shadow-xl"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
@@ -2,11 +2,15 @@
|
||||
import { MagnifyingGlass, Person } from 'radix-icons-svelte';
|
||||
import classNames from 'classnames';
|
||||
import { page } from '$app/stores';
|
||||
import TitleSearchModal from './TitleSearchModal.svelte';
|
||||
import IconButton from '../IconButton.svelte';
|
||||
|
||||
let y = 0;
|
||||
let transparent = true;
|
||||
let baseStyle = '';
|
||||
|
||||
let isSearchVisible = false;
|
||||
|
||||
function getLinkStyle(path) {
|
||||
return $page.url.pathname === path ? 'text-amber-200' : 'hover:text-zinc-50 cursor-pointer';
|
||||
}
|
||||
@@ -40,12 +44,14 @@
|
||||
<a href="/sources" class={$page && getLinkStyle('/sources')}>Sources</a>
|
||||
<a href="/settings" class={$page && getLinkStyle('/settings')}>Settings</a>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<div class="p-2 cursor-pointer text-zinc-200 hover:text-zinc-50">
|
||||
<div class="flex gap-2 items-center">
|
||||
<IconButton on:click={() => (isSearchVisible = true)}>
|
||||
<MagnifyingGlass size="20" />
|
||||
</div>
|
||||
<div class="p-2 cursor-pointer text-zinc-200 hover:text-zinc-50">
|
||||
</IconButton>
|
||||
<IconButton>
|
||||
<Person size="20" />
|
||||
</div>
|
||||
</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<TitleSearchModal bind:visible={isSearchVisible} />
|
||||
97
src/routes/components/Navbar/TitleSearchModal.svelte
Normal file
97
src/routes/components/Navbar/TitleSearchModal.svelte
Normal file
@@ -0,0 +1,97 @@
|
||||
<script lang="ts">
|
||||
import Modal from '../Modal/Modal.svelte';
|
||||
import ModalContent from '../Modal/ModalContent.svelte';
|
||||
import { Cross1, Cross2, MagnifyingGlass } from 'radix-icons-svelte';
|
||||
import IconButton from '../IconButton.svelte';
|
||||
import { TmdbApi } from '$lib/tmdb-api';
|
||||
import type { MultiSearchResponse } from '$lib/tmdb-api';
|
||||
import { TMDB_IMAGES } from '$lib/constants';
|
||||
import { onMount } from 'svelte';
|
||||
export let visible = false;
|
||||
let searchValue = '';
|
||||
|
||||
export let close = () => {
|
||||
visible = false;
|
||||
searchValue = '';
|
||||
fetching = false;
|
||||
results = null;
|
||||
if (timeout) clearTimeout(timeout);
|
||||
timeout = undefined;
|
||||
};
|
||||
|
||||
let timeout;
|
||||
let fetching = false;
|
||||
let results: MultiSearchResponse['results'] | null = null;
|
||||
const searchTimeout = () => {
|
||||
if (timeout) clearTimeout(timeout);
|
||||
timeout = setTimeout(() => {
|
||||
searchMovie(searchValue);
|
||||
}, 700);
|
||||
};
|
||||
|
||||
const searchMovie = (query: string) => {
|
||||
fetching = true;
|
||||
TmdbApi.get<MultiSearchResponse>('/search/movie', {
|
||||
params: {
|
||||
query
|
||||
}
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data) results = res.data.results;
|
||||
})
|
||||
.finally(() => (fetching = false));
|
||||
};
|
||||
|
||||
onMount(() => {
|
||||
searchValue = 'incepti';
|
||||
searchMovie('incepti');
|
||||
});
|
||||
|
||||
$: console.log(results);
|
||||
</script>
|
||||
|
||||
<Modal {visible} {close}>
|
||||
<ModalContent {close}>
|
||||
<div class="flex text-zinc-200 items-center p-3 px-5 gap-4 border-b border-zinc-700">
|
||||
<MagnifyingGlass size="20" class="text-zinc-400" />
|
||||
<input
|
||||
bind:value={searchValue}
|
||||
on:input={searchTimeout}
|
||||
type="text"
|
||||
class="flex-1 bg-transparent font-light outline-none"
|
||||
placeholder="Search for Movies and Shows..."
|
||||
/>
|
||||
<IconButton on:click={close}>
|
||||
<Cross2 size="20" />
|
||||
</IconButton>
|
||||
</div>
|
||||
{#if !results || searchValue === ''}
|
||||
<div class="text-sm text-zinc-200 opacity-50 font-light p-4">No recent searches</div>
|
||||
{:else if results?.length === 0 && !fetching}
|
||||
<div class="text-sm text-zinc-200 opacity-50 font-light p-4">No search results</div>
|
||||
{:else}
|
||||
<div class="py-2">
|
||||
{#each results.filter((m) => m).slice(0, 5) as result}
|
||||
<div
|
||||
class="flex px-4 py-2 gap-4 hover:bg-highlight-dim cursor-pointer"
|
||||
on:click={() => window.open('/movie/' + result.id)}
|
||||
>
|
||||
<div
|
||||
style={"background-image: url('" + TMDB_IMAGES + result.poster_path + "');"}
|
||||
class="bg-center bg-cover w-16 h-24 rounded-sm"
|
||||
/>
|
||||
<div class="flex-1 flex flex-col gap-1">
|
||||
<div class="flex gap-2">
|
||||
<div class="font-normal tracking-wide">{result.original_title}</div>
|
||||
<div class="text-zinc-400">
|
||||
{new Date(result.release_date).getFullYear()}
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-sm text-zinc-300 line-clamp-3">{result.overview}</div>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
@@ -4,6 +4,7 @@
|
||||
import { onMount } from 'svelte';
|
||||
import classNames from 'classnames';
|
||||
import { fade } from 'svelte/transition';
|
||||
import { TMDB_IMAGES } from '$lib/constants';
|
||||
|
||||
export let resource: MovieResource;
|
||||
export let trailer = true;
|
||||
@@ -62,9 +63,7 @@
|
||||
|
||||
<div
|
||||
class="h-screen w-screen bg-center bg-cover relative overflow-hidden"
|
||||
style={"background-image: url('https://www.themoviedb.org/t/p/original" +
|
||||
remoteResource.backdrop_path +
|
||||
"')"}
|
||||
style={"background-image: url('" + TMDB_IMAGES + remoteResource.backdrop_path + "')"}
|
||||
>
|
||||
<div class="youtube-container absolute h-full scale-[150%] hidden sm:block">
|
||||
{#if video.key}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import type { TmdbMovieFull } from '$lib/tmdb-api';
|
||||
import { formatGenres, getRuntime } from '$lib/utils';
|
||||
import classNames from 'classnames';
|
||||
import { TMDB_IMAGES } from '$lib/constants';
|
||||
|
||||
export let tmdbMovie: TmdbMovieFull;
|
||||
|
||||
@@ -14,8 +15,7 @@
|
||||
}
|
||||
|
||||
const backdropUrl =
|
||||
'https://www.themoviedb.org/t/p/original' +
|
||||
tmdbMovie.images.backdrops.filter((b) => b.iso_639_1 === 'en')[0].file_path;
|
||||
TMDB_IMAGES + tmdbMovie.images.backdrops.filter((b) => b.iso_639_1 === 'en')[0].file_path;
|
||||
</script>
|
||||
|
||||
<div
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { TmdbApi } from '$lib/tmdb-api';
|
||||
import { onMount } from 'svelte';
|
||||
import { TMDB_IMAGES } from '$lib/constants';
|
||||
|
||||
export let tmdbId;
|
||||
export let progress = 0;
|
||||
@@ -16,7 +17,7 @@
|
||||
TmdbApi.get('/' + type + '/' + tmdbId)
|
||||
.then((res) => res.data)
|
||||
.then((data: any) => {
|
||||
bg = 'https://www.themoviedb.org/t/p/original/' + data.poster_path;
|
||||
bg = TMDB_IMAGES + data.poster_path;
|
||||
title = data.title;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import type { PageData } from './$types';
|
||||
import SmallHorizontalPoster from '../components/SmallHorizontalPoster/SmallHorizontalPoster.svelte';
|
||||
import type { TmdbMovieFull } from '$lib/tmdb-api';
|
||||
import { TMDB_IMAGES } from '$lib/constants.js';
|
||||
export let data: PageData;
|
||||
console.log(data);
|
||||
|
||||
@@ -25,9 +26,7 @@
|
||||
const headerStyle = 'uppercase tracking-widest font-bold text-center mt-2';
|
||||
</script>
|
||||
|
||||
<div
|
||||
style="background-image: url('https://www.themoviedb.org/t/p/original/vvjYv7bSWerbsi0LsMjLnTVOX7c.jpg')"
|
||||
>
|
||||
<div style={"background-image: url('" + TMDB_IMAGES + "/vvjYv7bSWerbsi0LsMjLnTVOX7c.jpg')"}>
|
||||
<div class="py-24 backdrop-blur-2xl bg-darken px-8 flex flex-col gap-4">
|
||||
<!-- Contains all the titles available locally, the ones already watched previously (greyed out at the-->
|
||||
<!-- bottom), and the ones that are in some sort of watchlist and not available via any source.-->
|
||||
|
||||
@@ -8,7 +8,8 @@ export default {
|
||||
display: ['Inter', 'system', 'sans-serif']
|
||||
},
|
||||
colors: {
|
||||
darken: '#070501bf'
|
||||
darken: '#070501bf',
|
||||
'highlight-dim': '#fde68a20'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user