@@ -5,42 +5,27 @@ import {
55 SandpackProvider ,
66 SandpackLayout ,
77 SandpackCodeEditor ,
8- SandpackPreview ,
98 SandpackConsole ,
9+ SandpackPreview ,
1010 useSandpack ,
1111} from '@codesandbox/sandpack-react'
12- // sandpackDark is bundled with sandpack-react
13- const sandpackDark = 'dark' as const
1412
15- function RunButton ( ) {
16- const { dispatch, sandpack } = useSandpack ( )
17- const isLoading = sandpack . status === 'initial' || sandpack . status === 'timeout'
18- return (
19- < button
20- onClick = { ( ) => dispatch ( { type : 'refresh' } ) }
21- disabled = { isLoading }
22- style = { {
23- display : 'flex' ,
24- alignItems : 'center' ,
25- gap : '6px' ,
26- padding : '4px 14px' ,
27- borderRadius : '4px' ,
28- border : 'none' ,
29- cursor : isLoading ? 'not-allowed' : 'pointer' ,
30- fontFamily : 'var(--sp-font-mono)' ,
31- fontSize : '12px' ,
32- fontWeight : 600 ,
33- background : isLoading ? 'var(--sp-colors-surface2)' : '#22c55e' ,
34- color : isLoading ? 'var(--sp-colors-fg-inactive)' : '#fff' ,
35- transition : 'background 0.15s' ,
36- } }
37- >
38- ▶ Run
39- </ button >
40- )
41- }
13+ // Hard-coded dark toolbar colors — CSS vars are only scoped inside SandpackLayout
14+ const T = {
15+ bg : '#1c1c1e' ,
16+ border : '#3a3a3c' ,
17+ muted : '#888' ,
18+ text : '#ccc' ,
19+ activeBg : '#0070f3' ,
20+ activeText : '#fff' ,
21+ pillBg : '#2a2a2c' ,
22+ runBg : '#22c55e' ,
23+ runText : '#fff' ,
24+ runDisabledBg : '#2a2a2c' ,
25+ runDisabledText : '#666' ,
26+ } as const
4227
43- // Conflux network configs
28+ // ── Conflux network configs ──────────────────────────────────────────────────
4429const NETWORKS = {
4530 testnet : {
4631 label : 'Testnet' ,
@@ -58,25 +43,40 @@ const NETWORKS = {
5843
5944type Network = keyof typeof NETWORKS
6045
61- interface PlaygroundProps {
62- /** The active code file name, e.g. "index.ts" */
63- file ?: string
64- /** Record of filename → code content */
65- files ?: Record < string , string >
66- /** Template: "vanilla-ts" | "nextjs" | "node" */
67- template ?: 'vanilla-ts' | 'node'
68- /** Show console instead of preview */
69- showConsole ?: boolean
70- /** Extra npm dependencies beyond the defaults */
71- extraDeps ?: Record < string , string >
72- }
46+ // ── Run button — must be inside SandpackProvider ─────────────────────────────
47+ function RunButton ( ) {
48+ const { sandpack } = useSandpack ( )
49+ const busy =
50+ sandpack . status === 'initial' ||
51+ sandpack . status === 'timeout'
7352
74- const DEFAULT_DEPS : Record < string , string > = {
75- viem : '^2.0.0' ,
76- '@cfxdevkit/core' : 'latest' ,
77- '@cfxdevkit/contracts' : 'latest' ,
53+ return (
54+ < button
55+ onClick = { ( ) => sandpack . runSandpack ( ) }
56+ disabled = { busy }
57+ style = { {
58+ display : 'flex' ,
59+ alignItems : 'center' ,
60+ gap : '5px' ,
61+ padding : '4px 14px' ,
62+ borderRadius : '4px' ,
63+ border : 'none' ,
64+ cursor : busy ? 'not-allowed' : 'pointer' ,
65+ fontFamily : 'ui-monospace, monospace' ,
66+ fontSize : '12px' ,
67+ fontWeight : 600 ,
68+ background : busy ? T . runDisabledBg : T . runBg ,
69+ color : busy ? T . runDisabledText : T . runText ,
70+ transition : 'background 0.15s' ,
71+ flexShrink : 0 ,
72+ } }
73+ >
74+ ▶ Run
75+ </ button >
76+ )
7877}
7978
79+ // ── Network toggle ────────────────────────────────────────────────────────────
8080function NetworkToggle ( {
8181 network,
8282 onChange,
@@ -85,33 +85,67 @@ function NetworkToggle({
8585 onChange : ( n : Network ) => void
8686} ) {
8787 return (
88- < div style = { { display : 'flex' , alignItems : 'center' , gap : '8px' , fontSize : '12px' , fontFamily : 'var(--sp-font-mono)' } } >
89- < span style = { { color : 'var(--sp-colors-fg-inactive)' } } > network:</ span >
88+ < div
89+ style = { {
90+ display : 'flex' ,
91+ alignItems : 'center' ,
92+ gap : '6px' ,
93+ fontSize : '12px' ,
94+ fontFamily : 'ui-monospace, monospace' ,
95+ color : T . muted ,
96+ minWidth : 0 ,
97+ overflow : 'hidden' ,
98+ } }
99+ >
100+ < span style = { { whiteSpace : 'nowrap' } } > network:</ span >
90101 { ( Object . keys ( NETWORKS ) as Network [ ] ) . map ( ( key ) => (
91102 < button
92103 key = { key }
93104 onClick = { ( ) => onChange ( key ) }
94105 style = { {
95- padding : '2px 10px ' ,
106+ padding : '2px 9px ' ,
96107 borderRadius : '4px' ,
97108 border : 'none' ,
98109 cursor : 'pointer' ,
99110 fontFamily : 'inherit' ,
100111 fontSize : '11px' ,
101- background : network === key ? 'var(--sp-colors-accent)' : 'var(--sp-colors-surface2)' ,
102- color : network === key ? '#fff' : 'var(--sp-colors-fg-inactive)' ,
112+ whiteSpace : 'nowrap' ,
113+ background : network === key ? T . activeBg : T . pillBg ,
114+ color : network === key ? T . activeText : T . text ,
103115 } }
104116 >
105117 { NETWORKS [ key ] . label }
106118 </ button >
107119 ) ) }
108- < span style = { { color : 'var(--sp-colors-fg-inactive)' , fontSize : '10px' } } >
120+ < span
121+ style = { {
122+ color : T . muted ,
123+ fontSize : '10px' ,
124+ whiteSpace : 'nowrap' ,
125+ } }
126+ >
109127 · chain { NETWORKS [ network ] . chainId }
110128 </ span >
111129 </ div >
112130 )
113131}
114132
133+ // ── Props ────────────────────────────────────────────────────────────────────
134+ interface PlaygroundProps {
135+ file ?: string
136+ files ?: Record < string , string >
137+ template ?: 'vanilla-ts' | 'node'
138+ showConsole ?: boolean
139+ extraDeps ?: Record < string , string >
140+ }
141+
142+ const DEFAULT_DEPS : Record < string , string > = {
143+ viem : '^2.0.0' ,
144+ '@cfxdevkit/core' : 'latest' ,
145+ '@cfxdevkit/contracts' : 'latest' ,
146+ }
147+
148+ // ── Main component ────────────────────────────────────────────────────────────
115149export function Playground ( {
116150 files = { } ,
117151 template = 'vanilla-ts' ,
@@ -123,14 +157,7 @@ export function Playground({
123157
124158 const networkConfig = NETWORKS [ network ]
125159
126- // Inject a network-config helper that examples can import
127- const networkFile = `// Auto-generated — re-renders when you toggle network above
128- export const NETWORK = {
129- chainId: ${ networkConfig . chainId } ,
130- rpcUrl: '${ networkConfig . rpcUrl } ',
131- blockExplorer: '${ networkConfig . blockExplorer } ',
132- } as const
133- `
160+ const networkFile = `// Auto-generated — changes when you toggle network\nexport const NETWORK = {\n chainId: ${ networkConfig . chainId } ,\n rpcUrl: '${ networkConfig . rpcUrl } ',\n blockExplorer: '${ networkConfig . blockExplorer } ',\n} as const\n`
134161
135162 const mergedFiles = {
136163 '/network-config.ts' : { code : networkFile , readOnly : true } ,
@@ -142,40 +169,49 @@ export const NETWORK = {
142169 ) ,
143170 }
144171
172+ const activeFile = file . startsWith ( '/' ) ? file : `/${ file } `
173+
145174 return (
146- < div style = { { margin : '1.5rem 0' , borderRadius : '8px' , overflow : 'hidden' } } >
175+ < div
176+ style = { {
177+ margin : '1.5rem 0' ,
178+ borderRadius : '8px' ,
179+ overflow : 'hidden' ,
180+ border : `1px solid ${ T . border } ` ,
181+ } }
182+ >
147183 < SandpackProvider
148- key = { network } // remount on network change to reset execution
184+ key = { network }
149185 template = { template }
150- theme = { sandpackDark }
186+ theme = "dark"
151187 files = { mergedFiles }
152188 options = { {
153- activeFile : file . startsWith ( '/' ) ? file : `/ ${ file } ` ,
189+ activeFile,
154190 visibleFiles : Object . keys ( mergedFiles ) ,
155191 recompileMode : 'delayed' ,
156- recompileDelay : 500 ,
192+ recompileDelay : 600 ,
193+ autorun : true ,
157194 } }
158195 customSetup = { {
159- dependencies : {
160- ...DEFAULT_DEPS ,
161- ...extraDeps ,
162- } ,
196+ dependencies : { ...DEFAULT_DEPS , ...extraDeps } ,
163197 } }
164198 >
165- { /* Inner toolbar — inside Provider so RunButton can access sandpack context */ }
199+ { /* Toolbar — inside Provider to access sandpack context, outside Layout to control bg */ }
166200 < div
167201 style = { {
168202 display : 'flex' ,
169203 alignItems : 'center' ,
170204 justifyContent : 'space-between' ,
171- padding : '6px 12px' ,
172- borderBottom : '1px solid var(--sp-colors-surface2)' ,
173- background : 'var(--sp-colors-surface1)' ,
205+ padding : '6px 10px' ,
206+ background : T . bg ,
207+ borderBottom : `1px solid ${ T . border } ` ,
208+ gap : '8px' ,
174209 } }
175210 >
176211 < NetworkToggle network = { network } onChange = { setNetwork } />
177212 < RunButton />
178213 </ div >
214+
179215 < SandpackLayout >
180216 < SandpackCodeEditor
181217 showLineNumbers
@@ -184,11 +220,7 @@ export const NETWORK = {
184220 style = { { height : 380 } }
185221 />
186222 { showConsole ? (
187- < SandpackConsole
188- showHeader
189- showResetConsoleButton
190- style = { { height : 380 } }
191- />
223+ < SandpackConsole showHeader style = { { height : 380 } } />
192224 ) : (
193225 < SandpackPreview style = { { height : 380 } } showNavigator = { false } />
194226 ) }
0 commit comments