Added actor stash.
This commit is contained in:
10
pages/+config.js
Normal file
10
pages/+config.js
Normal file
@@ -0,0 +1,10 @@
|
||||
export default {
|
||||
meta: {
|
||||
data: {
|
||||
env: {
|
||||
server: true,
|
||||
client: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
5
pages/_error/+data.js
Normal file
5
pages/_error/+data.js
Normal file
@@ -0,0 +1,5 @@
|
||||
export function data() {
|
||||
return {
|
||||
foo: 'bar',
|
||||
};
|
||||
}
|
||||
@@ -1,270 +1,9 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<Filters :results="total">
|
||||
<div class="filter">
|
||||
<input
|
||||
v-model="q"
|
||||
type="search"
|
||||
placeholder="Search actors"
|
||||
class="input search"
|
||||
@search="search"
|
||||
>
|
||||
</div>
|
||||
|
||||
<GenderFilter
|
||||
:filters="filters"
|
||||
@update="updateFilter"
|
||||
/>
|
||||
|
||||
<BirthdateFilter
|
||||
:filters="filters"
|
||||
@update="updateFilter"
|
||||
/>
|
||||
|
||||
<BoobsFilter
|
||||
:filters="filters"
|
||||
:cup-range="cupRange"
|
||||
@update="updateFilter"
|
||||
/>
|
||||
|
||||
<PhysiqueFilter
|
||||
:filters="filters"
|
||||
@update="updateFilter"
|
||||
/>
|
||||
|
||||
<CountryFilter
|
||||
:filters="filters"
|
||||
:countries="countries"
|
||||
@update="updateFilter"
|
||||
/>
|
||||
|
||||
<div class="filter">
|
||||
<Checkbox
|
||||
:checked="filters.avatarRequired"
|
||||
label="Require photo"
|
||||
@change="(checked) => updateFilter('avatarRequired', checked, true)"
|
||||
/>
|
||||
</div>
|
||||
</Filters>
|
||||
|
||||
<div class="actors-container">
|
||||
<div class="actors-header">
|
||||
<div class="meta">
|
||||
<span class="count">{{ total }} results</span>
|
||||
|
||||
<select
|
||||
v-model="order"
|
||||
class="input"
|
||||
@change="search({ autoScope: false })"
|
||||
>
|
||||
<option value="name.asc">Name</option>
|
||||
<option value="likes.desc">Likes</option>
|
||||
<option value="scenes.desc">Scenes</option>
|
||||
<option
|
||||
value="relevance.desc"
|
||||
:disabled="!q"
|
||||
>Relevance</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul class="actors nolist">
|
||||
<li
|
||||
v-for="actor in actors"
|
||||
:key="`actor-${actor.id}`"
|
||||
>
|
||||
<ActorTile
|
||||
:actor="actor"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<Pagination
|
||||
:page="currentPage"
|
||||
:total="total"
|
||||
:redirect="false"
|
||||
@navigation="paginate"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Actors />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, inject } from 'vue';
|
||||
import { format, subYears } from 'date-fns';
|
||||
|
||||
import navigate from '#/src/navigate.js';
|
||||
import { get } from '#/src/api.js';
|
||||
import events from '#/src/events.js';
|
||||
|
||||
import ActorTile from '#/components/actors/tile.vue';
|
||||
import Pagination from '#/components/pagination/pagination.vue';
|
||||
import Checkbox from '#/components/form/checkbox.vue';
|
||||
import Filters from '#/components/filters/filters.vue';
|
||||
import GenderFilter from '#/components/filters/gender.vue';
|
||||
import BirthdateFilter from '#/components/filters/birthdate.vue';
|
||||
import BoobsFilter from '#/components/filters/boobs.vue';
|
||||
import PhysiqueFilter from '#/components/filters/physique.vue';
|
||||
import CountryFilter from '#/components/filters/country.vue';
|
||||
|
||||
const pageContext = inject('pageContext');
|
||||
const { pageProps, urlParsed, routeParams } = pageContext;
|
||||
|
||||
const q = ref(urlParsed.search.q);
|
||||
const actors = ref([]);
|
||||
const countries = ref(pageProps.countries);
|
||||
const cupRange = ref(pageProps.cupRange);
|
||||
|
||||
actors.value = pageProps.actors;
|
||||
|
||||
const currentPage = ref(Number(routeParams.page));
|
||||
const total = ref(Number(pageProps.total));
|
||||
const order = ref(urlParsed.search.order || 'likes.desc');
|
||||
|
||||
const filters = ref({
|
||||
gender: urlParsed.search.gender,
|
||||
ageRequired: !!urlParsed.search.age,
|
||||
age: urlParsed.search.age?.split(',').map((age) => Number(age)) || [18, 100],
|
||||
dobRequired: !!urlParsed.search.dob,
|
||||
dobType: urlParsed.search.dobt ? ({ bd: 'birthday', dob: 'dob' })[urlParsed.search.dobt] : 'birthday',
|
||||
dob: urlParsed.search.dob || format(subYears(new Date(), 21), 'yyyy-MM-dd'),
|
||||
country: urlParsed.search.c,
|
||||
braSizeRequired: !!urlParsed.search.cup,
|
||||
braSize: urlParsed.search.cup?.split(',') || ['A', 'Z'],
|
||||
naturalBoobs: urlParsed.search.nb ? urlParsed.search.nb === 'true' : undefined,
|
||||
heightRequired: !!urlParsed.search.height,
|
||||
height: urlParsed.search.height?.split(',').map((height) => Number(height)) || [50, 220],
|
||||
weightRequired: !!urlParsed.search.weight,
|
||||
weight: urlParsed.search.weight?.split(',').map((weight) => Number(weight)) || [30, 200],
|
||||
avatarRequired: !!urlParsed.search.avatar,
|
||||
});
|
||||
|
||||
async function search(options = {}) {
|
||||
if (options.resetPage !== false) {
|
||||
currentPage.value = 1;
|
||||
}
|
||||
|
||||
if (options.autoScope !== false) {
|
||||
if (q.value) {
|
||||
order.value = 'relevance.desc';
|
||||
}
|
||||
|
||||
if (!q.value && order.value.includes('relevance')) {
|
||||
order.value = 'likes.desc';
|
||||
}
|
||||
}
|
||||
|
||||
const query = {
|
||||
q: q.value || undefined,
|
||||
order: order.value,
|
||||
gender: filters.value.gender || undefined,
|
||||
age: filters.value.ageRequired ? filters.value.age.join(',') : undefined,
|
||||
dob: filters.value.dobRequired ? filters.value.dob : undefined,
|
||||
dobt: filters.value.dobRequired ? ({ birthday: 'bd', dob: 'dob' })[filters.value.dobType] : undefined,
|
||||
cup: filters.value.braSizeRequired ? filters.value.braSize.join(',') : undefined,
|
||||
c: filters.value.country || undefined,
|
||||
nb: filters.value.naturalBoobs,
|
||||
height: filters.value.heightRequired ? filters.value.height.join(',') : undefined,
|
||||
weight: filters.value.weightRequired ? filters.value.weight.join(',') : undefined,
|
||||
avatar: filters.value.avatarRequired || undefined,
|
||||
};
|
||||
|
||||
navigate(`/actors/${currentPage.value}`, query, { redirect: false });
|
||||
|
||||
const res = await get('/actors', {
|
||||
...query,
|
||||
page: currentPage.value, // client uses param rather than query pagination
|
||||
});
|
||||
|
||||
actors.value = res.actors;
|
||||
total.value = res.total;
|
||||
|
||||
countries.value = res.countries;
|
||||
|
||||
events.emit('scrollUp');
|
||||
}
|
||||
|
||||
function paginate({ page }) {
|
||||
currentPage.value = page;
|
||||
|
||||
search({ resetPage: false });
|
||||
}
|
||||
|
||||
function updateFilter(prop, value, reload = true) {
|
||||
filters.value[prop] = value;
|
||||
|
||||
if (reload) {
|
||||
search();
|
||||
}
|
||||
}
|
||||
import Actors from '#/components/actors/actors.vue';
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.gender-button {
|
||||
&.selected .gender .icon {
|
||||
fill: var(--text-light);
|
||||
filter: none;
|
||||
}
|
||||
|
||||
&:hover:not(.selected) {
|
||||
.gender .icon {
|
||||
fill: var(--text-light);
|
||||
}
|
||||
|
||||
.male .icon {
|
||||
filter: drop-shadow(0 0 1px var(--male));
|
||||
}
|
||||
|
||||
.female .icon {
|
||||
filter: drop-shadow(0 0 1px var(--female));
|
||||
}
|
||||
}
|
||||
|
||||
&:hover:not(.selected) .transsexual .icon {
|
||||
fill: var(--female);
|
||||
filter: drop-shadow(1px 0 0 var(--text-light)) drop-shadow(-1px 0 0 var(--text-light)) drop-shadow(0 1px 0 var(--text-light)) drop-shadow(0 -1px 0 var(--text-light)) drop-shadow(1px 0 0 var(--male)) drop-shadow(-1px 0 0 var(--male)) drop-shadow(0 1px 0 var(--male)) drop-shadow(0 -1px 0 var(--male)) drop-shadow(0 0 1px rgba(0, 0, 0, 0.5));
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
min-height: 100%;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.actors-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: .5rem 0 .25rem 2rem;
|
||||
}
|
||||
|
||||
.meta {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.actors-container {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
padding: 0 1rem 1rem 1rem;
|
||||
}
|
||||
|
||||
.actors {
|
||||
display: grid;
|
||||
flex-grow: 1;
|
||||
grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
|
||||
gap: .25rem;
|
||||
}
|
||||
|
||||
@media(--small-40) {
|
||||
.actors {
|
||||
grid-template-columns: repeat(auto-fill, minmax(7rem, 1fr));
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -12,7 +12,7 @@ export async function onBeforeRender(pageContext) {
|
||||
page: Number(pageContext.routeParams.page) || 1,
|
||||
limit: Number(pageContext.urlParsed.search.limit) || 120,
|
||||
order: pageContext.urlParsed.search.order?.split('.') || ['likes', 'desc'],
|
||||
});
|
||||
}, pageContext.user);
|
||||
|
||||
return {
|
||||
pageContext: {
|
||||
|
||||
@@ -25,20 +25,19 @@
|
||||
</span>
|
||||
</li>
|
||||
|
||||
<!--
|
||||
<Social
|
||||
v-if="actor.social && actor.social.length > 0"
|
||||
:actor="actor"
|
||||
class="header-social"
|
||||
<Icon
|
||||
v-show="favorited"
|
||||
icon="heart7"
|
||||
class="heart favorited"
|
||||
@click.native.stop="unstash"
|
||||
/>
|
||||
|
||||
<StashButton
|
||||
:stashed-by="stashedBy"
|
||||
class="actor-stash light"
|
||||
@stash="(stash) => stashActor(stash)"
|
||||
@unstash="(stash) => unstashActor(stash)"
|
||||
<Icon
|
||||
v-show="!favorited && user"
|
||||
icon="heart8"
|
||||
class="heart"
|
||||
@click.native.stop="stash"
|
||||
/>
|
||||
-->
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
@@ -50,15 +49,61 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { inject } from 'vue';
|
||||
import { ref, inject } from 'vue';
|
||||
|
||||
import { post, del } from '#/src/api.js';
|
||||
import events from '#/src/events.js';
|
||||
|
||||
import Bio from '#/components/actors/bio.vue';
|
||||
import Gender from '#/components/actors/gender.vue';
|
||||
import Scenes from '#/components/scenes/scenes.vue';
|
||||
|
||||
const pageContext = inject('pageContext');
|
||||
const { pageProps } = pageContext;
|
||||
const { pageProps, user } = pageContext;
|
||||
const { actor } = pageProps;
|
||||
|
||||
const favorited = ref(actor.stashes?.some((sceneStash) => sceneStash.primary) || false);
|
||||
|
||||
async function stash() {
|
||||
try {
|
||||
favorited.value = true;
|
||||
|
||||
await post(`/stashes/${user.primaryStash.id}/actors`, { actorId: actor.id });
|
||||
|
||||
events.emit('feedback', {
|
||||
type: 'success',
|
||||
message: `${actor.name} stashed to ${user.primaryStash.name}`,
|
||||
});
|
||||
} catch (error) {
|
||||
favorited.value = false;
|
||||
|
||||
events.emit('feedback', {
|
||||
type: 'error',
|
||||
message: `Failed to stash ${actor.name} to ${user.primaryStash.name}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function unstash() {
|
||||
try {
|
||||
favorited.value = false;
|
||||
await del(`/stashes/${user.primaryStash.id}/actors/${actor.id}`);
|
||||
|
||||
events.emit('feedback', {
|
||||
type: 'remove',
|
||||
message: `${actor.name} unstashed from ${user.primaryStash.name}`,
|
||||
});
|
||||
} catch (error) {
|
||||
favorited.value = true;
|
||||
|
||||
console.error(error);
|
||||
|
||||
events.emit('feedback', {
|
||||
type: 'error',
|
||||
message: `Failed to unstash ${actor.name} from ${user.primaryStash.name}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -73,6 +118,7 @@ const { actor } = pageProps;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
color: var(--highlight-strong-30);
|
||||
background: var(--grey-dark-40);
|
||||
}
|
||||
@@ -103,4 +149,24 @@ const { actor } = pageProps;
|
||||
flex-grow: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.icon.heart {
|
||||
width: 2rem;
|
||||
height: 1.5rem;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding: .5rem 1rem 1rem 1rem;
|
||||
fill: var(--highlight-strong-10);
|
||||
filter: drop-shadow(0 0 3px var(--shadow));
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
fill: var(--primary);
|
||||
}
|
||||
|
||||
&.favorited {
|
||||
fill: var(--primary);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { curateScenesQuery } from '#/src/web/scenes.js';
|
||||
|
||||
export async function onBeforeRender(pageContext) {
|
||||
const [[actor], actorScenes] = await Promise.all([
|
||||
fetchActorsById([Number(pageContext.routeParams.actorId)]),
|
||||
fetchActorsById([Number(pageContext.routeParams.actorId)], {}, pageContext.user),
|
||||
fetchScenes(await curateScenesQuery({
|
||||
...pageContext.urlQuery,
|
||||
scope: pageContext.routeParams.scope || 'latest',
|
||||
@@ -13,7 +13,7 @@ export async function onBeforeRender(pageContext) {
|
||||
page: Number(pageContext.routeParams.page) || 1,
|
||||
limit: Number(pageContext.urlParsed.search.limit) || 30,
|
||||
aggregate: true,
|
||||
}),
|
||||
}, pageContext.user),
|
||||
]);
|
||||
|
||||
const {
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
<div
|
||||
v-if="scene.photos.length > 0"
|
||||
class="album"
|
||||
:class="{ single: scene.photos.length === 1 }"
|
||||
>
|
||||
<div
|
||||
v-for="photo in scene.photos"
|
||||
@@ -92,7 +93,10 @@
|
||||
>{{ scene.title }}</h2>
|
||||
|
||||
<div class="actions">
|
||||
<div class="bookmarks">
|
||||
<div
|
||||
v-if="user"
|
||||
class="bookmarks"
|
||||
>
|
||||
<Icon icon="folder-heart" />
|
||||
|
||||
<Icon
|
||||
@@ -103,7 +107,7 @@
|
||||
/>
|
||||
|
||||
<Icon
|
||||
v-show="!favorited && user"
|
||||
v-show="!favorited"
|
||||
icon="heart8"
|
||||
class="heart"
|
||||
@click.native.stop="stash"
|
||||
@@ -179,7 +183,11 @@
|
||||
<div class="section details">
|
||||
<div class="detail">
|
||||
<h3 class="heading">Added</h3>
|
||||
<span class="added-date">{{ formatDate(scene.createdAt, 'yyyy-MM-dd hh:mm') }}</span> <span class="added-batch">batch #{{ scene.createdBatchId }}</span>
|
||||
<span class="added-date">{{ formatDate(scene.createdAt, 'yyyy-MM-dd') }}</span>
|
||||
<span
|
||||
:title="`Batch ${scene.createdBatchId}`"
|
||||
class="added-batch"
|
||||
>#{{ scene.createdBatchId }}</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
@@ -246,28 +254,29 @@ async function unstash() {
|
||||
.banner-container {
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
border-radius: .25rem .5rem 0 0;
|
||||
border-radius: .5rem .5rem 0 0;
|
||||
margin-top: .5rem;
|
||||
box-shadow: 0 0 3px var(--shadow-weak-30);
|
||||
}
|
||||
|
||||
.banner {
|
||||
max-height: 21rem;
|
||||
border-radius: .5rem .5rem 0 0;
|
||||
border-radius: .5rem 0 0 0;
|
||||
display: flex;
|
||||
font-size: 0;
|
||||
backdrop-filter: blur(1rem);
|
||||
backdrop-filter: brightness(150%) blur(1rem);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.poster-container {
|
||||
flex-shrink: 0;
|
||||
padding: .5rem;
|
||||
margin-right: .5rem;
|
||||
}
|
||||
|
||||
.poster {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border-radius: .25rem;
|
||||
border-radius: .25rem 0 0 0;
|
||||
}
|
||||
|
||||
.poster,
|
||||
@@ -282,19 +291,33 @@ async function unstash() {
|
||||
height: auto;
|
||||
flex-grow: 1;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
|
||||
gap: .5rem;
|
||||
grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
|
||||
gap: .25rem;
|
||||
box-sizing: border-box;
|
||||
padding: .5rem .5rem .5rem 0;
|
||||
overflow-y: auto;
|
||||
scrollbar-width: 0;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.single .photo {
|
||||
max-height: calc(100% - 1.5rem);
|
||||
}
|
||||
}
|
||||
|
||||
.photo-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.photo-link {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.photo {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -341,7 +364,7 @@ async function unstash() {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 1rem 1rem 1.5rem 1rem;
|
||||
padding: 1rem 1rem 0.5rem 1rem;
|
||||
}
|
||||
|
||||
.title {
|
||||
@@ -447,7 +470,8 @@ async function unstash() {
|
||||
}
|
||||
|
||||
.added-batch {
|
||||
color: var(--shadow);
|
||||
color: var(--shadow-weak-10);
|
||||
margin-left: .25rem;
|
||||
}
|
||||
|
||||
@media(--small-10) {
|
||||
@@ -473,6 +497,14 @@ async function unstash() {
|
||||
.album {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.header {
|
||||
padding: 1rem .5rem 1.5rem .5rem;
|
||||
}
|
||||
|
||||
.info {
|
||||
padding: 0 .5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (--small) {
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { fetchScenesById } from '#/src/scenes.js';
|
||||
|
||||
export async function onBeforeRender(pageContext) {
|
||||
const [scene] = await fetchScenesById([Number(pageContext.routeParams.sceneId)], pageContext.user);
|
||||
const [scene] = await fetchScenesById([Number(pageContext.routeParams.sceneId)], {
|
||||
reqUser: pageContext.user,
|
||||
actorStashes: true,
|
||||
});
|
||||
|
||||
return {
|
||||
pageContext: {
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
<template>
|
||||
<div class="stash">
|
||||
<div class="header">
|
||||
<h2 class="title">
|
||||
<Icon
|
||||
v-if="stash.primary"
|
||||
icon="heart7"
|
||||
/>
|
||||
|
||||
<Icon
|
||||
v-else
|
||||
icon="box"
|
||||
/>
|
||||
|
||||
{{ stash.name }}
|
||||
</h2>
|
||||
|
||||
<a
|
||||
:href="`/user/${stash.user.username}`"
|
||||
class="user nolink"
|
||||
>
|
||||
<img
|
||||
:src="stash.user.avatar"
|
||||
class="avatar"
|
||||
><span class="userame ellipsis">{{ stash.user.username }}</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="scenes-container">
|
||||
<Scenes />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { inject } from 'vue';
|
||||
|
||||
import Scenes from '#/components/scenes/scenes.vue';
|
||||
|
||||
const pageContext = inject('pageContext');
|
||||
const stash = pageContext.pageProps.stash;
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.stash {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: .5rem 1rem;
|
||||
color: var(--text-light);
|
||||
background: var(--grey-dark-40);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 0;
|
||||
text-transform: capitalize;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 1.2rem;
|
||||
margin-right: 1rem;
|
||||
|
||||
.icon {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
margin-right: .75rem;
|
||||
fill: var(--text-light);
|
||||
}
|
||||
}
|
||||
|
||||
.user {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-weight: bold;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
margin-right: .75rem;
|
||||
border-radius: .25rem;
|
||||
}
|
||||
|
||||
.scenes-container {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
@media(--small-50) {
|
||||
.title {
|
||||
font-size: 1rem;
|
||||
|
||||
.icon {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
10
pages/stashes/@username/@stashSlug/actors/+Page.vue
Normal file
10
pages/stashes/@username/@stashSlug/actors/+Page.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<Stash>
|
||||
<Actors />
|
||||
</Stash>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Stash from '#/components/stashes/stash.vue';
|
||||
import Actors from '#/components/actors/actors.vue';
|
||||
</script>
|
||||
49
pages/stashes/@username/@stashSlug/actors/+onBeforeRender.js
Normal file
49
pages/stashes/@username/@stashSlug/actors/+onBeforeRender.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import { render } from 'vike/abort'; /* eslint-disable-line import/extensions */
|
||||
|
||||
import { fetchStashByUsernameAndSlug } from '#/src/stashes.js';
|
||||
import { fetchActors } from '#/src/actors.js';
|
||||
import { curateActorsQuery } from '#/src/web/actors.js';
|
||||
import { HttpError } from '#/src/errors.js';
|
||||
|
||||
export async function onBeforeRender(pageContext) {
|
||||
try {
|
||||
const stash = await fetchStashByUsernameAndSlug(pageContext.routeParams.username, pageContext.routeParams.stashSlug, pageContext.user);
|
||||
|
||||
const stashActors = await fetchActors(curateActorsQuery({
|
||||
...pageContext.urlQuery,
|
||||
stashId: stash.id,
|
||||
}), {
|
||||
page: Number(pageContext.routeParams.page) || 1,
|
||||
limit: Number(pageContext.urlParsed.search.limit) || 120,
|
||||
order: pageContext.urlParsed.search.order?.split('.') || ['stashed', 'desc'],
|
||||
}, pageContext.user);
|
||||
|
||||
const {
|
||||
actors,
|
||||
countries,
|
||||
cupRange,
|
||||
limit,
|
||||
total,
|
||||
} = stashActors;
|
||||
|
||||
return {
|
||||
pageContext: {
|
||||
title: `${stash.name} by ${stash.user.username}`,
|
||||
pageProps: {
|
||||
stash,
|
||||
actors,
|
||||
countries,
|
||||
cupRange,
|
||||
limit,
|
||||
total,
|
||||
},
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
if (error instanceof HttpError) {
|
||||
throw render(error.httpCode, error.message);
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
24
pages/stashes/@username/@stashSlug/actors/+route.js
Normal file
24
pages/stashes/@username/@stashSlug/actors/+route.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import { match } from 'path-to-regexp';
|
||||
// import { resolveRoute } from 'vike/routing'; // eslint-disable-line import/extensions
|
||||
|
||||
const path = '/stash/:username/:stashSlug/:domain(actors)/:page?';
|
||||
const urlMatch = match(path, { decode: decodeURIComponent });
|
||||
|
||||
export default (pageContext) => {
|
||||
const matched = urlMatch(pageContext.urlPathname);
|
||||
|
||||
if (matched) {
|
||||
return {
|
||||
routeParams: {
|
||||
username: matched.params.username,
|
||||
stashSlug: matched.params.stashSlug,
|
||||
domain: matched.params.domain,
|
||||
order: 'stashed.desc',
|
||||
page: matched.params.page || '1',
|
||||
path,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
10
pages/stashes/@username/@stashSlug/movies/+Page.vue
Normal file
10
pages/stashes/@username/@stashSlug/movies/+Page.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<Stash>
|
||||
<h2>Movies</h2>
|
||||
</Stash>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Stash from '#/components/stashes/stash.vue';
|
||||
// import Actors from '#/components/actors/actors.vue';
|
||||
</script>
|
||||
25
pages/stashes/@username/@stashSlug/movies/+onBeforeRender.js
Normal file
25
pages/stashes/@username/@stashSlug/movies/+onBeforeRender.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import { render } from 'vike/abort'; /* eslint-disable-line import/extensions */
|
||||
|
||||
import { fetchStashByUsernameAndSlug } from '#/src/stashes.js';
|
||||
import { HttpError } from '#/src/errors.js';
|
||||
|
||||
export async function onBeforeRender(pageContext) {
|
||||
try {
|
||||
const stash = await fetchStashByUsernameAndSlug(pageContext.routeParams.username, pageContext.routeParams.stashSlug, pageContext.user);
|
||||
|
||||
return {
|
||||
pageContext: {
|
||||
title: `${stash.name} by ${stash.user.username}`,
|
||||
pageProps: {
|
||||
stash,
|
||||
},
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
if (error instanceof HttpError) {
|
||||
throw render(error.httpCode, error.message);
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { match } from 'path-to-regexp';
|
||||
// import { resolveRoute } from 'vike/routing'; // eslint-disable-line import/extensions
|
||||
|
||||
const path = '/stash/:username/:stashSlug/:scope?/:page?';
|
||||
const path = '/stash/:username/:stashSlug/:domain(movies)/:scope?/:page?';
|
||||
const urlMatch = match(path, { decode: decodeURIComponent });
|
||||
|
||||
export default (pageContext) => {
|
||||
@@ -12,6 +12,7 @@ export default (pageContext) => {
|
||||
routeParams: {
|
||||
username: matched.params.username,
|
||||
stashSlug: matched.params.stashSlug,
|
||||
domain: matched.params.domain,
|
||||
scope: matched.params.scope || 'stashed',
|
||||
page: matched.params.page || '1',
|
||||
path,
|
||||
10
pages/stashes/@username/@stashSlug/scenes/+Page.vue
Normal file
10
pages/stashes/@username/@stashSlug/scenes/+Page.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<Stash>
|
||||
<Scenes />
|
||||
</Stash>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Stash from '#/components/stashes/stash.vue';
|
||||
import Scenes from '#/components/scenes/scenes.vue';
|
||||
</script>
|
||||
24
pages/stashes/@username/@stashSlug/scenes/+route.js
Normal file
24
pages/stashes/@username/@stashSlug/scenes/+route.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import { match } from 'path-to-regexp';
|
||||
// import { resolveRoute } from 'vike/routing'; // eslint-disable-line import/extensions
|
||||
|
||||
const path = '/stash/:username/:stashSlug/:domain?/:scope?/:page?';
|
||||
const urlMatch = match(path, { decode: decodeURIComponent });
|
||||
|
||||
export default (pageContext) => {
|
||||
const matched = urlMatch(pageContext.urlPathname);
|
||||
|
||||
if (matched) {
|
||||
return {
|
||||
routeParams: {
|
||||
username: matched.params.username,
|
||||
stashSlug: matched.params.stashSlug,
|
||||
domain: matched.params.domain || 'scenes',
|
||||
scope: matched.params.scope || 'stashed',
|
||||
page: matched.params.page || '1',
|
||||
path,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
Reference in New Issue
Block a user