@visualizevalue/mint-app-base 0.1.43 → 0.1.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/styles/variables/colors.css +1 -1
- package/components/ImageVoid.vue +5 -0
- package/components/Token/Detail.client.vue +2 -1
- package/components/Token/MintTimeline.client.vue +45 -32
- package/components/Token/MintTimelineItem.vue +5 -3
- package/components/Token/MintTimelineVirtualScroller.client.vue +44 -0
- package/components/Token/OverviewCard.vue +2 -1
- package/composables/collections.ts +3 -3
- package/package.json +3 -3
- package/utils/time.ts +6 -8
|
@@ -3,34 +3,35 @@
|
|
|
3
3
|
<slot :mints="mints" :loading="loading">
|
|
4
4
|
<h1>Mint Timeline</h1>
|
|
5
5
|
|
|
6
|
-
<
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
</
|
|
25
|
-
</
|
|
26
|
-
</
|
|
27
|
-
</
|
|
6
|
+
<template v-if="currentBlock">
|
|
7
|
+
<TokenMintTimelineVirtualScroller
|
|
8
|
+
:mints="mints"
|
|
9
|
+
:block="currentBlock"
|
|
10
|
+
>
|
|
11
|
+
<template #after>
|
|
12
|
+
<TokenMintTimelineItem v-if="backfillComplete">
|
|
13
|
+
<Account :address="collection.owner" class="account" />
|
|
14
|
+
|
|
15
|
+
<span class="amount">1<span>×</span></span>
|
|
16
|
+
<span class="price">Artist Mint</span>
|
|
17
|
+
|
|
18
|
+
<span class="time-ago"><BlocksTimeAgo v-if="currentBlock" :blocks="currentBlock - mintedAtBlock" /></span>
|
|
19
|
+
|
|
20
|
+
<span class="links">
|
|
21
|
+
<NuxtLink :to="`${config.public.blockExplorer}/nft/${token.collection}/${token.tokenId}`" target="_blank">
|
|
22
|
+
<Icon type="link" />
|
|
23
|
+
</NuxtLink>
|
|
24
|
+
</span>
|
|
25
|
+
</TokenMintTimelineItem>
|
|
26
|
+
</template>
|
|
27
|
+
</TokenMintTimelineVirtualScroller>
|
|
28
|
+
</template>
|
|
28
29
|
|
|
29
30
|
<div v-if="! backfillComplete" v-show="! loading" ref="loadMore" class="load-more">
|
|
30
31
|
<Button @click="backfill">Load more</Button>
|
|
31
32
|
</div>
|
|
32
33
|
|
|
33
|
-
<Loading v-if="loading || ! currentBlock" txt="Mint History..." />
|
|
34
|
+
<Loading v-if="loading || ! currentBlock" txt="Loading Mint History..." />
|
|
34
35
|
</slot>
|
|
35
36
|
</section>
|
|
36
37
|
</template>
|
|
@@ -72,16 +73,27 @@ watch(currentBlock, () => {
|
|
|
72
73
|
state.fetchTokenMints(token)
|
|
73
74
|
})
|
|
74
75
|
|
|
76
|
+
const loadMore = ref()
|
|
77
|
+
const loadMoreVisible = useElementVisibility(loadMore)
|
|
75
78
|
const backfill = async () => {
|
|
76
79
|
loading.value = true
|
|
77
|
-
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
await state.backfillTokenMints(token)
|
|
83
|
+
|
|
84
|
+
if (loadMoreVisible.value) {
|
|
85
|
+
await delay(300)
|
|
86
|
+
await backfill()
|
|
87
|
+
}
|
|
88
|
+
} catch (e) {
|
|
89
|
+
console.error(`Issue during backfill`, e)
|
|
90
|
+
}
|
|
91
|
+
|
|
78
92
|
loading.value = false
|
|
79
93
|
}
|
|
80
|
-
|
|
81
|
-
const loadMore = ref()
|
|
82
|
-
const loadMoreVisible = useElementVisibility(loadMore)
|
|
83
94
|
watch(loadMoreVisible, () => {
|
|
84
|
-
if
|
|
95
|
+
// Skip if we have enough mints for the viewport or we're already loading
|
|
96
|
+
if (! loadMoreVisible.value || loading.value) return
|
|
85
97
|
|
|
86
98
|
backfill()
|
|
87
99
|
})
|
|
@@ -92,6 +104,11 @@ watch(loadMoreVisible, () => {
|
|
|
92
104
|
padding-top: var(--spacer-lg);
|
|
93
105
|
padding-bottom: var(--spacer-lg);
|
|
94
106
|
container-type: inline-size;
|
|
107
|
+
|
|
108
|
+
:deep(.token-mint-timeline-items) {
|
|
109
|
+
display: grid;
|
|
110
|
+
gap: var(--spacer);
|
|
111
|
+
}
|
|
95
112
|
}
|
|
96
113
|
|
|
97
114
|
h1 {
|
|
@@ -102,10 +119,6 @@ h1 {
|
|
|
102
119
|
margin: 0 0 var(--spacer);
|
|
103
120
|
}
|
|
104
121
|
|
|
105
|
-
.token-mint-timeline-items {
|
|
106
|
-
display: grid;
|
|
107
|
-
gap: var(--spacer);
|
|
108
|
-
}
|
|
109
122
|
|
|
110
123
|
.load-more {
|
|
111
124
|
.button {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="token-mint-timeline-item">
|
|
3
3
|
<slot :mint="mint" :formatted-price="formattedPrice">
|
|
4
|
-
<NuxtLink :to="{ name: 'profile-address', params: { address: mint.address } }">
|
|
5
|
-
<Account :address="mint.address"
|
|
4
|
+
<NuxtLink :to="{ name: 'profile-address', params: { address: mint.address } }" class="account">
|
|
5
|
+
<Account :address="mint.address" />
|
|
6
6
|
</NuxtLink>
|
|
7
7
|
|
|
8
8
|
<span class="amount">{{ mint.amount.toString() }}<span>×</span></span>
|
|
@@ -49,7 +49,7 @@ const formattedPrice = computed(() => props.mint && customFormatEther(props.mint
|
|
|
49
49
|
span {
|
|
50
50
|
white-space: nowrap;
|
|
51
51
|
|
|
52
|
-
&:not(.account) {
|
|
52
|
+
&:not(.account):not(.account *) {
|
|
53
53
|
color: var(--muted);
|
|
54
54
|
font-size: var(--font-sm);
|
|
55
55
|
}
|
|
@@ -57,6 +57,8 @@ const formattedPrice = computed(() => props.mint && customFormatEther(props.mint
|
|
|
57
57
|
|
|
58
58
|
a,
|
|
59
59
|
button {
|
|
60
|
+
color: var(--color);
|
|
61
|
+
|
|
60
62
|
&:--highlight {
|
|
61
63
|
color: var(--color);
|
|
62
64
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div ref="wrapper">
|
|
3
|
+
<RecycleScroller
|
|
4
|
+
:items="mints"
|
|
5
|
+
:item-size="itemSize"
|
|
6
|
+
key-field="tx"
|
|
7
|
+
list-class="token-mint-timeline-items"
|
|
8
|
+
page-mode
|
|
9
|
+
>
|
|
10
|
+
<template #before>
|
|
11
|
+
<slot name="before" />
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<template #default="{ item: mint }">
|
|
15
|
+
<TokenMintTimelineItem
|
|
16
|
+
:mint="mint"
|
|
17
|
+
:key="mint.tx"
|
|
18
|
+
:block="block"
|
|
19
|
+
/>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<template #after>
|
|
23
|
+
<slot name="after" />
|
|
24
|
+
</template>
|
|
25
|
+
</RecycleScroller>
|
|
26
|
+
</div>
|
|
27
|
+
</template>
|
|
28
|
+
|
|
29
|
+
<script setup>
|
|
30
|
+
import { useElementSize } from '@vueuse/core'
|
|
31
|
+
import { RecycleScroller } from 'vue-virtual-scroller'
|
|
32
|
+
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
|
|
33
|
+
|
|
34
|
+
defineProps({
|
|
35
|
+
mints: Array,
|
|
36
|
+
block: BigInt,
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
const wrapper = ref()
|
|
40
|
+
const REM = 16
|
|
41
|
+
const { width: wrapperWidth } = useElementSize(wrapper)
|
|
42
|
+
const itemSize = computed(() => 24 * REM > wrapperWidth.value ? 60 : 40)
|
|
43
|
+
</script>
|
|
44
|
+
|
|
@@ -32,7 +32,8 @@
|
|
|
32
32
|
<p v-if="mintOpen" class="closes-in">Closes in {{ blocksRemaining }} {{ pluralize('block', Number(blocksRemaining))}}</p>
|
|
33
33
|
<p v-else class="closed-at">Closed at block {{ token.untilBlock }}</p>
|
|
34
34
|
</header>
|
|
35
|
-
<Image :src="token.artifact" :alt="token.name" />
|
|
35
|
+
<Image v-if="token.artifact" :src="token.artifact" :alt="token.name" />
|
|
36
|
+
<ImageVoid v-else />
|
|
36
37
|
<CardLink :to="{
|
|
37
38
|
name: 'id-collection-tokenId',
|
|
38
39
|
params: { id: collection.owner, collection: token.collection, tokenId: `${token.tokenId}` }
|
|
@@ -4,7 +4,7 @@ import { parseAbiItem, type PublicClient } from 'viem'
|
|
|
4
4
|
import type { MintEvent } from '~/utils/types'
|
|
5
5
|
|
|
6
6
|
export const CURRENT_STATE_VERSION = 4
|
|
7
|
-
export const MAX_BLOCK_RANGE =
|
|
7
|
+
export const MAX_BLOCK_RANGE = 1000n
|
|
8
8
|
export const MINT_BLOCKS = BLOCKS_PER_DAY
|
|
9
9
|
|
|
10
10
|
export const useOnchainStore = () => {
|
|
@@ -320,7 +320,7 @@ export const useOnchainStore = () => {
|
|
|
320
320
|
},
|
|
321
321
|
|
|
322
322
|
async fetchTokenMints (token: Token) {
|
|
323
|
-
const client = getPublicClient($wagmi) as PublicClient
|
|
323
|
+
const client = getPublicClient($wagmi, { chainId }) as PublicClient
|
|
324
324
|
const currentBlock = await client.getBlockNumber()
|
|
325
325
|
const mintedAtBlock = token.untilBlock - MINT_BLOCKS
|
|
326
326
|
const storedToken = this.collections[token.collection].tokens[token.tokenId.toString()]
|
|
@@ -365,7 +365,7 @@ export const useOnchainStore = () => {
|
|
|
365
365
|
|
|
366
366
|
// We want to fetch until our max range (5000), or until when the token minted
|
|
367
367
|
const fromBlock = toBlock - MAX_BLOCK_RANGE > mintedAtBlock ? toBlock - MAX_BLOCK_RANGE : mintedAtBlock
|
|
368
|
-
console.
|
|
368
|
+
console.info(`Backfilling token mints blocks ${fromBlock}-${toBlock}`)
|
|
369
369
|
|
|
370
370
|
// Finally, we update our database
|
|
371
371
|
this.addTokenMints(token, await this.loadMintEvents(token, fromBlock, toBlock), 'append')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@visualizevalue/mint-app-base",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.45",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./nuxt.config.ts",
|
|
6
6
|
"dependencies": {
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
"postcss-preset-env": "^9.5.13",
|
|
22
22
|
"viem": "2.x",
|
|
23
23
|
"vite": "^5.4.3",
|
|
24
|
-
"vue-virtual-scroller": "
|
|
25
|
-
"@visualizevalue/mint-utils": "^0.0.
|
|
24
|
+
"vue-virtual-scroller": "2.0.0-beta.8",
|
|
25
|
+
"@visualizevalue/mint-utils": "^0.0.3"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"nuxt": "^3.13.2",
|
package/utils/time.ts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export const BLOCKS_PER_DAY = 7200n // 300n * 24n (300 blocks per hour * 24 hours)
|
|
1
|
+
import { BLOCKS_PER_CACHE, BLOCKS_PER_HOUR, BLOCKS_PER_DAY } from '@visualizevalue/mint-utils/time'
|
|
2
|
+
import { blocksToSeconds, delay, nowInSeconds } from '@visualizevalue/mint-utils'
|
|
4
3
|
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export const nowInSeconds = (): number => Math.floor(Date.now() / 1000)
|
|
4
|
+
export {
|
|
5
|
+
BLOCKS_PER_CACHE, BLOCKS_PER_HOUR, BLOCKS_PER_DAY,
|
|
6
|
+
blocksToSeconds, delay, nowInSeconds,
|
|
7
|
+
}
|
|
10
8
|
|
|
11
9
|
const now = ref(nowInSeconds())
|
|
12
10
|
let nowInterval: NodeJS.Timeout
|