forked from Txio-labs/txio
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPlayground.tsx
More file actions
173 lines (157 loc) · 10.1 KB
/
Copy pathPlayground.tsx
File metadata and controls
173 lines (157 loc) · 10.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
import React, { useState } from 'react';
import { motion } from 'framer-motion';
import {
Zap, Terminal, Globe, Cpu, Database,
Play, Shield, Search, Plus, Trash2,
RefreshCcw, Code2, Layers, Sparkles, Loader2
} from 'lucide-react';
import { useAppStore } from '@/lib/store';
export const Playground: React.FC = () => {
const { theme } = useAppStore();
const [selectedChain, setSelectedChain] = useState('sui');
const [script, setScript] = useState(`const supply = await sui.getTotalSupply();\nconst events = await sui.queryEvents({ limit: 10 });\nconsole.log(\`Current Supply: \${supply}\`);`);
const [isExecuting, setIsExecuting] = useState(false);
const [tps, setTps] = useState('297,102');
const [gas, setGas] = useState('0.00042');
const [output, setOutput] = useState('Playground terminal ready.');
const chains = [
{ id: 'sui', name: 'Sui', color: 'text-[#38bdf8]' },
{ id: 'solana', name: 'Solana', color: 'text-[#14f195]' },
{ id: 'evm', name: 'Ethereum', color: 'text-[#6366f1]' },
{ id: 'aptos', name: 'Aptos', color: 'text-[#2dd4bf]' }
];
const snippets = [
{ name: 'Fetch Objects', time: '2m ago', content: 'const objects = await sui.getOwnedObjects();\nconsole.log(`Found ${objects.length} objects`);' },
{ name: 'Batch Transfer', time: '1h ago', content: 'const txb = new TransactionBlock();\ntxb.transferObjects([coin], recipient);\nconst res = await sui.signAndExecuteTransactionBlock({ transactionBlock: txb });' },
{ name: 'Verify Proof', time: '3h ago', content: 'const isValid = await zk.verifyZkLogin(proof, maxEpoch);\nconsole.log(`Proof valid: ${isValid}`);' }
];
const handleExecute = () => {
setIsExecuting(true);
setOutput('Executing script...');
// TODO: Replace with real SDK execution or WebWorker sandbox
setTimeout(() => {
setIsExecuting(false);
setTps(Math.floor(Math.random() * 50000 + 250000).toLocaleString());
setGas((Math.random() * 0.001).toFixed(5));
setOutput(`[Success] Execution completed in 125ms.\nResult: {\n status: "success",\n gasUsed: ${Math.floor(Math.random() * 1000)}\n}`);
}, 1500);
};
const handleRefresh = () => {
setScript('');
setOutput('Playground terminal ready.');
setTps('0');
setGas('0.00000');
};
return (
<div className="h-full flex flex-col bg-[#0a0a0a] text-slate-300 font-sans overflow-hidden">
{/* Toolbar */}
<header className="h-14 border-b border-white/5 flex items-center justify-between px-6 bg-[#18181b] relative z-10">
<div className="flex items-center gap-6">
<div className="flex items-center gap-2">
<div className="w-8 h-8 rounded-lg bg-electric-violet/10 flex items-center justify-center text-electric-violet">
<Sparkles size={18} />
</div>
<span className="text-sm font-black text-white uppercase tracking-widest">Protocol Playground</span>
</div>
<div className="h-6 w-px bg-white/10" />
<div className="flex items-center gap-2">
{chains.map(chain => (
<button
key={chain.id}
onClick={() => setSelectedChain(chain.id)}
className={`px-4 py-1.5 rounded-full text-[10px] font-black uppercase tracking-widest transition-all ${
selectedChain === chain.id
? 'bg-white/10 text-white border border-white/10'
: 'text-slate-600 hover:text-slate-400'
}`}
>
{chain.name}
</button>
))}
</div>
</div>
<div className="flex items-center gap-3">
<button onClick={handleRefresh} className="p-2 rounded-lg hover:bg-white/5 text-slate-500 transition-colors">
<RefreshCcw size={16} />
</button>
<button onClick={handleExecute} disabled={isExecuting || !script.trim()} className="flex items-center gap-2 px-6 py-1.5 rounded-xl bg-electric-violet text-white text-[10px] font-black uppercase tracking-widest shadow-lg shadow-electric-violet/20 hover:bg-soft-purple transition-all disabled:opacity-50">
{isExecuting ? <Loader2 size={14} className="animate-spin" /> : <Play size={14} />} Execute Snippet
</button>
</div>
</header>
<div className="flex-1 flex overflow-hidden">
{/* Main Sandbox */}
<main className="flex-1 flex flex-col border-r border-white/5 bg-[#0a0a0a]">
{/* Editor */}
<div className="flex-1 p-8 flex flex-col space-y-6 overflow-y-auto custom-scrollbar">
<div className="flex-1 rounded-[1.5rem] bg-[#18181b] border border-white/10 relative group flex flex-col min-h-[300px]">
<div className="flex items-center justify-between px-6 py-4 border-b border-white/5">
<div className="text-[10px] font-black text-slate-600 uppercase tracking-widest">Active Script</div>
</div>
<textarea
value={script}
onChange={(e) => setScript(e.target.value)}
spellCheck={false}
className="flex-1 w-full bg-transparent text-sm font-mono text-slate-300 p-6 focus:outline-none resize-none custom-scrollbar"
placeholder="// Write your SDK snippet here..."
/>
</div>
{/* Interactive Widgets */}
<div className="grid grid-cols-2 gap-6 shrink-0">
<div className="p-6 rounded-3xl bg-white/[0.02] border border-white/5 space-y-4">
<div className="flex items-center justify-between">
<div className="text-[10px] font-black text-slate-600 uppercase tracking-widest">State Watcher</div>
<div className="w-2 h-2 rounded-full bg-emerald-400 animate-pulse" />
</div>
<div className="space-y-2">
<div className="flex justify-between text-xs">
<span className="text-slate-500">TPS</span>
<span className="text-white font-bold">{tps}</span>
</div>
<div className="w-full h-1 bg-white/5 rounded-full overflow-hidden">
<div className="w-3/4 h-full bg-electric-violet" />
</div>
</div>
</div>
<div className="p-6 rounded-3xl bg-white/[0.02] border border-white/5 space-y-4">
<div className="text-[10px] font-black text-slate-600 uppercase tracking-widest">Gas Meter</div>
<div className="flex items-end gap-2">
<div className="text-2xl font-black text-white">{gas}</div>
<div className="text-[10px] font-black text-slate-600 uppercase tracking-widest mb-1">SUI / Op</div>
</div>
</div>
</div>
{/* Terminal Output */}
<div className="h-48 rounded-2xl bg-[#18181b] border border-white/10 p-4 font-mono text-xs text-slate-400 overflow-y-auto shrink-0 whitespace-pre-wrap">
{output}
</div>
</div>
</main>
{/* Right Sidebar - Toolbox */}
<aside className="w-80 bg-[#18181b] p-6 space-y-8 flex flex-col">
<div className="space-y-4">
<h3 className="text-xs font-black uppercase tracking-[0.3em] text-slate-600">Snippet Library</h3>
<div className="space-y-2">
{snippets.map(s => (
<div key={s.name} onClick={() => setScript(s.content)} className="p-4 rounded-2xl bg-white/[0.02] border border-white/5 hover:bg-white/[0.04] transition-all cursor-pointer group">
<div className="text-xs font-bold text-white mb-1 group-hover:text-electric-violet transition-colors">{s.name}</div>
<div className="text-[9px] font-black text-slate-700 uppercase tracking-widest">{s.time}</div>
</div>
))}
</div>
</div>
<div className="flex-1" />
<div className="p-6 rounded-3xl bg-electric-violet/5 border border-electric-violet/10 space-y-4">
<div className="w-10 h-10 rounded-xl bg-electric-violet/20 flex items-center justify-center text-electric-violet">
<Zap size={20} />
</div>
<div className="space-y-1">
<div className="text-xs font-black text-white">Advanced Simulation</div>
<p className="text-[10px] leading-relaxed text-slate-500">Run this snippet in a dedicated fork to prevent state contamination.</p>
</div>
</div>
</aside>
</div>
</div>
);
};