traxxx/assets/components/tags/tags.vue

339 lines
4.9 KiB
Vue
Executable File

<template>
<div class="tags">
<div class="content-inner">
<SearchBar
:placeholder="'Search tags'"
class="search"
/>
<div
v-for="(tags, category) in categories"
:key="category"
class="category"
>
<h3 class="heading">{{ category }}</h3>
<div
:key="sfw"
class="tiles"
>
<Tag
v-for="tag in tags"
:key="`tag-${tag.id}`"
:tag="tag"
:lazy="true"
/>
</div>
</div>
</div>
<Footer />
</div>
</template>
<script>
import Tag from './tile.vue';
import SearchBar from '../search/bar.vue';
const tagSlugsByCategory = {
popular: [
'anal',
'lesbian',
'interracial',
'mff',
'mfm',
'teen',
'milf',
'blowjob',
'gay',
'transsexual',
'dp',
'gangbang',
'facial',
'creampie',
'squirting',
],
appearance: [
'asian',
'black',
'latina',
'white',
'natural-boobs',
'enhanced-boobs',
'blonde',
'brunette',
'redhead',
'tattoos',
'piercings',
],
sexuality: [
'gay',
'bisexual',
'transsexual',
],
oral: [
'blowjob',
'pussy-eating',
'ass-eating',
'deepthroat',
'facefucking',
'69',
'atm',
],
manual: [
'handjob',
'fingering',
'anal-fingering',
'titty-fucking',
'fisting',
'anal-fisting',
],
group: [
'mfm',
'mff',
'orgy',
'gangbang',
'blowbang',
],
cumshot: [
'facial',
'creampie',
'cum-in-mouth',
'cum-on-boobs',
'cum-on-butt',
'cum-on-pussy',
'anal-creampie',
'oral-creampie',
'bukkake',
'fake-cum',
],
roleplay: [
'family',
'parody',
'schoolgirl',
'nurse',
'maid',
'nun',
],
extreme: [
'dp',
'airtight',
'dap',
'dvp',
'triple-penetration',
'tap',
'tvp',
],
fetish: [
'bdsm',
'femdom',
'bondage',
'free-use',
'latex',
'blindfold',
],
toys: [
'toys',
'toy-anal',
'toy-dp',
'double-dildo',
'double-dildo-blowjob',
'double-dildo-kiss',
'double-dildo-anal',
'double-dildo-dp',
],
misc: [
'gaping',
'squirting',
'oil',
'vr',
'bts',
],
};
function sfw() {
return this.$store.state.ui.sfw;
}
async function fetchTags() {
if (this.$route.query.query) {
await this.searchTags();
return;
}
const tags = await this.$store.dispatch('fetchTags', {
slugs: Object.values(tagSlugsByCategory).flat(),
});
const tagsBySlug = tags.reduce((acc, tag) => ({ ...acc, [tag.slug]: tag }), {});
this.categories = Object.entries(tagSlugsByCategory).reduce((acc, [category, tagSlugs]) => {
const categoryTags = tagSlugs.map((tagSlug) => tagsBySlug[tagSlug]).filter(Boolean);
if (categoryTags.length === 0) {
return acc;
}
return {
...acc,
[category]: categoryTags,
};
}, {});
}
async function searchTags() {
const tags = await this.$store.dispatch('searchTags', {
minLength: 1,
query: this.$route.query.query,
limit: 20,
});
this.categories = {
results: tags,
};
}
async function mounted() {
this.pageTitle = 'Tags';
await this.fetchTags();
}
export default {
components: {
Tag,
SearchBar,
},
data() {
return {
categories: {},
pageTitle: null,
};
},
computed: {
sfw,
},
watch: {
$route: fetchTags,
'$store.state.ui.tagFilter': fetchTags,
},
mounted,
methods: {
fetchTags,
searchTags,
},
};
</script>
<style lang="scss" scoped>
@import 'breakpoints';
.tags {
display: flex;
flex-direction: column;
flex-grow: 1;
}
.content-inner {
padding: 1rem 1rem 0 1rem;
}
.tiles {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(20rem, .33fr));
grid-gap: 1rem;
}
.heading {
text-transform: capitalize;
padding: 0 0 0 .5rem;
margin: 1.25rem 0 1rem 0;
}
.category:first-child .heading {
margin: .5rem 0 1rem 0;
}
.search {
margin: 0 0 .25rem 0;
}
@media(max-width: $breakpoint-mega) {
.tiles {
grid-template-columns: repeat(auto-fill, minmax(17.75rem, .5fr));
}
::v-deep(.poster),
::v-deep(.blank) {
height: 12rem;
}
}
@media(max-width: $breakpoint-kilo) {
.tiles {
grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
grid-gap: .5rem;
}
::v-deep(.poster),
::v-deep(.blank) {
height: 14rem;
}
}
@media(max-width: $breakpoint) {
.tiles {
grid-template-columns: repeat(auto-fill, minmax(14.5rem, 1fr));
grid-gap: .5rem;
}
::v-deep(.poster),
::v-deep(.blank) {
height: 11rem;
}
}
@media(max-width: $breakpoint-small) {
::v-deep(.poster),
::v-deep(.blank) {
height: 10rem;
}
}
@media(max-width: $breakpoint-micro) {
.tiles {
grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
}
::v-deep(.poster),
::v-deep(.blank) {
height: 7.5rem;
}
}
@media(max-width: $breakpoint-mini) {
.tiles {
grid-template-columns: repeat(auto-fill, minmax(11.5rem, 1fr));
}
::v-deep(.poster),
::v-deep(.blank) {
height: 12rem;
}
}
@media(max-width: $breakpoint-nano) {
::v-deep(.poster),
::v-deep(.blank) {
height: 10rem;
}
}
@media(max-width: $breakpoint-pico) {
::v-deep(.poster),
::v-deep(.blank) {
height: 8rem;
}
}
</style>