vue-kaspa-cli 0.1.11 → 0.1.12

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vue-kaspa-cli",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "type": "module",
5
5
  "description": "Scaffold a Vue 3 or Nuxt app wired to the Kaspa blockchain",
6
6
  "license": "MIT",
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
- import { ref, computed, onMounted, onUnmounted } from 'vue'
3
- import { Droplet, BookOpen, Search, ArrowUpRight, Heart, Copy, Check } from 'lucide-vue-next'
2
+ import { ArrowUpRight, BookOpen, Check, Copy, Droplet, Heart, Search } from 'lucide-vue-next'
3
+ import { computed, onMounted, onUnmounted, ref } from 'vue'
4
4
  // useKaspa and useRpc are auto-imported by Nuxt.
5
5
 
6
6
  const kaspa = useKaspa()
@@ -41,12 +41,12 @@ const daaScore = computed(() =>
41
41
  )
42
42
 
43
43
  const links = [
44
- { label: 'Faucet', title: 'Testnet 10', desc: 'Get free test KAS', icon: Droplet, href: 'https://faucet-tn10.kaspanet.io/' },
45
- { label: 'Faucet', title: 'Testnet 12', desc: 'Get free test KAS', icon: Droplet, href: 'https://faucet-tn12.kaspanet.io/' },
46
- { label: 'Docs', title: 'vue-kaspa', desc: 'Read the full docs', icon: BookOpen, href: 'https://vue-kaspa.vercel.app/' },
47
- { label: 'Explorer', title: 'Testnet 10', desc: 'Browse transactions', icon: Search, href: 'https://tn10.kaspa.stream/' },
48
- { label: 'Explorer', title: 'Testnet 12', desc: 'Browse transactions', icon: Search, href: 'https://tn12.kaspa.stream/' },
49
- { label: 'Explorer', title: 'Mainnet', desc: 'Browse transactions', icon: Search, href: 'https://kaspa.stream/' },
44
+ { label: 'Faucet', title: 'Testnet 10', desc: 'Get free test KAS', icon: Droplet, href: 'https://faucet-tn10.kaspanet.io/' },
45
+ { label: 'Faucet', title: 'Testnet 12', desc: 'Get free test KAS', icon: Droplet, href: 'https://faucet-tn12.kaspanet.io/' },
46
+ { label: 'Docs', title: 'Vue Kaspa', desc: 'Read the full docs', icon: BookOpen, href: 'https://vue-kaspa.vercel.app/' },
47
+ { label: 'Explorer', title: 'Testnet 10', desc: 'Browse transactions', icon: Search, href: 'https://tn10.kaspa.stream/' },
48
+ { label: 'Explorer', title: 'Testnet 12', desc: 'Browse transactions', icon: Search, href: 'https://tn12.kaspa.stream/' },
49
+ { label: 'Explorer', title: 'Mainnet', desc: 'Browse transactions', icon: Search, href: 'https://kaspa.stream/' },
50
50
  ]
51
51
 
52
52
  function onMouseMove(e: MouseEvent) {
@@ -67,8 +67,9 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
67
67
  <dialog ref="donateDialog" class="ks-dialog" @click.self="donateDialog?.close()">
68
68
  <div class="ks-dialog-inner">
69
69
  <button class="ks-dialog-close" @click="donateDialog?.close()">✕</button>
70
- <p class="ks-dialog-title">Support vue-kaspa ❤️</p>
71
- <p class="ks-dialog-body">vue-kaspa is free and open-source. If it saves you time, consider sending some KAS — every bit helps keep the project alive and maintained.</p>
70
+ <p class="ks-dialog-title">Support Vue Kaspa ❤️</p>
71
+ <p class="ks-dialog-body">Vue Kaspa is free and open-source. If it saves you time, consider sending some KAS —
72
+ every bit helps keep the project alive and maintained.</p>
72
73
  <div class="ks-copy-wrap">
73
74
  <code class="ks-dialog-addr">{{ KASPA_ADDRESS }}</code>
74
75
  <button class="ks-copy-btn" :class="{ copied }" @click="copyAddress">
@@ -85,18 +86,14 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
85
86
 
86
87
  <!-- Header -->
87
88
  <header class="ks-header">
88
- <img src="/logo.png" alt="vue-kaspa" class="ks-header-logo" />
89
- <span class="ks-header-brand">vue-kaspa</span>
89
+ <img src="/logo.png" alt="Vue Kaspa" class="ks-header-logo" />
90
+ <span class="ks-header-brand">Vue Kaspa</span>
90
91
  <nav class="ks-header-nav">
91
- <a
92
- href="https://github.com/furatamasensei/vue-kaspa"
93
- target="_blank"
94
- rel="noopener"
95
- class="ks-icon-btn"
96
- title="GitHub"
97
- >
92
+ <a href="https://github.com/furatamasensei/vue-kaspa" target="_blank" rel="noopener" class="ks-icon-btn"
93
+ title="GitHub">
98
94
  <svg viewBox="0 0 24 24" width="18" height="18" fill="currentColor">
99
- <path d="M12 2C6.477 2 2 6.477 2 12c0 4.42 2.865 8.166 6.839 9.489.5.092.682-.217.682-.482 0-.237-.008-.866-.013-1.7-2.782.603-3.369-1.342-3.369-1.342-.454-1.155-1.11-1.463-1.11-1.463-.908-.62.069-.608.069-.608 1.003.07 1.531 1.03 1.531 1.03.892 1.529 2.341 1.087 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.11-4.555-4.943 0-1.091.39-1.984 1.029-2.683-.103-.253-.446-1.27.098-2.647 0 0 .84-.269 2.75 1.025A9.578 9.578 0 0112 6.836c.85.004 1.705.114 2.504.337 1.909-1.294 2.747-1.025 2.747-1.025.546 1.377.202 2.394.1 2.647.64.699 1.028 1.592 1.028 2.683 0 3.842-2.339 4.687-4.566 4.935.359.309.678.919.678 1.852 0 1.336-.012 2.415-.012 2.741 0 .267.18.578.688.48C19.138 20.163 22 16.418 22 12c0-5.523-4.477-10-10-10z"/>
95
+ <path
96
+ d="M12 2C6.477 2 2 6.477 2 12c0 4.42 2.865 8.166 6.839 9.489.5.092.682-.217.682-.482 0-.237-.008-.866-.013-1.7-2.782.603-3.369-1.342-3.369-1.342-.454-1.155-1.11-1.463-1.11-1.463-.908-.62.069-.608.069-.608 1.003.07 1.531 1.03 1.531 1.03.892 1.529 2.341 1.087 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.11-4.555-4.943 0-1.091.39-1.984 1.029-2.683-.103-.253-.446-1.27.098-2.647 0 0 .84-.269 2.75 1.025A9.578 9.578 0 0112 6.836c.85.004 1.705.114 2.504.337 1.909-1.294 2.747-1.025 2.747-1.025.546 1.377.202 2.394.1 2.647.64.699 1.028 1.592 1.028 2.683 0 3.842-2.339 4.687-4.566 4.935.359.309.678.919.678 1.852 0 1.336-.012 2.415-.012 2.741 0 .267.18.578.688.48C19.138 20.163 22 16.418 22 12c0-5.523-4.477-10-10-10z" />
100
97
  </svg>
101
98
  </a>
102
99
  <button class="ks-icon-btn" title="Support this project" @click="donateDialog?.showModal()">
@@ -108,64 +105,53 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
108
105
  <!-- Bento grid -->
109
106
  <div ref="bento" class="ks-grid">
110
107
 
111
- <!-- Network card: col 1–2, row 1–3 -->
112
- <div data-shine class="ks-shine ks-net-shine">
113
- <div class="ks-card ks-net-card">
114
- <div class="ks-net-top">
115
- <span class="ks-net-icon">⬡</span>
116
- <span
117
- class="ks-badge"
118
- :style="`border-color:${badgeColor};color:${badgeColor}`"
119
- >{{ stateLabel }}</span>
108
+ <!-- Network card: col 1–2, row 1–3 -->
109
+ <div data-shine class="ks-shine ks-net-shine">
110
+ <div class="ks-card ks-net-card">
111
+ <div class="ks-net-top">
112
+ <span class="ks-net-icon">⬡</span>
113
+ <span class="ks-badge" :style="`border-color:${badgeColor};color:${badgeColor}`">{{ stateLabel }}</span>
114
+ </div>
115
+ <div class="ks-stats">
116
+ <div class="ks-stat">
117
+ <span class="ks-stat-label">Network</span>
118
+ <span class="ks-stat-value">{{ rpc.networkId.value ?? '—' }}</span>
119
+ </div>
120
+ <div class="ks-stat">
121
+ <span class="ks-stat-label">Server version</span>
122
+ <span class="ks-stat-value">{{ rpc.serverVersion.value ?? '—' }}</span>
123
+ </div>
124
+ <div class="ks-stat">
125
+ <span class="ks-stat-label">DAA Score</span>
126
+ <span class="ks-stat-value" style="font-family:monospace">{{ daaScore }}</span>
120
127
  </div>
121
- <div class="ks-stats">
122
- <div class="ks-stat">
123
- <span class="ks-stat-label">Network</span>
124
- <span class="ks-stat-value">{{ rpc.networkId.value ?? '' }}</span>
125
- </div>
126
- <div class="ks-stat">
127
- <span class="ks-stat-label">Server version</span>
128
- <span class="ks-stat-value">{{ rpc.serverVersion.value ?? '—' }}</span>
129
- </div>
130
- <div class="ks-stat">
131
- <span class="ks-stat-label">DAA Score</span>
132
- <span class="ks-stat-value" style="font-family:monospace">{{ daaScore }}</span>
133
- </div>
134
- <div class="ks-stat">
135
- <span class="ks-stat-label">Synced</span>
136
- <span
137
- class="ks-stat-value"
138
- :style="`color:${rpc.isConnected.value ? (rpc.isSynced.value ? '#4caf50' : 'var(--ks-text)') : 'var(--ks-muted)'}`"
139
- >{{ rpc.isConnected.value ? (rpc.isSynced.value ? 'Yes' : 'Syncing…') : '—' }}</span>
140
- </div>
128
+ <div class="ks-stat">
129
+ <span class="ks-stat-label">Synced</span>
130
+ <span class="ks-stat-value"
131
+ :style="`color:${rpc.isConnected.value ? (rpc.isSynced.value ? '#4caf50' : 'var(--ks-text)') : 'var(--ks-muted)'}`">{{
132
+ rpc.isConnected.value ? (rpc.isSynced.value ? 'Yes' : 'Syncing…') : '—' }}</span>
141
133
  </div>
142
134
  </div>
143
135
  </div>
136
+ </div>
144
137
 
145
- <!-- Link cards: auto-placed into Γ shape -->
146
- <a
147
- v-for="link in links"
148
- :key="link.href"
149
- data-shine
150
- class="ks-shine ks-link-shine"
151
- :href="link.href"
152
- target="_blank"
153
- rel="noopener"
154
- >
155
- <div class="ks-card ks-link-card">
156
- <div class="ks-link-top">
157
- <component :is="link.icon" :size="20" class="ks-link-icon" />
158
- <ArrowUpRight :size="13" class="ks-link-arrow" />
159
- </div>
160
- <div>
161
- <div class="ks-link-label">{{ link.label }}</div>
162
- <div class="ks-link-title">{{ link.title }}</div>
163
- <div class="ks-link-desc">{{ link.desc }}</div>
164
- </div>
138
+ <!-- Link cards: auto-placed into Γ shape -->
139
+ <a v-for="link in links" :key="link.href" data-shine class="ks-shine ks-link-shine" :href="link.href"
140
+ target="_blank" rel="noopener">
141
+ <div class="ks-card ks-link-card">
142
+ <div class="ks-link-top">
143
+ <component :is="link.icon" :size="20" class="ks-link-icon" />
144
+ <ArrowUpRight :size="13" class="ks-link-arrow" />
165
145
  </div>
166
- </a>
146
+ <div>
147
+ <div class="ks-link-label">{{ link.label }}</div>
148
+ <div class="ks-link-title">{{ link.title }}</div>
149
+ <div class="ks-link-desc">{{ link.desc }}</div>
150
+ </div>
151
+ </div>
152
+ </a>
167
153
 
168
- </div>
154
+ </div>
169
155
  </div>
170
156
  </template>
171
157
 
@@ -178,10 +164,30 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
178
164
  }
179
165
 
180
166
  /* Header */
181
- .ks-header { display: flex; align-items: center; gap: .6rem; margin-bottom: .75rem; }
182
- .ks-header-logo { width: 28px; height: 28px; object-fit: contain; }
183
- .ks-header-brand { font-size: 1rem; font-weight: 700; color: var(--ks-heading); flex: 1; }
184
- .ks-header-nav { display: flex; gap: .15rem; }
167
+ .ks-header {
168
+ display: flex;
169
+ align-items: center;
170
+ gap: .6rem;
171
+ margin-bottom: .75rem;
172
+ }
173
+
174
+ .ks-header-logo {
175
+ width: 28px;
176
+ height: 28px;
177
+ object-fit: contain;
178
+ }
179
+
180
+ .ks-header-brand {
181
+ font-size: 1rem;
182
+ font-weight: 700;
183
+ color: var(--ks-heading);
184
+ flex: 1;
185
+ }
186
+
187
+ .ks-header-nav {
188
+ display: flex;
189
+ gap: .15rem;
190
+ }
185
191
 
186
192
  .ks-icon-btn {
187
193
  display: inline-flex;
@@ -197,7 +203,11 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
197
203
  text-decoration: none;
198
204
  transition: color .15s, background .15s;
199
205
  }
200
- .ks-icon-btn:hover { color: var(--ks-heading); background: var(--ks-border); }
206
+
207
+ .ks-icon-btn:hover {
208
+ color: var(--ks-heading);
209
+ background: var(--ks-border);
210
+ }
201
211
 
202
212
  /* Grid */
203
213
  .ks-grid {
@@ -210,18 +220,24 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
210
220
  .ks-shine {
211
221
  padding: 1px;
212
222
  border-radius: 14px;
213
- background: radial-gradient(
214
- 350px circle at var(--x, -9999px) var(--y, -9999px),
215
- var(--ks-shine),
216
- var(--ks-border) 80%
217
- );
223
+ background: radial-gradient(350px circle at var(--x, -9999px) var(--y, -9999px),
224
+ var(--ks-shine),
225
+ var(--ks-border) 80%);
218
226
  display: block;
219
227
  text-decoration: none;
220
228
  }
221
- .ks-net-shine { grid-column: 1 / span 2; grid-row: 1 / span 3; }
229
+
230
+ .ks-net-shine {
231
+ grid-column: 1 / span 2;
232
+ grid-row: 1 / span 3;
233
+ }
222
234
 
223
235
  /* Card base */
224
- .ks-card { border-radius: 13px; background: var(--ks-soft); height: 100%; }
236
+ .ks-card {
237
+ border-radius: 13px;
238
+ background: var(--ks-soft);
239
+ height: 100%;
240
+ }
225
241
 
226
242
  /* Network card */
227
243
  .ks-net-card {
@@ -231,8 +247,19 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
231
247
  gap: 1.5rem;
232
248
  min-height: 320px;
233
249
  }
234
- .ks-net-top { display: flex; align-items: center; justify-content: space-between; }
235
- .ks-net-icon { font-size: 2.25rem; color: var(--ks-accent); line-height: 1; }
250
+
251
+ .ks-net-top {
252
+ display: flex;
253
+ align-items: center;
254
+ justify-content: space-between;
255
+ }
256
+
257
+ .ks-net-icon {
258
+ font-size: 2.25rem;
259
+ color: var(--ks-accent);
260
+ line-height: 1;
261
+ }
262
+
236
263
  .ks-badge {
237
264
  font-size: .7rem;
238
265
  font-weight: 500;
@@ -241,10 +268,33 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
241
268
  border: 1px solid;
242
269
  white-space: nowrap;
243
270
  }
244
- .ks-stats { display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem; }
245
- .ks-stat { display: flex; flex-direction: column; gap: .25rem; }
246
- .ks-stat-label { font-size: .65rem; text-transform: uppercase; letter-spacing: .06em; color: var(--ks-muted); }
247
- .ks-stat-value { font-size: .95rem; color: var(--ks-heading); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
271
+
272
+ .ks-stats {
273
+ display: grid;
274
+ grid-template-columns: 1fr 1fr;
275
+ gap: 1.1rem;
276
+ }
277
+
278
+ .ks-stat {
279
+ display: flex;
280
+ flex-direction: column;
281
+ gap: .25rem;
282
+ }
283
+
284
+ .ks-stat-label {
285
+ font-size: .65rem;
286
+ text-transform: uppercase;
287
+ letter-spacing: .06em;
288
+ color: var(--ks-muted);
289
+ }
290
+
291
+ .ks-stat-value {
292
+ font-size: .95rem;
293
+ color: var(--ks-heading);
294
+ overflow: hidden;
295
+ text-overflow: ellipsis;
296
+ white-space: nowrap;
297
+ }
248
298
 
249
299
  /* Link cards */
250
300
  .ks-link-card {
@@ -255,12 +305,40 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
255
305
  gap: .5rem;
256
306
  min-height: 100px;
257
307
  }
258
- .ks-link-top { display: flex; justify-content: space-between; align-items: flex-start; }
259
- .ks-link-icon { color: var(--ks-accent); }
260
- .ks-link-arrow { color: var(--ks-muted); }
261
- .ks-link-label { font-size: .58rem; text-transform: uppercase; letter-spacing: .06em; color: var(--ks-muted); margin-bottom: .1rem; }
262
- .ks-link-title { font-size: .875rem; font-weight: 600; color: var(--ks-heading); }
263
- .ks-link-desc { font-size: .75rem; color: var(--ks-muted); margin-top: .1rem; }
308
+
309
+ .ks-link-top {
310
+ display: flex;
311
+ justify-content: space-between;
312
+ align-items: flex-start;
313
+ }
314
+
315
+ .ks-link-icon {
316
+ color: var(--ks-accent);
317
+ }
318
+
319
+ .ks-link-arrow {
320
+ color: var(--ks-muted);
321
+ }
322
+
323
+ .ks-link-label {
324
+ font-size: .58rem;
325
+ text-transform: uppercase;
326
+ letter-spacing: .06em;
327
+ color: var(--ks-muted);
328
+ margin-bottom: .1rem;
329
+ }
330
+
331
+ .ks-link-title {
332
+ font-size: .875rem;
333
+ font-weight: 600;
334
+ color: var(--ks-heading);
335
+ }
336
+
337
+ .ks-link-desc {
338
+ font-size: .75rem;
339
+ color: var(--ks-muted);
340
+ margin-top: .1rem;
341
+ }
264
342
 
265
343
  /* Dialog */
266
344
  .ks-dialog {
@@ -274,7 +352,12 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
274
352
  color: var(--ks-text);
275
353
  box-shadow: 0 20px 60px rgba(0, 0, 0, .25);
276
354
  }
277
- .ks-dialog-inner { padding: 2rem; position: relative; }
355
+
356
+ .ks-dialog-inner {
357
+ padding: 2rem;
358
+ position: relative;
359
+ }
360
+
278
361
  .ks-dialog-close {
279
362
  position: absolute;
280
363
  top: 1rem;
@@ -287,15 +370,31 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
287
370
  padding: .25rem;
288
371
  line-height: 1;
289
372
  }
290
- .ks-dialog-close:hover { color: var(--ks-heading); }
291
- .ks-dialog-title { margin: 0 0 .75rem; font-size: 1.05rem; font-weight: 700; color: var(--ks-heading); }
292
- .ks-dialog-body { font-size: .875rem; color: var(--ks-muted); margin: 0 0 1.25rem; line-height: 1.65; }
373
+
374
+ .ks-dialog-close:hover {
375
+ color: var(--ks-heading);
376
+ }
377
+
378
+ .ks-dialog-title {
379
+ margin: 0 0 .75rem;
380
+ font-size: 1.05rem;
381
+ font-weight: 700;
382
+ color: var(--ks-heading);
383
+ }
384
+
385
+ .ks-dialog-body {
386
+ font-size: .875rem;
387
+ color: var(--ks-muted);
388
+ margin: 0 0 1.25rem;
389
+ line-height: 1.65;
390
+ }
293
391
 
294
392
  .ks-copy-wrap {
295
393
  display: flex;
296
394
  flex-direction: column;
297
395
  gap: .5rem;
298
396
  }
397
+
299
398
  .ks-dialog-addr {
300
399
  display: block;
301
400
  padding: .6em .85em;
@@ -308,6 +407,7 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
308
407
  white-space: normal;
309
408
  color: var(--ks-text);
310
409
  }
410
+
311
411
  .ks-copy-btn {
312
412
  display: inline-flex;
313
413
  align-items: center;
@@ -322,10 +422,23 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
322
422
  cursor: pointer;
323
423
  transition: color .15s, border-color .15s;
324
424
  }
325
- .ks-copy-btn:hover { color: var(--ks-heading); border-color: var(--ks-heading); }
326
- .ks-copy-btn.copied { color: #4caf50; border-color: #4caf50; }
327
425
 
328
- .ks-dialog-thanks { font-size: .8rem; color: var(--ks-muted); margin: .75rem 0 0; text-align: center; }
426
+ .ks-copy-btn:hover {
427
+ color: var(--ks-heading);
428
+ border-color: var(--ks-heading);
429
+ }
430
+
431
+ .ks-copy-btn.copied {
432
+ color: #4caf50;
433
+ border-color: #4caf50;
434
+ }
435
+
436
+ .ks-dialog-thanks {
437
+ font-size: .8rem;
438
+ color: var(--ks-muted);
439
+ margin: .75rem 0 0;
440
+ text-align: center;
441
+ }
329
442
  </style>
330
443
 
331
444
  <style>
@@ -6,7 +6,7 @@ import KaspaStatus from './components/KaspaStatus.vue'
6
6
  const kaspa = useKaspa()
7
7
  const rpc = useRpc()
8
8
 
9
- // KaspaPlugin doesn't call init/connect automatically — we do it here.
9
+ // VueKaspa doesn't call init/connect automatically — we do it here.
10
10
  // The promise is not awaited so the app renders immediately while WASM
11
11
  // loads and the RPC connection establishes in the background.
12
12
  onMounted(() => {
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
- import { ref, computed, onMounted, onUnmounted } from 'vue'
2
+ import { ArrowUpRight, BookOpen, Check, Copy, Droplet, Heart, Search } from 'lucide-vue-next'
3
+ import { computed, onMounted, onUnmounted, ref } from 'vue'
3
4
  import { useKaspa, useRpc } from 'vue-kaspa'
4
- import { Droplet, BookOpen, Search, ArrowUpRight, Heart, Copy, Check } from 'lucide-vue-next'
5
5
 
6
6
  const kaspa = useKaspa()
7
7
  const rpc = useRpc()
@@ -41,12 +41,12 @@ const daaScore = computed(() =>
41
41
  )
42
42
 
43
43
  const links = [
44
- { label: 'Faucet', title: 'Testnet 10', desc: 'Get free test KAS', icon: Droplet, href: 'https://faucet-tn10.kaspanet.io/' },
45
- { label: 'Faucet', title: 'Testnet 12', desc: 'Get free test KAS', icon: Droplet, href: 'https://faucet-tn12.kaspanet.io/' },
46
- { label: 'Docs', title: 'vue-kaspa', desc: 'Read the full docs', icon: BookOpen, href: 'https://vue-kaspa.vercel.app/' },
47
- { label: 'Explorer', title: 'Testnet 10', desc: 'Browse transactions', icon: Search, href: 'https://tn10.kaspa.stream/' },
48
- { label: 'Explorer', title: 'Testnet 12', desc: 'Browse transactions', icon: Search, href: 'https://tn12.kaspa.stream/' },
49
- { label: 'Explorer', title: 'Mainnet', desc: 'Browse transactions', icon: Search, href: 'https://kaspa.stream/' },
44
+ { label: 'Faucet', title: 'Testnet 10', desc: 'Get free test KAS', icon: Droplet, href: 'https://faucet-tn10.kaspanet.io/' },
45
+ { label: 'Faucet', title: 'Testnet 12', desc: 'Get free test KAS', icon: Droplet, href: 'https://faucet-tn12.kaspanet.io/' },
46
+ { label: 'Docs', title: 'Vue Kaspa', desc: 'Read the full docs', icon: BookOpen, href: 'https://vue-kaspa.vercel.app/' },
47
+ { label: 'Explorer', title: 'Testnet 10', desc: 'Browse transactions', icon: Search, href: 'https://tn10.kaspa.stream/' },
48
+ { label: 'Explorer', title: 'Testnet 12', desc: 'Browse transactions', icon: Search, href: 'https://tn12.kaspa.stream/' },
49
+ { label: 'Explorer', title: 'Mainnet', desc: 'Browse transactions', icon: Search, href: 'https://kaspa.stream/' },
50
50
  ]
51
51
 
52
52
  function onMouseMove(e: MouseEvent) {
@@ -67,8 +67,9 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
67
67
  <dialog ref="donateDialog" class="dialog" @click.self="donateDialog?.close()">
68
68
  <div class="dialog-inner">
69
69
  <button class="dialog-close" @click="donateDialog?.close()">✕</button>
70
- <p class="dialog-title">Support vue-kaspa ❤️</p>
71
- <p class="dialog-body">vue-kaspa is free and open-source. If it saves you time, consider sending some KAS — every bit helps keep the project alive and maintained.</p>
70
+ <p class="dialog-title">Support Vue Kaspa ❤️</p>
71
+ <p class="dialog-body">Vue Kaspa is free and open-source. If it saves you time, consider sending some KAS — every
72
+ bit helps keep the project alive and maintained.</p>
72
73
  <div class="copy-wrap">
73
74
  <code class="dialog-addr">{{ KASPA_ADDRESS }}</code>
74
75
  <button class="copy-btn" :class="{ copied }" @click="copyAddress">
@@ -85,18 +86,14 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
85
86
 
86
87
  <!-- Header -->
87
88
  <header class="header">
88
- <img src="/logo.png" alt="vue-kaspa" class="header-logo" />
89
- <span class="header-brand">vue-kaspa</span>
89
+ <img src="/logo.png" alt="Vue Kaspa" class="header-logo" />
90
+ <span class="header-brand">Vue Kaspa</span>
90
91
  <nav class="header-nav">
91
- <a
92
- href="https://github.com/furatamasensei/vue-kaspa"
93
- target="_blank"
94
- rel="noopener"
95
- class="icon-btn"
96
- title="GitHub"
97
- >
92
+ <a href="https://github.com/furatamasensei/vue-kaspa" target="_blank" rel="noopener" class="icon-btn"
93
+ title="GitHub">
98
94
  <svg viewBox="0 0 24 24" width="18" height="18" fill="currentColor">
99
- <path d="M12 2C6.477 2 2 6.477 2 12c0 4.42 2.865 8.166 6.839 9.489.5.092.682-.217.682-.482 0-.237-.008-.866-.013-1.7-2.782.603-3.369-1.342-3.369-1.342-.454-1.155-1.11-1.463-1.11-1.463-.908-.62.069-.608.069-.608 1.003.07 1.531 1.03 1.531 1.03.892 1.529 2.341 1.087 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.11-4.555-4.943 0-1.091.39-1.984 1.029-2.683-.103-.253-.446-1.27.098-2.647 0 0 .84-.269 2.75 1.025A9.578 9.578 0 0112 6.836c.85.004 1.705.114 2.504.337 1.909-1.294 2.747-1.025 2.747-1.025.546 1.377.202 2.394.1 2.647.64.699 1.028 1.592 1.028 2.683 0 3.842-2.339 4.687-4.566 4.935.359.309.678.919.678 1.852 0 1.336-.012 2.415-.012 2.741 0 .267.18.578.688.48C19.138 20.163 22 16.418 22 12c0-5.523-4.477-10-10-10z"/>
95
+ <path
96
+ d="M12 2C6.477 2 2 6.477 2 12c0 4.42 2.865 8.166 6.839 9.489.5.092.682-.217.682-.482 0-.237-.008-.866-.013-1.7-2.782.603-3.369-1.342-3.369-1.342-.454-1.155-1.11-1.463-1.11-1.463-.908-.62.069-.608.069-.608 1.003.07 1.531 1.03 1.531 1.03.892 1.529 2.341 1.087 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.11-4.555-4.943 0-1.091.39-1.984 1.029-2.683-.103-.253-.446-1.27.098-2.647 0 0 .84-.269 2.75 1.025A9.578 9.578 0 0112 6.836c.85.004 1.705.114 2.504.337 1.909-1.294 2.747-1.025 2.747-1.025.546 1.377.202 2.394.1 2.647.64.699 1.028 1.592 1.028 2.683 0 3.842-2.339 4.687-4.566 4.935.359.309.678.919.678 1.852 0 1.336-.012 2.415-.012 2.741 0 .267.18.578.688.48C19.138 20.163 22 16.418 22 12c0-5.523-4.477-10-10-10z" />
100
97
  </svg>
101
98
  </a>
102
99
  <button class="icon-btn" title="Support this project" @click="donateDialog?.showModal()">
@@ -108,73 +105,88 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
108
105
  <!-- Bento grid -->
109
106
  <div ref="bento" class="grid">
110
107
 
111
- <!-- Network card: col 1–2, row 1–3 -->
112
- <div data-shine class="shine net-shine">
113
- <div class="card net-card">
114
- <div class="net-top">
115
- <span class="net-icon">⬡</span>
116
- <span class="badge" :style="`border-color:${badgeColor};color:${badgeColor}`">{{ stateLabel }}</span>
108
+ <!-- Network card: col 1–2, row 1–3 -->
109
+ <div data-shine class="shine net-shine">
110
+ <div class="card net-card">
111
+ <div class="net-top">
112
+ <span class="net-icon">⬡</span>
113
+ <span class="badge" :style="`border-color:${badgeColor};color:${badgeColor}`">{{ stateLabel }}</span>
114
+ </div>
115
+ <div class="stats">
116
+ <div class="stat">
117
+ <span class="stat-label">Network</span>
118
+ <span class="stat-value">{{ rpc.networkId.value ?? '—' }}</span>
119
+ </div>
120
+ <div class="stat">
121
+ <span class="stat-label">Server version</span>
122
+ <span class="stat-value">{{ rpc.serverVersion.value ?? '—' }}</span>
123
+ </div>
124
+ <div class="stat">
125
+ <span class="stat-label">DAA Score</span>
126
+ <span class="stat-value mono">{{ daaScore }}</span>
117
127
  </div>
118
- <div class="stats">
119
- <div class="stat">
120
- <span class="stat-label">Network</span>
121
- <span class="stat-value">{{ rpc.networkId.value ?? '' }}</span>
122
- </div>
123
- <div class="stat">
124
- <span class="stat-label">Server version</span>
125
- <span class="stat-value">{{ rpc.serverVersion.value ?? '—' }}</span>
126
- </div>
127
- <div class="stat">
128
- <span class="stat-label">DAA Score</span>
129
- <span class="stat-value mono">{{ daaScore }}</span>
130
- </div>
131
- <div class="stat">
132
- <span class="stat-label">Synced</span>
133
- <span
134
- class="stat-value"
135
- :style="`color:${rpc.isConnected.value ? (rpc.isSynced.value ? '#4caf50' : 'var(--ks-text)') : 'var(--ks-muted)'}`"
136
- >{{ rpc.isConnected.value ? (rpc.isSynced.value ? 'Yes' : 'Syncing…') : '—' }}</span>
137
- </div>
128
+ <div class="stat">
129
+ <span class="stat-label">Synced</span>
130
+ <span class="stat-value"
131
+ :style="`color:${rpc.isConnected.value ? (rpc.isSynced.value ? '#4caf50' : 'var(--ks-text)') : 'var(--ks-muted)'}`">{{
132
+ rpc.isConnected.value ? (rpc.isSynced.value ? 'Yes' : 'Syncing…') : '—' }}</span>
138
133
  </div>
139
134
  </div>
140
135
  </div>
136
+ </div>
141
137
 
142
- <!-- Link cards: auto-placed into Γ shape -->
143
- <a
144
- v-for="link in links"
145
- :key="link.href"
146
- data-shine
147
- class="shine link-shine"
148
- :href="link.href"
149
- target="_blank"
150
- rel="noopener"
151
- >
152
- <div class="card link-card">
153
- <div class="link-top">
154
- <component :is="link.icon" :size="20" class="link-icon" />
155
- <ArrowUpRight :size="13" class="link-arrow" />
156
- </div>
157
- <div>
158
- <div class="link-label">{{ link.label }}</div>
159
- <div class="link-title">{{ link.title }}</div>
160
- <div class="link-desc">{{ link.desc }}</div>
161
- </div>
138
+ <!-- Link cards: auto-placed into Γ shape -->
139
+ <a v-for="link in links" :key="link.href" data-shine class="shine link-shine" :href="link.href" target="_blank"
140
+ rel="noopener">
141
+ <div class="card link-card">
142
+ <div class="link-top">
143
+ <component :is="link.icon" :size="20" class="link-icon" />
144
+ <ArrowUpRight :size="13" class="link-arrow" />
162
145
  </div>
163
- </a>
146
+ <div>
147
+ <div class="link-label">{{ link.label }}</div>
148
+ <div class="link-title">{{ link.title }}</div>
149
+ <div class="link-desc">{{ link.desc }}</div>
150
+ </div>
151
+ </div>
152
+ </a>
164
153
 
165
- </div>
154
+ </div>
166
155
  </div>
167
156
  </template>
168
157
 
169
158
  <style scoped>
170
159
  /* Root */
171
- .root { width: 100%; font-family: Inter, system-ui, -apple-system, sans-serif; }
160
+ .root {
161
+ width: 100%;
162
+ font-family: Inter, system-ui, -apple-system, sans-serif;
163
+ }
172
164
 
173
165
  /* Header */
174
- .header { display: flex; align-items: center; gap: .6rem; margin-bottom: .75rem; }
175
- .header-logo { width: 28px; height: 28px; object-fit: contain; }
176
- .header-brand { font-size: 1rem; font-weight: 700; color: var(--ks-heading); flex: 1; }
177
- .header-nav { display: flex; gap: .15rem; }
166
+ .header {
167
+ display: flex;
168
+ align-items: center;
169
+ gap: .6rem;
170
+ margin-bottom: .75rem;
171
+ }
172
+
173
+ .header-logo {
174
+ width: 28px;
175
+ height: 28px;
176
+ object-fit: contain;
177
+ }
178
+
179
+ .header-brand {
180
+ font-size: 1rem;
181
+ font-weight: 700;
182
+ color: var(--ks-heading);
183
+ flex: 1;
184
+ }
185
+
186
+ .header-nav {
187
+ display: flex;
188
+ gap: .15rem;
189
+ }
178
190
 
179
191
  .icon-btn {
180
192
  display: inline-flex;
@@ -190,7 +202,11 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
190
202
  text-decoration: none;
191
203
  transition: color .15s, background .15s;
192
204
  }
193
- .icon-btn:hover { color: var(--ks-heading); background: var(--ks-border); }
205
+
206
+ .icon-btn:hover {
207
+ color: var(--ks-heading);
208
+ background: var(--ks-border);
209
+ }
194
210
 
195
211
  /* Grid */
196
212
  .grid {
@@ -203,38 +219,129 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
203
219
  .shine {
204
220
  padding: 1px;
205
221
  border-radius: 14px;
206
- background: radial-gradient(
207
- 350px circle at var(--x, -9999px) var(--y, -9999px),
208
- var(--ks-shine),
209
- var(--ks-border) 80%
210
- );
222
+ background: radial-gradient(350px circle at var(--x, -9999px) var(--y, -9999px),
223
+ var(--ks-shine),
224
+ var(--ks-border) 80%);
211
225
  display: block;
212
226
  text-decoration: none;
213
227
  }
214
- .net-shine { grid-column: 1 / span 2; grid-row: 1 / span 3; }
228
+
229
+ .net-shine {
230
+ grid-column: 1 / span 2;
231
+ grid-row: 1 / span 3;
232
+ }
215
233
 
216
234
  /* Card base */
217
- .card { border-radius: 13px; background: var(--ks-soft); height: 100%; }
235
+ .card {
236
+ border-radius: 13px;
237
+ background: var(--ks-soft);
238
+ height: 100%;
239
+ }
218
240
 
219
241
  /* Network card */
220
- .net-card { padding: 1.75rem; display: flex; flex-direction: column; gap: 1.5rem; min-height: 320px; }
221
- .net-top { display: flex; align-items: center; justify-content: space-between; }
222
- .net-icon { font-size: 2.25rem; color: var(--ks-accent); line-height: 1; }
223
- .badge { font-size: .7rem; font-weight: 500; padding: .2em .6em; border-radius: 999px; border: 1px solid; white-space: nowrap; }
224
- .stats { display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem; }
225
- .stat { display: flex; flex-direction: column; gap: .25rem; }
226
- .stat-label { font-size: .65rem; text-transform: uppercase; letter-spacing: .06em; color: var(--ks-muted); }
227
- .stat-value { font-size: .95rem; color: var(--ks-heading); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
228
- .mono { font-family: monospace; }
242
+ .net-card {
243
+ padding: 1.75rem;
244
+ display: flex;
245
+ flex-direction: column;
246
+ gap: 1.5rem;
247
+ min-height: 320px;
248
+ }
249
+
250
+ .net-top {
251
+ display: flex;
252
+ align-items: center;
253
+ justify-content: space-between;
254
+ }
255
+
256
+ .net-icon {
257
+ font-size: 2.25rem;
258
+ color: var(--ks-accent);
259
+ line-height: 1;
260
+ }
261
+
262
+ .badge {
263
+ font-size: .7rem;
264
+ font-weight: 500;
265
+ padding: .2em .6em;
266
+ border-radius: 999px;
267
+ border: 1px solid;
268
+ white-space: nowrap;
269
+ }
270
+
271
+ .stats {
272
+ display: grid;
273
+ grid-template-columns: 1fr 1fr;
274
+ gap: 1.1rem;
275
+ }
276
+
277
+ .stat {
278
+ display: flex;
279
+ flex-direction: column;
280
+ gap: .25rem;
281
+ }
282
+
283
+ .stat-label {
284
+ font-size: .65rem;
285
+ text-transform: uppercase;
286
+ letter-spacing: .06em;
287
+ color: var(--ks-muted);
288
+ }
289
+
290
+ .stat-value {
291
+ font-size: .95rem;
292
+ color: var(--ks-heading);
293
+ overflow: hidden;
294
+ text-overflow: ellipsis;
295
+ white-space: nowrap;
296
+ }
297
+
298
+ .mono {
299
+ font-family: monospace;
300
+ }
229
301
 
230
302
  /* Link cards */
231
- .link-card { padding: 1rem; display: flex; flex-direction: column; justify-content: space-between; gap: .5rem; min-height: 100px; }
232
- .link-top { display: flex; justify-content: space-between; align-items: flex-start; }
233
- .link-icon { color: var(--ks-accent); }
234
- .link-arrow { color: var(--ks-muted); }
235
- .link-label { font-size: .58rem; text-transform: uppercase; letter-spacing: .06em; color: var(--ks-muted); margin-bottom: .1rem; }
236
- .link-title { font-size: .875rem; font-weight: 600; color: var(--ks-heading); }
237
- .link-desc { font-size: .75rem; color: var(--ks-muted); margin-top: .1rem; }
303
+ .link-card {
304
+ padding: 1rem;
305
+ display: flex;
306
+ flex-direction: column;
307
+ justify-content: space-between;
308
+ gap: .5rem;
309
+ min-height: 100px;
310
+ }
311
+
312
+ .link-top {
313
+ display: flex;
314
+ justify-content: space-between;
315
+ align-items: flex-start;
316
+ }
317
+
318
+ .link-icon {
319
+ color: var(--ks-accent);
320
+ }
321
+
322
+ .link-arrow {
323
+ color: var(--ks-muted);
324
+ }
325
+
326
+ .link-label {
327
+ font-size: .58rem;
328
+ text-transform: uppercase;
329
+ letter-spacing: .06em;
330
+ color: var(--ks-muted);
331
+ margin-bottom: .1rem;
332
+ }
333
+
334
+ .link-title {
335
+ font-size: .875rem;
336
+ font-weight: 600;
337
+ color: var(--ks-heading);
338
+ }
339
+
340
+ .link-desc {
341
+ font-size: .75rem;
342
+ color: var(--ks-muted);
343
+ margin-top: .1rem;
344
+ }
238
345
 
239
346
  /* Dialog */
240
347
  .dialog {
@@ -248,13 +355,49 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
248
355
  color: var(--ks-text);
249
356
  box-shadow: 0 20px 60px rgba(0, 0, 0, .25);
250
357
  }
251
- .dialog-inner { padding: 2rem; position: relative; }
252
- .dialog-close { position: absolute; top: 1rem; right: 1rem; background: none; border: none; font-size: .9rem; cursor: pointer; color: var(--ks-muted); padding: .25rem; line-height: 1; }
253
- .dialog-close:hover { color: var(--ks-heading); }
254
- .dialog-title { margin: 0 0 .75rem; font-size: 1.05rem; font-weight: 700; color: var(--ks-heading); }
255
- .dialog-body { font-size: .875rem; color: var(--ks-muted); margin: 0 0 1.25rem; line-height: 1.65; }
256
358
 
257
- .copy-wrap { display: flex; flex-direction: column; gap: .5rem; }
359
+ .dialog-inner {
360
+ padding: 2rem;
361
+ position: relative;
362
+ }
363
+
364
+ .dialog-close {
365
+ position: absolute;
366
+ top: 1rem;
367
+ right: 1rem;
368
+ background: none;
369
+ border: none;
370
+ font-size: .9rem;
371
+ cursor: pointer;
372
+ color: var(--ks-muted);
373
+ padding: .25rem;
374
+ line-height: 1;
375
+ }
376
+
377
+ .dialog-close:hover {
378
+ color: var(--ks-heading);
379
+ }
380
+
381
+ .dialog-title {
382
+ margin: 0 0 .75rem;
383
+ font-size: 1.05rem;
384
+ font-weight: 700;
385
+ color: var(--ks-heading);
386
+ }
387
+
388
+ .dialog-body {
389
+ font-size: .875rem;
390
+ color: var(--ks-muted);
391
+ margin: 0 0 1.25rem;
392
+ line-height: 1.65;
393
+ }
394
+
395
+ .copy-wrap {
396
+ display: flex;
397
+ flex-direction: column;
398
+ gap: .5rem;
399
+ }
400
+
258
401
  .dialog-addr {
259
402
  display: block;
260
403
  padding: .6em .85em;
@@ -267,6 +410,7 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
267
410
  white-space: normal;
268
411
  color: var(--ks-text);
269
412
  }
413
+
270
414
  .copy-btn {
271
415
  display: inline-flex;
272
416
  align-items: center;
@@ -281,10 +425,23 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
281
425
  cursor: pointer;
282
426
  transition: color .15s, border-color .15s;
283
427
  }
284
- .copy-btn:hover { color: var(--ks-heading); border-color: var(--ks-heading); }
285
- .copy-btn.copied { color: #4caf50; border-color: #4caf50; }
286
428
 
287
- .dialog-thanks { font-size: .8rem; color: var(--ks-muted); margin: .75rem 0 0; text-align: center; }
429
+ .copy-btn:hover {
430
+ color: var(--ks-heading);
431
+ border-color: var(--ks-heading);
432
+ }
433
+
434
+ .copy-btn.copied {
435
+ color: #4caf50;
436
+ border-color: #4caf50;
437
+ }
438
+
439
+ .dialog-thanks {
440
+ font-size: .8rem;
441
+ color: var(--ks-muted);
442
+ margin: .75rem 0 0;
443
+ text-align: center;
444
+ }
288
445
  </style>
289
446
 
290
447
  <style>
@@ -1,8 +1,8 @@
1
1
  import { createApp } from 'vue'
2
- import { KaspaPlugin } from 'vue-kaspa'
2
+ import { VueKaspa } from 'vue-kaspa'
3
3
  import App from './App.vue'
4
4
  import './style.css'
5
5
 
6
6
  createApp(App)
7
- .use(KaspaPlugin, { network: 'mainnet', autoConnect: true })
7
+ .use(VueKaspa, { network: 'mainnet', autoConnect: true })
8
8
  .mount('#app')
@@ -7,7 +7,7 @@ export default defineConfig({
7
7
  optimizeDeps: { exclude: ['@vue-kaspa/kaspa-wasm'] },
8
8
  server: {
9
9
  headers: {
10
- 'Cross-Origin-Embedder-Policy': 'require-corp',
10
+ 'Cross-Origin-Embedder-Policy': 'credentialless',
11
11
  'Cross-Origin-Opener-Policy': 'same-origin',
12
12
  },
13
13
  },