@1001-digital/components 1.2.2 → 1.3.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.
- package/package.json +2 -22
- package/src/base/components/AppShell.vue +60 -0
- package/src/base/components/BottomNav.vue +44 -0
- package/src/base/components/Sidebar.vue +282 -0
- package/src/index.ts +3 -3
- package/src/evm/assets/wallets/coinbase.svg +0 -4
- package/src/evm/assets/wallets/in-app.svg +0 -5
- package/src/evm/assets/wallets/metamask.svg +0 -1
- package/src/evm/assets/wallets/phantom.svg +0 -4
- package/src/evm/assets/wallets/rabby.svg +0 -24
- package/src/evm/assets/wallets/rainbow.svg +0 -59
- package/src/evm/assets/wallets/safe.png +0 -0
- package/src/evm/assets/wallets/walletconnect.svg +0 -1
- package/src/evm/components/EvmAccount.vue +0 -28
- package/src/evm/components/EvmAvatar.vue +0 -62
- package/src/evm/components/EvmConnect.vue +0 -303
- package/src/evm/components/EvmConnectDialog.vue +0 -75
- package/src/evm/components/EvmConnectionStatus.vue +0 -13
- package/src/evm/components/EvmConnectorQR.vue +0 -86
- package/src/evm/components/EvmInAppWalletSetup.vue +0 -251
- package/src/evm/components/EvmMetaMaskQR.vue +0 -34
- package/src/evm/components/EvmProfile.vue +0 -186
- package/src/evm/components/EvmSeedPhraseInput.vue +0 -193
- package/src/evm/components/EvmSiwe.vue +0 -190
- package/src/evm/components/EvmSiweDialog.vue +0 -93
- package/src/evm/components/EvmSwitchNetwork.vue +0 -132
- package/src/evm/components/EvmTransactionFlow.vue +0 -353
- package/src/evm/components/EvmWalletConnectQR.vue +0 -13
- package/src/evm/components/EvmWalletConnectWallets.vue +0 -200
- package/src/evm/composables/base.ts +0 -7
- package/src/evm/composables/chainId.ts +0 -42
- package/src/evm/composables/ens.ts +0 -113
- package/src/evm/composables/gasPrice.ts +0 -37
- package/src/evm/composables/priceFeed.ts +0 -116
- package/src/evm/composables/siwe.ts +0 -89
- package/src/evm/composables/uri.ts +0 -12
- package/src/evm/composables/walletExplorer.ts +0 -130
- package/src/evm/config.ts +0 -35
- package/src/evm/connectors/inAppWallet.ts +0 -5
- package/src/evm/index.ts +0 -60
- package/src/evm/utils/addresses.ts +0 -6
- package/src/evm/utils/cache.ts +0 -59
- package/src/evm/utils/chains.ts +0 -32
- package/src/evm/utils/ens.ts +0 -116
- package/src/evm/utils/format-eth.ts +0 -15
- package/src/evm/utils/price.ts +0 -17
- package/src/evm/utils/siwe.ts +0 -70
- package/src/evm/utils/uri.ts +0 -24
|
@@ -1,353 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<slot
|
|
3
|
-
:start="start"
|
|
4
|
-
:step="step"
|
|
5
|
-
:open="open"
|
|
6
|
-
name="start"
|
|
7
|
-
></slot>
|
|
8
|
-
|
|
9
|
-
<Dialog
|
|
10
|
-
v-model:open="open"
|
|
11
|
-
:closable="canDismiss"
|
|
12
|
-
:click-outside="canDismiss"
|
|
13
|
-
:title="text.title[step]"
|
|
14
|
-
class="transaction-flow"
|
|
15
|
-
compat
|
|
16
|
-
>
|
|
17
|
-
<slot name="before" />
|
|
18
|
-
|
|
19
|
-
<Loading
|
|
20
|
-
v-if="step === 'requesting'"
|
|
21
|
-
spinner
|
|
22
|
-
stacked
|
|
23
|
-
:txt="connector?.name
|
|
24
|
-
? `Requesting signature from ${connector.name}...`
|
|
25
|
-
: text.lead[step] || ''"
|
|
26
|
-
/>
|
|
27
|
-
|
|
28
|
-
<p v-if="step !== 'requesting' && step !== 'error' && text.lead[step]">
|
|
29
|
-
{{ text.lead[step] }}
|
|
30
|
-
</p>
|
|
31
|
-
|
|
32
|
-
<Alert
|
|
33
|
-
v-if="error"
|
|
34
|
-
type="error"
|
|
35
|
-
>
|
|
36
|
-
<p v-if="text.lead[step]">{{ text.lead[step] }}</p>
|
|
37
|
-
<p>{{ error }}</p>
|
|
38
|
-
</Alert>
|
|
39
|
-
|
|
40
|
-
<slot
|
|
41
|
-
:name="step"
|
|
42
|
-
:cancel="cancel"
|
|
43
|
-
></slot>
|
|
44
|
-
|
|
45
|
-
<template #footer>
|
|
46
|
-
<template v-if="step === 'chain'">
|
|
47
|
-
<Button
|
|
48
|
-
@click="cancel"
|
|
49
|
-
class="secondary"
|
|
50
|
-
>Cancel</Button
|
|
51
|
-
>
|
|
52
|
-
</template>
|
|
53
|
-
|
|
54
|
-
<template v-if="step === 'confirm' || step === 'error'">
|
|
55
|
-
<Button
|
|
56
|
-
@click="cancel"
|
|
57
|
-
class="secondary"
|
|
58
|
-
>Cancel</Button
|
|
59
|
-
>
|
|
60
|
-
<Button @click="() => initializeRequest()">
|
|
61
|
-
{{ text.action[step] || 'Execute' }}
|
|
62
|
-
</Button>
|
|
63
|
-
</template>
|
|
64
|
-
|
|
65
|
-
<slot
|
|
66
|
-
name="actions"
|
|
67
|
-
:step="step"
|
|
68
|
-
:cancel="cancel"
|
|
69
|
-
:execute="() => initializeRequest()"
|
|
70
|
-
:tx-link="txLink"
|
|
71
|
-
/>
|
|
72
|
-
</template>
|
|
73
|
-
</Dialog>
|
|
74
|
-
</template>
|
|
75
|
-
|
|
76
|
-
<script setup lang="ts">
|
|
77
|
-
import { ref, computed, watch, onBeforeUnmount } from 'vue'
|
|
78
|
-
import { waitForTransactionReceipt, watchChainId } from '@wagmi/core'
|
|
79
|
-
import { useConfig, useConnection, type Config } from '@wagmi/vue'
|
|
80
|
-
import type { TransactionReceipt, Hash } from 'viem'
|
|
81
|
-
import Dialog from '../../base/components/Dialog.vue'
|
|
82
|
-
import Loading from '../../base/components/Loading.vue'
|
|
83
|
-
import Alert from '../../base/components/Alert.vue'
|
|
84
|
-
import Button from '../../base/components/Button.vue'
|
|
85
|
-
import { useEnsureChainIdCheck, useBlockExplorer } from '../composables/chainId'
|
|
86
|
-
import { useToast } from '../../base/composables/toast'
|
|
87
|
-
import { delay } from '../../base/utils/time'
|
|
88
|
-
|
|
89
|
-
interface TextConfig {
|
|
90
|
-
title?: Record<string, string>
|
|
91
|
-
lead?: Record<string, string>
|
|
92
|
-
action?: Record<string, string>
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
type Step =
|
|
96
|
-
| 'idle'
|
|
97
|
-
| 'confirm'
|
|
98
|
-
| 'chain'
|
|
99
|
-
| 'requesting'
|
|
100
|
-
| 'waiting'
|
|
101
|
-
| 'complete'
|
|
102
|
-
| 'error'
|
|
103
|
-
|
|
104
|
-
const defaultText = {
|
|
105
|
-
title: {
|
|
106
|
-
confirm: 'Confirm Transaction',
|
|
107
|
-
chain: 'Switch Network',
|
|
108
|
-
requesting: 'Requesting',
|
|
109
|
-
waiting: 'Processing',
|
|
110
|
-
complete: 'Complete',
|
|
111
|
-
error: 'Error',
|
|
112
|
-
},
|
|
113
|
-
lead: {
|
|
114
|
-
confirm: 'Please review and confirm this transaction.',
|
|
115
|
-
chain: 'Please switch to the correct network to continue.',
|
|
116
|
-
requesting: 'Requesting transaction signature...',
|
|
117
|
-
waiting: 'Waiting for transaction confirmation...',
|
|
118
|
-
complete: 'Transaction confirmed successfully.',
|
|
119
|
-
},
|
|
120
|
-
action: {
|
|
121
|
-
confirm: 'Execute',
|
|
122
|
-
error: 'Try Again',
|
|
123
|
-
},
|
|
124
|
-
} satisfies TextConfig
|
|
125
|
-
|
|
126
|
-
const props = withDefaults(
|
|
127
|
-
defineProps<{
|
|
128
|
-
chain?: string
|
|
129
|
-
text?: TextConfig
|
|
130
|
-
request?: () => Promise<Hash>
|
|
131
|
-
delayAfter?: number
|
|
132
|
-
delayAutoclose?: number
|
|
133
|
-
skipConfirmation?: boolean
|
|
134
|
-
autoCloseSuccess?: boolean
|
|
135
|
-
dismissable?: boolean
|
|
136
|
-
}>(),
|
|
137
|
-
{
|
|
138
|
-
delayAfter: 2000,
|
|
139
|
-
delayAutoclose: 2000,
|
|
140
|
-
skipConfirmation: false,
|
|
141
|
-
autoCloseSuccess: true,
|
|
142
|
-
dismissable: true,
|
|
143
|
-
},
|
|
144
|
-
)
|
|
145
|
-
|
|
146
|
-
function isUserRejection(e: unknown): boolean {
|
|
147
|
-
const re = /reject|denied|cancel/i
|
|
148
|
-
let current = e as Record<string, unknown> | undefined
|
|
149
|
-
while (current) {
|
|
150
|
-
if ((current as { code?: number }).code === 4001) return true
|
|
151
|
-
if (re.test((current as { details?: string }).details || '')) return true
|
|
152
|
-
current = current.cause as Record<string, unknown> | undefined
|
|
153
|
-
}
|
|
154
|
-
return false
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const checkChain = useEnsureChainIdCheck(props.chain)
|
|
158
|
-
|
|
159
|
-
const wagmiConfig = useConfig()
|
|
160
|
-
const { connector } = useConnection()
|
|
161
|
-
const blockExplorer = useBlockExplorer(props.chain)
|
|
162
|
-
const toast = useToast()
|
|
163
|
-
|
|
164
|
-
const emit = defineEmits<{
|
|
165
|
-
complete: [receipt: TransactionReceipt]
|
|
166
|
-
cancel: []
|
|
167
|
-
}>()
|
|
168
|
-
|
|
169
|
-
const text = computed<Required<TextConfig>>(() => ({
|
|
170
|
-
title: { ...defaultText.title, ...props.text?.title },
|
|
171
|
-
lead: { ...defaultText.lead, ...props.text?.lead },
|
|
172
|
-
action: { ...defaultText.action, ...props.text?.action },
|
|
173
|
-
}))
|
|
174
|
-
|
|
175
|
-
const step = ref<Step>('idle')
|
|
176
|
-
|
|
177
|
-
const open = computed({
|
|
178
|
-
get: () => step.value !== 'idle',
|
|
179
|
-
set: (v) => {
|
|
180
|
-
if (!v) {
|
|
181
|
-
step.value = 'idle'
|
|
182
|
-
error.value = ''
|
|
183
|
-
}
|
|
184
|
-
},
|
|
185
|
-
})
|
|
186
|
-
|
|
187
|
-
watchChainId(wagmiConfig as Config, {
|
|
188
|
-
async onChange() {
|
|
189
|
-
if (step.value !== 'chain') return
|
|
190
|
-
|
|
191
|
-
if (await checkChain()) {
|
|
192
|
-
initializeRequest()
|
|
193
|
-
}
|
|
194
|
-
},
|
|
195
|
-
})
|
|
196
|
-
|
|
197
|
-
const cachedRequest = ref(props.request)
|
|
198
|
-
watch(
|
|
199
|
-
() => props.request,
|
|
200
|
-
(v) => {
|
|
201
|
-
cachedRequest.value = v
|
|
202
|
-
},
|
|
203
|
-
)
|
|
204
|
-
|
|
205
|
-
const error = ref('')
|
|
206
|
-
const tx = ref<Hash | null>(null)
|
|
207
|
-
const receipt = ref<TransactionReceipt | null>(null)
|
|
208
|
-
const txLink = computed(() => `${blockExplorer}/tx/${tx.value}`)
|
|
209
|
-
|
|
210
|
-
let mounted = true
|
|
211
|
-
let progressTimer: ReturnType<typeof setInterval> | undefined
|
|
212
|
-
|
|
213
|
-
onBeforeUnmount(() => {
|
|
214
|
-
mounted = false
|
|
215
|
-
clearInterval(progressTimer)
|
|
216
|
-
})
|
|
217
|
-
|
|
218
|
-
const canDismiss = computed(
|
|
219
|
-
() => props.dismissable && step.value !== 'requesting',
|
|
220
|
-
)
|
|
221
|
-
|
|
222
|
-
const initializeRequest = async (request = cachedRequest.value) => {
|
|
223
|
-
cachedRequest.value = request
|
|
224
|
-
error.value = ''
|
|
225
|
-
tx.value = null
|
|
226
|
-
receipt.value = null
|
|
227
|
-
step.value = 'confirm'
|
|
228
|
-
|
|
229
|
-
if (!(await checkChain())) {
|
|
230
|
-
step.value = 'chain'
|
|
231
|
-
return
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// Phase 1: Signing (dialog)
|
|
235
|
-
try {
|
|
236
|
-
step.value = 'requesting'
|
|
237
|
-
tx.value = await request!()
|
|
238
|
-
} catch (e: unknown) {
|
|
239
|
-
if (isUserRejection(e)) {
|
|
240
|
-
error.value = 'Transaction rejected by user.'
|
|
241
|
-
} else {
|
|
242
|
-
const err = e as { shortMessage?: string }
|
|
243
|
-
error.value = err.shortMessage || 'Error submitting transaction request.'
|
|
244
|
-
}
|
|
245
|
-
step.value = 'error'
|
|
246
|
-
console.log(e)
|
|
247
|
-
return
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// Phase 2: Receipt (toast)
|
|
251
|
-
step.value = 'idle'
|
|
252
|
-
|
|
253
|
-
const link = `${blockExplorer}/tx/${tx.value}`
|
|
254
|
-
const toastId = toast.add({
|
|
255
|
-
variant: 'info',
|
|
256
|
-
title: text.value.title.waiting,
|
|
257
|
-
description: text.value.lead.waiting,
|
|
258
|
-
duration: Infinity,
|
|
259
|
-
loading: true,
|
|
260
|
-
progress: 0,
|
|
261
|
-
action: {
|
|
262
|
-
label: 'View on Block Explorer',
|
|
263
|
-
onClick: () => window.open(link, '_blank'),
|
|
264
|
-
persistent: true,
|
|
265
|
-
},
|
|
266
|
-
})
|
|
267
|
-
|
|
268
|
-
const start = Date.now()
|
|
269
|
-
progressTimer = setInterval(() => {
|
|
270
|
-
const elapsed = (Date.now() - start) / 1000
|
|
271
|
-
toast.update(toastId, { progress: Math.round(90 * (1 - Math.exp(-elapsed / 15))) })
|
|
272
|
-
}, 500)
|
|
273
|
-
|
|
274
|
-
try {
|
|
275
|
-
const receiptObject = await waitForTransactionReceipt(
|
|
276
|
-
wagmiConfig as Config,
|
|
277
|
-
{ hash: tx.value },
|
|
278
|
-
)
|
|
279
|
-
clearInterval(progressTimer)
|
|
280
|
-
toast.update(toastId, { progress: 100, loading: false })
|
|
281
|
-
await delay(props.delayAfter)
|
|
282
|
-
receipt.value = receiptObject
|
|
283
|
-
emit('complete', receiptObject)
|
|
284
|
-
|
|
285
|
-
toast.update(toastId, {
|
|
286
|
-
variant: 'success',
|
|
287
|
-
title: text.value.title.complete,
|
|
288
|
-
description: text.value.lead.complete,
|
|
289
|
-
progress: false,
|
|
290
|
-
...(props.autoCloseSuccess && { duration: props.delayAutoclose }),
|
|
291
|
-
})
|
|
292
|
-
} catch (e: unknown) {
|
|
293
|
-
clearInterval(progressTimer)
|
|
294
|
-
const err = e as { shortMessage?: string }
|
|
295
|
-
if (mounted) {
|
|
296
|
-
toast.dismiss(toastId)
|
|
297
|
-
error.value = err.shortMessage || 'Transaction failed.'
|
|
298
|
-
step.value = 'error'
|
|
299
|
-
} else {
|
|
300
|
-
toast.update(toastId, {
|
|
301
|
-
variant: 'error',
|
|
302
|
-
title: text.value.title.error,
|
|
303
|
-
description: err.shortMessage || 'Transaction failed.',
|
|
304
|
-
loading: false,
|
|
305
|
-
progress: false,
|
|
306
|
-
})
|
|
307
|
-
}
|
|
308
|
-
console.log(e)
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
return receipt.value
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
const start = () => {
|
|
315
|
-
if (props.skipConfirmation && step.value === 'idle') {
|
|
316
|
-
initializeRequest()
|
|
317
|
-
return
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
step.value = 'confirm'
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
const cancel = () => {
|
|
324
|
-
step.value = 'idle'
|
|
325
|
-
error.value = ''
|
|
326
|
-
emit('cancel')
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
defineExpose({
|
|
330
|
-
initializeRequest,
|
|
331
|
-
})
|
|
332
|
-
</script>
|
|
333
|
-
|
|
334
|
-
<style>
|
|
335
|
-
.transaction-flow > section {
|
|
336
|
-
display: grid;
|
|
337
|
-
gap: var(--spacer);
|
|
338
|
-
|
|
339
|
-
.text {
|
|
340
|
-
width: 100%;
|
|
341
|
-
height: min-content;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
p {
|
|
345
|
-
white-space: pre-wrap;
|
|
346
|
-
width: 100%;
|
|
347
|
-
|
|
348
|
-
a {
|
|
349
|
-
text-decoration: underline;
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
</style>
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<EvmConnectorQR :uri="uri">
|
|
3
|
-
<template #instruction> Scan the code in your wallet application </template>
|
|
4
|
-
</EvmConnectorQR>
|
|
5
|
-
</template>
|
|
6
|
-
|
|
7
|
-
<script setup lang="ts">
|
|
8
|
-
import EvmConnectorQR from './EvmConnectorQR.vue'
|
|
9
|
-
|
|
10
|
-
defineProps<{
|
|
11
|
-
uri: string
|
|
12
|
-
}>()
|
|
13
|
-
</script>
|
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="wc-wallets">
|
|
3
|
-
<EvmConnectorQR :uri="uri">
|
|
4
|
-
<template #instruction> Scan with your wallet app </template>
|
|
5
|
-
</EvmConnectorQR>
|
|
6
|
-
|
|
7
|
-
<div class="separator">
|
|
8
|
-
<span>Or choose a wallet</span>
|
|
9
|
-
</div>
|
|
10
|
-
|
|
11
|
-
<FormItem>
|
|
12
|
-
<template #prefix>
|
|
13
|
-
<Icon type="lucide:search" />
|
|
14
|
-
</template>
|
|
15
|
-
<input
|
|
16
|
-
v-model="searchQuery"
|
|
17
|
-
type="text"
|
|
18
|
-
placeholder="Search wallets"
|
|
19
|
-
@input="onSearchInput"
|
|
20
|
-
/>
|
|
21
|
-
</FormItem>
|
|
22
|
-
|
|
23
|
-
<div
|
|
24
|
-
v-if="displayedWallets.length > 0"
|
|
25
|
-
class="wallet-grid"
|
|
26
|
-
>
|
|
27
|
-
<Button
|
|
28
|
-
v-for="wallet in displayedWallets"
|
|
29
|
-
:key="wallet.id"
|
|
30
|
-
@click="openWallet(wallet)"
|
|
31
|
-
class="wallet-card tertiary"
|
|
32
|
-
>
|
|
33
|
-
<img
|
|
34
|
-
:src="explorer.imageUrl(wallet)"
|
|
35
|
-
:alt="wallet.name"
|
|
36
|
-
loading="lazy"
|
|
37
|
-
/>
|
|
38
|
-
<span>{{ wallet.name }}</span>
|
|
39
|
-
</Button>
|
|
40
|
-
</div>
|
|
41
|
-
|
|
42
|
-
<p
|
|
43
|
-
v-if="
|
|
44
|
-
searchQuery &&
|
|
45
|
-
!explorer.searching.value &&
|
|
46
|
-
displayedWallets.length === 0
|
|
47
|
-
"
|
|
48
|
-
class="empty-state"
|
|
49
|
-
>
|
|
50
|
-
No wallets found
|
|
51
|
-
</p>
|
|
52
|
-
|
|
53
|
-
<Loading
|
|
54
|
-
v-if="explorer.loading.value || explorer.searching.value"
|
|
55
|
-
spinner
|
|
56
|
-
stacked
|
|
57
|
-
txt=""
|
|
58
|
-
/>
|
|
59
|
-
|
|
60
|
-
<Button
|
|
61
|
-
class="link muted small"
|
|
62
|
-
@click="$emit('back')"
|
|
63
|
-
>
|
|
64
|
-
<Icon type="chevron-left" />
|
|
65
|
-
<span>Back</span>
|
|
66
|
-
</Button>
|
|
67
|
-
</div>
|
|
68
|
-
</template>
|
|
69
|
-
|
|
70
|
-
<script setup lang="ts">
|
|
71
|
-
import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
|
|
72
|
-
import Button from '../../base/components/Button.vue'
|
|
73
|
-
import FormItem from '../../base/components/FormItem.vue'
|
|
74
|
-
import Icon from '../../base/components/Icon.vue'
|
|
75
|
-
import Loading from '../../base/components/Loading.vue'
|
|
76
|
-
import EvmConnectorQR from './EvmConnectorQR.vue'
|
|
77
|
-
import {
|
|
78
|
-
useWalletExplorer,
|
|
79
|
-
type ExplorerWallet,
|
|
80
|
-
} from '../composables/walletExplorer'
|
|
81
|
-
|
|
82
|
-
const props = defineProps<{
|
|
83
|
-
uri: string
|
|
84
|
-
}>()
|
|
85
|
-
|
|
86
|
-
defineEmits<{
|
|
87
|
-
back: []
|
|
88
|
-
}>()
|
|
89
|
-
|
|
90
|
-
const explorer = useWalletExplorer()
|
|
91
|
-
const searchQuery = ref('')
|
|
92
|
-
let searchTimeout: ReturnType<typeof setTimeout>
|
|
93
|
-
|
|
94
|
-
const TOP_COUNT = 9
|
|
95
|
-
|
|
96
|
-
const displayedWallets = computed(() => {
|
|
97
|
-
if (searchQuery.value) return explorer.searchResults.value
|
|
98
|
-
|
|
99
|
-
const recents = explorer.recentWallets.value
|
|
100
|
-
const recentIds = new Set(recents.map((w) => w.id))
|
|
101
|
-
const rest = explorer.wallets.value
|
|
102
|
-
.filter((w) => !recentIds.has(w.id))
|
|
103
|
-
.slice(0, TOP_COUNT - recents.length)
|
|
104
|
-
|
|
105
|
-
return [...recents, ...rest]
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
function openWallet(wallet: ExplorerWallet) {
|
|
109
|
-
const href = explorer.walletHref(wallet, props.uri)
|
|
110
|
-
if (href) {
|
|
111
|
-
window.open(href, '_blank', 'noreferrer')
|
|
112
|
-
}
|
|
113
|
-
explorer.addRecent(wallet.id)
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function onSearchInput() {
|
|
117
|
-
clearTimeout(searchTimeout)
|
|
118
|
-
searchTimeout = setTimeout(() => {
|
|
119
|
-
if (searchQuery.value) {
|
|
120
|
-
explorer.search(searchQuery.value)
|
|
121
|
-
}
|
|
122
|
-
}, 300)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
onBeforeUnmount(() => {
|
|
126
|
-
clearTimeout(searchTimeout)
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
onMounted(() => {
|
|
130
|
-
explorer.fetchNextPage()
|
|
131
|
-
})
|
|
132
|
-
</script>
|
|
133
|
-
|
|
134
|
-
<style scoped>
|
|
135
|
-
.wc-wallets {
|
|
136
|
-
display: grid;
|
|
137
|
-
gap: var(--spacer);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/* Separator */
|
|
141
|
-
.separator {
|
|
142
|
-
display: flex;
|
|
143
|
-
align-items: center;
|
|
144
|
-
gap: var(--spacer-sm);
|
|
145
|
-
@mixin ui-font;
|
|
146
|
-
color: var(--muted);
|
|
147
|
-
font-size: var(--font-sm);
|
|
148
|
-
|
|
149
|
-
&::before,
|
|
150
|
-
&::after {
|
|
151
|
-
content: '';
|
|
152
|
-
flex: 1;
|
|
153
|
-
border-top: var(--border);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/* Wallet grid */
|
|
158
|
-
.wallet-grid {
|
|
159
|
-
display: grid;
|
|
160
|
-
grid-template-columns: repeat(auto-fill, minmax(6rem, 1fr));
|
|
161
|
-
gap: var(--spacer-sm);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
.wallet-card {
|
|
165
|
-
display: flex;
|
|
166
|
-
flex-direction: column;
|
|
167
|
-
align-items: center;
|
|
168
|
-
gap: var(--spacer-sm);
|
|
169
|
-
block-size: auto;
|
|
170
|
-
min-inline-size: 0;
|
|
171
|
-
inline-size: 100%;
|
|
172
|
-
|
|
173
|
-
img {
|
|
174
|
-
width: var(--size-6);
|
|
175
|
-
height: var(--size-6);
|
|
176
|
-
border-radius: var(--border-radius);
|
|
177
|
-
margin-top: var(--spacer-xs);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
span {
|
|
181
|
-
font-size: var(--font-xs);
|
|
182
|
-
text-align: center;
|
|
183
|
-
overflow: hidden;
|
|
184
|
-
text-overflow: ellipsis;
|
|
185
|
-
white-space: nowrap;
|
|
186
|
-
max-width: 100%;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
.link.muted {
|
|
191
|
-
justify-self: center;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/* Empty state */
|
|
195
|
-
.empty-state {
|
|
196
|
-
text-align: center;
|
|
197
|
-
@mixin ui-font;
|
|
198
|
-
color: var(--muted);
|
|
199
|
-
}
|
|
200
|
-
</style>
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { useConnection, useSwitchChain } from '@wagmi/vue'
|
|
2
|
-
import { useEvmConfig } from '../config'
|
|
3
|
-
|
|
4
|
-
interface ChainConfig {
|
|
5
|
-
id: number
|
|
6
|
-
blockExplorer: string
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export const useChainConfig = (key?: string): ChainConfig => {
|
|
10
|
-
const evmConfig = useEvmConfig()
|
|
11
|
-
const resolvedKey = key || evmConfig.defaultChain || 'mainnet'
|
|
12
|
-
const chain = evmConfig.chains[resolvedKey]
|
|
13
|
-
|
|
14
|
-
return {
|
|
15
|
-
id: chain?.id ?? 1,
|
|
16
|
-
blockExplorer: chain?.blockExplorer ?? 'https://etherscan.io',
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export const useMainChainId = () => useChainConfig().id
|
|
21
|
-
|
|
22
|
-
export const useBlockExplorer = (key?: string) =>
|
|
23
|
-
useChainConfig(key).blockExplorer
|
|
24
|
-
|
|
25
|
-
export const useEnsureChainIdCheck = (key?: string) => {
|
|
26
|
-
const chainId = useChainConfig(key).id
|
|
27
|
-
const { mutateAsync: switchChain } = useSwitchChain()
|
|
28
|
-
const { chainId: currentChainId } = useConnection()
|
|
29
|
-
|
|
30
|
-
return async () => {
|
|
31
|
-
if (chainId === currentChainId.value) {
|
|
32
|
-
return true
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
try {
|
|
36
|
-
await switchChain({ chainId })
|
|
37
|
-
return true
|
|
38
|
-
} catch {
|
|
39
|
-
return false
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|