@rubanrubi/hardhat-dashboard 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,13 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Hardhat Dashboard</title>
7
+ <link rel="stylesheet" href="./styles.css" />
8
+ </head>
9
+ <body>
10
+ <div id="root"></div>
11
+ <script type="module" src="./app.js"></script>
12
+ </body>
13
+ </html>
@@ -0,0 +1,371 @@
1
+ :root {
2
+ --bg: #0b1020;
3
+ --bg-elevated: rgba(13, 24, 48, 0.82);
4
+ --bg-panel: rgba(18, 30, 58, 0.9);
5
+ --bg-panel-strong: rgba(24, 42, 79, 0.96);
6
+ --border: rgba(154, 182, 255, 0.18);
7
+ --text: #edf2ff;
8
+ --text-dim: rgba(237, 242, 255, 0.72);
9
+ --accent: #54c6eb;
10
+ --accent-strong: #7ef29a;
11
+ --danger: #ff7b72;
12
+ --warning: #ffd166;
13
+ --shadow: 0 24px 80px rgba(0, 0, 0, 0.35);
14
+ --font-display: 'Space Grotesk', 'Avenir Next', 'Segoe UI', sans-serif;
15
+ --font-body: 'IBM Plex Sans', 'Helvetica Neue', sans-serif;
16
+ }
17
+
18
+ * {
19
+ box-sizing: border-box;
20
+ }
21
+
22
+ html,
23
+ body,
24
+ #root {
25
+ margin: 0;
26
+ min-height: 100%;
27
+ }
28
+
29
+ body {
30
+ font-family: var(--font-body);
31
+ color: var(--text);
32
+ background:
33
+ radial-gradient(circle at top left, rgba(84, 198, 235, 0.18), transparent 28%),
34
+ radial-gradient(circle at bottom right, rgba(126, 242, 154, 0.18), transparent 24%),
35
+ linear-gradient(135deg, #050813 0%, #0a1326 54%, #101e39 100%);
36
+ }
37
+
38
+ body::before {
39
+ content: '';
40
+ position: fixed;
41
+ inset: 0;
42
+ background-image:
43
+ linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px),
44
+ linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
45
+ background-size: 48px 48px;
46
+ mask-image: radial-gradient(circle at center, black, transparent 78%);
47
+ pointer-events: none;
48
+ }
49
+
50
+ .app-shell {
51
+ position: relative;
52
+ max-width: 1320px;
53
+ margin: 0 auto;
54
+ padding: 48px 24px 32px;
55
+ }
56
+
57
+ .hero {
58
+ display: grid;
59
+ grid-template-columns: 2fr 1fr;
60
+ gap: 24px;
61
+ align-items: start;
62
+ margin-bottom: 24px;
63
+ }
64
+
65
+ .hero-card,
66
+ .panel,
67
+ .status-strip {
68
+ border: 1px solid var(--border);
69
+ background: var(--bg-elevated);
70
+ backdrop-filter: blur(18px);
71
+ box-shadow: var(--shadow);
72
+ }
73
+
74
+ .hero-card {
75
+ padding: 28px;
76
+ border-radius: 28px;
77
+ }
78
+
79
+ .hero h1 {
80
+ margin: 0 0 12px;
81
+ font-family: var(--font-display);
82
+ font-size: clamp(2rem, 4vw, 3.4rem);
83
+ line-height: 0.95;
84
+ letter-spacing: -0.06em;
85
+ }
86
+
87
+ .hero p {
88
+ margin: 0;
89
+ color: var(--text-dim);
90
+ max-width: 58ch;
91
+ font-size: 1.02rem;
92
+ line-height: 1.6;
93
+ }
94
+
95
+ .hero-meta {
96
+ margin-top: 20px;
97
+ display: flex;
98
+ flex-wrap: wrap;
99
+ gap: 10px;
100
+ }
101
+
102
+ .pill,
103
+ .network-pill {
104
+ display: inline-flex;
105
+ align-items: center;
106
+ gap: 8px;
107
+ padding: 10px 14px;
108
+ border-radius: 999px;
109
+ border: 1px solid var(--border);
110
+ background: rgba(255, 255, 255, 0.04);
111
+ color: var(--text-dim);
112
+ font-size: 0.88rem;
113
+ }
114
+
115
+ .network-pill strong {
116
+ color: var(--text);
117
+ }
118
+
119
+ .status-card {
120
+ padding: 24px;
121
+ border-radius: 24px;
122
+ }
123
+
124
+ .status-card h2,
125
+ .panel h2 {
126
+ margin: 0 0 12px;
127
+ font-family: var(--font-display);
128
+ font-size: 1.25rem;
129
+ letter-spacing: -0.04em;
130
+ }
131
+
132
+ .status-card p {
133
+ margin: 0 0 18px;
134
+ color: var(--text-dim);
135
+ line-height: 1.5;
136
+ }
137
+
138
+ .button-row {
139
+ display: flex;
140
+ flex-wrap: wrap;
141
+ gap: 12px;
142
+ }
143
+
144
+ button {
145
+ border: 0;
146
+ border-radius: 14px;
147
+ padding: 12px 18px;
148
+ font: inherit;
149
+ font-weight: 600;
150
+ cursor: pointer;
151
+ transition:
152
+ transform 120ms ease,
153
+ opacity 120ms ease,
154
+ background 120ms ease;
155
+ }
156
+
157
+ button:hover:not(:disabled) {
158
+ transform: translateY(-1px);
159
+ }
160
+
161
+ button:disabled {
162
+ cursor: wait;
163
+ opacity: 0.6;
164
+ }
165
+
166
+ .button-primary {
167
+ background: linear-gradient(135deg, var(--accent), #6ef7c1);
168
+ color: #06111d;
169
+ }
170
+
171
+ .button-secondary {
172
+ background: rgba(255, 255, 255, 0.08);
173
+ color: var(--text);
174
+ border: 1px solid var(--border);
175
+ }
176
+
177
+ .button-danger {
178
+ background: rgba(255, 123, 114, 0.14);
179
+ color: #ffd0cb;
180
+ border: 1px solid rgba(255, 123, 114, 0.35);
181
+ }
182
+
183
+ .status-strip {
184
+ display: grid;
185
+ grid-template-columns: repeat(4, 1fr);
186
+ gap: 12px;
187
+ padding: 18px;
188
+ border-radius: 20px;
189
+ margin-bottom: 24px;
190
+ }
191
+
192
+ .metric {
193
+ padding: 14px;
194
+ border-radius: 16px;
195
+ background: rgba(255, 255, 255, 0.03);
196
+ }
197
+
198
+ .metric .label {
199
+ display: block;
200
+ margin-bottom: 8px;
201
+ color: var(--text-dim);
202
+ font-size: 0.82rem;
203
+ text-transform: uppercase;
204
+ letter-spacing: 0.08em;
205
+ }
206
+
207
+ .metric strong {
208
+ font-size: 1.2rem;
209
+ font-family: var(--font-display);
210
+ }
211
+
212
+ .dashboard-grid {
213
+ display: grid;
214
+ grid-template-columns: minmax(0, 1.6fr) minmax(360px, 1fr);
215
+ gap: 24px;
216
+ }
217
+
218
+ .panel {
219
+ padding: 22px;
220
+ border-radius: 24px;
221
+ }
222
+
223
+ .panel-header {
224
+ display: flex;
225
+ align-items: center;
226
+ justify-content: space-between;
227
+ gap: 12px;
228
+ margin-bottom: 18px;
229
+ }
230
+
231
+ .panel-subtitle {
232
+ color: var(--text-dim);
233
+ font-size: 0.92rem;
234
+ }
235
+
236
+ .card-list {
237
+ display: grid;
238
+ gap: 14px;
239
+ }
240
+
241
+ .request-card,
242
+ .history-card,
243
+ .warning-banner {
244
+ padding: 18px;
245
+ border-radius: 18px;
246
+ border: 1px solid rgba(154, 182, 255, 0.14);
247
+ background: var(--bg-panel);
248
+ }
249
+
250
+ .request-card.processing {
251
+ border-color: rgba(84, 198, 235, 0.55);
252
+ box-shadow: 0 0 0 1px rgba(84, 198, 235, 0.18) inset;
253
+ }
254
+
255
+ .request-top,
256
+ .history-top {
257
+ display: flex;
258
+ justify-content: space-between;
259
+ gap: 16px;
260
+ align-items: flex-start;
261
+ }
262
+
263
+ .method {
264
+ font-weight: 700;
265
+ font-size: 1rem;
266
+ }
267
+
268
+ .timestamp {
269
+ color: var(--text-dim);
270
+ font-size: 0.84rem;
271
+ }
272
+
273
+ .decoded-call {
274
+ margin: 14px 0;
275
+ padding: 12px 14px;
276
+ border-radius: 14px;
277
+ background: rgba(126, 242, 154, 0.08);
278
+ border: 1px solid rgba(126, 242, 154, 0.2);
279
+ }
280
+
281
+ .decoded-call strong {
282
+ display: block;
283
+ margin-bottom: 6px;
284
+ color: var(--accent-strong);
285
+ }
286
+
287
+ .decoded-call ul {
288
+ margin: 8px 0 0;
289
+ padding-left: 18px;
290
+ color: var(--text-dim);
291
+ }
292
+
293
+ .request-card pre,
294
+ .history-card pre {
295
+ margin: 0;
296
+ padding: 12px 14px;
297
+ border-radius: 14px;
298
+ background: rgba(0, 0, 0, 0.26);
299
+ color: #d8e6ff;
300
+ font-size: 0.82rem;
301
+ line-height: 1.5;
302
+ overflow: auto;
303
+ }
304
+
305
+ .tag-row {
306
+ display: flex;
307
+ flex-wrap: wrap;
308
+ gap: 8px;
309
+ margin: 12px 0 14px;
310
+ }
311
+
312
+ .tag {
313
+ display: inline-flex;
314
+ align-items: center;
315
+ padding: 6px 10px;
316
+ border-radius: 999px;
317
+ background: rgba(255, 255, 255, 0.06);
318
+ color: var(--text-dim);
319
+ font-size: 0.8rem;
320
+ }
321
+
322
+ .tag.success {
323
+ color: #c8ffd6;
324
+ background: rgba(126, 242, 154, 0.16);
325
+ }
326
+
327
+ .tag.error {
328
+ color: #ffd2cd;
329
+ background: rgba(255, 123, 114, 0.16);
330
+ }
331
+
332
+ .warning-banner {
333
+ margin-bottom: 16px;
334
+ border-color: rgba(255, 209, 102, 0.22);
335
+ background: rgba(255, 209, 102, 0.08);
336
+ }
337
+
338
+ .warning-banner strong {
339
+ display: block;
340
+ margin-bottom: 6px;
341
+ color: var(--warning);
342
+ }
343
+
344
+ .empty-state {
345
+ padding: 28px 18px;
346
+ text-align: center;
347
+ border-radius: 18px;
348
+ border: 1px dashed rgba(154, 182, 255, 0.2);
349
+ color: var(--text-dim);
350
+ }
351
+
352
+ @media (max-width: 1100px) {
353
+ .hero,
354
+ .dashboard-grid,
355
+ .status-strip {
356
+ grid-template-columns: 1fr;
357
+ }
358
+ }
359
+
360
+ @media (max-width: 720px) {
361
+ .app-shell {
362
+ padding: 24px 16px 20px;
363
+ }
364
+
365
+ .hero-card,
366
+ .panel,
367
+ .status-card {
368
+ padding: 18px;
369
+ border-radius: 20px;
370
+ }
371
+ }
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@rubanrubi/hardhat-dashboard",
3
+ "version": "0.1.0",
4
+ "description": "A Hardhat plugin that routes transaction signing through a local browser dashboard.",
5
+ "license": "MIT",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist",
10
+ "README.md",
11
+ "LICENSE"
12
+ ],
13
+ "scripts": {
14
+ "clean": "node ./scripts/clean.mjs",
15
+ "build:types": "tsc -p tsconfig.json",
16
+ "build:ui": "node ./scripts/build-ui.mjs",
17
+ "build": "npm run clean && npm run build:ui && npm run build:types",
18
+ "test": "mocha --require ts-node/register --extension ts \"test/**/*.spec.ts\"",
19
+ "lint": "eslint \"src/**/*.{ts,tsx}\" \"test/**/*.ts\" \"scripts/**/*.mjs\"",
20
+ "prepublishOnly": "npm run build && npm run lint && npm test",
21
+ "dev": "npm run build:ui && node scripts/dev-server.mjs"
22
+ },
23
+ "keywords": [
24
+ "hardhat",
25
+ "plugin",
26
+ "ethereum",
27
+ "metamask",
28
+ "dashboard"
29
+ ],
30
+ "dependencies": {
31
+ "chalk": "^4.1.2",
32
+ "cors": "^2.8.5",
33
+ "ethers": "^6.15.0",
34
+ "express": "^4.21.2",
35
+ "open": "^8.4.2",
36
+ "react": "^18.3.1",
37
+ "react-dom": "^18.3.1",
38
+ "ws": "^8.18.1"
39
+ },
40
+ "devDependencies": {
41
+ "@types/chai": "^4.3.20",
42
+ "@types/cors": "^2.8.17",
43
+ "@types/express": "^4.17.21",
44
+ "@types/mocha": "^10.0.10",
45
+ "@types/node": "^18.19.130",
46
+ "@types/react": "^18.3.18",
47
+ "@types/react-dom": "^18.3.5",
48
+ "@types/ws": "^8.5.14",
49
+ "@typescript-eslint/eslint-plugin": "^8.25.0",
50
+ "@typescript-eslint/parser": "^8.25.0",
51
+ "chai": "^4.5.0",
52
+ "esbuild": "^0.25.0",
53
+ "eslint": "^8.57.1",
54
+ "eslint-config-prettier": "^10.1.1",
55
+ "mocha": "^11.1.0",
56
+ "prettier": "^3.5.2",
57
+ "ts-node": "^10.9.2",
58
+ "typescript": "^5.8.2"
59
+ }
60
+ }