Skip to content
This repository was archived by the owner on Dec 5, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/components/landing/Series.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<template>
<div class="container mb-1">
<section>
<h1 class="title is-2">Top Collection</h1>
<p class="subtitle is-size-5">The top NFTs on RMRK, ranked by score, volume, floor price and other statistics.</p>
<h1 class="title is-2">{{ $t('series.title') }}</h1>
<p class="subtitle is-size-5">{{ $t('series.subtitle') }}</p>

<SeriesTable />
</section>
Expand Down
59 changes: 47 additions & 12 deletions src/components/rmrk/Gallery/CollectionItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
</div>
</div>

<Search v-bind.sync="searchQuery" />

<GalleryCardList :items="collection.nfts" />

</div>
Expand All @@ -63,12 +65,17 @@ import { sanitizeIpfsUrl, fetchCollectionMetadata } from '../utils'
import isShareMode from '@/utils/isShareMode'
import collectionById from '@/queries/collectionById.graphql'
import { CollectionMetadata } from '../types'
import { NFT } from '@/components/rmrk/service/scheme'
import { SearchQuery } from './Search/types'


const components = {
GalleryCardList: () => import('@/components/rmrk/Gallery/GalleryCardList.vue'),
CollectionActivity: () => import('@/components/rmrk/Gallery/CollectionActivity.vue'),
Sharing: () => import('@/components/rmrk/Gallery/Item/Sharing.vue'),
ProfileLink: () => import('@/components/rmrk/Profile/ProfileLink.vue'),
VueMarkdown: () => import('vue-markdown-render'),
Search: () => import('./Search/SearchBarCollection.vue'),
}
@Component<CollectionItem>({
metaInfo() {
Expand All @@ -94,45 +101,73 @@ export default class CollectionItem extends Vue {
private collection: CollectionWithMeta = emptyObject<CollectionWithMeta>();
private isLoading = false;
public meta: CollectionMetadata = emptyObject<CollectionMetadata>();

get image() {
private searchQuery: SearchQuery = {
search: '',
type: '',
sortBy: 'BLOCK_NUMBER_DESC',
listed: false,
};

get image(): string {
return this.meta.image || ''
}

get description() {
get description(): string {
return this.meta.description || ''
}

get name() {
get name(): string {
return this.collection.name || this.id
}

get nfts() {
get nfts(): NFT[] {
return this.collection.nfts || []
}

get issuer() {
get issuer(): string {
return this.collection.issuer || ''
}

get owner() {
get owner(): string {
return this.collection.issuer === (this.collection as any).currentOwner ? '' : (this.collection as any).currentOwner
}

get sharingVisible() {
get sharingVisible(): boolean {
return !isShareMode
}

private buildSearchParam(): Record<string, unknown>[] {
const params = []

if (this.searchQuery.search) {
params.push({
name: { likeInsensitive: `%${this.searchQuery.search}%` }
})
}

if (this.searchQuery.listed) {
params.push({
price: { greaterThan: '0' }
})
}

return params
}

public created() {
this.isLoading = true
this.checkId()
this.$apollo.addSmartQuery('collection',{
this.$apollo.addSmartQuery('collection', {
query: collectionById,
variables: {
id: this.id
variables: () => {
return {
id: this.id,
orderBy: this.searchQuery.sortBy,
search: this.buildSearchParam()
}
},
update: ({ collectionEntity }) => { return { ...collectionEntity, nfts: collectionEntity.nfts.nodes } },
result: () => this.fetchMetadata()
result: () => this.fetchMetadata(),
})
this.isLoading = false
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/rmrk/Gallery/Search/SearchBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export default class SearchBar extends Vue {
replaceUrl(value: string, key = 'search'): void {
this.$router
.replace({
name: 'nft',
name: String(this.$route.name),
query: { ...this.$route.query, search: this.searchQuery, [key]: value }
})
.catch(console.warn /*Navigation Duplicate err fix later */)
Expand Down
158 changes: 158 additions & 0 deletions src/components/rmrk/Gallery/Search/SearchBarCollection.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
<template>
<div class="box mb-3 mt-5">
<b-field grouped>
<b-field>
<b-button
aria-controls="contentIdForA11y1"
label="Filter"
icon-left="filter"
type="is-primary"
expanded
@click="isVisible = !isVisible"
/>
</b-field>
<b-field expanded>
<b-input
placeholder="Search..."
type="search"
v-model="searchQuery"
icon="search"
expanded
>
</b-input>
</b-field>
<BasicSwitch
class="is-flex"
v-model="vListed"
label="sort.listed"
size="is-medium"
/>
</b-field>
<slot />

<transition name="fade">
<div v-if="isVisible">
<Sort
:value="sortBy"
@input="updateSortBy"
/>
</div>
</transition>
</div>
</template>

<script lang="ts" >
import { Component, Prop, Vue, Emit } from 'vue-property-decorator'
import { Debounce } from 'vue-debounce-decorator'
import shouldUpdate from '@/utils/shouldUpdate'
import { exist } from './exist'

@Component({
components: {
Sort: () => import('./SearchSortDropdown.vue'),
TypeTagInput: () => import('./TypeTagInput.vue'),
Pagination: () => import('@/components/rmrk/Gallery/Pagination.vue'),
BasicSwitch: () => import('@/components/shared/form/BasicSwitch.vue'),
},
})
export default class SearchBar extends Vue {
@Prop(String) public search!: string
@Prop(String) public type!: string
@Prop(String) public sortBy!: string
@Prop(Boolean) public listed!: boolean

protected isVisible = false

public mounted(): void {
exist(this.$route.query.search, this.updateSearch)
exist(this.$route.query.type, this.updateType)
exist(this.$route.query.sort, this.updateSortBy)
exist(this.$route.query.listed, this.updateListed)
}

get vListed(): boolean {
return this.listed
}

set vListed(listed: boolean) {
this.updateListed(listed)
}

get searchQuery(): string {
return this.search
}

set searchQuery(value: string) {
this.updateSearch(value)
}

get typeQuery(): string {
return this.type
}

set typeQuery(value: string) {
this.updateType(value)
}

@Emit('update:listed')
@Debounce(50)
updateListed(value: string | boolean): boolean {
const v = String(value)
this.replaceUrl(v, 'listed')
return v === 'true'
}

@Emit('update:type')
@Debounce(50)
updateType(value: string): string {
this.replaceUrl(value, 'type')
return value
}

@Emit('update:sortBy')
@Debounce(400)
updateSortBy(value: string): string {
this.replaceUrl(value, 'sort')
return value
}

@Emit('update:search')
@Debounce(400)
updateSearch(value: string): string {
shouldUpdate(value, this.searchQuery) && this.replaceUrl(value)
return value
}

@Debounce(100)
replaceUrl(value: string, key = 'search'): void {
this.$router
.replace({
name: String(this.$route.name),
query: {
...this.$route.query,
search: this.searchQuery,
[key]: value,
},
})
.catch(console.warn /*Navigation Duplicate err fix later */)
}
}
</script>

<style scoped lang="scss">
@import '@/styles/variables';

.card {
box-shadow: 0px 0px 5px 0.5px $primary;
}

.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;
}

.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>
17 changes: 10 additions & 7 deletions src/components/rmrk/Gallery/Search/query.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Row } from '@/components/spotlight/types'
import { RowSeries } from '@/components/series/types'
import { RowSeries, SortType } from '@/components/series/types'
import { Query, Aggregator } from 'mingo'
import { Collection as Aggregation } from 'mingo/core'
import { NFTWithMeta } from '../../service/scheme'
Expand Down Expand Up @@ -80,7 +80,7 @@ export const spotlightAggregation = (): Aggregator => {
return new Aggregator(agg)
}

export const seriesAggregation = (limit = 10): Aggregator => {
export const seriesAggregation = (limit = 10, sort: SortType): Aggregator => {
const agg: Aggregation = [
{
$group: {
Expand All @@ -94,17 +94,20 @@ export const seriesAggregation = (limit = 10): Aggregator => {
averagePrice: { $avg: '$averagePrice' },
floorPrice: { $sum: '$floorPrice' },
count: { $sum: '$count' },
// owned: { $sum: '$currentOwner' },
rank: { $sum: '$rank' },
volume: { $sum: '$volume' },
dailyVolume: { $sum: '$dailyVolume' },
weeklyVolume: { $sum: '$weeklyVolume' },
monthlyVolume: { $sum: '$monthlyVolume' },
dailyrangeVolume: { $sum: '$dailyrangeVolume' },
weeklyrangeVolume: { $sum: '$weeklyrangeVolume' },
monthlyrangeVolume: { $sum: '$monthlyrangeVolume' },
name: { $first: '$name' },
metadata: { $first: '$metadata' },
metadata: { $first: '$metadata' }
}
},
{
$sort: { rank: -1 },
$sort: { [sort['field']]: sort['value'] }
},
{
$limit: limit
Expand Down Expand Up @@ -147,8 +150,8 @@ export const spotlightAggQuery = (nfts: Row[]) => {
return query.run(nfts)
}

export const seriesAggQuery = (limit: number, nfts: RowSeries[]) => {
const query = seriesAggregation(limit)
export const seriesAggQuery = (limit: number, sort: SortType, nfts: RowSeries[]) => {
const query = seriesAggregation(limit, sort)
return query.run(nfts)
}

Expand Down
Loading