@meddleware/walrus-ui 0.1.39 → 0.1.40
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 +33 -11
- package/src/App.vue +14 -1
- package/src/components/MyBlobs.vue +1 -1
- package/src/components/WalrusView.vue +86 -95
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meddleware/walrus-ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.40",
|
|
4
4
|
"homepage": "https://docs.meddleware.co.uk/blockchain/sui/walrus-storage/",
|
|
5
5
|
"description": "Standalone Vue 3 SPA for uploading blobs to Walrus decentralised storage and managing owned blobs — wallet-connected, NFT-gated relay support.",
|
|
6
6
|
"author": "Meddleware <dev@meddleware.co.uk>",
|
|
@@ -35,21 +35,25 @@
|
|
|
35
35
|
"type-check": "vue-tsc --noEmit",
|
|
36
36
|
"test": "vitest run",
|
|
37
37
|
"test:watch": "vitest",
|
|
38
|
-
"test:e2e": "playwright test"
|
|
38
|
+
"test:e2e": "playwright test",
|
|
39
|
+
"lint:css": "stylelint \"src/**/*.{css,vue}\"",
|
|
40
|
+
"lint:js": "eslint .",
|
|
41
|
+
"lint": "npm run lint:css && npm run lint:js && npm run lint:html",
|
|
42
|
+
"lint:html": "html-validate \"src/**/*.vue\""
|
|
39
43
|
},
|
|
40
44
|
"publishConfig": {
|
|
41
45
|
"access": "public"
|
|
42
46
|
},
|
|
43
47
|
"dependencies": {
|
|
44
|
-
"@meddleware/design-tokens": "^0.1.
|
|
45
|
-
"@meddleware/nft-gate-client": "^0.0.
|
|
46
|
-
"@meddleware/ui": "^0.1.
|
|
47
|
-
"@meddleware/wallet-adapter": "^0.0.
|
|
48
|
-
"@meddleware/walrus-client": "^0.0.
|
|
49
|
-
"@meddleware/walrus-relay": "^0.1.
|
|
50
|
-
"@mysten/sui": "^2.
|
|
48
|
+
"@meddleware/design-tokens": "^0.1.7",
|
|
49
|
+
"@meddleware/nft-gate-client": "^0.0.11",
|
|
50
|
+
"@meddleware/ui": "^0.1.28",
|
|
51
|
+
"@meddleware/wallet-adapter": "^0.0.9",
|
|
52
|
+
"@meddleware/walrus-client": "^0.0.17",
|
|
53
|
+
"@meddleware/walrus-relay": "^0.1.18",
|
|
54
|
+
"@mysten/sui": "^2.33.0",
|
|
51
55
|
"@mysten/wallet-standard": "^0.21.0",
|
|
52
|
-
"@mysten/walrus": "~1.2.
|
|
56
|
+
"@mysten/walrus": "~1.2.31",
|
|
53
57
|
"@mysten/walrus-wasm": "~0.3.1",
|
|
54
58
|
"vue": "^3.5.43"
|
|
55
59
|
},
|
|
@@ -57,12 +61,30 @@
|
|
|
57
61
|
"@playwright/test": "~1.63.0",
|
|
58
62
|
"@types/node": "~24.12.2",
|
|
59
63
|
"@vitejs/plugin-vue": "^6.0.8",
|
|
64
|
+
"@vue/eslint-config-typescript": "^14.9.0",
|
|
65
|
+
"autoprefixer": "^10.4.20",
|
|
66
|
+
"eslint": "^10.11.0",
|
|
67
|
+
"eslint-plugin-vue": "^10.11.1",
|
|
68
|
+
"eslint-plugin-vuejs-accessibility": "^2.6.0",
|
|
69
|
+
"html-validate": "^11.16.1",
|
|
70
|
+
"html-validate-vue": "^9.3.1",
|
|
71
|
+
"jiti": "^2.7.0",
|
|
72
|
+
"postcss": "^8.4.49",
|
|
73
|
+
"postcss-html": "^2.0.0",
|
|
74
|
+
"stylelint": "^17.15.0",
|
|
75
|
+
"stylelint-config-standard": "^40.0.0",
|
|
60
76
|
"typescript": "~6.0.0",
|
|
61
77
|
"vite": "^8.3.0",
|
|
62
78
|
"vitest": "~5.0.1",
|
|
79
|
+
"vue-eslint-parser": "^10.4.1",
|
|
63
80
|
"vue-tsc": "~3.3.0"
|
|
64
81
|
},
|
|
65
82
|
"engines": {
|
|
66
83
|
"node": "^22.18.0 || >=24.12.0"
|
|
67
|
-
}
|
|
84
|
+
},
|
|
85
|
+
"browserslist": [
|
|
86
|
+
"> 0.5%",
|
|
87
|
+
"last 2 versions",
|
|
88
|
+
"not dead"
|
|
89
|
+
]
|
|
68
90
|
}
|
package/src/App.vue
CHANGED
|
@@ -23,7 +23,9 @@ const DEV_URL = import.meta.env.VITE_DEV_URL || 'https://dev.meddleware.co.uk/
|
|
|
23
23
|
</template>
|
|
24
24
|
</AppHeader>
|
|
25
25
|
|
|
26
|
-
<
|
|
26
|
+
<div class="app__content">
|
|
27
|
+
<WalrusView />
|
|
28
|
+
</div>
|
|
27
29
|
|
|
28
30
|
<AppFooter :docs-url="DOCS_URL" :dev-url="DEV_URL" />
|
|
29
31
|
</div>
|
|
@@ -36,6 +38,17 @@ const DEV_URL = import.meta.env.VITE_DEV_URL || 'https://dev.meddleware.co.uk/
|
|
|
36
38
|
flex-direction: column;
|
|
37
39
|
}
|
|
38
40
|
|
|
41
|
+
/* Centre the tool at the shared tool-content width when running standalone. The dashboard
|
|
42
|
+
supplies its own width container, so this lives in the shell, not WalrusView. */
|
|
43
|
+
.app__content {
|
|
44
|
+
flex: 1;
|
|
45
|
+
width: 100%;
|
|
46
|
+
max-width: var(--mw-tool-content-max);
|
|
47
|
+
margin: 0 auto;
|
|
48
|
+
box-sizing: border-box;
|
|
49
|
+
padding: 1.5rem 1.25rem 4rem;
|
|
50
|
+
}
|
|
51
|
+
|
|
39
52
|
.brand-title {
|
|
40
53
|
font: inherit;
|
|
41
54
|
margin: 0;
|
|
@@ -93,7 +93,7 @@ function refreshPending(): void {
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
// ── Extend ──────────────────────────────────────────────────────────────────
|
|
96
|
-
|
|
96
|
+
const extendReq: Record<string, number> = {}
|
|
97
97
|
|
|
98
98
|
// User picked an amount → clamp and (re)price it. We estimate only on interaction, not for every row
|
|
99
99
|
// on load, to avoid spinning up a Walrus client per blob.
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
useAccessGate,
|
|
11
11
|
} from '@meddleware/walrus-relay'
|
|
12
12
|
import type { UploadResult, UploadProgress, ExistingCopy } from '@meddleware/walrus-relay'
|
|
13
|
-
import { AppTabNav, CopyableAddress, ExplorerLink, UiNotice, suiExplorerUrl, safeHref, type AppTab } from '@meddleware/ui'
|
|
13
|
+
import { AppTabNav, CopyableAddress, ExplorerLink, UiNotice, UiTabPanel, UiToolIntro, suiExplorerUrl, safeHref, type AppTab } from '@meddleware/ui'
|
|
14
14
|
// Lightweight URL import — just the wasm asset URL (does not pull the walrus client).
|
|
15
15
|
import walrusWasmUrl from '@mysten/walrus-wasm/web/walrus_wasm_bg.wasm?url'
|
|
16
16
|
import { WalletGuard } from '@meddleware/wallet-adapter'
|
|
@@ -230,110 +230,101 @@ function onSettled(): void {
|
|
|
230
230
|
</script>
|
|
231
231
|
|
|
232
232
|
<template>
|
|
233
|
-
|
|
234
|
-
<p class="sub">Upload and manage blobs on Walrus decentralised storage ({{ NETWORK }}).</p>
|
|
233
|
+
<UiToolIntro>Upload and manage blobs on Walrus decentralised storage ({{ NETWORK }}).</UiToolIntro>
|
|
235
234
|
|
|
236
|
-
<AppTabNav :tabs="TABS"
|
|
235
|
+
<AppTabNav v-model="activeTab" :tabs="TABS" id-prefix="walrus" aria-label="Feature tabs" class="walrus-tabs" />
|
|
237
236
|
|
|
238
237
|
<WalletGuard message="Connect a Sui wallet to upload and manage your blobs.">
|
|
239
|
-
<
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
<
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
<
|
|
286
|
-
|
|
287
|
-
<
|
|
288
|
-
|
|
289
|
-
<
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
<
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
<
|
|
302
|
-
|
|
303
|
-
<
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
238
|
+
<UiTabPanel id-prefix="walrus" :tab="activeTab">
|
|
239
|
+
<template v-if="activeTab === 'upload'">
|
|
240
|
+
<!-- Gated + no access: replace the form with the purchase CTA so the user is guided to buy
|
|
241
|
+
first, rather than facing a disabled form. -->
|
|
242
|
+
<div v-if="gateState.gateConfigured && gateState.hasAccess.value === false" class="gate-card">
|
|
243
|
+
<AccessGateCta
|
|
244
|
+
:gate-configured="gateState.gateConfigured"
|
|
245
|
+
:has-access="gateState.hasAccess.value"
|
|
246
|
+
:busy="purchasing"
|
|
247
|
+
:price-mist="gate?.priceMist ?? null"
|
|
248
|
+
@purchase="onPurchase"
|
|
249
|
+
/>
|
|
250
|
+
</div>
|
|
251
|
+
|
|
252
|
+
<!-- Ownership check still in flight. -->
|
|
253
|
+
<p
|
|
254
|
+
v-else-if="gateState.gateConfigured && gateState.hasAccess.value === null"
|
|
255
|
+
class="checking"
|
|
256
|
+
>
|
|
257
|
+
Checking access…
|
|
258
|
+
</p>
|
|
259
|
+
|
|
260
|
+
<!-- Access held (or ungated relay): show the upload form. -->
|
|
261
|
+
<template v-else>
|
|
262
|
+
<!-- Gated relays spend a credit before the file is stored — make the "attempt, not a
|
|
263
|
+
guarantee" nature explicit, while reassuring that attempts resume. -->
|
|
264
|
+
<UiNotice v-if="gateState.gateConfigured" type="info" class="credit-notice">
|
|
265
|
+
Uploading spends <strong>one credit</strong> from your access NFT (an on-chain step)
|
|
266
|
+
before the file is stored — it pays for an upload <em>attempt</em>, not a guaranteed
|
|
267
|
+
upload. Your attempt resumes automatically, even after a page reload if you re-select
|
|
268
|
+
the same file, so a credit is normally not lost. A credit is spent without a completed
|
|
269
|
+
upload only if you abandon the upload entirely, cancel a required wallet approval, or
|
|
270
|
+
wait long enough that the reserved storage lapses.
|
|
271
|
+
</UiNotice>
|
|
272
|
+
|
|
273
|
+
<WalrusUpload
|
|
274
|
+
:hosts="relayHosts(NETWORK)"
|
|
275
|
+
:connected="!!account"
|
|
276
|
+
:access="{ gateConfigured: gateState.gateConfigured, hasAccess: gateState.hasAccess }"
|
|
277
|
+
:perform-upload="performUpload"
|
|
278
|
+
:estimate-storage-cost="estimateUploadStorageCost"
|
|
279
|
+
@uploaded="onUploaded"
|
|
280
|
+
@settled="onSettled"
|
|
281
|
+
@manage-existing="onManageExisting"
|
|
282
|
+
/>
|
|
283
|
+
|
|
284
|
+
<section v-if="result" class="result">
|
|
285
|
+
<h2>Uploaded ✓</h2>
|
|
286
|
+
<p>
|
|
287
|
+
<strong>Blob ID:</strong>
|
|
288
|
+
<CopyableAddress :address="result.blobId" label="Copy blob ID">
|
|
289
|
+
<ExplorerLink
|
|
290
|
+
:href="walruscanBlobUrl(NETWORK, result.blobId)"
|
|
291
|
+
:value="result.blobId"
|
|
292
|
+
:chars="[8, 6]"
|
|
293
|
+
/>
|
|
294
|
+
</CopyableAddress>
|
|
295
|
+
</p>
|
|
296
|
+
<p>
|
|
297
|
+
<strong>URL:</strong>
|
|
298
|
+
<a :href="safeHref(result.url)" target="_blank" rel="noopener noreferrer">{{ result.url }}</a>
|
|
299
|
+
</p>
|
|
300
|
+
<p v-if="result.digest">
|
|
301
|
+
<strong>Certify tx:</strong>
|
|
302
|
+
<CopyableAddress :address="result.digest" label="Copy transaction digest">
|
|
303
|
+
<ExplorerLink
|
|
304
|
+
:href="suiExplorerUrl('txblock', result.digest, NETWORK)"
|
|
305
|
+
:value="result.digest"
|
|
306
|
+
:chars="[8, 6]"
|
|
307
|
+
/>
|
|
308
|
+
</CopyableAddress>
|
|
309
|
+
</p>
|
|
310
|
+
</section>
|
|
311
|
+
</template>
|
|
311
312
|
</template>
|
|
312
|
-
</template>
|
|
313
313
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
314
|
+
<MyBlobs
|
|
315
|
+
v-if="activeTab === 'blobs'"
|
|
316
|
+
:address="account?.address ?? null"
|
|
317
|
+
:build-executor="() => buildExecutor()"
|
|
318
|
+
:highlight-blob-id="highlightBlobId"
|
|
319
|
+
/>
|
|
320
|
+
</UiTabPanel>
|
|
320
321
|
</WalletGuard>
|
|
321
|
-
</div>
|
|
322
322
|
</template>
|
|
323
323
|
|
|
324
324
|
<style scoped>
|
|
325
|
-
.
|
|
326
|
-
|
|
327
|
-
margin: 0 auto;
|
|
328
|
-
padding: 2rem 1.25rem 4rem;
|
|
329
|
-
flex: 1;
|
|
325
|
+
.walrus-tabs {
|
|
326
|
+
margin: 1rem 0 0.5rem;
|
|
330
327
|
}
|
|
331
|
-
|
|
332
|
-
.sub {
|
|
333
|
-
color: var(--muted);
|
|
334
|
-
margin: 0.25rem 0 0;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
328
|
.result {
|
|
338
329
|
margin-top: 1.5rem;
|
|
339
330
|
padding: 1rem;
|