@visualizevalue/mint-app-base 0.0.1 → 0.0.3

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
@@ -18,6 +18,9 @@ NUXT_PUBLIC_CREATOR_ADDRESS=0xc8f8e2F59Dd95fF67c3d39109ecA2e2A017D4c8a
18
18
  # =========================
19
19
  NUXT_PUBLIC_BLOCK_EXPLORER=https://etherscan.io
20
20
  NUXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=
21
+ NUXT_PUBLIC_RPC1=
22
+ NUXT_PUBLIC_RPC2=
23
+ NUXT_PUBLIC_RPC3=
21
24
 
22
25
  # =========================
23
26
  # ONCHAIN
@@ -1,4 +1,5 @@
1
1
  @import "./variables.css";
2
+ @import "./theme.css";
2
3
  @import "./normalize.css";
3
4
  @import "./base.css";
4
5
  @import "./text.css";
@@ -0,0 +1,4 @@
1
+ :root {
2
+ --card-border: var(--border);
3
+ --card-border-radius: var(--border-radius);
4
+ }
@@ -30,25 +30,25 @@
30
30
  --black-semi: rgba(0, 0, 0, 0.7);
31
31
 
32
32
  /* COLORS */
33
- --red: #EF4444;
33
+ --red: #EF4444;
34
34
  --green: #94E337;
35
35
 
36
36
  /* PRESET COLORS */
37
- --error: var(--red);
37
+ --error: var(--red);
38
38
  --success: var(--green);
39
39
 
40
40
  /* SIZES */
41
- --100vh: 100dvh;
42
- --size-0: 0.125rem;
43
- --size-1: 0.25rem;
44
- --size-2: 0.5rem;
45
- --size-3: 0.75rem;
46
- --size-4: 1rem;
47
- --size-5: 1.25rem;
48
- --size-6: 1.5rem;
49
- --size-7: 2rem;
50
- --size-8: 3rem;
51
- --size-9: 4.5rem;
41
+ --100vh: 100dvh;
42
+ --size-0: 0.125rem;
43
+ --size-1: 0.25rem;
44
+ --size-2: 0.5rem;
45
+ --size-3: 0.75rem;
46
+ --size-4: 1rem;
47
+ --size-5: 1.25rem;
48
+ --size-6: 1.5rem;
49
+ --size-7: 2rem;
50
+ --size-8: 3rem;
51
+ --size-9: 4.5rem;
52
52
  --size-10: 6rem;
53
53
 
54
54
  --spacer-xs: var(--size-0);
@@ -107,16 +107,13 @@
107
107
  --border-color-dark: var(--gray-z-1);
108
108
  --border: 1px solid var(--border-color);
109
109
  --border-dark: 1px solid var(--border-color-dark);
110
+ --border-shadow: 0 0 0 1px var(--border-color);
110
111
 
111
112
  /* SHADOWS */
112
113
  --shadow:
113
114
  0 var(--size-0) var(--size-2) var(--gray-z-1-semi),
114
115
  0 var(--size-2) var(--size-7) calc(-1 * var(--size-5)) var(--gray-z-3-semi);
115
116
 
116
- --shadow-xl:
117
- 0 var(--size-3) var(--size-8) var(--gray-z-3-semi),
118
- 0 var(--size-8) var(--size-6) calc(-1 * var(--size-8)) var(--gray-z-6-semi);
119
-
120
117
  /* BACKGROUNDS */
121
118
  --blur: blur(var(--size-1));
122
119
  }
@@ -193,3 +190,4 @@
193
190
  --font-sm: calc(var(--size-3) + var(--size-0));
194
191
  }
195
192
  }
193
+
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <header>
2
+ <header class="collection-intro">
3
3
  <figure v-if="collection.image">
4
4
  <Image :src="collection.image" :alt="collection.name" />
5
5
  </figure>
@@ -49,7 +49,7 @@ const ownedByMe = useIsMeCheck(collection.owner)
49
49
  </script>
50
50
 
51
51
  <style scoped>
52
- header {
52
+ header.collection-intro {
53
53
  display: grid;
54
54
  gap: var(--spacer);
55
55
 
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <article>
2
+ <article class="collection-overview-card">
3
3
  <Image v-if="collection.image" :src="collection.image" :alt="collection.name" />
4
4
  <div class="text">
5
5
  <div>
@@ -27,11 +27,12 @@ const shortDescription = computed(() => shortString(collection.description, 40,
27
27
  </script>
28
28
 
29
29
  <style scoped>
30
- article {
30
+ article.collection-overview-card {
31
31
  display: grid;
32
32
  padding: var(--spacer);
33
33
  gap: var(--spacer);
34
34
  transition: all var(--speed);
35
+ border: var(--card-border);
35
36
 
36
37
  &:has(> a:--highlight) {
37
38
  background: var(--gray-z-0);
@@ -68,9 +68,8 @@ article.image {
68
68
  padding-bottom: 100%;
69
69
  display: flex;
70
70
 
71
- .bordered {
72
- border-radius: var(--border-radius);
73
- border: 1px solid var(--border-color);
71
+ &.bordered {
72
+ box-shadow: var(--border-shadow);
74
73
  }
75
74
 
76
75
  .loader {
@@ -1,8 +1,8 @@
1
1
  <template>
2
- <article class="token">
2
+ <article class="token-detail">
3
3
  <div class="artifact">
4
- <div :class="{ shaded }">
5
- <Image :src="token.artifact" :alt="token.name" class="borderless" />
4
+ <div>
5
+ <Image :src="token.artifact" :alt="token.name" />
6
6
  </div>
7
7
  </div>
8
8
 
@@ -64,18 +64,15 @@ const { token } = defineProps<{
64
64
  token: Token
65
65
  }>()
66
66
 
67
- const breakpoints = useBreakpoints()
68
- const shaded = computed(() => breakpoints.greater('sm').value && ! isDark.value)
69
-
70
67
  const store = useOnchainStore()
71
68
  const collection = computed(() => store.collection(token.collection))
72
69
 
73
70
  const mintCount = ref('1')
74
- const ownedBalance = computed(() => store.tokenBalance(collection.value.address, token.tokenId))
71
+ const ownedBalance = computed(() => collection.value && store.tokenBalance(collection.value.address, token.tokenId))
75
72
  </script>
76
73
 
77
74
  <style scoped>
78
- .token {
75
+ .token-detail {
79
76
  position: relative;
80
77
  container-type: inline-size;
81
78
 
@@ -116,7 +113,7 @@ const ownedBalance = computed(() => store.tokenBalance(collection.value.address,
116
113
  @media (--lg) {
117
114
  --padding-top: var(--spacer-xl);
118
115
  --padding-x: var(--spacer-xl);
119
- --padding-bottom: calc(var(--spacer-xl) + var(--spacer-lg));
116
+ --padding-bottom: calc(var(--spacer-xl) + var(--spacer));
120
117
  }
121
118
 
122
119
  height: var(--height);
@@ -139,13 +136,8 @@ const ownedBalance = computed(() => store.tokenBalance(collection.value.address,
139
136
  @media (--md) {
140
137
  border-bottom: none !important;
141
138
  }
142
-
143
- &.shaded {
144
- box-shadow: var(--shadow-xl);
145
- transform: translateY(calc(-1 * var(--size-2))) scale(1.001);
146
- }
147
139
  }
148
- }
140
+ }
149
141
 
150
142
  .details {
151
143
 
@@ -12,17 +12,17 @@
12
12
  transactionFlowConfig
13
13
  }"
14
14
  >
15
- <article class="token">
15
+ <article class="token-overview-card">
16
16
  <div class="content">
17
17
  <header>
18
18
  <h1>
19
19
  <span>{{ token.name }} <span class="muted">#{{ token.tokenId }}</span></span>
20
- <span v-if="token.description">{{ shortString(token.description, 40, 30) }}</span>
20
+ <span v-if="token.description">{{ shortString(token.description, 60, 30) }}</span>
21
21
  </h1>
22
22
  <p v-if="mintOpen" class="muted">Closes in {{ blocksRemaining }} {{ pluralize('block', Number(blocksRemaining))}}</p>
23
23
  <p v-else class="muted">Closed at block {{ token.untilBlock }}</p>
24
24
  </header>
25
- <Image :src="token.artifact" :alt="token.name" />
25
+ <Image :src="token.artifact" :alt="token.name" class="bordered" />
26
26
  <CardLink :to="{
27
27
  name: 'id-collection-tokenId',
28
28
  params: { id: collection.owner, collection: token.collection, tokenId: `${token.tokenId}` }
@@ -60,17 +60,16 @@ const ownedBalance = computed(() => store.tokenBalance(collection.value.address,
60
60
  </script>
61
61
 
62
62
  <style scoped>
63
- .token,
64
- .token > .content {
63
+ .token-overview-card,
64
+ .token-overview-card > .content {
65
65
  display: flex;
66
66
  flex-direction: column;
67
67
  justify-content: center;
68
68
  gap: var(--spacer);
69
69
  }
70
70
 
71
- .token {
71
+ .token-overview-card {
72
72
  padding: var(--spacer-xl) var(--spacer) !important;
73
- border: 0 !important;
74
73
 
75
74
  /* Tokens should be at min the screen height. */
76
75
  &:not(:first-of-type) {
@@ -88,7 +87,7 @@ const ownedBalance = computed(() => store.tokenBalance(collection.value.address,
88
87
  }
89
88
  }
90
89
 
91
- .token > .content {
90
+ .token-overview-card > .content {
92
91
  display: flex;
93
92
  flex-direction: column;
94
93
  justify-content: center;
@@ -1,4 +1,4 @@
1
- import { getPublicClient } from '@wagmi/core'
1
+ import { readContract } from '@wagmi/core'
2
2
 
3
3
  const CHAINLINK_PRICE_FEED_ABI = [
4
4
  {
@@ -45,17 +45,17 @@ export const usePriceFeedStore = () => {
45
45
 
46
46
  actions: {
47
47
  async fetchEthUsdPrice () {
48
- const client = getPublicClient($wagmi, { chainId: 1 })
49
48
 
50
49
  if (nowInSeconds() - this.lastUpdated < 3_600) {
51
50
  return this.ethUSD
52
51
  }
53
52
 
54
53
  try {
55
- const [, answer] = await client.readContract({
54
+ const [, answer] = await readContract($wagmi, {
56
55
  address: PRICE_FEED_ADDRESS,
57
56
  abi: CHAINLINK_PRICE_FEED_ABI,
58
- functionName: 'latestRoundData'
57
+ functionName: 'latestRoundData',
58
+ chainId: 1,
59
59
  })
60
60
 
61
61
  this.ethUSDRaw = answer
@@ -2,7 +2,7 @@
2
2
  <Authenticated>
3
3
  <PageFrame :title="breadcrumb" class="inset wide" id="mint-token">
4
4
  <article class="preview">
5
- <Image v-if="image" :src="image" alt="Preview" />
5
+ <Image v-if="image" :src="image" alt="Preview" class="bordered" />
6
6
  <VisualImagePreview v-else />
7
7
  <h1 :class="{ 'muted-light': !name }">{{ name || 'Token' }}</h1>
8
8
  <p :class="{ 'muted-light': !description }">
@@ -90,10 +90,11 @@ const isSmall = computed(() => imageSize.value / 1024 < 10)
90
90
  const setImage = async (file) => {
91
91
  try {
92
92
  image.value = await imageFileToDataUri(file)
93
+ imageSize.value = file.size
93
94
  } catch (e) {
94
95
  image.value = ''
96
+ imageSize.value = 0
95
97
  }
96
- imageSize.value = file.size
97
98
  }
98
99
  watch(ipfsCid, () => {
99
100
  const validated = validateCID(ipfsCid.value)
@@ -115,68 +116,72 @@ const mint = async () => {
115
116
 
116
117
  minting.value = true
117
118
 
118
- if (multiTransactionPrepare) {
119
- if (! confirm(`Due to the large artifact size, we have to split it into ${artifactChunks.length} chunks and store them in separate transactions. You will be prompted with multiple transaction requests before minting the final token.`)) {
120
- return
119
+ try {
120
+ if (multiTransactionPrepare) {
121
+ if (! confirm(`Due to the large artifact size, we have to split it into ${artifactChunks.length} chunks and store them in separate transactions. You will be prompted with multiple transaction requests before minting the final token.`)) {
122
+ return
123
+ }
124
+
125
+ // On the first iteration we want to clear existing artifact data
126
+ let clearExisting = true
127
+
128
+ for (const chunk of artifactChunks) {
129
+ await txFlow.value.initializeRequest(() => writeContract($wagmi, {
130
+ abi: MINT_ABI,
131
+ chainId,
132
+ address: collection.value.address,
133
+ functionName: 'prepareArtifact',
134
+ args: [
135
+ collection.value.latestTokenId + 1n,
136
+ chunk,
137
+ clearExisting
138
+ ],
139
+ }))
140
+
141
+ // Make sure to rerender the tx flow component
142
+ txFlowKey.value ++
143
+
144
+ // On following iterations we want to keep existing artifact data
145
+ clearExisting = false
146
+ }
121
147
  }
122
148
 
123
- // On the first iteration we want to clear existing artifact data
124
- let clearExisting = true
125
-
126
- for (const chunk of artifactChunks) {
127
- await txFlow.value.initializeRequest(() => writeContract($wagmi, {
128
- abi: MINT_ABI,
129
- chainId,
130
- address: collection.value.address,
131
- functionName: 'prepareArtifact',
132
- args: [
133
- collection.value.latestTokenId + 1n,
134
- chunk,
135
- clearExisting
136
- ],
137
- }))
138
-
139
- // Make sure to rerender the tx flow component
140
- txFlowKey.value ++
141
-
142
- // On following iterations we want to keep existing artifact data
143
- clearExisting = false
144
- }
149
+ const receipt = await txFlow.value.initializeRequest(() => writeContract($wagmi, {
150
+ abi: MINT_ABI,
151
+ chainId,
152
+ address: collection.value.address,
153
+ functionName: 'create',
154
+ args: [
155
+ name.value,
156
+ description.value,
157
+ multiTransactionPrepare ? [] : artifact,
158
+ 0,
159
+ 0n,
160
+ ],
161
+ }))
162
+
163
+ const logs = receipt.logs.map(log => decodeEventLog({
164
+ abi: MINT_ABI,
165
+ data: log.data,
166
+ topics: log.topics,
167
+ strict: false,
168
+ }))
169
+
170
+ const mintedEvent = logs.find(log => log.eventName === 'TransferSingle')
171
+
172
+ await store.fetchToken(collection.value.address, mintedEvent.args.id)
173
+
174
+ // Force update the collection mint ID
175
+ store.collections[collection.value.address].latestTokenId = mintedEvent.args.id
176
+
177
+ await navigateTo({
178
+ name: 'id-collection-tokenId',
179
+ params: { id: id.value, collection: collection.value.address, tokenId: mintedEvent.args.id }
180
+ })
181
+ } catch (e) {
182
+ console.error(e)
145
183
  }
146
184
 
147
- const receipt = await txFlow.value.initializeRequest(() => writeContract($wagmi, {
148
- abi: MINT_ABI,
149
- chainId,
150
- address: collection.value.address,
151
- functionName: 'create',
152
- args: [
153
- name.value,
154
- description.value,
155
- multiTransactionPrepare ? [] : artifact,
156
- 0,
157
- 0n,
158
- ],
159
- }))
160
-
161
- const logs = receipt.logs.map(log => decodeEventLog({
162
- abi: MINT_ABI,
163
- data: log.data,
164
- topics: log.topics,
165
- strict: false,
166
- }))
167
-
168
- const mintedEvent = logs.find(log => log.eventName === 'TransferSingle')
169
-
170
- await store.fetchToken(collection.value.address, mintedEvent.args.id)
171
-
172
- // Force update the collection mint ID
173
- store.collections[collection.value.address].latestTokenId = mintedEvent.args.id
174
-
175
- await navigateTo({
176
- name: 'id-collection-tokenId',
177
- params: { id: id.value, collection: collection.value.address, tokenId: mintedEvent.args.id }
178
- })
179
-
180
185
  minting.value = false
181
186
  }
182
187
 
@@ -227,12 +232,14 @@ useMetaData({
227
232
 
228
233
  .image,
229
234
  svg {
230
- border-radius: var(--border-radius);
231
- border: var(--border);
232
235
  margin-bottom: var(--spacer-sm);
233
236
  width: 100%;
234
237
  }
235
238
 
239
+ svg {
240
+ box-shadow: var(--border-shadow);
241
+ }
242
+
236
243
  h1 {
237
244
  display: flex;
238
245
  gap: var(--spacer-sm);
@@ -1,18 +1,26 @@
1
1
  // import { custom, fallback } from 'viem'
2
2
  import { VueQueryPlugin } from '@tanstack/vue-query'
3
- import { http, cookieStorage, createConfig, createStorage, WagmiPlugin } from '@wagmi/vue'
3
+ import { http, cookieStorage, createConfig, createStorage, WagmiPlugin, fallback, custom } from '@wagmi/vue'
4
4
  import { mainnet, sepolia, holesky, localhost } from '@wagmi/vue/chains'
5
5
  import { coinbaseWallet, injected, metaMask, walletConnect } from '@wagmi/vue/connectors'
6
-
7
- // const isBrowser = typeof window !== 'undefined' && window !== null
8
- // const transports = isBrowser && window.ethereum
9
- // ? fallback([ custom(window.ethereum!), http() ])
10
- // : http()
11
- const transports = http()
6
+ import type { CustomTransport, Transport } from 'viem'
12
7
 
13
8
  export default defineNuxtPlugin(nuxtApp => {
14
9
  const title = nuxtApp.$config.public.title || 'Mint'
15
10
 
11
+ const transportDefinitions: CustomTransport|Transport[] = []
12
+
13
+ console.log(nuxtApp.$config.public)
14
+
15
+ if (nuxtApp.$config.public.rpc1) transportDefinitions.push(http(nuxtApp.$config.public.rpc1 as string))
16
+ if (nuxtApp.$config.public.rpc2) transportDefinitions.push(http(nuxtApp.$config.public.rpc2 as string))
17
+ if (nuxtApp.$config.public.rpc3) transportDefinitions.push(http(nuxtApp.$config.public.rpc3 as string))
18
+ transportDefinitions.push(http())
19
+
20
+ console.log(transportDefinitions)
21
+
22
+ const transports = fallback(transportDefinitions)
23
+
16
24
  const wagmiConfig = createConfig({
17
25
  chains: [mainnet, sepolia, holesky, localhost],
18
26
  batch: {
package/nuxt.config.ts CHANGED
@@ -18,6 +18,9 @@ export default defineNuxtConfig({
18
18
  chainId: 1337,
19
19
  walletConnectProjectId: '',
20
20
  platformUrl: 'https://networked.art',
21
+ rpc1: '',
22
+ rpc2: '',
23
+ rpc3: '',
21
24
  }
22
25
  },
23
26
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@visualizevalue/mint-app-base",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "type": "module",
5
5
  "main": "./nuxt.config.ts",
6
6
  "dependencies": {
@@ -10,6 +10,8 @@
10
10
  "@tanstack/vue-query": ">=5.45.0",
11
11
  "@visualizevalue/mint-utils": "npm:@visualizevalue/mint-utils@^0.0.1",
12
12
  "@vueuse/components": "^10.11.0",
13
+ "@vueuse/core": "^11.0.3",
14
+ "@vueuse/nuxt": "^11.0.3",
13
15
  "@wagmi/vue": "^0.0.40",
14
16
  "buffer": "^6.0.3",
15
17
  "eventemitter3": "^5.0.1",
@@ -27,8 +29,6 @@
27
29
  "devDependencies": {
28
30
  "@types/node": "^22.5.4",
29
31
  "@vue/devtools-api": "^6.6.3",
30
- "@vueuse/core": "^11.0.3",
31
- "@vueuse/nuxt": "^11.0.3",
32
32
  "eventemitter3": "^5.0.1",
33
33
  "nuxt": "latest",
34
34
  "typescript": "^5.5.4",