@meddleware/token-deployer-ui 0.0.2 → 0.0.4
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 +3 -1
- package/src/App.vue +1 -2
- package/src/component-styles.css +257 -0
- package/src/components/ConfigForm.vue +104 -93
- package/src/components/GithubPush.vue +4 -4
- package/src/components/IconPicker.vue +19 -73
- package/src/components/LicensePicker.vue +7 -9
- package/src/components/ResultPanel.vue +2 -2
- package/src/components/ReviewPanel.vue +3 -3
- package/src/components/TokenDeployerView.vue +81 -14
- package/src/components/WalletBar.vue +6 -7
- package/src/components/WalrusBlobBrowser.vue +2 -2
- package/src/components/WalrusIconUpload.vue +4 -4
- package/src/index.ts +1 -0
- package/src/main.ts +5 -1
- package/src/styles.css +3 -335
- package/src/components/AppNotice.vue +0 -15
- package/src/components/ColorModeControl.vue +0 -81
- package/src/components/FieldHint.vue +0 -79
- package/src/components/FormField.vue +0 -28
- package/src/components/FormSelect.vue +0 -43
- package/src/composables/useColorMode.ts +0 -76
|
@@ -14,8 +14,7 @@ import {
|
|
|
14
14
|
} from '../lib/accessGate.js'
|
|
15
15
|
import type { WalrusNetwork } from '../lib/walrus.js'
|
|
16
16
|
import type { Network } from '../lib/types.js'
|
|
17
|
-
import
|
|
18
|
-
import FieldHint from './FieldHint.vue'
|
|
17
|
+
import { UiNotice, UiFieldHint, UiSegmentedControl } from '@meddleware/ui'
|
|
19
18
|
import WalrusBlobBrowser from './WalrusBlobBrowser.vue'
|
|
20
19
|
import walrusWasmUrl from '@mysten/walrus-wasm/web/walrus_wasm_bg.wasm?url'
|
|
21
20
|
|
|
@@ -77,7 +76,7 @@ async function purchaseAccess(): Promise<void> {
|
|
|
77
76
|
}
|
|
78
77
|
}
|
|
79
78
|
|
|
80
|
-
const tab = ref
|
|
79
|
+
const tab = ref('url')
|
|
81
80
|
|
|
82
81
|
// Upload state
|
|
83
82
|
const uploading = ref(false)
|
|
@@ -229,26 +228,16 @@ function onBrowseSelect(url: string): void {
|
|
|
229
228
|
<fieldset class="icon-picker">
|
|
230
229
|
<legend>Icon <span class="hint">(optional)</span></legend>
|
|
231
230
|
|
|
232
|
-
<
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
URL
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
Upload to Walrus
|
|
243
|
-
</label>
|
|
244
|
-
<label
|
|
245
|
-
:class="{ active: tab === 'browse', disabled: !isWalrusNetwork }"
|
|
246
|
-
:title="isWalrusNetwork ? undefined : 'Not available on localnet'"
|
|
247
|
-
>
|
|
248
|
-
<input type="radio" v-model="tab" value="browse" :disabled="!isWalrusNetwork" />
|
|
249
|
-
My Walrus blobs
|
|
250
|
-
</label>
|
|
251
|
-
</div>
|
|
231
|
+
<UiSegmentedControl
|
|
232
|
+
v-model="tab"
|
|
233
|
+
:options="[
|
|
234
|
+
{ id: 'url', label: 'URL' },
|
|
235
|
+
{ id: 'upload', label: 'Upload to Walrus', disabled: !isWalrusNetwork, title: isWalrusNetwork ? undefined : 'Not available on localnet' },
|
|
236
|
+
{ id: 'browse', label: 'My Walrus blobs', disabled: !isWalrusNetwork, title: isWalrusNetwork ? undefined : 'Not available on localnet' },
|
|
237
|
+
]"
|
|
238
|
+
aria-label="Icon source"
|
|
239
|
+
style="margin-bottom: 0.75rem"
|
|
240
|
+
/>
|
|
252
241
|
|
|
253
242
|
<!-- URL panel -->
|
|
254
243
|
<div v-show="tab === 'url'" class="icon-panel">
|
|
@@ -286,11 +275,11 @@ function onBrowseSelect(url: string): void {
|
|
|
286
275
|
<label class="permanent-toggle">
|
|
287
276
|
<input type="checkbox" v-model="permanent" />
|
|
288
277
|
Permanent blob <span class="hint">(cannot be deleted)</span>
|
|
289
|
-
<
|
|
278
|
+
<UiFieldHint field-id="blob-permanent">
|
|
290
279
|
A permanent blob cannot be deleted once registered, even within its storage period.
|
|
291
280
|
Deletable blobs can be removed early by the owner to reclaim unused storage fees (WAL).
|
|
292
281
|
Permanent is the safer default for a token icon that should remain available indefinitely.
|
|
293
|
-
</
|
|
282
|
+
</UiFieldHint>
|
|
294
283
|
</label>
|
|
295
284
|
|
|
296
285
|
<fieldset v-if="fileName && availableRelays.length > 1" style="margin: 0.5rem 0">
|
|
@@ -312,13 +301,13 @@ function onBrowseSelect(url: string): void {
|
|
|
312
301
|
</div>
|
|
313
302
|
</fieldset>
|
|
314
303
|
|
|
315
|
-
<
|
|
304
|
+
<UiNotice v-if="fileName && estimatedCost" style="margin: 0.5rem 0">
|
|
316
305
|
<strong>Estimated cost:</strong> {{ estimatedCost.label }}
|
|
317
|
-
</
|
|
306
|
+
</UiNotice>
|
|
318
307
|
|
|
319
308
|
<!-- NFT-gated relay: the operator relay is live but this wallet lacks the access NFT.
|
|
320
309
|
The public relay is still available; purchasing unlocks the operator relay. -->
|
|
321
|
-
<
|
|
310
|
+
<UiNotice v-if="fileName && purchaseAccessAvailable" style="margin: 0.5rem 0">
|
|
322
311
|
<p style="margin: 0 0 0.5rem">
|
|
323
312
|
The operator relay requires an access NFT. You can keep using the public relay, or
|
|
324
313
|
purchase access to support this app’s relay.
|
|
@@ -326,7 +315,7 @@ function onBrowseSelect(url: string): void {
|
|
|
326
315
|
<button type="button" :disabled="purchasing || !connected" @click="purchaseAccess">
|
|
327
316
|
{{ purchasing ? 'Purchasing…' : 'Purchase relay access' }}
|
|
328
317
|
</button>
|
|
329
|
-
</
|
|
318
|
+
</UiNotice>
|
|
330
319
|
|
|
331
320
|
<p v-if="showFreeRelayTip" class="hint" style="margin: 0.5rem 0">
|
|
332
321
|
Tip: select the public relay above to avoid the relay fee.
|
|
@@ -337,7 +326,7 @@ function onBrowseSelect(url: string): void {
|
|
|
337
326
|
<strong>SUI</strong> (gas + relay fee) in your wallet; two approvals. Stored for
|
|
338
327
|
~{{ ICON_YEARS }} years. <span v-if="status">{{ status }}</span>
|
|
339
328
|
</p>
|
|
340
|
-
<
|
|
329
|
+
<UiNotice v-if="uploadError" type="error">{{ uploadError }}</UiNotice>
|
|
341
330
|
</div>
|
|
342
331
|
|
|
343
332
|
<!-- Browse panel -->
|
|
@@ -348,49 +337,6 @@ function onBrowseSelect(url: string): void {
|
|
|
348
337
|
</template>
|
|
349
338
|
|
|
350
339
|
<style scoped>
|
|
351
|
-
.icon-tabs {
|
|
352
|
-
display: flex;
|
|
353
|
-
border: 1px solid var(--border);
|
|
354
|
-
border-radius: 6px;
|
|
355
|
-
overflow: hidden;
|
|
356
|
-
width: fit-content;
|
|
357
|
-
margin-bottom: 0.75rem;
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
.icon-tabs label {
|
|
361
|
-
display: flex;
|
|
362
|
-
align-items: center;
|
|
363
|
-
padding: 0.4rem 0.75rem;
|
|
364
|
-
cursor: pointer;
|
|
365
|
-
font-size: 0.875rem;
|
|
366
|
-
background: transparent;
|
|
367
|
-
border-right: 1px solid var(--border);
|
|
368
|
-
transition: background 0.15s, color 0.15s;
|
|
369
|
-
user-select: none;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
.icon-tabs label:last-child {
|
|
373
|
-
border-right: none;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
.icon-tabs label.active {
|
|
377
|
-
background: var(--accent);
|
|
378
|
-
color: var(--accent-contrast);
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
.icon-tabs label.disabled {
|
|
382
|
-
opacity: 0.5;
|
|
383
|
-
cursor: not-allowed;
|
|
384
|
-
pointer-events: none;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
.icon-tabs input[type='radio'] {
|
|
388
|
-
position: absolute;
|
|
389
|
-
opacity: 0;
|
|
390
|
-
width: 0;
|
|
391
|
-
height: 0;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
340
|
.icon-panel {
|
|
395
341
|
padding-top: 0.5rem;
|
|
396
342
|
}
|
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
import { computed, onMounted, ref } from 'vue'
|
|
3
3
|
import { fetchLicenseList, fetchLicenseText, NO_LICENSE } from '../lib/licenses.js'
|
|
4
4
|
import type { SpdxLicense } from '../lib/licenses.js'
|
|
5
|
-
import
|
|
6
|
-
import FieldHint from './FieldHint.vue'
|
|
7
|
-
import AppNotice from './AppNotice.vue'
|
|
5
|
+
import { UiSelect, UiFieldHint, UiNotice } from '@meddleware/ui'
|
|
8
6
|
|
|
9
7
|
const props = defineProps<{ modelValue: string }>()
|
|
10
8
|
const emit = defineEmits<{
|
|
@@ -73,14 +71,14 @@ async function openLicenseModal(): Promise<void> {
|
|
|
73
71
|
<div>
|
|
74
72
|
<label for="license-select">
|
|
75
73
|
License
|
|
76
|
-
<
|
|
74
|
+
<UiFieldHint field-id="license-select">
|
|
77
75
|
Applies only to the downloadable Move source package — embedded in the LICENSE file and
|
|
78
76
|
source headers. Has <b>no effect on the on-chain token</b> or its transferability.
|
|
79
77
|
Choose <b>CC0-1.0</b> (default) for public domain. Choose <b>None</b> to retain all rights.
|
|
80
|
-
</
|
|
78
|
+
</UiFieldHint>
|
|
81
79
|
</label>
|
|
82
80
|
<div class="license-row">
|
|
83
|
-
<
|
|
81
|
+
<UiSelect
|
|
84
82
|
id="license-select"
|
|
85
83
|
v-model="selectModel"
|
|
86
84
|
:disabled="loading || Boolean(error)"
|
|
@@ -103,7 +101,7 @@ async function openLicenseModal(): Promise<void> {
|
|
|
103
101
|
:title="`${l.id} — ${l.name}`"
|
|
104
102
|
>{{ l.id }}</option>
|
|
105
103
|
</optgroup>
|
|
106
|
-
</
|
|
104
|
+
</UiSelect>
|
|
107
105
|
<button type="button" class="view-btn" :disabled="loading" @click="openLicenseModal">
|
|
108
106
|
View
|
|
109
107
|
</button>
|
|
@@ -127,7 +125,7 @@ async function openLicenseModal(): Promise<void> {
|
|
|
127
125
|
<div v-if="licenseLoading" style="padding: 1rem 0">
|
|
128
126
|
<span class="spinner" aria-hidden="true"></span> Loading…
|
|
129
127
|
</div>
|
|
130
|
-
<
|
|
128
|
+
<UiNotice v-else-if="licenseError" type="error">{{ licenseError }}</UiNotice>
|
|
131
129
|
<template v-else-if="modelValue === NO_LICENSE.id">
|
|
132
130
|
<p>No LICENSE file will be generated. All rights are reserved by the author.</p>
|
|
133
131
|
</template>
|
|
@@ -154,7 +152,7 @@ async function openLicenseModal(): Promise<void> {
|
|
|
154
152
|
align-items: center;
|
|
155
153
|
}
|
|
156
154
|
|
|
157
|
-
.license-row :deep(.select
|
|
155
|
+
.license-row :deep(.mw-select) {
|
|
158
156
|
flex: 1;
|
|
159
157
|
}
|
|
160
158
|
|
|
@@ -5,7 +5,7 @@ import { explorerObjectUrl } from '../config.js'
|
|
|
5
5
|
import { generatePackageZip } from '../lib/generatePackage.js'
|
|
6
6
|
import { fetchLicenseText } from '../lib/licenses.js'
|
|
7
7
|
import GithubPush from './GithubPush.vue'
|
|
8
|
-
import
|
|
8
|
+
import { UiNotice } from '@meddleware/ui'
|
|
9
9
|
|
|
10
10
|
const props = defineProps<{ result: PublishResult; config: TokenConfig }>()
|
|
11
11
|
defineEmits<{ (e: 'restart'): void }>()
|
|
@@ -70,7 +70,7 @@ async function downloadPackage(): Promise<void> {
|
|
|
70
70
|
</button>
|
|
71
71
|
<button type="button" @click="$emit('restart')">Deploy another</button>
|
|
72
72
|
</div>
|
|
73
|
-
<
|
|
73
|
+
<UiNotice v-if="downloadError" type="error">{{ downloadError }}</UiNotice>
|
|
74
74
|
|
|
75
75
|
<div style="margin-top: 1rem">
|
|
76
76
|
<GithubPush :config="config" :result="result" />
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { TokenConfig, Network } from '../lib/types.js'
|
|
3
3
|
import { FEE_MIST } from '../config.js'
|
|
4
|
-
import
|
|
4
|
+
import { UiNotice } from '@meddleware/ui'
|
|
5
5
|
|
|
6
6
|
const props = defineProps<{ config: TokenConfig; network: Network }>()
|
|
7
7
|
defineEmits<{ (e: 'back'): void; (e: 'confirm'): void }>()
|
|
@@ -13,7 +13,7 @@ const feeSui = Number(FEE_MIST) / 1e9
|
|
|
13
13
|
<section class="card" aria-labelledby="review-h">
|
|
14
14
|
<h2 id="review-h">Review — deploying to {{ props.network }}</h2>
|
|
15
15
|
|
|
16
|
-
<
|
|
16
|
+
<UiNotice>
|
|
17
17
|
These values are <strong>permanent</strong> once published: symbol
|
|
18
18
|
<span class="mono">{{ config.symbol }}</span
|
|
19
19
|
>, name <span class="mono">{{ config.name }}</span
|
|
@@ -21,7 +21,7 @@ const feeSui = Number(FEE_MIST) / 1e9
|
|
|
21
21
|
>, and the coin type
|
|
22
22
|
<span class="mono"><package>::{{ config.moduleName }}::{{ config.structName }}</span
|
|
23
23
|
>.
|
|
24
|
-
</
|
|
24
|
+
</UiNotice>
|
|
25
25
|
|
|
26
26
|
<dl class="grid2" v-once>
|
|
27
27
|
<div>
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, reactive, ref } from 'vue'
|
|
3
3
|
import { useWallet, useNetwork, WalletGuard } from '@meddleware/wallet-adapter'
|
|
4
|
-
import ConfigForm from './ConfigForm.vue'
|
|
4
|
+
import ConfigForm, { type ConfigFormStep } from './ConfigForm.vue'
|
|
5
5
|
import ReviewPanel from './ReviewPanel.vue'
|
|
6
6
|
import DeployProgress from './DeployProgress.vue'
|
|
7
7
|
import ResultPanel from './ResultPanel.vue'
|
|
8
8
|
import TermsDialog from './TermsDialog.vue'
|
|
9
|
-
import
|
|
9
|
+
import { UiNotice, UiStepper, type StepperStep } from '@meddleware/ui'
|
|
10
10
|
import { emptyForm, toTokenConfig } from '../lib/form.js'
|
|
11
|
-
import { validateForm
|
|
11
|
+
import { validateForm } from '../lib/validation.js'
|
|
12
|
+
import type { FormErrors } from '../lib/validation.js'
|
|
12
13
|
import { deployToken } from '../lib/deploy.js'
|
|
13
14
|
import type { DeployStep } from '../lib/deploy.js'
|
|
14
15
|
import { buildDeployExecutor } from '../lib/deployExecutor.js'
|
|
@@ -16,13 +17,23 @@ import { FEE_MIST, FEE_TREASURY, PUBLISH_GAS_BUDGET, isFeeConfigured } from '../
|
|
|
16
17
|
import { extractErrorMessage } from '../lib/errors.js'
|
|
17
18
|
import type { Network, PublishResult } from '../lib/types.js'
|
|
18
19
|
|
|
19
|
-
type Step = '
|
|
20
|
+
type Step = 'identity' | 'token' | 'settings' | 'review' | 'deploying' | 'done'
|
|
21
|
+
|
|
22
|
+
const STEPS: StepperStep[] = [
|
|
23
|
+
{ id: 'identity', label: 'Identity' },
|
|
24
|
+
{ id: 'token', label: 'Token' },
|
|
25
|
+
{ id: 'settings', label: 'Settings' },
|
|
26
|
+
{ id: 'review', label: 'Review' },
|
|
27
|
+
{ id: 'done', label: 'Done' },
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
const CONFIG_STEPS: ConfigFormStep[] = ['identity', 'token', 'settings']
|
|
20
31
|
|
|
21
32
|
const { account } = useWallet()
|
|
22
33
|
const { network } = useNetwork()
|
|
23
34
|
|
|
24
35
|
const form = reactive(emptyForm())
|
|
25
|
-
const step = ref<Step>('
|
|
36
|
+
const step = ref<Step>('identity')
|
|
26
37
|
const deployStep = ref<DeployStep | null>(null)
|
|
27
38
|
const deployError = ref<string | null>(null)
|
|
28
39
|
const result = ref<PublishResult | null>(null)
|
|
@@ -32,12 +43,65 @@ const showTerms = ref(false)
|
|
|
32
43
|
const errors = computed(() => validateForm(form))
|
|
33
44
|
const config = computed(() => toTokenConfig(form))
|
|
34
45
|
const connected = computed(() => Boolean(account.value))
|
|
35
|
-
const canProceed = computed(() => isValid(errors.value) && connected.value)
|
|
36
46
|
|
|
37
|
-
|
|
47
|
+
const IDENTITY_KEYS: (keyof FormErrors)[] = ['packageName', 'moduleName']
|
|
48
|
+
const TOKEN_KEYS: (keyof FormErrors)[] = ['name', 'symbol', 'description', 'iconUrl', 'decimals']
|
|
49
|
+
const SETTINGS_KEYS: (keyof FormErrors)[] = ['initialSupply', 'recipient']
|
|
50
|
+
|
|
51
|
+
function stepHasErrors(keys: (keyof FormErrors)[]): boolean {
|
|
52
|
+
return keys.some((k) => Boolean(errors.value[k]))
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const canProceed = computed((): boolean => {
|
|
56
|
+
if (!connected.value) return false
|
|
57
|
+
switch (step.value) {
|
|
58
|
+
case 'identity': return !stepHasErrors(IDENTITY_KEYS)
|
|
59
|
+
case 'token': return !stepHasErrors(TOKEN_KEYS)
|
|
60
|
+
case 'settings': return !stepHasErrors(SETTINGS_KEYS)
|
|
61
|
+
default: return true
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
const formStep = computed((): ConfigFormStep => {
|
|
66
|
+
if (step.value === 'token') return 'token'
|
|
67
|
+
if (step.value === 'settings') return 'settings'
|
|
68
|
+
return 'identity'
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
const stepIndex = computed((): number => {
|
|
72
|
+
const map: Record<Step, number> = {
|
|
73
|
+
identity: 0,
|
|
74
|
+
token: 1,
|
|
75
|
+
settings: 2,
|
|
76
|
+
review: 3,
|
|
77
|
+
deploying: 3,
|
|
78
|
+
done: 4,
|
|
79
|
+
}
|
|
80
|
+
return map[step.value]
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
function onStepperBack(i: number): void {
|
|
84
|
+
const configStepAt = CONFIG_STEPS[i]
|
|
85
|
+
if (configStepAt && step.value === 'review') step.value = configStepAt
|
|
86
|
+
if (i < stepIndex.value && CONFIG_STEPS.includes(step.value as ConfigFormStep)) {
|
|
87
|
+
step.value = CONFIG_STEPS[i] ?? 'identity'
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function goNext(): void {
|
|
38
92
|
if (!canProceed.value) return
|
|
39
|
-
if (
|
|
40
|
-
step.value = '
|
|
93
|
+
if (step.value === 'identity') { step.value = 'token'; return }
|
|
94
|
+
if (step.value === 'token') { step.value = 'settings'; return }
|
|
95
|
+
if (step.value === 'settings') {
|
|
96
|
+
if (!termsAccepted.value) { showTerms.value = true; return }
|
|
97
|
+
step.value = 'review'
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function goBack(): void {
|
|
102
|
+
if (step.value === 'token') { step.value = 'identity'; return }
|
|
103
|
+
if (step.value === 'settings') { step.value = 'token'; return }
|
|
104
|
+
if (step.value === 'review') { step.value = 'settings'; return }
|
|
41
105
|
}
|
|
42
106
|
|
|
43
107
|
function onTermsAccept(): void {
|
|
@@ -80,26 +144,29 @@ async function confirmDeploy(): Promise<void> {
|
|
|
80
144
|
function restart(): void {
|
|
81
145
|
result.value = null
|
|
82
146
|
deployError.value = null
|
|
83
|
-
step.value = '
|
|
147
|
+
step.value = 'identity'
|
|
84
148
|
}
|
|
85
149
|
</script>
|
|
86
150
|
|
|
87
151
|
<template>
|
|
88
152
|
<WalletGuard message="Connect a Sui wallet to deploy your token.">
|
|
153
|
+
<UiStepper :steps="STEPS" :model-value="stepIndex" @update:model-value="onStepperBack" />
|
|
89
154
|
<ConfigForm
|
|
90
|
-
v-if="step === '
|
|
155
|
+
v-if="step === 'identity' || step === 'token' || step === 'settings'"
|
|
91
156
|
:form="form"
|
|
92
157
|
:errors="errors"
|
|
93
158
|
:can-proceed="canProceed"
|
|
94
159
|
:network="network"
|
|
95
160
|
:connected="connected"
|
|
96
|
-
|
|
161
|
+
:form-step="formStep"
|
|
162
|
+
@next="goNext"
|
|
163
|
+
@back="goBack"
|
|
97
164
|
/>
|
|
98
165
|
<ReviewPanel
|
|
99
166
|
v-if="step === 'review'"
|
|
100
167
|
:config="config"
|
|
101
168
|
:network="network"
|
|
102
|
-
@back="
|
|
169
|
+
@back="goBack"
|
|
103
170
|
@confirm="confirmDeploy"
|
|
104
171
|
/>
|
|
105
172
|
<DeployProgress v-if="step === 'deploying'" :step="deployStep" />
|
|
@@ -109,7 +176,7 @@ function restart(): void {
|
|
|
109
176
|
:config="config"
|
|
110
177
|
@restart="restart"
|
|
111
178
|
/>
|
|
112
|
-
<
|
|
179
|
+
<UiNotice v-if="deployError" type="error">{{ deployError }}</UiNotice>
|
|
113
180
|
<TermsDialog :open="showTerms" @accept="onTermsAccept" @cancel="onTermsCancel" />
|
|
114
181
|
</WalletGuard>
|
|
115
182
|
</template>
|
|
@@ -3,8 +3,7 @@ import { computed, ref, watch } from 'vue'
|
|
|
3
3
|
import { useWallet, useNetwork } from '@meddleware/wallet-adapter'
|
|
4
4
|
import { SELECTABLE_NETWORKS } from '../config.js'
|
|
5
5
|
import type { Network } from '../lib/types.js'
|
|
6
|
-
import
|
|
7
|
-
import AppNotice from './AppNotice.vue'
|
|
6
|
+
import { UiSelect, UiNotice } from '@meddleware/ui'
|
|
8
7
|
|
|
9
8
|
const { wallets, currentWallet, account, connecting, error, connect, disconnect } = useWallet()
|
|
10
9
|
const { network, setNetwork } = useNetwork()
|
|
@@ -42,9 +41,9 @@ watch(() => account.value, (acc) => {
|
|
|
42
41
|
<div class="row" style="justify-content: space-between">
|
|
43
42
|
<div class="row">
|
|
44
43
|
<label for="network-select" style="margin: 0">Network</label>
|
|
45
|
-
<
|
|
44
|
+
<UiSelect id="network-select" v-model="networkModel">
|
|
46
45
|
<option v-for="n in SELECTABLE_NETWORKS" :key="n" :value="n">{{ n }}</option>
|
|
47
|
-
</
|
|
46
|
+
</UiSelect>
|
|
48
47
|
</div>
|
|
49
48
|
|
|
50
49
|
<div class="row">
|
|
@@ -68,7 +67,7 @@ watch(() => account.value, (acc) => {
|
|
|
68
67
|
</div>
|
|
69
68
|
</template>
|
|
70
69
|
|
|
71
|
-
<
|
|
70
|
+
<UiNotice v-if="error" type="error" style="margin-top: 0.75rem">{{ error }}</UiNotice>
|
|
72
71
|
</div>
|
|
73
72
|
|
|
74
73
|
<dialog ref="dialogEl" aria-labelledby="wallet-dialog-title" @click.self="closeDialog">
|
|
@@ -86,9 +85,9 @@ watch(() => account.value, (acc) => {
|
|
|
86
85
|
|
|
87
86
|
<div>
|
|
88
87
|
<label for="dialog-network-select">Network</label>
|
|
89
|
-
<
|
|
88
|
+
<UiSelect id="dialog-network-select" v-model="networkModel">
|
|
90
89
|
<option v-for="n in SELECTABLE_NETWORKS" :key="n" :value="n">{{ n }}</option>
|
|
91
|
-
</
|
|
90
|
+
</UiSelect>
|
|
92
91
|
</div>
|
|
93
92
|
|
|
94
93
|
<div class="wallet-list">
|
|
@@ -4,7 +4,7 @@ import { useWallet } from '@meddleware/wallet-adapter'
|
|
|
4
4
|
import { getReadClient } from '../lib/readClient.js'
|
|
5
5
|
import type { OwnedBlob, WalrusNetwork } from '../lib/walrus.js'
|
|
6
6
|
import type { Network } from '../lib/types.js'
|
|
7
|
-
import
|
|
7
|
+
import { UiNotice } from '@meddleware/ui'
|
|
8
8
|
|
|
9
9
|
const props = defineProps<{ network: WalrusNetwork; connected: boolean }>()
|
|
10
10
|
const emit = defineEmits<{ (e: 'select', url: string): void }>()
|
|
@@ -84,7 +84,7 @@ function selectBlob(item: BlobItem): void {
|
|
|
84
84
|
</div>
|
|
85
85
|
<p class="hint">Browse Walrus blobs owned by this address. Only image blobs show a preview.</p>
|
|
86
86
|
|
|
87
|
-
<
|
|
87
|
+
<UiNotice v-if="loadError" type="error">{{ loadError }}</UiNotice>
|
|
88
88
|
|
|
89
89
|
<p v-if="hasLoaded && blobs.length === 0 && !loading" class="hint">
|
|
90
90
|
No Walrus blobs found at this address.
|
|
@@ -7,7 +7,7 @@ import { ICON_EPOCHS } from '../lib/walrus-constants.js'
|
|
|
7
7
|
import { ICON_MAX_BYTES, validateIconFile } from '../config.js'
|
|
8
8
|
import type { WalrusNetwork } from '../lib/walrus.js'
|
|
9
9
|
import type { Network } from '../lib/types.js'
|
|
10
|
-
import
|
|
10
|
+
import { UiNotice } from '@meddleware/ui'
|
|
11
11
|
// Vite serves the Walrus wasm as an asset URL (lightweight import — just the URL).
|
|
12
12
|
import walrusWasmUrl from '@mysten/walrus-wasm/web/walrus_wasm_bg.wasm?url'
|
|
13
13
|
|
|
@@ -185,9 +185,9 @@ async function upload(): Promise<void> {
|
|
|
185
185
|
</fieldset>
|
|
186
186
|
|
|
187
187
|
<!-- Cost estimation (shown after file selection) -->
|
|
188
|
-
<
|
|
188
|
+
<UiNotice v-if="fileName && estimatedCost" style="margin: 0.75rem 0">
|
|
189
189
|
<strong>Estimated cost:</strong> {{ estimatedCost.label }}
|
|
190
|
-
</
|
|
190
|
+
</UiNotice>
|
|
191
191
|
|
|
192
192
|
<!-- Public relay notice -->
|
|
193
193
|
<p v-if="showFreeRelayTip" class="hint" style="margin: 0.75rem 0">
|
|
@@ -200,6 +200,6 @@ async function upload(): Promise<void> {
|
|
|
200
200
|
stored for ~{{ ICON_YEARS }} years.
|
|
201
201
|
<span v-if="status">{{ status }}</span>
|
|
202
202
|
</p>
|
|
203
|
-
<
|
|
203
|
+
<UiNotice v-if="error" type="error">{{ error }}</UiNotice>
|
|
204
204
|
</div>
|
|
205
205
|
</template>
|
package/src/index.ts
CHANGED
package/src/main.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
import '@meddleware/design-tokens/tokens.css'
|
|
2
|
+
import '@meddleware/design-tokens/seasons.css'
|
|
3
|
+
import '@meddleware/ui/base.css'
|
|
1
4
|
import { createApp } from 'vue'
|
|
2
5
|
import App from './App.vue'
|
|
3
6
|
import './styles.css'
|
|
7
|
+
import './component-styles.css'
|
|
4
8
|
import { configureWasm } from './lib/template.js'
|
|
5
|
-
import { useColorMode } from '
|
|
9
|
+
import { useColorMode } from '@meddleware/ui'
|
|
6
10
|
|
|
7
11
|
// Apply the colour mode before mount so there is no theme flash. Defaults to
|
|
8
12
|
// `system` (follows the OS) while enabling the in-app light/dark/system control.
|