@visualizevalue/mint-app-base 0.0.7 → 0.1.0

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.
Files changed (69) hide show
  1. package/.env.example +1 -1
  2. package/app/assets/styles/animation.css +1 -9
  3. package/app/assets/styles/base.css +3 -12
  4. package/app/assets/styles/forms.css +18 -54
  5. package/app/assets/styles/index.css +24 -6
  6. package/app/assets/styles/normalize.css +8 -3
  7. package/app/assets/styles/prose.css +2 -128
  8. package/app/assets/styles/variables/animations.css +8 -0
  9. package/app/assets/styles/variables/borders.css +13 -0
  10. package/app/assets/styles/variables/colors.css +48 -0
  11. package/app/assets/styles/{theme.css → variables/components.css} +8 -2
  12. package/app/assets/styles/variables/effects.css +11 -0
  13. package/app/assets/styles/variables/fonts.css +26 -0
  14. package/app/assets/styles/variables/layout.css +9 -0
  15. package/app/assets/styles/variables/sizes.css +23 -0
  16. package/app/assets/styles/variables/ui.css +17 -0
  17. package/app/assets/styles/variables.css +16 -192
  18. package/app/assets/styles/web3-modals.css +2 -7
  19. package/app/components/Account.client.vue +1 -1
  20. package/app/components/Actions.vue +2 -3
  21. package/app/components/AppHeader.vue +2 -25
  22. package/app/components/Breadcrumbs.vue +1 -1
  23. package/app/components/Button/AddCollection.vue +10 -0
  24. package/app/components/Button/EditProfile.vue +10 -0
  25. package/app/components/Button/Profile/Discord.vue +10 -0
  26. package/app/components/Button/Profile/Email.vue +10 -0
  27. package/app/components/Button/Profile/Github.vue +11 -0
  28. package/app/components/Button/Profile/Twitter.vue +10 -0
  29. package/app/components/Button/Profile/Website.vue +10 -0
  30. package/app/components/Button.vue +17 -36
  31. package/app/components/CheckSpinner.vue +0 -18
  32. package/app/components/Collection/Intro.vue +9 -6
  33. package/app/components/Collection/OverviewCard.vue +11 -5
  34. package/app/components/Collection/Withdraw.client.vue +2 -1
  35. package/app/components/DialogFrame.vue +4 -7
  36. package/app/components/Form/Group.vue +19 -4
  37. package/app/components/Form/SelectFile.vue +1 -1
  38. package/app/components/Icon.vue +21 -17
  39. package/app/components/Image.client.vue +0 -4
  40. package/app/components/Loading.vue +2 -38
  41. package/app/components/MintGasPricePopover.client.vue +2 -2
  42. package/app/components/MintToken.vue +1 -1
  43. package/app/components/Modal.vue +3 -2
  44. package/app/components/Popover.client.vue +3 -23
  45. package/app/components/Profile/Header.client.vue +6 -35
  46. package/app/components/Token/Detail.client.vue +19 -10
  47. package/app/components/Token/MintTimeline.client.vue +14 -43
  48. package/app/components/Token/MintTimelineItem.vue +50 -13
  49. package/app/components/Token/OverviewCard.vue +10 -17
  50. package/app/components/TransactionFlow.vue +4 -10
  51. package/app/layouts/default.vue +2 -14
  52. package/app/pages/[id]/[collection]/[tokenId]/index.vue +1 -1
  53. package/app/pages/[id]/[collection]/index.vue +1 -1
  54. package/app/pages/[id]/[collection]/mint.vue +4 -4
  55. package/app/pages/[id]/create.vue +49 -49
  56. package/app/pages/[id]/index.vue +1 -6
  57. package/app/pages/profile/[address]/index.vue +1 -4
  58. package/app/plugins/2.wagmi.ts +2 -2
  59. package/package.json +2 -1
  60. package/app/assets/styles/scroll.css +0 -13
  61. package/app/assets/styles/text.css +0 -14
  62. package/app/assets/styles/utils.css +0 -24
  63. package/app/components/Avatar.vue +0 -61
  64. package/app/components/CountDown.vue +0 -153
  65. package/app/components/IconLink.vue +0 -29
  66. package/app/components/Navbar.client.vue +0 -86
  67. package/app/components/QueryDialog.vue +0 -38
  68. package/app/components/ToggleDarkMode.client.vue +0 -58
  69. /package/app/components/{Visual/ImagePreview.vue → ImagePreview.vue} +0 -0
@@ -10,7 +10,7 @@
10
10
  <div class="text">
11
11
  <CheckSpinner class="spinner" />
12
12
  <h1 v-if="text.title[step]">{{ text.title[step] }}</h1>
13
- <p class="muted-light">{{ text.lead[step] }}</p>
13
+ <p v-if="text.lead[step]">{{ text.lead[step] }}</p>
14
14
  <p v-if="error">{{ error }}</p>
15
15
  </div>
16
16
 
@@ -158,7 +158,7 @@ const initializeRequest = async (request = props.request) => {
158
158
  requesting.value = false
159
159
  waiting.value = false
160
160
 
161
- if (props.autoCloseSuccess) {
161
+ if (props.autoCloseSuccess && step.value === 'complete') {
162
162
  await delay(2_000)
163
163
  open.value = false
164
164
  await delay(300) // Animations...
@@ -189,37 +189,31 @@ defineExpose({
189
189
  <style>
190
190
  .transaction-flow {
191
191
  display: grid;
192
- justify-content: center;
193
192
  gap: var(--spacer);
194
193
 
195
194
  .spinner {
196
195
  width: var(--size-7);
197
196
  height: var(--size-7);
198
- margin: calc(-1 * var(--size-4)) auto var(--size-3);
197
+ margin: calc(-1 * var(--size-4)) 0 var(--size-3);
199
198
  }
200
199
 
201
200
  .text {
201
+ width: 100%;
202
202
  height: min-content;
203
203
  }
204
204
 
205
205
  h1 {
206
206
  font-size: var(--font-lg);
207
207
  margin-bottom: var(--size-4);
208
- text-align: center;
209
208
  }
210
209
 
211
210
  p {
212
211
  white-space: pre-wrap;
213
212
  width: 100%;
214
- text-align: center;
215
213
 
216
214
  a {
217
215
  text-decoration: underline;
218
216
  }
219
217
  }
220
-
221
- .block-explorer {
222
- justify-self: center;
223
- }
224
218
  }
225
219
  </style>
@@ -5,20 +5,16 @@
5
5
  <main>
6
6
  <slot />
7
7
  </main>
8
-
9
- <Navbar />
10
-
11
- <ToggleDarkMode />
12
8
  </div>
13
9
  </template>
14
10
 
15
11
  <script setup>
16
- // Fetch and update price feed
12
+ // Fetch and update USD price feed
17
13
  const priceFeed = usePriceFeedStore()
18
14
  onMounted(() => {
19
15
  priceFeed.fetchEthUsdPrice()
20
16
 
21
- setInterval(() => priceFeed.fetchEthUsdPrice(), 60 * 60 * 1000)
17
+ setInterval(() => priceFeed.fetchEthUsdPrice(), 60 * 60 * 1000) // once per hour
22
18
  })
23
19
  </script>
24
20
 
@@ -26,17 +22,9 @@ onMounted(() => {
26
22
  main {
27
23
  display: grid;
28
24
  gap: var(--spacer);
29
- min-height: 100dvh;
30
25
 
31
26
  &:not(:has(> .frame-sm)) {
32
27
  grid-auto-rows: min-content;
33
28
  }
34
-
35
- /* Frame space around navbars */
36
- padding: var(--navbar-height) 0 var(--navbar-height);
37
-
38
- @media (--md) {
39
- padding: var(--navbar-height) 0 0;
40
- }
41
29
  }
42
30
  </style>
@@ -48,7 +48,7 @@ const breadcrumb = computed(() => {
48
48
  return [
49
49
  ...path,
50
50
  {
51
- text: `${ collection.value.name }`,
51
+ text: `${ collection.value.name || 'Unnamed Collection' }`,
52
52
  to: { name: 'id-collection', params: { id: id.value, collection: collection.value.address } }
53
53
  },
54
54
  {
@@ -29,7 +29,7 @@ const breadcrumb = computed(() => {
29
29
  return [
30
30
  ...path,
31
31
  {
32
- text: collection.value.name
32
+ text: collection.value.name || 'Unnamed Collection'
33
33
  }
34
34
  ]
35
35
  })
@@ -2,10 +2,10 @@
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" class="bordered" />
6
- <VisualImagePreview v-else />
7
- <h1 :class="{ 'muted-light': !name }">{{ name || 'Token' }}</h1>
8
- <p :class="{ 'muted-light': !description }">
5
+ <Image v-if="image" :src="image" alt="Preview" />
6
+ <ImagePreview v-else />
7
+ <h1 :class="{ '': !name }">{{ name || 'Token' }}</h1>
8
+ <p :class="{ '': !description }">
9
9
  {{ description || 'No description' }}
10
10
  </p>
11
11
  </article>
@@ -12,64 +12,64 @@
12
12
  <article class="preview">
13
13
  <div class="visual">
14
14
  <Image v-if="image" :src="image" alt="Preview" />
15
- <VisualImagePreview v-else />
15
+ <ImagePreview v-else />
16
16
  </div>
17
17
  <h1>
18
- <span :class="{ 'muted-light': !title }">{{ title || 'Token' }}</span>
19
- <small :class="{ 'muted-light': !symbol }">{{ symbol || '$T' }}</small>
18
+ <span :class="{ '': !title }">{{ title || 'Token' }}</span>
19
+ <small :class="{ '': !symbol }">{{ symbol || '$T' }}</small>
20
20
  </h1>
21
- <p :class="{ 'muted-light': !description }">
21
+ <p :class="{ '': !description }">
22
22
  {{ description || 'No description' }}
23
23
  </p>
24
24
  </article>
25
25
 
26
- <form @submit.stop.prevent="deploy" class="card borderless">
27
- <div class="card">
28
- <div>
29
- <FormSelectFile @change="setImage" />
30
- <p v-if="! isSmall" class="muted"><small>Note: This should be a small file, prefferably a simple SVG like <a href="/example-contract-icon.svg" target="_blank">this one (273 bytes)</a>. Try to make it less than 10kb.</small></p>
31
- </div>
32
- <FormGroup>
33
- <FormInput v-model="title" placeholder="Title" required class="title" />
34
- <FormInput v-model="symbol" placeholder="Symbol" required />
35
- </FormGroup>
36
- <FormInput v-model="description" placeholder="Description" />
37
- </div>
38
-
39
- <Actions class="borderless">
40
- <TransactionFlow
41
- :request="deployRequest"
42
- :text="{
43
- title: {
44
- chain: 'Switch Chain',
45
- requesting: 'Confirm In Wallet',
46
- waiting: '2. Transaction Submitted',
47
- complete: '3. Success!'
48
- },
49
- lead: {
50
- chain: 'Requesting to switch chain...',
51
- requesting: 'Requesting Signature...',
52
- waiting: 'Checking Deployment Transaction...',
53
- complete: `New Collection Created...`,
54
- },
55
- action: {
56
- confirm: 'Mint',
57
- error: 'Retry',
58
- complete: 'OK',
59
- },
60
- }"
61
- @complete="deployed"
62
- skip-confirmation
63
- auto-close-success
64
- >
65
- <template #start="{ start }">
66
- <Button @click="start">
26
+ <TransactionFlow
27
+ :request="deployRequest"
28
+ :text="{
29
+ title: {
30
+ chain: 'Switch Chain',
31
+ requesting: 'Confirm In Wallet',
32
+ waiting: '2. Transaction Submitted',
33
+ complete: '3. Success!'
34
+ },
35
+ lead: {
36
+ chain: 'Requesting to switch chain...',
37
+ requesting: 'Requesting Signature...',
38
+ waiting: 'Checking Deployment Transaction...',
39
+ complete: `New Collection Created...`,
40
+ },
41
+ action: {
42
+ confirm: 'Mint',
43
+ error: 'Retry',
44
+ complete: 'OK',
45
+ },
46
+ }"
47
+ @complete="deployed"
48
+ skip-confirmation
49
+ auto-close-success
50
+ >
51
+ <template #start="{ start }">
52
+ <form @submit.stop.prevent="start" class="card borderless">
53
+ <div class="card">
54
+ <div>
55
+ <FormSelectFile @change="setImage" />
56
+ <p v-if="! isSmall" class="muted"><small>Note: This should be a small file, prefferably a simple SVG like <a href="/example-contract-icon.svg" target="_blank">this one (273 bytes)</a>. Try to make it less than 10kb.</small></p>
57
+ </div>
58
+ <FormGroup>
59
+ <FormInput v-model="title" placeholder="Title" required class="title" />
60
+ <FormInput v-model="symbol" placeholder="Symbol" required />
61
+ </FormGroup>
62
+ <FormInput v-model="description" placeholder="Description" />
63
+ </div>
64
+
65
+ <Actions class="borderless">
66
+ <Button type="submit">
67
67
  Deploy
68
68
  </Button>
69
- </template>
70
- </TransactionFlow>
71
- </Actions>
72
- </form>
69
+ </Actions>
70
+ </form>
71
+ </template>
72
+ </TransactionFlow>
73
73
 
74
74
  </PageFrame>
75
75
  </Authenticated>
@@ -7,10 +7,7 @@
7
7
  <HeaderSection v-if="isMe && collections.length">
8
8
  <h1>Your Collections</h1>
9
9
  <Actions>
10
- <Button :to="{ name: `id-create`, params: { id } }" class="small">
11
- <Icon type="plus" />
12
- <span>Collection</span>
13
- </Button>
10
+ <ButtonAddCollection :id="id" />
14
11
  </Actions>
15
12
  </HeaderSection>
16
13
  </template>
@@ -39,5 +36,3 @@ useMetaData({
39
36
  })
40
37
  </script>
41
38
 
42
- <style scoped>
43
- </style>
@@ -5,10 +5,7 @@
5
5
  <ProfileHeader :address="address">
6
6
  <template v-if="isMe" #before>
7
7
  <Actions>
8
- <Button :to="`https://app.ens.domains/${address}`" class="small">
9
- <Icon type="edit-2" />
10
- <span>Edit Profile</span>
11
- </Button>
8
+ <ButtonEditProfile :address="address" />
12
9
  </Actions>
13
10
  </template>
14
11
  </ProfileHeader>
@@ -1,5 +1,5 @@
1
1
  import { VueQueryPlugin } from '@tanstack/vue-query'
2
- import { http, cookieStorage, createConfig, createStorage, WagmiPlugin, fallback } from '@wagmi/vue'
2
+ import { http, cookieStorage, createConfig, createStorage, WagmiPlugin, fallback, type Config } from '@wagmi/vue'
3
3
  import { mainnet, sepolia, holesky, localhost } from '@wagmi/vue/chains'
4
4
  import { coinbaseWallet, injected, metaMask, walletConnect } from '@wagmi/vue/connectors'
5
5
  import type { CustomTransport, Transport } from 'viem'
@@ -16,7 +16,7 @@ export default defineNuxtPlugin(nuxtApp => {
16
16
 
17
17
  const transports = fallback(transportDefinitions)
18
18
 
19
- const wagmiConfig = createConfig({
19
+ const wagmiConfig: Config = createConfig({
20
20
  chains: [mainnet, sepolia, holesky, localhost],
21
21
  batch: {
22
22
  multicall: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@visualizevalue/mint-app-base",
3
- "version": "0.0.7",
3
+ "version": "0.1.0",
4
4
  "type": "module",
5
5
  "main": "./nuxt.config.ts",
6
6
  "dependencies": {
@@ -29,6 +29,7 @@
29
29
  "devDependencies": {
30
30
  "@types/node": "^22.5.4",
31
31
  "@vue/devtools-api": "^6.6.3",
32
+ "@wagmi/core": "^2.13.5",
32
33
  "eventemitter3": "^5.0.1",
33
34
  "nuxt": "latest",
34
35
  "typescript": "^5.5.4",
@@ -1,13 +0,0 @@
1
- .hide-scrollbar {
2
- -ms-overflow-style: none;
3
- scrollbar-width: none;
4
-
5
- &::-webkit-scrollbar {
6
- display: none;
7
- }
8
- }
9
-
10
- .scroll-x {
11
- overflow-x: auto !important;
12
- -webkit-overflow-scrolling: auto;
13
- }
@@ -1,14 +0,0 @@
1
- h1.display {
2
- font-size: var(--font-display);
3
- }
4
- h1.title {
5
- font-size: var(--font-title);
6
- }
7
-
8
- .lead {
9
- font-size: var(--font-lg);
10
- }
11
-
12
- .centered {
13
- text-align: center;
14
- }
@@ -1,24 +0,0 @@
1
- .centered {
2
- display: flex;
3
- flex-direction: column;
4
- align-items: center;
5
- justify-content: center;
6
- gap: var(--spacer);
7
- }
8
-
9
- .muted {
10
- color: var(--muted) !important;
11
- }
12
-
13
- .muted-light {
14
- color: var(--muted-light) !important;
15
-
16
- &a, &.button,
17
- > a, > .button {
18
- transition: color var(--speed);
19
-
20
- :--highlight {
21
- color: var(--color) !important;
22
- }
23
- }
24
- }
@@ -1,61 +0,0 @@
1
- <template>
2
- <div class="avatar">
3
- <Image v-if="user.pfp" :image="user.pfp" class="bordered round" />
4
- <span v-else>{{ user.domain.slice(0, 2) }}</span>
5
- </div>
6
- </template>
7
-
8
- <script setup>
9
- const { user } = defineProps({
10
- user: Object,
11
- })
12
- </script>
13
-
14
- <style scoped>
15
- .avatar {
16
- display: flex;
17
- align-items: center;
18
- justify-content: center;
19
- height: 0;
20
- padding-bottom: 100%;
21
- position: relative;
22
- container-type: inline-size;
23
- container-name: avatar;
24
-
25
- > * {
26
- position: absolute;
27
- width: 100%;
28
- height: 100%;
29
- top: 0;
30
- left: 0;
31
- overflow: hidden;
32
- }
33
-
34
- > span {
35
- font-family: var(--font-family-ui);
36
- text-transform: var(--text-transform-ui);
37
- font-size: var(--font-sm);
38
- color: var(--white);
39
- text-align: center;
40
- display: flex;
41
- align-items: center;
42
- justify-content: center;
43
- font-size: var(--font-sm);
44
- background: var(--gray-z-2);
45
- border-radius: 50%;
46
- border: var(--border);
47
-
48
- @container avatar (min-width: 2rem) {
49
- font-size: var(--font-base);
50
- }
51
-
52
- @container avatar (min-width: 2.75rem) {
53
- font-size: var(--font-lg);
54
- }
55
-
56
- @container avatar (min-width: 3.5rem) {
57
- font-size: var(--font-xl);
58
- }
59
- }
60
- }
61
- </style>
@@ -1,153 +0,0 @@
1
- <template>
2
- <div v-if="countDownComplete" class="complete countdown">
3
- <slot name="complete"></slot>
4
- </div>
5
- <div v-else class="countdown">
6
- <slot name="header"></slot>
7
- <span v-if="timeUntil">{{ countdown }}</span>
8
- <span v-else>_d _h _m _s</span>
9
- <slot />
10
- <slot name="footer" />
11
- </div>
12
- </template>
13
-
14
- <script>
15
- export default {
16
- emits: ['start', 'complete'],
17
-
18
- props: {
19
- adjustSeconds: {
20
- type: Number,
21
- default: 0,
22
- },
23
- until: {
24
- type: Number,
25
- default: 1632552931,
26
- },
27
- minimal: {
28
- type: Boolean,
29
- default: false,
30
- },
31
- },
32
-
33
- data () {
34
- return {
35
- timeUntil: null,
36
- interval: null,
37
- }
38
- },
39
-
40
- computed: {
41
- countDownComplete () {
42
- return this.timeUntil <= 0
43
- },
44
-
45
- years () {
46
- return Math.floor(this.timeUntil / 60 / 60 / 24 / 365)
47
- },
48
-
49
- accountedForYears () {
50
- return this.years * 60 * 60 * 24 * 365
51
- },
52
-
53
- days () {
54
- return Math.floor((this.timeUntil - this.accountedForYears) / 60 / 60 / 24)
55
- },
56
-
57
- accountedForDays () {
58
- return this.days * 60 * 60 * 24
59
- },
60
-
61
- hours () {
62
- return Math.floor((this.timeUntil - this.accountedForYears - this.accountedForDays) / 60 / 60)
63
- },
64
-
65
- accountedForHours () {
66
- return this.hours * 60 * 60
67
- },
68
-
69
- minutes () {
70
- return Math.floor((this.timeUntil - this.accountedForYears - this.accountedForDays - this.accountedForHours) / 60)
71
- },
72
-
73
- totalSeconds () {
74
- return this.timeUntil / 60
75
- },
76
-
77
- seconds () {
78
- return this.timeUntil % 60
79
- },
80
-
81
- countdown () {
82
- const yearsString = this.years + 'y'
83
- const daysString = this.days + 'd'
84
- const hoursString = this.hours + 'h'
85
- const minutesString = this.minutes + 'm'
86
- const secondsString = this.seconds + 's'
87
-
88
- return [
89
- this.years && yearsString,
90
- this.days && daysString,
91
- this.hours && hoursString,
92
- minutesString,
93
- (!this.minimal || this.totalSeconds < 600) && secondsString,
94
- ].filter(i => !!i).join(' ')
95
- }
96
- },
97
-
98
- mounted () {
99
- this.update()
100
- this.interval = setInterval(() => this.update(), 1000)
101
- },
102
-
103
- beforeUnmount () {
104
- clearInterval(this.interval)
105
- },
106
-
107
- methods: {
108
- update () {
109
- let start = this.until
110
-
111
- start += this.adjustSeconds
112
-
113
- this.timeUntil = start - nowInSeconds()
114
-
115
- if (this.countDownComplete) {
116
- this.$emit('complete')
117
- clearInterval(this.interval)
118
- }
119
- },
120
- },
121
-
122
- }
123
- </script>
124
-
125
- <style scoped>
126
- .countdown {
127
- text-align: center;
128
-
129
- small,
130
- span {
131
- display: block;
132
- }
133
-
134
- > *:first-child {
135
- margin-top: 0;
136
- }
137
-
138
- > *:last-child {
139
- margin-bottom: 0;
140
- }
141
-
142
- &.inline,
143
- &.inline * {
144
- display: inline !important;
145
- text-align: left !important;
146
- font-size: 1em !important;
147
- }
148
- }
149
-
150
- .complete {
151
- padding: 0;
152
- }
153
- </style>
@@ -1,29 +0,0 @@
1
- <template>
2
- <NuxtLink :to="to" :title="title">
3
- <Icon :type="type" />
4
- </NuxtLink>
5
- </template>
6
-
7
- <script setup>
8
- defineProps({
9
- to: String,
10
- title: String,
11
- type: String,
12
- })
13
- </script>
14
-
15
- <style scoped>
16
- a {
17
- color: var(--muted);
18
- transition: all var(--speed);
19
- width: var(--size-5);
20
- height: var(--size-5);
21
- display: flex;
22
- align-items: center;
23
- justify-content: center;
24
-
25
- &:--highlight {
26
- color: var(--color);
27
- }
28
- }
29
- </style>