vue-kaspa-cli 0.1.9 → 0.1.10
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,11 +1,21 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
|
3
|
-
|
|
3
|
+
import { Droplet, BookOpen, Search, ArrowUpRight, Heart, Copy, Check } from 'lucide-vue-next'
|
|
4
|
+
// useKaspa and useRpc are auto-imported by Nuxt.
|
|
4
5
|
|
|
5
6
|
const kaspa = useKaspa()
|
|
6
7
|
const rpc = useRpc()
|
|
7
8
|
const bento = ref<HTMLElement | null>(null)
|
|
8
9
|
const donateDialog = ref<HTMLDialogElement | null>(null)
|
|
10
|
+
const copied = ref(false)
|
|
11
|
+
|
|
12
|
+
const KASPA_ADDRESS = 'kaspa:qypr7ayn2g55fccyv9n6gf9zgrcnpepkfgjf9d8mtfp68ezv3mgqnggxqs902q4'
|
|
13
|
+
|
|
14
|
+
async function copyAddress() {
|
|
15
|
+
await navigator.clipboard.writeText(KASPA_ADDRESS)
|
|
16
|
+
copied.value = true
|
|
17
|
+
setTimeout(() => { copied.value = false }, 2000)
|
|
18
|
+
}
|
|
9
19
|
|
|
10
20
|
const stateLabel = computed(() => {
|
|
11
21
|
if (kaspa.wasmStatus.value === 'loading') return 'Loading WASM…'
|
|
@@ -31,12 +41,12 @@ const daaScore = computed(() =>
|
|
|
31
41
|
)
|
|
32
42
|
|
|
33
43
|
const links = [
|
|
34
|
-
{ label: 'Faucet', title: 'Testnet 10', desc: 'Get free test KAS', icon:
|
|
35
|
-
{ label: 'Faucet', title: 'Testnet 12', desc: 'Get free test KAS', icon:
|
|
36
|
-
{ label: 'Docs', title: 'vue-kaspa', desc: 'Read the full docs', icon:
|
|
37
|
-
{ label: 'Explorer', title: 'Testnet 10', desc: 'Browse transactions', icon:
|
|
38
|
-
{ label: 'Explorer', title: 'Testnet 12', desc: 'Browse transactions', icon:
|
|
39
|
-
{ label: 'Explorer', title: 'Mainnet', desc: 'Browse transactions', icon:
|
|
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/' },
|
|
40
50
|
]
|
|
41
51
|
|
|
42
52
|
function onMouseMove(e: MouseEvent) {
|
|
@@ -59,7 +69,14 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
|
|
|
59
69
|
<button class="ks-dialog-close" @click="donateDialog?.close()">✕</button>
|
|
60
70
|
<p class="ks-dialog-title">Support vue-kaspa ❤️</p>
|
|
61
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>
|
|
62
|
-
<
|
|
72
|
+
<div class="ks-copy-wrap">
|
|
73
|
+
<code class="ks-dialog-addr">{{ KASPA_ADDRESS }}</code>
|
|
74
|
+
<button class="ks-copy-btn" :class="{ copied }" @click="copyAddress">
|
|
75
|
+
<Check v-if="copied" :size="13" />
|
|
76
|
+
<Copy v-else :size="13" />
|
|
77
|
+
{{ copied ? 'Copied!' : 'Copy' }}
|
|
78
|
+
</button>
|
|
79
|
+
</div>
|
|
63
80
|
<p class="ks-dialog-thanks">Thank you for your support 🙏</p>
|
|
64
81
|
</div>
|
|
65
82
|
</dialog>
|
|
@@ -83,73 +100,73 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
|
|
|
83
100
|
</svg>
|
|
84
101
|
</a>
|
|
85
102
|
<button class="ks-icon-btn" title="Support this project" @click="donateDialog?.showModal()">
|
|
86
|
-
<
|
|
87
|
-
<path d="M12 21.593c-.425-.396-8.8-8.044-8.8-12.593C3.2 5.796 7.192 3 12 3s8.8 2.796 8.8 6c0 4.549-8.375 12.197-8.8 12.593z"/>
|
|
88
|
-
</svg>
|
|
103
|
+
<Heart :size="18" />
|
|
89
104
|
</button>
|
|
90
105
|
</nav>
|
|
91
106
|
</header>
|
|
92
107
|
|
|
93
|
-
<!--
|
|
94
|
-
<div
|
|
108
|
+
<!-- Gradient + bento grid -->
|
|
109
|
+
<div class="ks-grid-wrap">
|
|
110
|
+
<div ref="bento" class="ks-grid">
|
|
95
111
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
<span
|
|
102
|
-
class="ks-badge"
|
|
103
|
-
:style="`border-color:${badgeColor};color:${badgeColor}`"
|
|
104
|
-
>{{ stateLabel }}</span>
|
|
105
|
-
</div>
|
|
106
|
-
<div class="ks-stats">
|
|
107
|
-
<div class="ks-stat">
|
|
108
|
-
<span class="ks-stat-label">Network</span>
|
|
109
|
-
<span class="ks-stat-value">{{ rpc.networkId.value ?? '—' }}</span>
|
|
110
|
-
</div>
|
|
111
|
-
<div class="ks-stat">
|
|
112
|
-
<span class="ks-stat-label">Server version</span>
|
|
113
|
-
<span class="ks-stat-value">{{ rpc.serverVersion.value ?? '—' }}</span>
|
|
114
|
-
</div>
|
|
115
|
-
<div class="ks-stat">
|
|
116
|
-
<span class="ks-stat-label">DAA Score</span>
|
|
117
|
-
<span class="ks-stat-value" style="font-family:monospace">{{ daaScore }}</span>
|
|
118
|
-
</div>
|
|
119
|
-
<div class="ks-stat">
|
|
120
|
-
<span class="ks-stat-label">Synced</span>
|
|
112
|
+
<!-- Network card: col 1–2, row 1–3 -->
|
|
113
|
+
<div data-shine class="ks-shine ks-net-shine">
|
|
114
|
+
<div class="ks-card ks-net-card">
|
|
115
|
+
<div class="ks-net-top">
|
|
116
|
+
<span class="ks-net-icon">⬡</span>
|
|
121
117
|
<span
|
|
122
|
-
class="ks-
|
|
123
|
-
:style="`color:${
|
|
124
|
-
>{{
|
|
118
|
+
class="ks-badge"
|
|
119
|
+
:style="`border-color:${badgeColor};color:${badgeColor}`"
|
|
120
|
+
>{{ stateLabel }}</span>
|
|
121
|
+
</div>
|
|
122
|
+
<div class="ks-stats">
|
|
123
|
+
<div class="ks-stat">
|
|
124
|
+
<span class="ks-stat-label">Network</span>
|
|
125
|
+
<span class="ks-stat-value">{{ rpc.networkId.value ?? '—' }}</span>
|
|
126
|
+
</div>
|
|
127
|
+
<div class="ks-stat">
|
|
128
|
+
<span class="ks-stat-label">Server version</span>
|
|
129
|
+
<span class="ks-stat-value">{{ rpc.serverVersion.value ?? '—' }}</span>
|
|
130
|
+
</div>
|
|
131
|
+
<div class="ks-stat">
|
|
132
|
+
<span class="ks-stat-label">DAA Score</span>
|
|
133
|
+
<span class="ks-stat-value" style="font-family:monospace">{{ daaScore }}</span>
|
|
134
|
+
</div>
|
|
135
|
+
<div class="ks-stat">
|
|
136
|
+
<span class="ks-stat-label">Synced</span>
|
|
137
|
+
<span
|
|
138
|
+
class="ks-stat-value"
|
|
139
|
+
:style="`color:${rpc.isConnected.value ? (rpc.isSynced.value ? '#4caf50' : 'var(--ks-text)') : 'var(--ks-muted)'}`"
|
|
140
|
+
>{{ rpc.isConnected.value ? (rpc.isSynced.value ? 'Yes' : 'Syncing…') : '—' }}</span>
|
|
141
|
+
</div>
|
|
125
142
|
</div>
|
|
126
143
|
</div>
|
|
127
144
|
</div>
|
|
128
|
-
</div>
|
|
129
145
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
146
|
+
<!-- Link cards: auto-placed into Γ shape -->
|
|
147
|
+
<a
|
|
148
|
+
v-for="link in links"
|
|
149
|
+
:key="link.href"
|
|
150
|
+
data-shine
|
|
151
|
+
class="ks-shine ks-link-shine"
|
|
152
|
+
:href="link.href"
|
|
153
|
+
target="_blank"
|
|
154
|
+
rel="noopener"
|
|
155
|
+
>
|
|
156
|
+
<div class="ks-card ks-link-card">
|
|
157
|
+
<div class="ks-link-top">
|
|
158
|
+
<component :is="link.icon" :size="20" class="ks-link-icon" />
|
|
159
|
+
<ArrowUpRight :size="13" class="ks-link-arrow" />
|
|
160
|
+
</div>
|
|
161
|
+
<div>
|
|
162
|
+
<div class="ks-link-label">{{ link.label }}</div>
|
|
163
|
+
<div class="ks-link-title">{{ link.title }}</div>
|
|
164
|
+
<div class="ks-link-desc">{{ link.desc }}</div>
|
|
165
|
+
</div>
|
|
149
166
|
</div>
|
|
150
|
-
</
|
|
151
|
-
</a>
|
|
167
|
+
</a>
|
|
152
168
|
|
|
169
|
+
</div>
|
|
153
170
|
</div>
|
|
154
171
|
</div>
|
|
155
172
|
</template>
|
|
@@ -163,15 +180,10 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
|
|
|
163
180
|
}
|
|
164
181
|
|
|
165
182
|
/* Header */
|
|
166
|
-
.ks-header {
|
|
167
|
-
display: flex;
|
|
168
|
-
align-items: center;
|
|
169
|
-
gap: 0.6rem;
|
|
170
|
-
margin-bottom: 0.75rem;
|
|
171
|
-
}
|
|
183
|
+
.ks-header { display: flex; align-items: center; gap: .6rem; margin-bottom: .75rem; }
|
|
172
184
|
.ks-header-logo { width: 28px; height: 28px; object-fit: contain; }
|
|
173
185
|
.ks-header-brand { font-size: 1rem; font-weight: 700; color: var(--ks-heading); flex: 1; }
|
|
174
|
-
.ks-header-nav { display: flex; gap:
|
|
186
|
+
.ks-header-nav { display: flex; gap: .15rem; }
|
|
175
187
|
|
|
176
188
|
.ks-icon-btn {
|
|
177
189
|
display: inline-flex;
|
|
@@ -185,18 +197,36 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
|
|
|
185
197
|
color: var(--ks-muted);
|
|
186
198
|
cursor: pointer;
|
|
187
199
|
text-decoration: none;
|
|
188
|
-
transition: color
|
|
200
|
+
transition: color .15s, background .15s;
|
|
189
201
|
}
|
|
190
202
|
.ks-icon-btn:hover { color: var(--ks-heading); background: var(--ks-border); }
|
|
191
203
|
|
|
204
|
+
/* Grid wrap + U-shaped gradient backdrop */
|
|
205
|
+
.ks-grid-wrap {
|
|
206
|
+
position: relative;
|
|
207
|
+
}
|
|
208
|
+
.ks-grid-wrap::before {
|
|
209
|
+
content: '';
|
|
210
|
+
position: absolute;
|
|
211
|
+
inset: 0 -20px -28px;
|
|
212
|
+
z-index: 0;
|
|
213
|
+
pointer-events: none;
|
|
214
|
+
background:
|
|
215
|
+
radial-gradient(ellipse 55% 65% at 8% 100%, rgba(73, 197, 163, .38) 0%, transparent 55%),
|
|
216
|
+
radial-gradient(ellipse 55% 65% at 92% 100%, rgba(73, 197, 163, .38) 0%, transparent 55%),
|
|
217
|
+
radial-gradient(ellipse 85% 30% at 50% 100%, rgba(73, 197, 163, .22) 0%, transparent 60%);
|
|
218
|
+
}
|
|
219
|
+
|
|
192
220
|
/* Grid */
|
|
193
221
|
.ks-grid {
|
|
194
222
|
display: grid;
|
|
195
223
|
grid-template-columns: repeat(3, 1fr);
|
|
196
|
-
gap:
|
|
224
|
+
gap: .75rem;
|
|
225
|
+
position: relative;
|
|
226
|
+
z-index: 1;
|
|
197
227
|
}
|
|
198
228
|
|
|
199
|
-
/* Shine wrapper
|
|
229
|
+
/* Shine wrapper */
|
|
200
230
|
.ks-shine {
|
|
201
231
|
padding: 1px;
|
|
202
232
|
border-radius: 14px;
|
|
@@ -208,19 +238,10 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
|
|
|
208
238
|
display: block;
|
|
209
239
|
text-decoration: none;
|
|
210
240
|
}
|
|
241
|
+
.ks-net-shine { grid-column: 1 / span 2; grid-row: 1 / span 3; }
|
|
211
242
|
|
|
212
|
-
/*
|
|
213
|
-
.ks-
|
|
214
|
-
grid-column: 1 / span 2;
|
|
215
|
-
grid-row: 1 / span 3;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/* Card base — solid fill sits inside the 1px shine gap */
|
|
219
|
-
.ks-card {
|
|
220
|
-
border-radius: 13px;
|
|
221
|
-
background: var(--ks-soft);
|
|
222
|
-
height: 100%;
|
|
223
|
-
}
|
|
243
|
+
/* Card base */
|
|
244
|
+
.ks-card { border-radius: 13px; background: var(--ks-soft); height: 100%; }
|
|
224
245
|
|
|
225
246
|
/* Network card */
|
|
226
247
|
.ks-net-card {
|
|
@@ -242,19 +263,8 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
|
|
|
242
263
|
}
|
|
243
264
|
.ks-stats { display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem; }
|
|
244
265
|
.ks-stat { display: flex; flex-direction: column; gap: .25rem; }
|
|
245
|
-
.ks-stat-label {
|
|
246
|
-
|
|
247
|
-
text-transform: uppercase;
|
|
248
|
-
letter-spacing: .06em;
|
|
249
|
-
color: var(--ks-muted);
|
|
250
|
-
}
|
|
251
|
-
.ks-stat-value {
|
|
252
|
-
font-size: .95rem;
|
|
253
|
-
color: var(--ks-heading);
|
|
254
|
-
overflow: hidden;
|
|
255
|
-
text-overflow: ellipsis;
|
|
256
|
-
white-space: nowrap;
|
|
257
|
-
}
|
|
266
|
+
.ks-stat-label { font-size: .65rem; text-transform: uppercase; letter-spacing: .06em; color: var(--ks-muted); }
|
|
267
|
+
.ks-stat-value { font-size: .95rem; color: var(--ks-heading); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
258
268
|
|
|
259
269
|
/* Link cards */
|
|
260
270
|
.ks-link-card {
|
|
@@ -262,19 +272,13 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
|
|
|
262
272
|
display: flex;
|
|
263
273
|
flex-direction: column;
|
|
264
274
|
justify-content: space-between;
|
|
265
|
-
gap:
|
|
275
|
+
gap: .5rem;
|
|
266
276
|
min-height: 100px;
|
|
267
277
|
}
|
|
268
278
|
.ks-link-top { display: flex; justify-content: space-between; align-items: flex-start; }
|
|
269
|
-
.ks-link-icon {
|
|
270
|
-
.ks-link-arrow {
|
|
271
|
-
.ks-link-label {
|
|
272
|
-
font-size: .58rem;
|
|
273
|
-
text-transform: uppercase;
|
|
274
|
-
letter-spacing: .06em;
|
|
275
|
-
color: var(--ks-muted);
|
|
276
|
-
margin-bottom: .1rem;
|
|
277
|
-
}
|
|
279
|
+
.ks-link-icon { color: var(--ks-accent); }
|
|
280
|
+
.ks-link-arrow { color: var(--ks-muted); }
|
|
281
|
+
.ks-link-label { font-size: .58rem; text-transform: uppercase; letter-spacing: .06em; color: var(--ks-muted); margin-bottom: .1rem; }
|
|
278
282
|
.ks-link-title { font-size: .875rem; font-weight: 600; color: var(--ks-heading); }
|
|
279
283
|
.ks-link-desc { font-size: .75rem; color: var(--ks-muted); margin-top: .1rem; }
|
|
280
284
|
|
|
@@ -283,8 +287,9 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
|
|
|
283
287
|
border: 1px solid var(--ks-border);
|
|
284
288
|
border-radius: 16px;
|
|
285
289
|
padding: 0;
|
|
286
|
-
|
|
287
|
-
width:
|
|
290
|
+
width: min(440px, calc(100vw - 2rem));
|
|
291
|
+
max-width: none;
|
|
292
|
+
overflow: hidden;
|
|
288
293
|
background: var(--ks-surface);
|
|
289
294
|
color: var(--ks-text);
|
|
290
295
|
box-shadow: 0 20px 60px rgba(0, 0, 0, .25);
|
|
@@ -305,6 +310,12 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
|
|
|
305
310
|
.ks-dialog-close:hover { color: var(--ks-heading); }
|
|
306
311
|
.ks-dialog-title { margin: 0 0 .75rem; font-size: 1.05rem; font-weight: 700; color: var(--ks-heading); }
|
|
307
312
|
.ks-dialog-body { font-size: .875rem; color: var(--ks-muted); margin: 0 0 1.25rem; line-height: 1.65; }
|
|
313
|
+
|
|
314
|
+
.ks-copy-wrap {
|
|
315
|
+
display: flex;
|
|
316
|
+
flex-direction: column;
|
|
317
|
+
gap: .5rem;
|
|
318
|
+
}
|
|
308
319
|
.ks-dialog-addr {
|
|
309
320
|
display: block;
|
|
310
321
|
padding: .6em .85em;
|
|
@@ -313,13 +324,31 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
|
|
|
313
324
|
border: 1px solid var(--ks-border);
|
|
314
325
|
font-size: .7rem;
|
|
315
326
|
word-break: break-all;
|
|
327
|
+
overflow-wrap: anywhere;
|
|
328
|
+
white-space: normal;
|
|
316
329
|
color: var(--ks-text);
|
|
317
330
|
}
|
|
331
|
+
.ks-copy-btn {
|
|
332
|
+
display: inline-flex;
|
|
333
|
+
align-items: center;
|
|
334
|
+
gap: .3rem;
|
|
335
|
+
align-self: flex-end;
|
|
336
|
+
padding: .35em .75em;
|
|
337
|
+
border-radius: 6px;
|
|
338
|
+
border: 1px solid var(--ks-border);
|
|
339
|
+
background: var(--ks-soft);
|
|
340
|
+
color: var(--ks-muted);
|
|
341
|
+
font-size: .75rem;
|
|
342
|
+
cursor: pointer;
|
|
343
|
+
transition: color .15s, border-color .15s;
|
|
344
|
+
}
|
|
345
|
+
.ks-copy-btn:hover { color: var(--ks-heading); border-color: var(--ks-heading); }
|
|
346
|
+
.ks-copy-btn.copied { color: #4caf50; border-color: #4caf50; }
|
|
347
|
+
|
|
318
348
|
.ks-dialog-thanks { font-size: .8rem; color: var(--ks-muted); margin: .75rem 0 0; text-align: center; }
|
|
319
349
|
</style>
|
|
320
350
|
|
|
321
351
|
<style>
|
|
322
|
-
/* ::backdrop can't receive scoped attribute — must be global */
|
|
323
352
|
.ks-dialog::backdrop {
|
|
324
353
|
background: rgba(0, 0, 0, .5);
|
|
325
354
|
backdrop-filter: blur(4px);
|
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
|
3
3
|
import { useKaspa, useRpc } from 'vue-kaspa'
|
|
4
|
+
import { Droplet, BookOpen, Search, ArrowUpRight, Heart, Copy, Check } from 'lucide-vue-next'
|
|
4
5
|
|
|
5
6
|
const kaspa = useKaspa()
|
|
6
7
|
const rpc = useRpc()
|
|
7
8
|
const bento = ref<HTMLElement | null>(null)
|
|
8
9
|
const donateDialog = ref<HTMLDialogElement | null>(null)
|
|
10
|
+
const copied = ref(false)
|
|
11
|
+
|
|
12
|
+
const KASPA_ADDRESS = 'kaspa:qypr7ayn2g55fccyv9n6gf9zgrcnpepkfgjf9d8mtfp68ezv3mgqnggxqs902q4'
|
|
13
|
+
|
|
14
|
+
async function copyAddress() {
|
|
15
|
+
await navigator.clipboard.writeText(KASPA_ADDRESS)
|
|
16
|
+
copied.value = true
|
|
17
|
+
setTimeout(() => { copied.value = false }, 2000)
|
|
18
|
+
}
|
|
9
19
|
|
|
10
20
|
const stateLabel = computed(() => {
|
|
11
21
|
if (kaspa.wasmStatus.value === 'loading') return 'Loading WASM…'
|
|
@@ -31,12 +41,12 @@ const daaScore = computed(() =>
|
|
|
31
41
|
)
|
|
32
42
|
|
|
33
43
|
const links = [
|
|
34
|
-
{ label: 'Faucet', title: 'Testnet 10', desc: 'Get free test KAS', icon:
|
|
35
|
-
{ label: 'Faucet', title: 'Testnet 12', desc: 'Get free test KAS', icon:
|
|
36
|
-
{ label: 'Docs', title: 'vue-kaspa', desc: 'Read the full docs', icon:
|
|
37
|
-
{ label: 'Explorer', title: 'Testnet 10', desc: 'Browse transactions', icon:
|
|
38
|
-
{ label: 'Explorer', title: 'Testnet 12', desc: 'Browse transactions', icon:
|
|
39
|
-
{ label: 'Explorer', title: 'Mainnet', desc: 'Browse transactions', icon:
|
|
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/' },
|
|
40
50
|
]
|
|
41
51
|
|
|
42
52
|
function onMouseMove(e: MouseEvent) {
|
|
@@ -59,7 +69,14 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
|
|
|
59
69
|
<button class="dialog-close" @click="donateDialog?.close()">✕</button>
|
|
60
70
|
<p class="dialog-title">Support vue-kaspa ❤️</p>
|
|
61
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>
|
|
62
|
-
<
|
|
72
|
+
<div class="copy-wrap">
|
|
73
|
+
<code class="dialog-addr">{{ KASPA_ADDRESS }}</code>
|
|
74
|
+
<button class="copy-btn" :class="{ copied }" @click="copyAddress">
|
|
75
|
+
<Check v-if="copied" :size="13" />
|
|
76
|
+
<Copy v-else :size="13" />
|
|
77
|
+
{{ copied ? 'Copied!' : 'Copy' }}
|
|
78
|
+
</button>
|
|
79
|
+
</div>
|
|
63
80
|
<p class="dialog-thanks">Thank you for your support 🙏</p>
|
|
64
81
|
</div>
|
|
65
82
|
</dialog>
|
|
@@ -83,83 +100,77 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
|
|
|
83
100
|
</svg>
|
|
84
101
|
</a>
|
|
85
102
|
<button class="icon-btn" title="Support this project" @click="donateDialog?.showModal()">
|
|
86
|
-
<
|
|
87
|
-
<path d="M12 21.593c-.425-.396-8.8-8.044-8.8-12.593C3.2 5.796 7.192 3 12 3s8.8 2.796 8.8 6c0 4.549-8.375 12.197-8.8 12.593z"/>
|
|
88
|
-
</svg>
|
|
103
|
+
<Heart :size="18" />
|
|
89
104
|
</button>
|
|
90
105
|
</nav>
|
|
91
106
|
</header>
|
|
92
107
|
|
|
93
|
-
<!--
|
|
94
|
-
<div
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
<div class="
|
|
99
|
-
<div class="net-
|
|
100
|
-
<
|
|
101
|
-
|
|
102
|
-
class="badge"
|
|
103
|
-
:style="`border-color:${badgeColor};color:${badgeColor}`"
|
|
104
|
-
>{{ stateLabel }}</span>
|
|
105
|
-
</div>
|
|
106
|
-
<div class="stats">
|
|
107
|
-
<div class="stat">
|
|
108
|
-
<span class="stat-label">Network</span>
|
|
109
|
-
<span class="stat-value">{{ rpc.networkId.value ?? '—' }}</span>
|
|
110
|
-
</div>
|
|
111
|
-
<div class="stat">
|
|
112
|
-
<span class="stat-label">Server version</span>
|
|
113
|
-
<span class="stat-value">{{ rpc.serverVersion.value ?? '—' }}</span>
|
|
114
|
-
</div>
|
|
115
|
-
<div class="stat">
|
|
116
|
-
<span class="stat-label">DAA Score</span>
|
|
117
|
-
<span class="stat-value mono">{{ daaScore }}</span>
|
|
108
|
+
<!-- Gradient + bento grid -->
|
|
109
|
+
<div class="grid-wrap">
|
|
110
|
+
<div ref="bento" class="grid">
|
|
111
|
+
|
|
112
|
+
<!-- Network card: col 1–2, row 1–3 -->
|
|
113
|
+
<div data-shine class="shine net-shine">
|
|
114
|
+
<div class="card net-card">
|
|
115
|
+
<div class="net-top">
|
|
116
|
+
<span class="net-icon">⬡</span>
|
|
117
|
+
<span class="badge" :style="`border-color:${badgeColor};color:${badgeColor}`">{{ stateLabel }}</span>
|
|
118
118
|
</div>
|
|
119
|
-
<div class="
|
|
120
|
-
<
|
|
121
|
-
|
|
122
|
-
class="stat-value"
|
|
123
|
-
|
|
124
|
-
|
|
119
|
+
<div class="stats">
|
|
120
|
+
<div class="stat">
|
|
121
|
+
<span class="stat-label">Network</span>
|
|
122
|
+
<span class="stat-value">{{ rpc.networkId.value ?? '—' }}</span>
|
|
123
|
+
</div>
|
|
124
|
+
<div class="stat">
|
|
125
|
+
<span class="stat-label">Server version</span>
|
|
126
|
+
<span class="stat-value">{{ rpc.serverVersion.value ?? '—' }}</span>
|
|
127
|
+
</div>
|
|
128
|
+
<div class="stat">
|
|
129
|
+
<span class="stat-label">DAA Score</span>
|
|
130
|
+
<span class="stat-value mono">{{ daaScore }}</span>
|
|
131
|
+
</div>
|
|
132
|
+
<div class="stat">
|
|
133
|
+
<span class="stat-label">Synced</span>
|
|
134
|
+
<span
|
|
135
|
+
class="stat-value"
|
|
136
|
+
:style="`color:${rpc.isConnected.value ? (rpc.isSynced.value ? '#4caf50' : 'var(--ks-text)') : 'var(--ks-muted)'}`"
|
|
137
|
+
>{{ rpc.isConnected.value ? (rpc.isSynced.value ? 'Yes' : 'Syncing…') : '—' }}</span>
|
|
138
|
+
</div>
|
|
125
139
|
</div>
|
|
126
140
|
</div>
|
|
127
141
|
</div>
|
|
128
|
-
</div>
|
|
129
142
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
143
|
+
<!-- Link cards: auto-placed into Γ shape -->
|
|
144
|
+
<a
|
|
145
|
+
v-for="link in links"
|
|
146
|
+
:key="link.href"
|
|
147
|
+
data-shine
|
|
148
|
+
class="shine link-shine"
|
|
149
|
+
:href="link.href"
|
|
150
|
+
target="_blank"
|
|
151
|
+
rel="noopener"
|
|
152
|
+
>
|
|
153
|
+
<div class="card link-card">
|
|
154
|
+
<div class="link-top">
|
|
155
|
+
<component :is="link.icon" :size="20" class="link-icon" />
|
|
156
|
+
<ArrowUpRight :size="13" class="link-arrow" />
|
|
157
|
+
</div>
|
|
158
|
+
<div>
|
|
159
|
+
<div class="link-label">{{ link.label }}</div>
|
|
160
|
+
<div class="link-title">{{ link.title }}</div>
|
|
161
|
+
<div class="link-desc">{{ link.desc }}</div>
|
|
162
|
+
</div>
|
|
149
163
|
</div>
|
|
150
|
-
</
|
|
151
|
-
</a>
|
|
164
|
+
</a>
|
|
152
165
|
|
|
166
|
+
</div>
|
|
153
167
|
</div>
|
|
154
168
|
</div>
|
|
155
169
|
</template>
|
|
156
170
|
|
|
157
171
|
<style scoped>
|
|
158
172
|
/* Root */
|
|
159
|
-
.root {
|
|
160
|
-
width: 100%;
|
|
161
|
-
font-family: Inter, system-ui, -apple-system, sans-serif;
|
|
162
|
-
}
|
|
173
|
+
.root { width: 100%; font-family: Inter, system-ui, -apple-system, sans-serif; }
|
|
163
174
|
|
|
164
175
|
/* Header */
|
|
165
176
|
.header { display: flex; align-items: center; gap: .6rem; margin-bottom: .75rem; }
|
|
@@ -183,10 +194,30 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
|
|
|
183
194
|
}
|
|
184
195
|
.icon-btn:hover { color: var(--ks-heading); background: var(--ks-border); }
|
|
185
196
|
|
|
197
|
+
/* Grid wrap + U-shaped gradient backdrop */
|
|
198
|
+
.grid-wrap { position: relative; }
|
|
199
|
+
.grid-wrap::before {
|
|
200
|
+
content: '';
|
|
201
|
+
position: absolute;
|
|
202
|
+
inset: 0 -20px -28px;
|
|
203
|
+
z-index: 0;
|
|
204
|
+
pointer-events: none;
|
|
205
|
+
background:
|
|
206
|
+
radial-gradient(ellipse 55% 65% at 8% 100%, rgba(73, 197, 163, .38) 0%, transparent 55%),
|
|
207
|
+
radial-gradient(ellipse 55% 65% at 92% 100%, rgba(73, 197, 163, .38) 0%, transparent 55%),
|
|
208
|
+
radial-gradient(ellipse 85% 30% at 50% 100%, rgba(73, 197, 163, .22) 0%, transparent 60%);
|
|
209
|
+
}
|
|
210
|
+
|
|
186
211
|
/* Grid */
|
|
187
|
-
.grid {
|
|
212
|
+
.grid {
|
|
213
|
+
display: grid;
|
|
214
|
+
grid-template-columns: repeat(3, 1fr);
|
|
215
|
+
gap: .75rem;
|
|
216
|
+
position: relative;
|
|
217
|
+
z-index: 1;
|
|
218
|
+
}
|
|
188
219
|
|
|
189
|
-
/* Shine wrapper
|
|
220
|
+
/* Shine wrapper */
|
|
190
221
|
.shine {
|
|
191
222
|
padding: 1px;
|
|
192
223
|
border-radius: 14px;
|
|
@@ -198,8 +229,6 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
|
|
|
198
229
|
display: block;
|
|
199
230
|
text-decoration: none;
|
|
200
231
|
}
|
|
201
|
-
|
|
202
|
-
/* Network card occupies col 1–2, row 1–3 */
|
|
203
232
|
.net-shine { grid-column: 1 / span 2; grid-row: 1 / span 3; }
|
|
204
233
|
|
|
205
234
|
/* Card base */
|
|
@@ -219,8 +248,8 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
|
|
|
219
248
|
/* Link cards */
|
|
220
249
|
.link-card { padding: 1rem; display: flex; flex-direction: column; justify-content: space-between; gap: .5rem; min-height: 100px; }
|
|
221
250
|
.link-top { display: flex; justify-content: space-between; align-items: flex-start; }
|
|
222
|
-
.link-icon {
|
|
223
|
-
.link-arrow {
|
|
251
|
+
.link-icon { color: var(--ks-accent); }
|
|
252
|
+
.link-arrow { color: var(--ks-muted); }
|
|
224
253
|
.link-label { font-size: .58rem; text-transform: uppercase; letter-spacing: .06em; color: var(--ks-muted); margin-bottom: .1rem; }
|
|
225
254
|
.link-title { font-size: .875rem; font-weight: 600; color: var(--ks-heading); }
|
|
226
255
|
.link-desc { font-size: .75rem; color: var(--ks-muted); margin-top: .1rem; }
|
|
@@ -230,8 +259,9 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
|
|
|
230
259
|
border: 1px solid var(--ks-border);
|
|
231
260
|
border-radius: 16px;
|
|
232
261
|
padding: 0;
|
|
233
|
-
|
|
234
|
-
width:
|
|
262
|
+
width: min(440px, calc(100vw - 2rem));
|
|
263
|
+
max-width: none;
|
|
264
|
+
overflow: hidden;
|
|
235
265
|
background: var(--ks-surface);
|
|
236
266
|
color: var(--ks-text);
|
|
237
267
|
box-shadow: 0 20px 60px rgba(0, 0, 0, .25);
|
|
@@ -241,12 +271,41 @@ onUnmounted(() => window.removeEventListener('mousemove', onMouseMove))
|
|
|
241
271
|
.dialog-close:hover { color: var(--ks-heading); }
|
|
242
272
|
.dialog-title { margin: 0 0 .75rem; font-size: 1.05rem; font-weight: 700; color: var(--ks-heading); }
|
|
243
273
|
.dialog-body { font-size: .875rem; color: var(--ks-muted); margin: 0 0 1.25rem; line-height: 1.65; }
|
|
244
|
-
|
|
274
|
+
|
|
275
|
+
.copy-wrap { display: flex; flex-direction: column; gap: .5rem; }
|
|
276
|
+
.dialog-addr {
|
|
277
|
+
display: block;
|
|
278
|
+
padding: .6em .85em;
|
|
279
|
+
border-radius: 8px;
|
|
280
|
+
background: var(--ks-soft);
|
|
281
|
+
border: 1px solid var(--ks-border);
|
|
282
|
+
font-size: .7rem;
|
|
283
|
+
word-break: break-all;
|
|
284
|
+
overflow-wrap: anywhere;
|
|
285
|
+
white-space: normal;
|
|
286
|
+
color: var(--ks-text);
|
|
287
|
+
}
|
|
288
|
+
.copy-btn {
|
|
289
|
+
display: inline-flex;
|
|
290
|
+
align-items: center;
|
|
291
|
+
gap: .3rem;
|
|
292
|
+
align-self: flex-end;
|
|
293
|
+
padding: .35em .75em;
|
|
294
|
+
border-radius: 6px;
|
|
295
|
+
border: 1px solid var(--ks-border);
|
|
296
|
+
background: var(--ks-soft);
|
|
297
|
+
color: var(--ks-muted);
|
|
298
|
+
font-size: .75rem;
|
|
299
|
+
cursor: pointer;
|
|
300
|
+
transition: color .15s, border-color .15s;
|
|
301
|
+
}
|
|
302
|
+
.copy-btn:hover { color: var(--ks-heading); border-color: var(--ks-heading); }
|
|
303
|
+
.copy-btn.copied { color: #4caf50; border-color: #4caf50; }
|
|
304
|
+
|
|
245
305
|
.dialog-thanks { font-size: .8rem; color: var(--ks-muted); margin: .75rem 0 0; text-align: center; }
|
|
246
306
|
</style>
|
|
247
307
|
|
|
248
308
|
<style>
|
|
249
|
-
/* ::backdrop can't receive scoped attribute — must be global */
|
|
250
309
|
.dialog::backdrop {
|
|
251
310
|
background: rgba(0, 0, 0, .5);
|
|
252
311
|
backdrop-filter: blur(4px);
|