You've already forked AstralRinth
forked from didirus/AstralRinth
Finish Search
This commit is contained in:
100
components/Pagination.vue
Normal file
100
components/Pagination.vue
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
<template>
|
||||||
|
<div v-if="pages.length > 1" class="columns paginates">
|
||||||
|
<svg
|
||||||
|
:class="{ 'disabled-paginate': currentPage === 1 }"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
@click="currentPage !== 1 ? switchPage(currentPage - 1) : null"
|
||||||
|
>
|
||||||
|
<polyline points="15 18 9 12 15 6"></polyline>
|
||||||
|
</svg>
|
||||||
|
<p
|
||||||
|
v-for="(item, index) in pages"
|
||||||
|
:key="'page-' + item"
|
||||||
|
:class="{
|
||||||
|
'active-page-number': currentPage !== item,
|
||||||
|
}"
|
||||||
|
@click="currentPage !== item ? switchPage(item) : null"
|
||||||
|
>
|
||||||
|
<span v-if="pages[index - 1] + 1 !== item && item !== 1">...</span>
|
||||||
|
<span :class="{ 'disabled-page-number': currentPage === item }">{{
|
||||||
|
item
|
||||||
|
}}</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<svg
|
||||||
|
:class="{
|
||||||
|
'disabled-paginate': currentPage === pages[pages.length - 1],
|
||||||
|
}"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
@click="
|
||||||
|
currentPage !== pages[pages.length - 1]
|
||||||
|
? switchPage(currentPage + 1)
|
||||||
|
: null
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<polyline points="9 18 15 12 9 6"></polyline>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'Pagination',
|
||||||
|
props: {
|
||||||
|
currentPage: {
|
||||||
|
type: Number,
|
||||||
|
default: 1,
|
||||||
|
},
|
||||||
|
pages: {
|
||||||
|
type: Array,
|
||||||
|
default() {
|
||||||
|
return []
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
switchPage(newPage) {
|
||||||
|
this.$emit('switch-page', newPage)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.paginates {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.paginates p {
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disabled-paginate {
|
||||||
|
cursor: default;
|
||||||
|
color: var(--color-grey-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.active-page-number {
|
||||||
|
user-select: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disabled-page-number {
|
||||||
|
user-select: none;
|
||||||
|
cursor: default;
|
||||||
|
padding: 2px 3px;
|
||||||
|
border-radius: 3px;
|
||||||
|
background-color: var(--color-grey-1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
247
pages/mods.vue
247
pages/mods.vue
@@ -2,7 +2,7 @@
|
|||||||
<div class="columns">
|
<div class="columns">
|
||||||
<div class="content column-grow-4">
|
<div class="content column-grow-4">
|
||||||
<h2>Mods</h2>
|
<h2>Mods</h2>
|
||||||
<section id="search-pagination">
|
<section class="search-bar">
|
||||||
<div class="iconified-input column-grow-2">
|
<div class="iconified-input column-grow-2">
|
||||||
<input
|
<input
|
||||||
id="search"
|
id="search"
|
||||||
@@ -43,52 +43,11 @@
|
|||||||
<polyline points="6 9 12 15 18 9"></polyline>
|
<polyline points="6 9 12 15 18 9"></polyline>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="pages.length > 1" class="columns paginates">
|
<pagination
|
||||||
<svg
|
:current-page="currentPage"
|
||||||
:class="{ 'disabled-paginate': currentPage === 1 }"
|
:pages="pages"
|
||||||
viewBox="0 0 24 24"
|
@switch-page="onSearchChange"
|
||||||
fill="none"
|
></pagination>
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
@click="currentPage !== 1 ? onSearchChange(currentPage - 1) : null"
|
|
||||||
>
|
|
||||||
<polyline points="15 18 9 12 15 6"></polyline>
|
|
||||||
</svg>
|
|
||||||
<p
|
|
||||||
v-for="(item, index) in pages"
|
|
||||||
:key="'page-' + item"
|
|
||||||
:class="{
|
|
||||||
'active-page-number': currentPage !== item,
|
|
||||||
}"
|
|
||||||
@click="currentPage !== item ? onSearchChange(item) : null"
|
|
||||||
>
|
|
||||||
<span v-if="pages[index - 1] + 1 !== item && item !== 1">...</span>
|
|
||||||
<span :class="{ 'disabled-page-number': currentPage === item }">{{
|
|
||||||
item
|
|
||||||
}}</span>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<svg
|
|
||||||
:class="{
|
|
||||||
'disabled-paginate': currentPage === pages[pages.length - 1],
|
|
||||||
}"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
@click="
|
|
||||||
currentPage !== pages[pages.length - 1]
|
|
||||||
? onSearchChange(currentPage + 1)
|
|
||||||
: null
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<polyline points="9 18 15 12 9 6"></polyline>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
<div class="results column-grow-4">
|
<div class="results column-grow-4">
|
||||||
<SearchResult
|
<SearchResult
|
||||||
@@ -108,6 +67,34 @@
|
|||||||
:categories="result.categories"
|
:categories="result.categories"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<section v-if="pages.length > 1" class="search-bottom">
|
||||||
|
<div class="iconified-select">
|
||||||
|
<select id="max-results" @input="changeMaxResults">
|
||||||
|
<option value="5" selected>5</option>
|
||||||
|
<option value="10">10</option>
|
||||||
|
<option value="15">15</option>
|
||||||
|
<option value="20">20</option>
|
||||||
|
<option value="50">50</option>
|
||||||
|
<option value="100">100</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
>
|
||||||
|
<polyline points="6 9 12 15 18 9"></polyline>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<pagination
|
||||||
|
:current-page="currentPage"
|
||||||
|
:pages="pages"
|
||||||
|
@switch-page="onSearchChangeToTop"
|
||||||
|
></pagination>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<section class="filters">
|
<section class="filters">
|
||||||
<!--#region filters -->
|
<!--#region filters -->
|
||||||
@@ -374,6 +361,7 @@
|
|||||||
import Multiselect from 'vue-multiselect'
|
import Multiselect from 'vue-multiselect'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import SearchResult from '@/components/ModResult'
|
import SearchResult from '@/components/ModResult'
|
||||||
|
import Pagination from '@/components/Pagination'
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
headers: {
|
headers: {
|
||||||
@@ -384,6 +372,7 @@ const config = {
|
|||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
SearchResult,
|
SearchResult,
|
||||||
|
Pagination,
|
||||||
Multiselect,
|
Multiselect,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@@ -395,12 +384,11 @@ export default {
|
|||||||
results: [],
|
results: [],
|
||||||
pages: [],
|
pages: [],
|
||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
overrideOffset: 0,
|
|
||||||
sortType: 'relevance',
|
sortType: 'relevance',
|
||||||
maxResults: 6,
|
maxResults: 5,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted() {
|
async created() {
|
||||||
if (this.$route.query.q) this.query = this.$route.query.q
|
if (this.$route.query.q) this.query = this.$route.query.q
|
||||||
if (this.$route.query.f) {
|
if (this.$route.query.f) {
|
||||||
const facets = this.$route.query.f.split(',')
|
const facets = this.$route.query.f.split(',')
|
||||||
@@ -409,16 +397,21 @@ export default {
|
|||||||
}
|
}
|
||||||
if (this.$route.query.v)
|
if (this.$route.query.v)
|
||||||
this.selectedVersions = this.$route.query.v.split(',')
|
this.selectedVersions = this.$route.query.v.split(',')
|
||||||
if (this.$route.query.s) this.sortType = this.$route.query.s
|
if (this.$route.query.s) {
|
||||||
if (this.$route.query.o) this.overrideOffset = this.$route.query.o
|
this.sortType = this.$route.query.s
|
||||||
|
}
|
||||||
|
if (this.$route.query.m) {
|
||||||
|
this.maxResults = this.$route.query.m
|
||||||
|
}
|
||||||
|
if (this.$route.query.o)
|
||||||
|
this.currentPage = Math.ceil(this.$route.query.o / this.maxResults) + 1
|
||||||
|
|
||||||
await this.fillInitialVersions()
|
await this.fillInitialVersions()
|
||||||
|
await this.onSearchChange(this.currentPage)
|
||||||
window.addEventListener('resize', this.resize)
|
|
||||||
await this.resize()
|
|
||||||
},
|
},
|
||||||
destroyed() {
|
mounted() {
|
||||||
window.removeEventListener('resize', this.resize)
|
document.getElementById('sort-type').value = this.sortType
|
||||||
|
document.getElementById('max-results').value = this.maxResults
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async fillInitialVersions() {
|
async fillInitialVersions() {
|
||||||
@@ -429,27 +422,20 @@ export default {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const versions = res.data.versions
|
const versions = res.data.versions
|
||||||
|
const betaVersions = []
|
||||||
|
const legacyVersions = []
|
||||||
for (const version of versions) {
|
for (const version of versions) {
|
||||||
this.versions.push(version.id)
|
if (version.type === 'release') this.versions.push(version.id)
|
||||||
|
if (version.type === 'snapshot') betaVersions.push(version.id)
|
||||||
|
if (version.type === 'old_beta' || version.type === 'old_alpha')
|
||||||
|
legacyVersions.push(version.id)
|
||||||
}
|
}
|
||||||
|
this.versions.concat(betaVersions, legacyVersions)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
console.error(err)
|
console.error(err)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async resize() {
|
|
||||||
const vh = Math.max(
|
|
||||||
document.documentElement.clientHeight || 0,
|
|
||||||
window.innerHeight || 0
|
|
||||||
)
|
|
||||||
this.maxResults = Math.floor((vh - 200) / 120)
|
|
||||||
|
|
||||||
await this.onSearchChange(this.currentPage)
|
|
||||||
|
|
||||||
if (this.currentPage > this.pages[this.pages.length - 1]) {
|
|
||||||
this.currentPage = this.pages[this.pages.length - 1]
|
|
||||||
await this.onSearchChange(this.currentPage)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async clearFilters() {
|
async clearFilters() {
|
||||||
for (const facet of [...this.facets]) await this.toggleFacet(facet, true)
|
for (const facet of [...this.facets]) await this.toggleFacet(facet, true)
|
||||||
|
|
||||||
@@ -457,24 +443,38 @@ export default {
|
|||||||
await this.onSearchChange(1)
|
await this.onSearchChange(1)
|
||||||
},
|
},
|
||||||
async toggleFacet(elementName, sendRequest) {
|
async toggleFacet(elementName, sendRequest) {
|
||||||
const element = document.getElementById(elementName)
|
const element = process.client
|
||||||
const index = this.facets.indexOf(element.id)
|
? document.getElementById(elementName)
|
||||||
|
: null
|
||||||
|
const index = this.facets.indexOf(elementName)
|
||||||
|
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
element.classList.remove('filter-active')
|
if (process.client) element.classList.remove('filter-active')
|
||||||
this.facets.splice(index, 1)
|
this.facets.splice(index, 1)
|
||||||
} else {
|
} else {
|
||||||
element.classList.add('filter-active')
|
if (process.client) element.classList.add('filter-active')
|
||||||
this.facets.push(element.id)
|
this.facets.push(elementName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sendRequest) await this.onSearchChange(1)
|
if (!sendRequest) await this.onSearchChange(1)
|
||||||
},
|
},
|
||||||
async changeSortType() {
|
async changeSortType() {
|
||||||
this.sortType = document.getElementById('sort-type').value
|
if (process.client)
|
||||||
|
this.sortType = document.getElementById('sort-type').value
|
||||||
|
|
||||||
await this.onSearchChange(1)
|
await this.onSearchChange(1)
|
||||||
},
|
},
|
||||||
|
async changeMaxResults() {
|
||||||
|
if (process.client)
|
||||||
|
this.maxResults = document.getElementById('max-results').value
|
||||||
|
|
||||||
|
await this.onSearchChangeToTop(1)
|
||||||
|
},
|
||||||
|
async onSearchChangeToTop(newPageNumber) {
|
||||||
|
if (process.client) window.scrollTo(0, 0)
|
||||||
|
|
||||||
|
await this.onSearchChange(newPageNumber)
|
||||||
|
},
|
||||||
async onSearchChange(newPageNumber) {
|
async onSearchChange(newPageNumber) {
|
||||||
try {
|
try {
|
||||||
const params = [`limit=${this.maxResults}`, `index=${this.sortType}`]
|
const params = [`limit=${this.maxResults}`, `index=${this.sortType}`]
|
||||||
@@ -501,11 +501,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const offset = (newPageNumber - 1) * this.maxResults
|
const offset = (newPageNumber - 1) * this.maxResults
|
||||||
if (this.overrideOffset > 0) {
|
if (newPageNumber !== 1) {
|
||||||
console.log(this.overrideOffset)
|
|
||||||
params.push(`offset=${this.overrideOffset}`)
|
|
||||||
this.overrideOffset = 0
|
|
||||||
} else if (newPageNumber !== 1) {
|
|
||||||
params.push(`offset=${offset}`)
|
params.push(`offset=${offset}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -547,15 +543,21 @@ export default {
|
|||||||
this.pages = Array.from({ length: pageAmount }, (_, i) => i + 1)
|
this.pages = Array.from({ length: pageAmount }, (_, i) => i + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
url = `mods?q=${encodeURIComponent(
|
if (process.client) {
|
||||||
this.query
|
url = `mods?q=${encodeURIComponent(this.query)}`
|
||||||
)}&o=${offset}&f=${encodeURIComponent(
|
|
||||||
this.facets.toString()
|
|
||||||
)}&v=${encodeURIComponent(
|
|
||||||
this.selectedVersions.toString()
|
|
||||||
)}&s=${encodeURIComponent(this.sortType)}`
|
|
||||||
|
|
||||||
window.history.pushState(new Date(), 'Mods', url)
|
if (offset > 0) url += `&o=${offset}`
|
||||||
|
if (this.facets.length > 0)
|
||||||
|
url += `&f=${encodeURIComponent(this.facets)}`
|
||||||
|
if (this.selectedVersions.length > 0)
|
||||||
|
url += `&v=${encodeURIComponent(this.selectedVersions)}`
|
||||||
|
if (this.sortType !== 'relevance')
|
||||||
|
url += `&s=${encodeURIComponent(this.sortType)}`
|
||||||
|
if (this.maxResults > 5)
|
||||||
|
url += `&m=${encodeURIComponent(this.maxResults)}`
|
||||||
|
|
||||||
|
window.history.pushState(new Date(), 'Mods', url)
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.error(err)
|
console.error(err)
|
||||||
@@ -570,23 +572,24 @@ export default {
|
|||||||
|
|
||||||
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
|
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
#search-pagination {
|
.search-bar {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
.paginates {
|
.search-bottom {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
.paginates p {
|
select {
|
||||||
margin-left: 5px;
|
width: 100px;
|
||||||
margin-right: 5px;
|
margin-right: 20px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
min-height: 95vh;
|
min-height: 96vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filters {
|
.filters {
|
||||||
@@ -620,12 +623,14 @@ export default {
|
|||||||
button {
|
button {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 5px 0;
|
padding: 5px 0;
|
||||||
color: #718096;
|
outline: none;
|
||||||
|
color: var(--color-grey-5);
|
||||||
|
background-color: var(--color-grey-1);
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--color-grey-1);
|
background-color: var(--color-grey-2);
|
||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -661,24 +666,6 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.disabled-paginate {
|
|
||||||
cursor: default;
|
|
||||||
color: var(--color-grey-3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.active-page-number {
|
|
||||||
user-select: none;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.disabled-page-number {
|
|
||||||
user-select: none;
|
|
||||||
cursor: default;
|
|
||||||
padding: 2px 3px;
|
|
||||||
border-radius: 3px;
|
|
||||||
background-color: var(--color-grey-3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconified-select {
|
.iconified-select {
|
||||||
margin-left: 1em;
|
margin-left: 1em;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -726,4 +713,26 @@ select {
|
|||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.multiselect__tags {
|
||||||
|
background: var(--color-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.multiselect__input {
|
||||||
|
color: var(--color-text);
|
||||||
|
background: var(--color-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.multiselect__option {
|
||||||
|
color: var(--color-text);
|
||||||
|
background: var(--color-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.multiselect__option--highlight {
|
||||||
|
background: var(--color-brand);
|
||||||
|
}
|
||||||
|
|
||||||
|
.multiselect__tag {
|
||||||
|
background: var(--color-brand);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user