218 lines
4.1 KiB
Vue
218 lines
4.1 KiB
Vue
<template>
|
|
<div class="page">
|
|
<Filters v-if="showFilters">
|
|
<TagsFilter
|
|
:filters="filters"
|
|
:tags="aggTags"
|
|
@update="updateFilter"
|
|
/>
|
|
|
|
<ActorsFilter
|
|
:filters="filters"
|
|
:actors="aggActors"
|
|
@update="updateFilter"
|
|
/>
|
|
</Filters>
|
|
|
|
<div class="scenes-container">
|
|
<div
|
|
v-if="showMeta"
|
|
class="scenes-header"
|
|
>
|
|
<div class="meta">{{ total }} results</div>
|
|
</div>
|
|
|
|
<nav class="scopes">
|
|
<Link
|
|
:href="getPath('latest')"
|
|
class="scope nolink"
|
|
:active="scope === 'latest'"
|
|
>Latest</Link>
|
|
|
|
<Link
|
|
:href="getPath('upcoming')"
|
|
class="scope nolink"
|
|
:active="scope === 'upcoming'"
|
|
>Upcoming</Link>
|
|
|
|
<Link
|
|
:href="getPath('new')"
|
|
class="scope nolink"
|
|
:active="scope === 'new'"
|
|
>New</Link>
|
|
</nav>
|
|
|
|
<ul class="scenes nolist">
|
|
<li
|
|
v-for="scene in scenes"
|
|
:key="scene.id"
|
|
>
|
|
<Scene :scene="scene" />
|
|
</li>
|
|
</ul>
|
|
|
|
<Pagination />
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, inject } from 'vue';
|
|
import { parse } from 'path-to-regexp';
|
|
|
|
import navigate from '#/src/navigate.js';
|
|
import { get } from '#/src/api.js';
|
|
import events from '#/src/events.js';
|
|
|
|
import Filters from '#/components/filters/filters.vue';
|
|
import ActorsFilter from '#/components/filters/actors.vue';
|
|
import TagsFilter from '#/components/filters/tags.vue';
|
|
import Scene from './tile.vue';
|
|
import Pagination from '../pagination/pagination.vue';
|
|
|
|
defineProps({
|
|
showFilters: {
|
|
type: Boolean,
|
|
default: true,
|
|
},
|
|
showMeta: {
|
|
type: Boolean,
|
|
default: true,
|
|
},
|
|
});
|
|
|
|
const { pageProps, routeParams, urlParsed } = inject('pageContext');
|
|
const { scope } = routeParams;
|
|
|
|
const {
|
|
actor,
|
|
} = pageProps;
|
|
|
|
const scenes = ref(pageProps.scenes);
|
|
const aggActors = ref(pageProps.aggActors);
|
|
const aggTags = ref(pageProps.aggTags);
|
|
|
|
const currentPage = ref(Number(routeParams.page));
|
|
const total = ref(Number(pageProps.total));
|
|
|
|
const filters = ref({
|
|
actors: urlParsed.search.actors?.split(',').filter(Boolean).map((actorId) => Number(actorId)) || [],
|
|
tags: urlParsed.search.tags?.split(',').filter(Boolean) || [],
|
|
});
|
|
|
|
function getPath(targetScope, preserveQuery) {
|
|
const path = parse(routeParams.path)
|
|
.map((segment) => {
|
|
if (segment.name === 'scope') {
|
|
return targetScope;
|
|
}
|
|
|
|
if (segment.name === 'page') {
|
|
return 1;
|
|
}
|
|
|
|
return routeParams[segment.name] || segment;
|
|
})
|
|
.join('/');
|
|
|
|
if (preserveQuery && urlParsed.searchOriginal) {
|
|
return `${path}${urlParsed.searchOriginal}`;
|
|
}
|
|
|
|
return path;
|
|
}
|
|
|
|
async function search(resetPage = true) {
|
|
if (resetPage) {
|
|
currentPage.value = 1;
|
|
}
|
|
|
|
const query = {
|
|
tags: filters.value.tags.join(','),
|
|
};
|
|
|
|
console.log('actor id', actor?.id);
|
|
|
|
const res = await get('/scenes', {
|
|
...query,
|
|
actors: [actor?.id, filters.value.actors].filter(Boolean).join(','), // if we're on an actor page, that actor ID needs to be included
|
|
scope,
|
|
page: currentPage.value, // client uses param rather than query pagination
|
|
});
|
|
|
|
scenes.value = res.scenes;
|
|
aggActors.value = res.aggActors;
|
|
aggTags.value = res.aggTags;
|
|
total.value = res.total;
|
|
|
|
console.log(scenes.value);
|
|
|
|
events.emit('scrollUp');
|
|
|
|
navigate(getPath(scope, false), {
|
|
...query,
|
|
actors: filters.value.actors.join(',') || undefined, // don't include actor page ID in query, already a parameter
|
|
}, { redirect: false });
|
|
}
|
|
|
|
function updateFilter(prop, value, reload = true) {
|
|
filters.value[prop] = value;
|
|
|
|
console.log(prop, value);
|
|
|
|
if (reload) {
|
|
search();
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.page {
|
|
display: flex;
|
|
background: var(--background-base-10);
|
|
}
|
|
|
|
.scenes-header {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: .5rem 0 .25rem 2rem;
|
|
}
|
|
|
|
.scenes-container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
flex-grow: 1;
|
|
}
|
|
|
|
.meta {
|
|
display: flex;
|
|
flex-grow: 1;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.scenes {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(22rem, 1fr));
|
|
gap: .75rem .5rem;
|
|
padding: 1rem;
|
|
}
|
|
|
|
.scopes {
|
|
margin-left: 1rem;
|
|
}
|
|
|
|
.scope {
|
|
box-sizing: border-box;
|
|
padding: 1rem;
|
|
color: var(--shadow);
|
|
font-size: .9rem;
|
|
font-weight: bold;
|
|
|
|
&.active {
|
|
color: var(--primary);
|
|
font-weight: bold;
|
|
}
|
|
}
|
|
</style>
|