@visualizevalue/mint-app-base 0.1.92 → 0.1.94
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/.env.example +2 -0
- package/app.config.ts +15 -13
- package/assets/styles/variables/colors.css +1 -0
- package/components/Embed.vue +3 -2
- package/components/Image.client.vue +2 -1
- package/components/Mint/Renderer/Animation.client.vue +5 -14
- package/components/Mint/Renderer/Base.client.vue +3 -7
- package/components/Mint/SelectRenderer.client.vue +4 -1
- package/components/Renderer/Overview.client.vue +2 -1
- package/components/Renderer/OverviewCard.vue +9 -1
- package/composables/collections.ts +6 -3
- package/nuxt.config.ts +2 -0
- package/package.json +1 -1
- package/utils/arweave.ts +12 -0
- package/utils/ipfs.ts +14 -0
- package/utils/urls.ts +15 -4
- package/utils/images.ts +0 -27
package/.env.example
CHANGED
|
@@ -17,6 +17,8 @@ NUXT_PUBLIC_CREATOR_ADDRESS=0xc8f8e2f59dd95ff67c3d39109eca2e2a017d4c8a
|
|
|
17
17
|
# SERVICES
|
|
18
18
|
# =========================
|
|
19
19
|
NUXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=
|
|
20
|
+
NUXT_PUBLIC_IPFS_GATEWAY=
|
|
21
|
+
NUXT_PUBLIC_ARWEAVE_GATEWAY=
|
|
20
22
|
|
|
21
23
|
# =========================
|
|
22
24
|
# MAINNET
|
package/app.config.ts
CHANGED
|
@@ -2,13 +2,6 @@ export default defineAppConfig({
|
|
|
2
2
|
knownRenderers: {
|
|
3
3
|
// Mainnet
|
|
4
4
|
1: [
|
|
5
|
-
{
|
|
6
|
-
component: 'P5',
|
|
7
|
-
name: 'P5 Renderer [Deprecated]',
|
|
8
|
-
version: 1n,
|
|
9
|
-
address: '0x32b8ffa14e7f77c252b6d43bec5498fcef2b205f',
|
|
10
|
-
description: 'Allows using P5 scripts as the artifact content. Deprecated: Please use V2'
|
|
11
|
-
},
|
|
12
5
|
{
|
|
13
6
|
component: 'P5',
|
|
14
7
|
name: 'P5 Renderer',
|
|
@@ -23,16 +16,17 @@ export default defineAppConfig({
|
|
|
23
16
|
address: '0xcb681409046e45e6187ec2205498e4adbe19749c',
|
|
24
17
|
description: 'Allows linking to both an image and an animation url'
|
|
25
18
|
},
|
|
26
|
-
],
|
|
27
|
-
// Sepolia
|
|
28
|
-
11155111: [
|
|
29
19
|
{
|
|
30
20
|
component: 'P5',
|
|
31
|
-
name: 'P5 Renderer
|
|
21
|
+
name: 'P5 Renderer',
|
|
32
22
|
version: 1n,
|
|
33
|
-
address: '
|
|
34
|
-
description: 'Allows using P5 scripts as the artifact content.
|
|
23
|
+
address: '0x32b8ffa14e7f77c252b6d43bec5498fcef2b205f',
|
|
24
|
+
description: 'Allows using P5 scripts as the artifact content.',
|
|
25
|
+
deprecated: true,
|
|
35
26
|
},
|
|
27
|
+
],
|
|
28
|
+
// Sepolia
|
|
29
|
+
11155111: [
|
|
36
30
|
{
|
|
37
31
|
component: 'P5',
|
|
38
32
|
name: 'P5 Renderer (Sepolia)',
|
|
@@ -47,6 +41,14 @@ export default defineAppConfig({
|
|
|
47
41
|
address: '0xeeaf428251c477002d52c69e022b357a91f36517',
|
|
48
42
|
description: 'Allows linking to both an image and an animation url'
|
|
49
43
|
},
|
|
44
|
+
{
|
|
45
|
+
component: 'P5',
|
|
46
|
+
name: 'P5 Renderer (Sepolia)',
|
|
47
|
+
version: 1n,
|
|
48
|
+
address: '0xfadf2fb2f8a15fc830c176b71d2c905e95f4169e',
|
|
49
|
+
description: 'Allows using P5 scripts as the artifact content.',
|
|
50
|
+
deprecated: true,
|
|
51
|
+
},
|
|
50
52
|
],
|
|
51
53
|
}
|
|
52
54
|
})
|
package/components/Embed.vue
CHANGED
|
@@ -42,12 +42,13 @@ async function fetchMediaType(url: string): Promise<string | null> {
|
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
const config = useRuntimeConfig()
|
|
45
46
|
const props = defineProps({
|
|
46
47
|
src: String,
|
|
47
48
|
})
|
|
48
49
|
|
|
49
50
|
// Update on input change
|
|
50
|
-
const src = ref(
|
|
51
|
+
const src = ref()
|
|
51
52
|
const mediaType = ref()
|
|
52
53
|
const isPlayable = computed(() => {
|
|
53
54
|
if (! mediaType.value) return false
|
|
@@ -55,7 +56,7 @@ const isPlayable = computed(() => {
|
|
|
55
56
|
})
|
|
56
57
|
|
|
57
58
|
watchEffect(async () => {
|
|
58
|
-
src.value = props.src
|
|
59
|
+
src.value = validateURI(props.src, config.public)
|
|
59
60
|
mediaType.value = await fetchMediaType(src.value)
|
|
60
61
|
})
|
|
61
62
|
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
<script setup>
|
|
21
21
|
import { vIntersectionObserver } from '@vueuse/components'
|
|
22
22
|
|
|
23
|
+
const config = useRuntimeConfig()
|
|
23
24
|
const props = defineProps({
|
|
24
25
|
src: String,
|
|
25
26
|
alt: String,
|
|
@@ -46,7 +47,7 @@ const loadImage = ([{ isIntersecting }]) => {
|
|
|
46
47
|
|
|
47
48
|
if (! props.src) return
|
|
48
49
|
|
|
49
|
-
uri.value = props.src
|
|
50
|
+
uri.value = validateURI(props.src, config.public)
|
|
50
51
|
}
|
|
51
52
|
watch(() => props.src, () => loadImage([{ isIntersecting: true }]))
|
|
52
53
|
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
</template>
|
|
51
51
|
|
|
52
52
|
<script setup>
|
|
53
|
+
const config = useRuntimeConfig()
|
|
53
54
|
const {
|
|
54
55
|
artifact,
|
|
55
56
|
image,
|
|
@@ -92,28 +93,18 @@ const setAnimationArtifact = async (file) => {
|
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
watch(imageIpfsCid, () => {
|
|
95
|
-
|
|
96
|
-
if (! validated) {
|
|
97
|
-
image.value = ''
|
|
98
|
-
} else {
|
|
99
|
-
image.value = ipfsToHttpURI(`ipfs://${validated}`)
|
|
100
|
-
}
|
|
96
|
+
image.value = getValidIpfsURI(imageIpfsCid.value)
|
|
101
97
|
})
|
|
102
98
|
watch(imageArTxId, () => {
|
|
103
|
-
image.value =
|
|
99
|
+
image.value = getValidArweaveURI(imageArTxId.value)
|
|
104
100
|
})
|
|
105
101
|
watch(mode, () => image.value = '')
|
|
106
102
|
|
|
107
103
|
watch(animationIpfsCid, () => {
|
|
108
|
-
|
|
109
|
-
if (! validated) {
|
|
110
|
-
animationUrl.value = ''
|
|
111
|
-
} else {
|
|
112
|
-
animationUrl.value = ipfsToHttpURI(`ipfs://${validated}`)
|
|
113
|
-
}
|
|
104
|
+
animationUrl.value = getValidIpfsURI(animationIpfsCid.value)
|
|
114
105
|
})
|
|
115
106
|
watch(animationArTxId, () => {
|
|
116
|
-
animationUrl.value =
|
|
107
|
+
animationUrl.value = getValidArweaveURI(animationArTxId.value)
|
|
117
108
|
})
|
|
118
109
|
watch(mode, () => {
|
|
119
110
|
image.value = ''
|
|
@@ -36,6 +36,7 @@ const props = defineProps({
|
|
|
36
36
|
},
|
|
37
37
|
})
|
|
38
38
|
|
|
39
|
+
const config = useRuntimeConfig()
|
|
39
40
|
const {
|
|
40
41
|
artifact,
|
|
41
42
|
image,
|
|
@@ -60,15 +61,10 @@ const setArtifact = async (file) => {
|
|
|
60
61
|
}
|
|
61
62
|
}
|
|
62
63
|
watch(ipfsCid, () => {
|
|
63
|
-
|
|
64
|
-
if (! validated) {
|
|
65
|
-
image.value = ''
|
|
66
|
-
} else {
|
|
67
|
-
image.value = ipfsToHttpURI(`ipfs://${validated}`)
|
|
68
|
-
}
|
|
64
|
+
image.value = getValidIpfsURI(ipfsCid.value)
|
|
69
65
|
})
|
|
70
66
|
watch(arTxId, () => {
|
|
71
|
-
image.value =
|
|
67
|
+
image.value = getValidArweaveURI(arTxId.value)
|
|
72
68
|
})
|
|
73
69
|
watch(mode, () => image.value = '')
|
|
74
70
|
|
|
@@ -8,7 +8,10 @@
|
|
|
8
8
|
v-for="( renderer, index ) in collection.renderers"
|
|
9
9
|
:value="index"
|
|
10
10
|
:title="renderer.name"
|
|
11
|
-
|
|
11
|
+
:disabled="renderer.deprecated"
|
|
12
|
+
>
|
|
13
|
+
{{ renderer.name }} {{ renderer.version > 1 ? `V${renderer.version}` : ''}}
|
|
14
|
+
</option>
|
|
12
15
|
<option disabled>----</option>
|
|
13
16
|
<option value="new">{{ $t('mint.select.install_new') }}</option>
|
|
14
17
|
</select>
|
|
@@ -48,7 +48,8 @@ const installedRenderers = computed(() => props.collection.renderers)
|
|
|
48
48
|
|
|
49
49
|
const availableRenderers = computed(
|
|
50
50
|
() => appConfig.knownRenderers[mainChainId].filter(r =>
|
|
51
|
-
!installedRenderers.value.map(cr => cr.address).includes(r.address)
|
|
51
|
+
!installedRenderers.value.map(cr => cr.address).includes(r.address) &&
|
|
52
|
+
!r.deprecated
|
|
52
53
|
)
|
|
53
54
|
)
|
|
54
55
|
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<article class="renderer-overview-card">
|
|
3
3
|
<div class="details">
|
|
4
|
-
<h1>
|
|
4
|
+
<h1>
|
|
5
|
+
<span>{{ renderer.name }}</span>
|
|
6
|
+
<small> v{{ renderer.version }}</small>
|
|
7
|
+
<small v-if="renderer.deprecated" class="deprecated"> [DEPRECATED]</small>
|
|
8
|
+
</h1>
|
|
5
9
|
<p v-if="renderer.description">{{ renderer.description }}</p>
|
|
6
10
|
<p class="address">{{ renderer.address }}</p>
|
|
7
11
|
</div>
|
|
@@ -28,5 +32,9 @@ article {
|
|
|
28
32
|
.address {
|
|
29
33
|
color: var(--muted);
|
|
30
34
|
}
|
|
35
|
+
|
|
36
|
+
.deprecated {
|
|
37
|
+
color: var(--error);
|
|
38
|
+
}
|
|
31
39
|
}
|
|
32
40
|
</style>
|
|
@@ -9,6 +9,7 @@ export const MINT_BLOCKS = BLOCKS_PER_DAY
|
|
|
9
9
|
|
|
10
10
|
export const useOnchainStore = () => {
|
|
11
11
|
const { $wagmi } = useNuxtApp()
|
|
12
|
+
const appConfig = useAppConfig()
|
|
12
13
|
const chainId = useMainChainId()
|
|
13
14
|
|
|
14
15
|
return defineStore('onchainStore', {
|
|
@@ -241,13 +242,13 @@ export const useOnchainStore = () => {
|
|
|
241
242
|
let index = renderers.length
|
|
242
243
|
while (true) {
|
|
243
244
|
try {
|
|
244
|
-
const rendererAddress = await readContract($wagmi, {
|
|
245
|
+
const rendererAddress = (await readContract($wagmi, {
|
|
245
246
|
abi: MINT_ABI,
|
|
246
247
|
address,
|
|
247
248
|
functionName: 'renderers',
|
|
248
249
|
args: [BigInt(index)],
|
|
249
250
|
chainId,
|
|
250
|
-
})
|
|
251
|
+
}))?.toLowerCase() as `0x${string}`
|
|
251
252
|
|
|
252
253
|
const rendererArgs = { abi: RENDERER_ABI, address: rendererAddress, chainId }
|
|
253
254
|
|
|
@@ -263,9 +264,11 @@ export const useOnchainStore = () => {
|
|
|
263
264
|
])
|
|
264
265
|
|
|
265
266
|
this.collections[address].renderers[index] = {
|
|
266
|
-
address: rendererAddress
|
|
267
|
+
address: rendererAddress,
|
|
267
268
|
name,
|
|
268
269
|
version,
|
|
270
|
+
// Enrich with configured renderer data
|
|
271
|
+
...appConfig.knownRenderers[chainId].find(r => r.address === rendererAddress)
|
|
269
272
|
}
|
|
270
273
|
|
|
271
274
|
index ++
|
package/nuxt.config.ts
CHANGED
|
@@ -25,6 +25,8 @@ export default defineNuxtConfig({
|
|
|
25
25
|
rpc1: 'https://eth.llamarpc.com',
|
|
26
26
|
rpc2: 'https://ethereum-rpc.publicnode.com',
|
|
27
27
|
rpc3: 'https://eth.drpc.org',
|
|
28
|
+
ipfsGateway: 'https://ipfs.io/ipfs/',
|
|
29
|
+
arweaveGateway: 'https://arweave.net/',
|
|
28
30
|
title: 'Mint',
|
|
29
31
|
walletConnectProjectId: '',
|
|
30
32
|
}
|
package/package.json
CHANGED
package/utils/arweave.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const validateArweaveTx = (tx: string): string|false => {
|
|
2
|
+
return tx
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export const getValidArweaveURI = (tx: string): string => {
|
|
6
|
+
const validated = validateArweaveTx(tx)
|
|
7
|
+
|
|
8
|
+
return validated ? `ipfs://${validated}` : ''
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const arweaveToHttpURI = (url: string, gateway: string = 'https://arweave.net/') => url.replace('ar://', gateway)
|
|
12
|
+
|
package/utils/ipfs.ts
CHANGED
|
@@ -11,3 +11,17 @@ export const validateCID = (cid: string): string|false => {
|
|
|
11
11
|
return false
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
|
+
|
|
15
|
+
export const getValidIpfsURI = (cid: string): string => {
|
|
16
|
+
const validated = validateCID(cid)
|
|
17
|
+
|
|
18
|
+
return validated ? `ipfs://${validated}` : ''
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const ipfsToHttpURI = (
|
|
22
|
+
url: string,
|
|
23
|
+
gateway: string = 'https://ipfs.io/ipfs/'
|
|
24
|
+
) => url
|
|
25
|
+
.replace('https://ipfs.io/ipfs/', gateway)
|
|
26
|
+
.replace('ipfs://', gateway)
|
|
27
|
+
|
package/utils/urls.ts
CHANGED
|
@@ -1,13 +1,24 @@
|
|
|
1
|
-
|
|
1
|
+
type UrlValidationConfig = {
|
|
2
|
+
ipfsGateway?: string,
|
|
3
|
+
arweaveGateway?: string,
|
|
4
|
+
}
|
|
2
5
|
|
|
3
|
-
export const validateURI = (url: string) => {
|
|
6
|
+
export const validateURI = (url: string, config: UrlValidationConfig = {}) => {
|
|
4
7
|
if (! url || ! url.length) return false
|
|
5
8
|
|
|
6
9
|
let validated = url.trim()
|
|
7
10
|
|
|
8
11
|
// Normalize protocol
|
|
9
|
-
if (
|
|
10
|
-
if (
|
|
12
|
+
// if (validated.startsWith('ipfs://') || validated.contains('ipfs')) {
|
|
13
|
+
if (validated.indexOf('ipfs') > -1) {
|
|
14
|
+
validated = ipfsToHttpURI(validated, config.ipfsGateway)
|
|
15
|
+
}
|
|
16
|
+
if (validated.startsWith('ar://')) {
|
|
17
|
+
validated = arweaveToHttpURI(validated, config.arweaveGateway)
|
|
18
|
+
}
|
|
19
|
+
if (! validated.startsWith('data:') && ! validated.startsWith('http')) {
|
|
20
|
+
validated = `https://${validated}`
|
|
21
|
+
}
|
|
11
22
|
|
|
12
23
|
// Check url validity
|
|
13
24
|
try {
|
package/utils/images.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
export type ImageVersions = {
|
|
2
|
-
xs?: boolean, // 215
|
|
3
|
-
sm?: boolean, // 512
|
|
4
|
-
md?: boolean, // 1024
|
|
5
|
-
lg?: boolean, // 2048
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export type Image = {
|
|
9
|
-
id: string,
|
|
10
|
-
versions: ImageVersions,
|
|
11
|
-
cdn: string,
|
|
12
|
-
path: string,
|
|
13
|
-
type: string,
|
|
14
|
-
aspectRatio?: number,
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const CDN_BASE = `cdn.evverydays.com`
|
|
18
|
-
|
|
19
|
-
export const imageURI = (image: Image, version?: keyof ImageVersions) => {
|
|
20
|
-
if (! image) return null
|
|
21
|
-
|
|
22
|
-
const name = (version && image.versions[version])
|
|
23
|
-
? `${image.id}@${version}.webp`
|
|
24
|
-
: `${image.id}.${image.type}`
|
|
25
|
-
|
|
26
|
-
return `https://${image.cdn}.${CDN_BASE}/${image.path}/${name}`
|
|
27
|
-
}
|