Skip to content
This repository was archived by the owner on Dec 5, 2025. It is now read-only.

Commit 5bfab51

Browse files
authored
Merge pull request #1291 from rhaicode/issue-1121
1121: median line, trailing average and h-spread
2 parents e5ea300 + 9160039 commit 5bfab51

File tree

5 files changed

+269
-93
lines changed

5 files changed

+269
-93
lines changed

components/rmrk/Gallery/CollectionItem.vue

Lines changed: 150 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,30 @@
2929
<ProfileLink :address="issuer" inline showTwitter />
3030
</div>
3131
</div>
32-
<b-skeleton :active="isLoading" width="40%" size="is-small"></b-skeleton>
33-
<b-skeleton :active="isLoading" width="60%" size="is-small"></b-skeleton>
32+
<b-skeleton
33+
:active="isLoading"
34+
width="40%"
35+
size="is-small"
36+
></b-skeleton>
37+
<b-skeleton
38+
:active="isLoading"
39+
width="60%"
40+
size="is-small"
41+
></b-skeleton>
3442
</div>
3543

3644
<div class="column is-6-tablet is-7-desktop is-8-widescreen">
3745
<CollectionActivity :nfts="stats" />
3846
</div>
3947

4048
<div class="column has-text-right">
41-
<Sharing v-if="sharingVisible"
49+
<Sharing
50+
v-if="sharingVisible"
4251
class="mb-2"
4352
:label="name"
44-
:iframe="iframeSettings">
45-
<DonationButton :address="issuer" />
53+
:iframe="iframeSettings"
54+
>
55+
<DonationButton :address="issuer" />
4656
</Sharing>
4757
</div>
4858
</div>
@@ -63,7 +73,15 @@
6373
<Search v-bind.sync="searchQuery">
6474
<Layout class="mr-5" />
6575
<b-field>
66-
<Pagination hasMagicBtn simple replace preserveScroll :total="total" v-model="currentValue" :per-page="first" />
76+
<Pagination
77+
hasMagicBtn
78+
simple
79+
replace
80+
preserveScroll
81+
:total="total"
82+
v-model="currentValue"
83+
:per-page="first"
84+
/>
6785
</b-field>
6886
</Search>
6987

@@ -85,61 +103,95 @@
85103
</section>
86104
</template>
87105

88-
<script lang="ts" >
89-
import { emptyObject } from '@/utils/empty'
90-
import { Component, mixins, Watch } from 'nuxt-property-decorator'
91-
import { CollectionWithMeta, Interaction } from '../service/scheme'
106+
<script lang="ts">
107+
import { emptyObject } from '@/utils/empty';
108+
import { Component, mixins, Watch } from 'nuxt-property-decorator';
109+
import { CollectionWithMeta, Interaction } from '../service/scheme';
92110
import {
93-
sanitizeIpfsUrl, fetchCollectionMetadata, sortByTimeStamp, onlyEvents, onlyPriceEvents,
94-
eventTimestamp, soldNFTPrice, collectionFloorPriceList, PriceDataType, onlyBuyEvents
95-
} from '../utils'
96-
import isShareMode from '@/utils/isShareMode'
97-
import shouldUpdate from '@/utils/shouldUpdate'
98-
import collectionById from '@/queries/collectionById.graphql'
99-
import nftListByCollection from '@/queries/nftListByCollection.graphql'
100-
import { CollectionMetadata } from '../types'
101-
import { NFT } from '@/components/rmrk/service/scheme'
102-
import { exist } from '@/components/rmrk/Gallery/Search/exist'
103-
import { SearchQuery } from './Search/types'
104-
import ChainMixin from '@/utils/mixins/chainMixin'
111+
sanitizeIpfsUrl,
112+
fetchCollectionMetadata,
113+
sortByTimeStamp,
114+
onlyEvents,
115+
onlyPriceEvents,
116+
eventTimestamp,
117+
soldNFTPrice,
118+
collectionFloorPriceList,
119+
PriceDataType,
120+
onlyBuyEvents,
121+
} from '../utils';
122+
import isShareMode from '@/utils/isShareMode';
123+
import shouldUpdate from '@/utils/shouldUpdate';
124+
import collectionById from '@/queries/collectionById.graphql';
125+
import nftListByCollection from '@/queries/nftListByCollection.graphql';
126+
import { CollectionMetadata } from '../types';
127+
import { NFT } from '@/components/rmrk/service/scheme';
128+
import { exist } from '@/components/rmrk/Gallery/Search/exist';
129+
import { SearchQuery } from './Search/types';
130+
import ChainMixin from '@/utils/mixins/chainMixin';
105131
106132
const components = {
107-
GalleryCardList: () => import('@/components/rmrk/Gallery/GalleryCardList.vue'),
108-
CollectionActivity: () => import('@/components/rmrk/Gallery/CollectionActivity.vue'),
133+
GalleryCardList: () =>
134+
import('@/components/rmrk/Gallery/GalleryCardList.vue'),
135+
CollectionActivity: () =>
136+
import('@/components/rmrk/Gallery/CollectionActivity.vue'),
109137
Sharing: () => import('@/components/rmrk/Gallery/Item/Sharing.vue'),
110138
ProfileLink: () => import('@/components/rmrk/Profile/ProfileLink.vue'),
111139
VueMarkdown: () => import('vue-markdown-render'),
112140
Search: () => import('./Search/SearchBarCollection.vue'),
113141
Pagination: () => import('@/components/rmrk/Gallery/Pagination.vue'),
114142
DonationButton: () => import('@/components/transfer/DonationButton.vue'),
115143
Layout: () => import('@/components/rmrk/Gallery/Layout.vue'),
116-
CollectionPriceChart: () => import('@/components/rmrk/Gallery/CollectionPriceChart.vue'),
144+
CollectionPriceChart: () =>
145+
import('@/components/rmrk/Gallery/CollectionPriceChart.vue'),
117146
BasicImage: () => import('@/components/shared/view/BasicImage.vue'),
118-
CollapseWrapper: () => import('@/components/shared/collapse/CollapseWrapper.vue'),
119-
}
147+
CollapseWrapper: () =>
148+
import('@/components/shared/collapse/CollapseWrapper.vue'),
149+
};
120150
@Component<CollectionItem>({
121151
metaInfo() {
122-
const image = `https://og-image-green-seven.vercel.app/${encodeURIComponent(this.collection.name as string)}.png?price=Items: ${this.collection?.nfts?.length}&image=${(this.meta.image as string)}`
152+
const image = `https://og-image-green-seven.vercel.app/${encodeURIComponent(
153+
this.collection.name as string
154+
)}.png?price=Items: ${this.collection?.nfts?.length}&image=${
155+
this.meta.image as string
156+
}`;
123157
return {
124158
title: 'KodaDot cares about environmental impact',
125159
titleTemplate: '%s | Low Carbon NFTs',
126160
meta: [
127161
{ name: 'description', content: 'Creating Carbonless NFTs on Kusama' },
128-
{ property: 'og:title', content: this.collection.name || 'KodaDot cares about environmental impact'},
129-
{ property: 'og:url', content: 'https://nft.kodadot.xyz/' + this.$route.path },
130-
{ property: 'og:image', content: image},
131-
{ property: 'og:description', content: this.meta.description || 'Creating Carbonless NFTs on Kusama'},
162+
{
163+
property: 'og:title',
164+
content:
165+
this.collection.name || 'KodaDot cares about environmental impact',
166+
},
167+
{
168+
property: 'og:url',
169+
content: 'https://nft.kodadot.xyz/' + this.$route.path,
170+
},
171+
{ property: 'og:image', content: image },
172+
{
173+
property: 'og:description',
174+
content:
175+
this.meta.description || 'Creating Carbonless NFTs on Kusama',
176+
},
132177
{ property: 'twitter:card', content: 'summary_large_image' },
133-
{ property: 'twitter:title', content: this.collection.name || 'KodaDOT cares about environmental impact'},
134-
{ property: 'twitter:description', content: this.meta.description || 'Creating Carbonless NFTs on Kusama'},
135-
{ property: 'twitter:image', content: image},
136-
]
137-
}
178+
{
179+
property: 'twitter:title',
180+
content:
181+
this.collection.name || 'KodaDOT cares about environmental impact',
182+
},
183+
{
184+
property: 'twitter:description',
185+
content:
186+
this.meta.description || 'Creating Carbonless NFTs on Kusama',
187+
},
188+
{ property: 'twitter:image', content: image },
189+
],
190+
};
138191
},
139-
components })
140-
export default class CollectionItem extends mixins(
141-
ChainMixin
142-
) {
192+
components,
193+
})
194+
export default class CollectionItem extends mixins(ChainMixin) {
143195
private id = '';
144196
private collection: CollectionWithMeta = emptyObject<CollectionWithMeta>();
145197
public meta: CollectionMetadata = emptyObject<CollectionMetadata>();
@@ -157,59 +209,59 @@ export default class CollectionItem extends mixins(
157209
protected priceData: any = [];
158210
159211
get isLoading(): boolean {
160-
return this.$apollo.queries.collection.loading
212+
return this.$apollo.queries.collection.loading;
161213
}
162214
163215
get offset(): number {
164-
return this.currentValue * this.first - this.first
216+
return this.currentValue * this.first - this.first;
165217
}
166218
167-
get image(): string|undefined {
168-
return this.meta.image
219+
get image(): string | undefined {
220+
return this.meta.image;
169221
}
170222
171223
get description(): string {
172-
return this.meta.description || ''
224+
return this.meta.description || '';
173225
}
174226
175227
get name(): string {
176-
return this.collection.name || this.id
228+
return this.collection.name || this.id;
177229
}
178230
179231
get nfts(): NFT[] {
180-
return this.collection.nfts || []
232+
return this.collection.nfts || [];
181233
}
182234
183235
get issuer(): string {
184-
return this.collection.issuer || ''
236+
return this.collection.issuer || '';
185237
}
186238
187239
get sharingVisible(): boolean {
188-
return !isShareMode
240+
return !isShareMode;
189241
}
190242
191243
private buildSearchParam(): Record<string, unknown>[] {
192-
const params: any[] = []
244+
const params: any[] = [];
193245
194246
if (this.searchQuery.search) {
195247
params.push({
196-
name: { likeInsensitive: `%${this.searchQuery.search}%` }
197-
})
248+
name: { likeInsensitive: `%${this.searchQuery.search}%` },
249+
});
198250
}
199251
200252
if (this.searchQuery.listed) {
201253
params.push({
202-
price: { greaterThan: '0' }
203-
})
254+
price: { greaterThan: '0' },
255+
});
204256
}
205257
206-
return params
258+
return params;
207259
}
208260
209261
public created(): void {
210-
this.checkId()
211-
this.checkActiveTab()
212-
this.loadStats()
262+
this.checkId();
263+
this.checkActiveTab();
264+
this.loadStats();
213265
this.$apollo.addSmartQuery('collection', {
214266
query: collectionById,
215267
loadingKey: 'isLoading',
@@ -219,73 +271,81 @@ export default class CollectionItem extends mixins(
219271
orderBy: this.searchQuery.sortBy,
220272
search: this.buildSearchParam(),
221273
first: this.first,
222-
offset: this.offset
223-
}
274+
offset: this.offset,
275+
};
224276
},
225277
update: ({ collectionEntity }) => ({
226278
...collectionEntity,
227-
nfts: collectionEntity.nfts.nodes
279+
nfts: collectionEntity.nfts.nodes,
228280
}),
229281
result: this.handleResult,
230-
})
231-
282+
});
232283
}
233284
234285
public loadStats(): void {
235286
const nftStatsP = this.$apollo.query({
236287
query: nftListByCollection,
237288
variables: {
238289
id: this.id,
239-
}
240-
})
241-
242-
nftStatsP.then(({ data }) => data?.nFTEntities?.nodes || []).then(nfts => {
243-
this.stats = nfts
244-
this.loadPriceData()
245-
})
290+
},
291+
});
292+
293+
nftStatsP
294+
.then(({ data }) => data?.nFTEntities?.nodes || [])
295+
.then((nfts) => {
296+
this.stats = nfts;
297+
this.loadPriceData();
298+
});
246299
}
247300
248301
public loadPriceData(): void {
249-
this.priceData = []
302+
this.priceData = [];
250303
251-
const events: Interaction[][] = this.stats?.map(onlyEvents) || []
252-
const priceEvents: Interaction[][] = events.map(this.priceEvents) || []
304+
const events: Interaction[][] = this.stats?.map(onlyEvents) || [];
305+
const priceEvents: Interaction[][] = events.map(this.priceEvents) || [];
253306
254-
const overTime: string[] = priceEvents.flat().sort(sortByTimeStamp).map(eventTimestamp)
307+
const overTime: string[] = priceEvents
308+
.flat()
309+
.sort(sortByTimeStamp)
310+
.map(eventTimestamp);
255311
256-
const floorPriceData: PriceDataType[] = overTime.map(collectionFloorPriceList(priceEvents, this.decimals))
312+
const floorPriceData: PriceDataType[] = overTime.map(
313+
collectionFloorPriceList(priceEvents, this.decimals)
314+
);
257315
258-
const buyEvents = events.map(onlyBuyEvents)?.flat().sort(sortByTimeStamp)
259-
const soldPriceData: PriceDataType[] = buyEvents?.map(soldNFTPrice(this.decimals))
316+
const buyEvents = events.map(onlyBuyEvents)?.flat().sort(sortByTimeStamp);
317+
const soldPriceData: PriceDataType[] = buyEvents?.map(
318+
soldNFTPrice(this.decimals)
319+
);
260320
261-
this.priceData = [floorPriceData, soldPriceData]
321+
this.priceData = [floorPriceData, soldPriceData];
262322
}
263323
264-
public async handleResult({data}: any): Promise<void> {
265-
this.total = data.collectionEntity.nfts.totalCount
266-
await this.fetchMetadata()
324+
public async handleResult({ data }: any): Promise<void> {
325+
this.total = data.collectionEntity.nfts.totalCount;
326+
await this.fetchMetadata();
267327
}
268328
269329
public async fetchMetadata(): Promise<void> {
270330
if (this.collection['metadata'] && !this.meta['image']) {
271-
const meta = await fetchCollectionMetadata(this.collection)
331+
const meta = await fetchCollectionMetadata(this.collection);
272332
this.meta = {
273333
...meta,
274334
image: sanitizeIpfsUrl(meta.image || ''),
275-
}
335+
};
276336
}
277337
}
278338
279339
public checkId(): void {
280340
if (this.$route.params.id) {
281-
this.id = this.$route.params.id
341+
this.id = this.$route.params.id;
282342
}
283343
}
284344
285345
public checkActiveTab(): void {
286346
exist(this.$route.query.tab, (val) => {
287-
this.activeTab = val
288-
})
347+
this.activeTab = val;
348+
});
289349
}
290350
291351
@Watch('activeTab')
@@ -294,16 +354,16 @@ export default class CollectionItem extends mixins(
294354
this.$router.replace({
295355
path: String(this.$route.path),
296356
query: { tab: val },
297-
})
357+
});
298358
}
299359
}
300360
301361
get iframeSettings(): Record<string, unknown> {
302-
return { width: '100%', height: '100vh' }
362+
return { width: '100%', height: '100vh' };
303363
}
304364
305365
protected priceEvents(nftEvents: Interaction[]): Interaction[] {
306-
return nftEvents.filter(onlyPriceEvents)
366+
return nftEvents.filter(onlyPriceEvents);
307367
}
308368
}
309369
</script>

0 commit comments

Comments
 (0)