forked from DebaucheryLibrarian/traxxx
Added pagination and search to movies page.
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
>
|
||||
<input
|
||||
v-model="query"
|
||||
:placeholder="`Find ${channelCount} channels in ${entities.length} networks`"
|
||||
:placeholder="`Search ${channelCount} channels in ${entities.length} networks`"
|
||||
class="query"
|
||||
@input="searchEntities"
|
||||
>
|
||||
@@ -98,45 +98,7 @@ export default {
|
||||
}
|
||||
|
||||
.search {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
max-width: 40rem;
|
||||
}
|
||||
|
||||
.query {
|
||||
color: var(--text);
|
||||
background: var(--background);
|
||||
flex-grow: 1;
|
||||
box-sizing: border-box;
|
||||
padding: 1rem;
|
||||
border: none;
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0 0 3px var(--darken-weak);
|
||||
margin: 1rem 0;
|
||||
font-size: 1rem;
|
||||
outline: none;
|
||||
|
||||
&:focus {
|
||||
box-shadow: 0 0 3px var(--primary);
|
||||
}
|
||||
}
|
||||
|
||||
.search-button {
|
||||
padding: 1rem;
|
||||
background: none;
|
||||
border: none;
|
||||
|
||||
.icon {
|
||||
fill: var(--shadow);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
|
||||
.icon {
|
||||
fill: var(--primary);
|
||||
}
|
||||
}
|
||||
margin: 1rem 0 0 0;
|
||||
}
|
||||
|
||||
.entity-tiles {
|
||||
|
||||
@@ -179,7 +179,7 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
@media(max-width: $breakpoint) {
|
||||
@media(max-width: $breakpoint-kilo) {
|
||||
.movie {
|
||||
height: 12rem;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
<template>
|
||||
<div class="movies">
|
||||
<div class="content-inner">
|
||||
<Search
|
||||
:search="searchMovies"
|
||||
:placeholder="`Search ${totalCount} movies`"
|
||||
/>
|
||||
|
||||
<div class="tiles">
|
||||
<MovieTile
|
||||
v-for="movie in movies"
|
||||
@@ -8,6 +13,13 @@
|
||||
:movie="movie"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Pagination
|
||||
v-if="totalCount > 0"
|
||||
:items-total="totalCount"
|
||||
:items-per-page="limit"
|
||||
class="pagination-bottom"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Footer />
|
||||
@@ -16,27 +28,62 @@
|
||||
|
||||
<script>
|
||||
import MovieTile from './movie-tile.vue';
|
||||
import Search from '../search/bar.vue';
|
||||
import Pagination from '../pagination/pagination.vue';
|
||||
|
||||
async function fetchMovies() {
|
||||
if (this.$route.query.query) {
|
||||
await this.searchMovies();
|
||||
return;
|
||||
}
|
||||
|
||||
async function mounted() {
|
||||
const { movies, totalCount } = await this.$store.dispatch('fetchMovies', {
|
||||
limit: 30,
|
||||
limit: this.limit,
|
||||
range: this.$route.params.range,
|
||||
pageNumber: this.$route.params.pageNumber,
|
||||
});
|
||||
|
||||
this.movies = movies;
|
||||
this.totalCount = totalCount;
|
||||
}
|
||||
|
||||
async function searchMovies() {
|
||||
const movies = await this.$store.dispatch('searchMovies', {
|
||||
query: this.$route.query.query,
|
||||
limit: this.limit,
|
||||
});
|
||||
|
||||
this.movies = movies;
|
||||
this.totalCount = movies.length;
|
||||
}
|
||||
|
||||
async function mounted() {
|
||||
this.pageTitle = 'Movies';
|
||||
|
||||
await this.fetchMovies();
|
||||
}
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MovieTile,
|
||||
Search,
|
||||
Pagination,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
movies: [],
|
||||
totalCount: 0,
|
||||
limit: 30,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
$route: fetchMovies,
|
||||
},
|
||||
mounted,
|
||||
methods: {
|
||||
fetchMovies,
|
||||
searchMovies,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -49,14 +96,22 @@ export default {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.content-inner {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
.search {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.tiles {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(25rem, 1fr));
|
||||
grid-gap: 1rem;
|
||||
padding: 1rem;
|
||||
margin: 0 0 1rem 0;
|
||||
}
|
||||
|
||||
@media(max-width: $breakpoint) {
|
||||
@media(max-width: $breakpoint-kilo) {
|
||||
.tiles {
|
||||
grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
|
||||
}
|
||||
|
||||
84
assets/components/search/bar.vue
Normal file
84
assets/components/search/bar.vue
Normal file
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<form
|
||||
class="search"
|
||||
@submit.prevent="search"
|
||||
>
|
||||
<input
|
||||
v-model="query"
|
||||
:placeholder="placeholder || 'Search'"
|
||||
class="query"
|
||||
@input="search"
|
||||
>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="search-button"
|
||||
><Icon icon="search" /></button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
function search() {
|
||||
this.$router.replace({ query: { query: this.query || undefined } });
|
||||
}
|
||||
|
||||
export default {
|
||||
props: {
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
query: this.$route.query.query || null,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
search,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.search {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
max-width: 40rem;
|
||||
}
|
||||
|
||||
.query {
|
||||
color: var(--text);
|
||||
background: var(--background);
|
||||
flex-grow: 1;
|
||||
box-sizing: border-box;
|
||||
padding: 1rem;
|
||||
border: none;
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0 0 3px var(--darken-weak);
|
||||
font-size: 1rem;
|
||||
outline: none;
|
||||
|
||||
&:focus {
|
||||
box-shadow: 0 0 3px var(--primary);
|
||||
}
|
||||
}
|
||||
|
||||
.search-button {
|
||||
padding: 1rem;
|
||||
background: none;
|
||||
border: none;
|
||||
|
||||
.icon {
|
||||
fill: var(--shadow);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
|
||||
.icon {
|
||||
fill: var(--primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -132,6 +132,7 @@ async function mounted() {
|
||||
'da-tp',
|
||||
'dv-tp',
|
||||
'tap',
|
||||
'tvp',
|
||||
],
|
||||
misc: [
|
||||
'gaping',
|
||||
|
||||
@@ -96,6 +96,57 @@ const actorFields = `
|
||||
${actorStashesFields}
|
||||
`;
|
||||
|
||||
const movieFields = `
|
||||
id
|
||||
title
|
||||
url
|
||||
slug
|
||||
date
|
||||
datePrecision
|
||||
actors {
|
||||
id
|
||||
name
|
||||
slug
|
||||
}
|
||||
tags {
|
||||
id
|
||||
name
|
||||
slug
|
||||
}
|
||||
entity {
|
||||
id
|
||||
name
|
||||
slug
|
||||
type
|
||||
parent {
|
||||
id
|
||||
name
|
||||
slug
|
||||
type
|
||||
}
|
||||
}
|
||||
covers: moviesCovers {
|
||||
media {
|
||||
id
|
||||
path
|
||||
thumbnail
|
||||
lazy
|
||||
width
|
||||
height
|
||||
thumbnailWidth
|
||||
thumbnailHeight
|
||||
isS3
|
||||
sfw: sfwMedia {
|
||||
id
|
||||
path
|
||||
thumbnail
|
||||
lazy
|
||||
comment
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const campaignsFragment = `
|
||||
campaigns(filter: {
|
||||
or: [
|
||||
@@ -543,6 +594,7 @@ export {
|
||||
actorFields,
|
||||
actorStashesFields,
|
||||
campaignsFragment,
|
||||
movieFields,
|
||||
releaseActorsFragment,
|
||||
releaseFields,
|
||||
releaseTagsFragment,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { graphql } from '../api';
|
||||
import { releasesFragment, releaseFragment, releaseFields } from '../fragments';
|
||||
import { releasesFragment, releaseFragment, releaseFields, movieFields } from '../fragments';
|
||||
import { curateRelease } from '../curate';
|
||||
import getDateRange from '../get-date-range';
|
||||
|
||||
@@ -79,54 +79,7 @@ function initReleasesActions(store, router) {
|
||||
}
|
||||
) {
|
||||
movies: nodes {
|
||||
id
|
||||
title
|
||||
url
|
||||
slug
|
||||
date
|
||||
datePrecision
|
||||
actors {
|
||||
id
|
||||
name
|
||||
slug
|
||||
}
|
||||
tags {
|
||||
id
|
||||
name
|
||||
slug
|
||||
}
|
||||
entity {
|
||||
id
|
||||
name
|
||||
slug
|
||||
type
|
||||
parent {
|
||||
id
|
||||
name
|
||||
slug
|
||||
type
|
||||
}
|
||||
}
|
||||
covers: moviesCovers {
|
||||
media {
|
||||
id
|
||||
path
|
||||
thumbnail
|
||||
lazy
|
||||
width
|
||||
height
|
||||
thumbnailWidth
|
||||
thumbnailHeight
|
||||
isS3
|
||||
sfw: sfwMedia {
|
||||
id
|
||||
path
|
||||
thumbnail
|
||||
lazy
|
||||
comment
|
||||
}
|
||||
}
|
||||
}
|
||||
${movieFields}
|
||||
}
|
||||
totalCount
|
||||
}
|
||||
@@ -142,6 +95,28 @@ function initReleasesActions(store, router) {
|
||||
};
|
||||
}
|
||||
|
||||
async function searchMovies({ _commit }, { query, limit = 20 }) {
|
||||
const { movies } = await graphql(`
|
||||
query SearchMovies(
|
||||
$query: String!
|
||||
$limit:Int = 20,
|
||||
) {
|
||||
movies: searchMovies(
|
||||
query: $query
|
||||
minLength: 1
|
||||
first: $limit
|
||||
) {
|
||||
${movieFields}
|
||||
}
|
||||
}
|
||||
`, {
|
||||
query,
|
||||
limit,
|
||||
});
|
||||
|
||||
return movies.map(movie => curateRelease(movie));
|
||||
}
|
||||
|
||||
async function fetchMovieById({ _commit }, movieId) {
|
||||
// const release = await get(`/releases/${releaseId}`);
|
||||
|
||||
@@ -297,6 +272,7 @@ function initReleasesActions(store, router) {
|
||||
fetchReleaseById,
|
||||
fetchMovies,
|
||||
fetchMovieById,
|
||||
searchMovies,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -196,6 +196,17 @@ const routes = [
|
||||
{
|
||||
path: '/movies',
|
||||
component: Movies,
|
||||
redirect: {
|
||||
name: 'movies',
|
||||
params: {
|
||||
range: 'latest',
|
||||
pageNumber: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/movies/:range/:pageNumber',
|
||||
component: Movies,
|
||||
name: 'movies',
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user