@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 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 (Sepolia) [Deprecated]',
21
+ name: 'P5 Renderer',
32
22
  version: 1n,
33
- address: '0xfadf2fb2f8a15fc830c176b71d2c905e95f4169e',
34
- description: 'Allows using P5 scripts as the artifact content. Deprecated: Please use V2'
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
  })
@@ -6,6 +6,7 @@
6
6
 
7
7
  /* COLORS */
8
8
  --primary: blue;
9
+ --error: red;
9
10
 
10
11
  /*
11
12
  * Z-COLORS
@@ -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(props.src)
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
- const validated = validateCID(imageIpfsCid.value)
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 = `https://arweave.net/${imageArTxId.value}`
99
+ image.value = getValidArweaveURI(imageArTxId.value)
104
100
  })
105
101
  watch(mode, () => image.value = '')
106
102
 
107
103
  watch(animationIpfsCid, () => {
108
- const validated = validateCID(animationIpfsCid.value)
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 = `https://arweave.net/${animationArTxId.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
- const validated = validateCID(ipfsCid.value)
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 = `https://arweave.net/${arTxId.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
- >{{ renderer.name }}</option>
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>{{ renderer.name }} <small>v{{ renderer.version }}</small></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.toLowerCase() as `0x${string}`,
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@visualizevalue/mint-app-base",
3
- "version": "0.1.92",
3
+ "version": "0.1.94",
4
4
  "type": "module",
5
5
  "main": "./nuxt.config.ts",
6
6
  "dependencies": {
@@ -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
- export const ipfsToHttpURI = (url: string, gateway: string = 'https://ipfs.io/ipfs/') => url.replace('ipfs://', gateway)
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 (! validated.startsWith('https://')) validated = `https://${validated}`
10
- if (! validated.startsWith('http')) validated = `http://${validated}`
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
- }