2023-12-30 05:29:53 +00:00
|
|
|
<template>
|
|
|
|
<div class="page">
|
|
|
|
<form
|
|
|
|
class="filters"
|
|
|
|
@submit.prevent
|
|
|
|
>
|
|
|
|
<div class="filter">
|
|
|
|
<input
|
|
|
|
v-model="q"
|
|
|
|
type="search"
|
|
|
|
placeholder="Search actors"
|
|
|
|
class="input search"
|
|
|
|
@search="search"
|
|
|
|
>
|
|
|
|
</div>
|
|
|
|
|
2023-12-31 02:02:03 +00:00
|
|
|
<ul class="filter genders nolist">
|
|
|
|
<li>
|
|
|
|
<button
|
|
|
|
:class="{ selected: filters.gender === undefined }"
|
|
|
|
class="gender-button all"
|
|
|
|
@click="updateFilter('gender', undefined, true)"
|
|
|
|
>all</button>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
<li>
|
|
|
|
<button
|
|
|
|
:class="{ selected: filters.gender === 'female' }"
|
|
|
|
class="gender-button female"
|
|
|
|
@click="updateFilter('gender', 'female', true)"
|
|
|
|
><Gender gender="female" /></button>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
<li>
|
|
|
|
<button
|
|
|
|
:class="{ selected: filters.gender === 'male' }"
|
|
|
|
class="gender-button male"
|
|
|
|
@click="updateFilter('gender', 'male', true)"
|
|
|
|
><Gender gender="male" /></button>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
<li>
|
|
|
|
<button
|
|
|
|
:class="{ selected: filters.gender === 'transsexual' }"
|
|
|
|
class="gender-button transsexual"
|
|
|
|
@click="updateFilter('gender', 'transsexual', true)"
|
|
|
|
><Gender gender="transsexual" /></button>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
<li>
|
|
|
|
<button
|
|
|
|
:class="{ selected: filters.gender === 'other' }"
|
|
|
|
class="gender-button other"
|
|
|
|
@click="updateFilter('gender', 'other', true)"
|
|
|
|
><Icon icon="question5" /></button>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
|
2023-12-30 05:29:53 +00:00
|
|
|
<div class="filter">
|
|
|
|
<RangeFilter
|
|
|
|
label="age"
|
|
|
|
:min="18"
|
|
|
|
:max="100"
|
|
|
|
:value="filters.age"
|
|
|
|
:disabled="!filters.ageRequired"
|
|
|
|
@enable="(checked) => updateFilter('ageRequired', checked, filters.ageRequired !== checked)"
|
|
|
|
@input="(range) => updateFilter('age', range, false)"
|
|
|
|
@change="(range) => updateFilter('age', range, true)"
|
|
|
|
>
|
|
|
|
<template #start><Icon icon="leaf" /></template>
|
|
|
|
<template #end><Icon icon="tree3" /></template>
|
|
|
|
</RangeFilter>
|
|
|
|
</div>
|
|
|
|
|
2023-12-31 02:02:03 +00:00
|
|
|
<div class="filter">
|
|
|
|
<RangeFilter
|
|
|
|
label="bra size"
|
|
|
|
:min="0"
|
|
|
|
:max="braSizes.length - 1"
|
|
|
|
:value="filters.braSize"
|
|
|
|
:values="braSizes"
|
|
|
|
:disabled="!filters.braSizeRequired"
|
|
|
|
@enable="(checked) => updateFilter('braSizeRequired', checked, true)"
|
|
|
|
@input="(range) => updateFilter('braSize', range, false)"
|
|
|
|
@change="(range) => updateFilter('braSize', range, true)"
|
|
|
|
>
|
|
|
|
<template #start><Icon icon="boobs-small" /></template>
|
|
|
|
<template #end><Icon icon="boobs-big" /></template>
|
|
|
|
</RangeFilter>
|
|
|
|
|
|
|
|
<span class="filter-label">Enhanced Boobs</span>
|
|
|
|
|
|
|
|
<span
|
|
|
|
:class="{ [['off', 'default', 'on'][naturalBoobsValues.indexOf(filters.naturalBoobs)]]: true }"
|
|
|
|
class="toggle-container noclick"
|
|
|
|
>
|
|
|
|
<span
|
|
|
|
class="toggle-label off"
|
|
|
|
@click="updateFilter('naturalBoobs', true, true)"
|
|
|
|
><Icon icon="leaf" /></span>
|
|
|
|
|
|
|
|
<input
|
|
|
|
:value="naturalBoobsValues.indexOf(filters.naturalBoobs)"
|
|
|
|
class="toggle"
|
|
|
|
type="range"
|
|
|
|
min="0"
|
|
|
|
max="2"
|
|
|
|
@change="updateFilter('naturalBoobs', naturalBoobsValues[$event.target.value], true)"
|
|
|
|
>
|
|
|
|
|
|
|
|
<span
|
|
|
|
class="toggle-label on"
|
|
|
|
@click="updateFilter('naturalBoobs', false, true)"
|
|
|
|
><Icon icon="magic-wand2" /></span>
|
|
|
|
</span>
|
|
|
|
</div>
|
|
|
|
|
2023-12-30 05:29:53 +00:00
|
|
|
<div class="filter">
|
|
|
|
<RangeFilter
|
|
|
|
label="height"
|
|
|
|
:min="50"
|
|
|
|
:max="220"
|
|
|
|
:value="filters.height"
|
|
|
|
:disabled="!filters.heightRequired"
|
|
|
|
unit="cm"
|
|
|
|
@enable="(checked) => updateFilter('heightRequired', checked, filters.heightRequired !== checked)"
|
|
|
|
@input="(range) => updateFilter('height', range, false)"
|
|
|
|
@change="(range) => updateFilter('height', range, true)"
|
|
|
|
>
|
|
|
|
<template #start><Icon icon="height-short" /></template>
|
|
|
|
<template #end><Icon icon="height" /></template>
|
|
|
|
</RangeFilter>
|
|
|
|
|
|
|
|
<RangeFilter
|
|
|
|
label="weight"
|
|
|
|
:min="30"
|
|
|
|
:max="200"
|
|
|
|
:value="filters.weight"
|
|
|
|
:disabled="!filters.weightRequired"
|
|
|
|
unit="kg"
|
|
|
|
@enable="(checked) => updateFilter('weightRequired', checked, filters.weightRequired !== checked)"
|
|
|
|
@input="(range) => updateFilter('weight', range, false)"
|
|
|
|
@change="(range) => updateFilter('weight', range, true)"
|
|
|
|
>
|
|
|
|
<template #start><Icon icon="meter-slow" /></template>
|
|
|
|
<template #end><Icon icon="meter-fast" /></template>
|
|
|
|
</RangeFilter>
|
|
|
|
</div>
|
|
|
|
|
2023-12-31 02:02:03 +00:00
|
|
|
<Tooltip class="filter">
|
|
|
|
<span
|
|
|
|
:class="{ enabled: filters.country }"
|
|
|
|
class="filter-trigger"
|
|
|
|
>
|
|
|
|
<img
|
|
|
|
v-if="filters.country"
|
|
|
|
:src="`/img/flags/${filters.country.toLowerCase()}.svg`"
|
|
|
|
class="flag"
|
|
|
|
>
|
|
|
|
|
|
|
|
<Icon
|
|
|
|
v-else
|
|
|
|
icon="earth2"
|
|
|
|
/>Country
|
|
|
|
</span>
|
|
|
|
|
|
|
|
<template #tooltip>
|
|
|
|
<input
|
|
|
|
v-model="countryQuery"
|
|
|
|
placeholder="Search"
|
|
|
|
class="input"
|
|
|
|
>
|
|
|
|
|
|
|
|
<Countries
|
|
|
|
v-if="!countryQuery"
|
|
|
|
:countries="topCountries"
|
|
|
|
:selected-country="country"
|
|
|
|
:update-value="updateFilter"
|
|
|
|
/>
|
|
|
|
|
|
|
|
<Countries
|
|
|
|
:countries="filteredCountries"
|
|
|
|
:selected-country="country"
|
|
|
|
:update-value="updateFilter"
|
|
|
|
/>
|
|
|
|
</template>
|
|
|
|
</Tooltip>
|
|
|
|
|
2023-12-30 05:29:53 +00:00
|
|
|
<div class="filter">
|
|
|
|
<Checkbox
|
2023-12-31 02:02:03 +00:00
|
|
|
:checked="filters.avatarRequired"
|
2023-12-30 05:29:53 +00:00
|
|
|
label="Require photo"
|
2023-12-31 02:02:03 +00:00
|
|
|
@change="(checked) => updateFilter('avatarRequired', checked, true)"
|
2023-12-30 05:29:53 +00:00
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</form>
|
|
|
|
|
|
|
|
<ul class="actors nolist">
|
|
|
|
<li
|
|
|
|
v-for="actor in actors"
|
|
|
|
:key="`actor-${actor.id}`"
|
|
|
|
>
|
|
|
|
<ActorTile
|
|
|
|
:actor="actor"
|
|
|
|
/>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script setup>
|
2023-12-31 02:02:03 +00:00
|
|
|
import { ref, computed, inject } from 'vue';
|
2023-12-30 05:29:53 +00:00
|
|
|
|
|
|
|
import navigate from '#/src/navigate.js';
|
|
|
|
import { get } from '#/src/api.js';
|
|
|
|
|
|
|
|
import ActorTile from '#/components/actors/tile.vue';
|
2023-12-31 02:02:03 +00:00
|
|
|
import Gender from '#/components/actors/gender.vue';
|
2023-12-30 05:29:53 +00:00
|
|
|
import Checkbox from '#/components/form/checkbox.vue';
|
|
|
|
import RangeFilter from '#/components/filters/range.vue';
|
2023-12-31 02:02:03 +00:00
|
|
|
import Tooltip from '#/components/tooltip/tooltip.vue';
|
|
|
|
import Countries from '#/components/filters/countries.vue';
|
2023-12-30 05:29:53 +00:00
|
|
|
|
2023-12-31 02:02:03 +00:00
|
|
|
const { pageProps, urlParsed } = inject('pageContext');
|
|
|
|
|
|
|
|
const q = ref(urlParsed.search.q);
|
2023-12-30 05:29:53 +00:00
|
|
|
const actors = ref([]);
|
|
|
|
|
2023-12-31 02:02:03 +00:00
|
|
|
const countries = ref(pageProps.countries);
|
|
|
|
const countryQuery = ref('');
|
|
|
|
|
|
|
|
const topCountryAlpha2s = ['AU', 'BR', 'CZ', 'DE', 'JP', 'RU', 'GB', 'US'];
|
|
|
|
const topCountries = computed(() => countries.value.filter((country) => topCountryAlpha2s.includes(country.alpha2)));
|
|
|
|
const filteredCountries = computed(() => countries.value.filter((country) => new RegExp(countryQuery.value, 'i').test(country.name)));
|
2023-12-30 05:29:53 +00:00
|
|
|
|
|
|
|
actors.value = pageProps.actors;
|
|
|
|
|
2023-12-31 02:02:03 +00:00
|
|
|
console.log(countries.value);
|
|
|
|
|
|
|
|
const braSizes = 'ABCDEFGHIJKZ'.split('');
|
|
|
|
const naturalBoobsValues = [true, undefined, false];
|
2023-12-30 05:29:53 +00:00
|
|
|
|
|
|
|
const filters = ref({
|
2023-12-31 02:02:03 +00:00
|
|
|
gender: urlParsed.search.gender,
|
2023-12-30 05:29:53 +00:00
|
|
|
ageRequired: !!urlParsed.search.age,
|
|
|
|
age: urlParsed.search.age?.split(',').map((age) => Number(age)) || [18, 100],
|
2023-12-31 02:02:03 +00:00
|
|
|
braSizeRequired: !!urlParsed.search.cup,
|
|
|
|
braSize: urlParsed.search.cup?.split(',') || ['A', 'Z'],
|
|
|
|
naturalBoobs: urlParsed.search.nb ? urlParsed.search.nb === 'true' : undefined,
|
2023-12-30 05:29:53 +00:00
|
|
|
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],
|
2023-12-31 02:02:03 +00:00
|
|
|
avatarRequired: !!urlParsed.search.avatar,
|
2023-12-30 05:29:53 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
async function search() {
|
|
|
|
const query = {
|
|
|
|
q: q.value || undefined,
|
2023-12-31 02:02:03 +00:00
|
|
|
gender: filters.value.gender || undefined,
|
2023-12-30 05:29:53 +00:00
|
|
|
age: filters.value.ageRequired ? filters.value.age.join(',') : undefined,
|
2023-12-31 02:02:03 +00:00
|
|
|
cup: filters.value.braSizeRequired ? filters.value.braSize.join(',') : undefined,
|
|
|
|
nb: filters.value.naturalBoobs,
|
2023-12-30 05:29:53 +00:00
|
|
|
height: filters.value.heightRequired ? filters.value.height.join(',') : undefined,
|
|
|
|
weight: filters.value.weightRequired ? filters.value.weight.join(',') : undefined,
|
2023-12-31 02:02:03 +00:00
|
|
|
avatar: filters.value.avatarRequired || undefined,
|
2023-12-30 05:29:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
navigate('/actors', query, { redirect: false });
|
|
|
|
|
|
|
|
const res = await get('/actors', query);
|
|
|
|
|
|
|
|
actors.value = res.actors;
|
2023-12-31 02:02:03 +00:00
|
|
|
countries.value = res.countries;
|
2023-12-30 05:29:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function updateFilter(prop, value, reload = true) {
|
|
|
|
filters.value[prop] = value;
|
|
|
|
|
|
|
|
if (reload) {
|
|
|
|
search();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
|
2023-12-31 02:02:03 +00:00
|
|
|
<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>
|
|
|
|
|
2023-12-30 05:29:53 +00:00
|
|
|
<style scoped>
|
|
|
|
.page {
|
|
|
|
height: 100%;
|
|
|
|
display: flex;
|
|
|
|
overflow: hidden;
|
|
|
|
}
|
|
|
|
|
|
|
|
.filters {
|
2023-12-31 02:02:03 +00:00
|
|
|
width: 17rem;
|
2023-12-30 05:29:53 +00:00
|
|
|
flex-shrink: 0;
|
|
|
|
padding: .5rem 0;
|
|
|
|
border-right: solid 1px var(--shadow-weak-30);
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
|
|
.input {
|
|
|
|
width: 100%;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.filter {
|
|
|
|
padding: .5rem;
|
2023-12-31 02:02:03 +00:00
|
|
|
border-bottom: solid 1px var(--shadow-weak-30);
|
2023-12-30 05:29:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
.actors {
|
|
|
|
display: grid;
|
|
|
|
flex-grow: 1;
|
|
|
|
grid-template-columns: repeat(auto-fill, 10rem);
|
|
|
|
gap: .25rem;
|
|
|
|
padding: 1rem;
|
|
|
|
overflow-y: auto;
|
|
|
|
}
|
2023-12-31 02:02:03 +00:00
|
|
|
|
|
|
|
.genders {
|
|
|
|
display: flex;
|
|
|
|
justify-content: center;
|
|
|
|
gap: .5rem;
|
|
|
|
}
|
|
|
|
|
|
|
|
.gender-button {
|
|
|
|
width: 2.5rem;
|
|
|
|
height: 2.5rem;
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
justify-content: center;
|
|
|
|
box-sizing: border-box;
|
|
|
|
border: none;
|
|
|
|
color: var(--shadow);
|
|
|
|
background: var(--background);
|
|
|
|
font-weight: bold;
|
|
|
|
text-decoration: none;
|
|
|
|
font-size: .9rem;
|
|
|
|
box-shadow: 0 0 3px var(--shadow-weak-20);
|
|
|
|
|
|
|
|
.male,
|
|
|
|
.female,
|
|
|
|
.transsexual {
|
|
|
|
padding: .2rem 0 0 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
.icon {
|
|
|
|
fill: var(--shadow);
|
|
|
|
}
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
color: var(--text);
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
|
|
.icon {
|
|
|
|
fill: var(--text);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
&.selected {
|
|
|
|
background: var(--primary);
|
|
|
|
color: var(--text-light);
|
|
|
|
|
|
|
|
&.other .icon {
|
|
|
|
fill: var(--text-light);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.countries {
|
|
|
|
overflow: hidden;
|
|
|
|
}
|
2023-12-30 05:29:53 +00:00
|
|
|
</style>
|