@@ -16,7 +16,7 @@ import {
16
16
import VoltLabIcon from "../../jscpg.svg" ;
17
17
18
18
const BinaryBackground = ( ) => {
19
- const [ binaryStrings , setBinaryStrings ] = useState < string [ ] > ( [ ] ) ;
19
+ const [ binaryStrings , setBinaryStrings ] = useState ( [ ] ) ;
20
20
21
21
useEffect ( ( ) => {
22
22
const generateBinaryString = ( ) => {
@@ -45,7 +45,7 @@ const BinaryBackground = () => {
45
45
{ binaryStrings . map ( ( str , i ) => (
46
46
< div
47
47
key = { i }
48
- className = "font-mono text-sm whitespace-nowrap animate-fade-in"
48
+ className = "font-mono text-xs sm:text- sm whitespace-nowrap animate-fade-in"
49
49
style = { {
50
50
transform : `translateY(${ i * 24 } px)` ,
51
51
color : "currentColor" ,
@@ -59,17 +59,28 @@ const BinaryBackground = () => {
59
59
} ;
60
60
61
61
const Index = ( ) => {
62
- const [ code , setCode ] = useState < string > ( ( ) => {
62
+ const [ code , setCode ] = useState ( ( ) => {
63
63
if ( typeof window !== "undefined" ) {
64
64
return localStorage . getItem ( "editorCode" ) || "" ;
65
65
}
66
66
return "" ;
67
67
} ) ;
68
- const [ output , setOutput ] = useState < string > ( "" ) ;
69
- const [ error , setError ] = useState < string | null > ( null ) ;
70
- const [ isFullScreen , setIsFullScreen ] = useState < boolean > ( false ) ;
68
+ const [ output , setOutput ] = useState ( "" ) ;
69
+ const [ error , setError ] = useState ( null ) ;
70
+ const [ isFullScreen , setIsFullScreen ] = useState ( false ) ;
71
+ const [ isVerticalLayout , setIsVerticalLayout ] = useState ( false ) ;
71
72
72
- const handleEditorChange = ( value : string | undefined ) => {
73
+ useEffect ( ( ) => {
74
+ const handleResize = ( ) => {
75
+ setIsVerticalLayout ( window . innerWidth < 768 ) ;
76
+ } ;
77
+
78
+ handleResize ( ) ;
79
+ window . addEventListener ( 'resize' , handleResize ) ;
80
+ return ( ) => window . removeEventListener ( 'resize' , handleResize ) ;
81
+ } , [ ] ) ;
82
+
83
+ const handleEditorChange = ( value ) => {
73
84
if ( value !== undefined ) {
74
85
setCode ( value ) ;
75
86
localStorage . setItem ( "editorCode" , value ) ;
@@ -82,10 +93,10 @@ const Index = () => {
82
93
setOutput ( "" ) ;
83
94
84
95
let outputBuffer = "" ;
85
- const timers : { [ key : string ] : number } = { } ;
96
+ const timers = { } ;
86
97
87
98
const secureConsole = {
88
- log : ( ...args : any [ ] ) => {
99
+ log : ( ...args ) => {
89
100
outputBuffer +=
90
101
args
91
102
. map ( ( arg ) =>
@@ -94,33 +105,23 @@ const Index = () => {
94
105
. join ( " " ) + "\n" ;
95
106
setOutput ( outputBuffer ) ;
96
107
} ,
97
- error : ( ...args : any [ ] ) => {
108
+ error : ( ...args ) => {
98
109
outputBuffer += "Error: " + args . join ( " " ) + "\n" ;
99
110
setOutput ( outputBuffer ) ;
100
111
} ,
101
- time : ( label : string = "default" ) => {
112
+ time : ( label = "default" ) => {
102
113
if ( timers [ label ] ) {
103
114
secureConsole . error (
104
- `Timer '${ label } ' already exists. Use a different label or call console.timeEnd(' ${ label } ') before starting a new timer with the same label. `
115
+ `Timer '${ label } ' already exists.`
105
116
) ;
106
117
return ;
107
118
}
108
- if ( typeof performance !== "undefined" && performance . now ) {
109
- timers [ label ] = performance . now ( ) ;
110
- } else {
111
- timers [ label ] = Date . now ( ) ;
112
- }
119
+ timers [ label ] = performance . now ( ) ;
113
120
} ,
114
- timeEnd : ( label : string = "default" ) => {
121
+ timeEnd : ( label = "default" ) => {
115
122
if ( timers [ label ] ) {
116
- let duration : number ;
117
- if ( typeof performance !== "undefined" && performance . now ) {
118
- duration = performance . now ( ) - timers [ label ] ;
119
- duration = parseFloat ( duration . toFixed ( 3 ) ) ;
120
- } else {
121
- duration = Date . now ( ) - timers [ label ] ;
122
- }
123
- outputBuffer += `${ label } : ${ duration } ms\n` ;
123
+ const duration = performance . now ( ) - timers [ label ] ;
124
+ outputBuffer += `${ label } : ${ parseFloat ( duration . toFixed ( 3 ) ) } ms\n` ;
124
125
setOutput ( outputBuffer ) ;
125
126
delete timers [ label ] ;
126
127
} else {
@@ -154,7 +155,7 @@ const Index = () => {
154
155
} ;
155
156
156
157
useEffect ( ( ) => {
157
- const handleEsc = ( event : KeyboardEvent ) => {
158
+ const handleEsc = ( event ) => {
158
159
if ( event . key === 'Escape' ) {
159
160
setIsFullScreen ( false ) ;
160
161
}
@@ -170,19 +171,19 @@ const Index = () => {
170
171
isFullScreen ? 'fixed inset-0 z-50 bg-background' : ''
171
172
} `} >
172
173
< BinaryBackground />
173
- < div className = { `container mx-auto py-6 px-4 relative ${
174
+ < div className = { `container mx-auto py-4 sm:py-6 px-2 sm: px-4 relative ${
174
175
isFullScreen ? 'h-full p-0' : ''
175
176
} `} >
176
177
< TooltipProvider >
177
178
< Tooltip >
178
179
< TooltipTrigger asChild >
179
180
< button
180
181
onClick = { goToGitHub }
181
- className = { `absolute top-8 right-4 border p-2 rounded-full ${
182
+ className = { `absolute top-4 sm:top-8 bg-white right-2 sm: right-4 border p-2 rounded-full ${
182
183
isFullScreen ? 'hidden' : ''
183
184
} `}
184
185
>
185
- < Github className = "text-black" />
186
+ < Github className = "w-4 h-4 sm:w-5 sm:h-5 text-black" />
186
187
</ button >
187
188
</ TooltipTrigger >
188
189
< TooltipContent >
@@ -191,74 +192,74 @@ const Index = () => {
191
192
</ Tooltip >
192
193
</ TooltipProvider >
193
194
194
- < div className = { `flex justify-center items-center gap-4 mb-8 ${
195
+ < div className = { `flex justify-center items-center gap-2 sm:gap-4 mb-4 sm: mb-8 ${
195
196
isFullScreen ? 'hidden' : ''
196
197
} `} >
197
198
< img
198
199
src = { VoltLabIcon }
199
200
alt = "Logo"
200
- className = "w-12 h-12 transition-transform hover:scale-110"
201
+ className = "w-8 h-8 sm:w- 12 sm: h-12 transition-transform hover:scale-110"
201
202
/>
202
203
< h1
203
- className = "text-4xl font-bold tracking-tighter"
204
+ className = "text-2xl sm:text- 4xl font-bold tracking-tighter"
204
205
style = { { fontFamily : "'Space Mono', monospace" } }
205
206
>
206
207
Volt Lab
207
208
</ h1 >
208
209
</ div >
209
210
210
211
< ResizablePanelGroup
211
- direction = " horizontal"
212
+ direction = { isVerticalLayout ? "vertical" : " horizontal"}
212
213
className = { `${
213
214
isFullScreen
214
215
? 'fixed inset-0 rounded-none border-none'
215
- : 'min-h-[80vh] rounded-xl border shadow-lg'
216
+ : 'min-h-[70vh] sm:min-h-[ 80vh] rounded-lg sm: rounded-xl border shadow-lg'
216
217
} bg-background/95 backdrop-blur-sm`}
217
218
>
218
219
< ResizablePanel defaultSize = { 50 } >
219
220
< div className = "h-full flex flex-col" >
220
- < div className = "flex justify-between items-center p-4 border-b bg-muted/30" >
221
- < span className = "text-sm font-medium" > JavaScript Editor</ span >
222
- < div className = "flex gap-2" >
221
+ < div className = "flex justify-between items-center p-2 sm:p- 4 border-b bg-muted/30" >
222
+ < span className = "text-xs sm:text- sm font-medium" > JavaScript Editor</ span >
223
+ < div className = "flex gap-1 sm:gap- 2" >
223
224
< TooltipProvider >
224
225
< Tooltip >
225
226
< TooltipTrigger asChild >
226
227
< button
227
228
onClick = { toggleFullScreen }
228
- className = "p-2 hover:bg-muted rounded-md transition-colors"
229
+ className = "p-1 sm:p- 2 hover:bg-muted rounded-md transition-colors"
229
230
>
230
231
{ isFullScreen ? (
231
- < Minimize className = "h-5 w-5" />
232
+ < Minimize className = "h-4 w-4 sm:h-5 sm: w-5" />
232
233
) : (
233
- < Expand className = "h-5 w-5" />
234
+ < Expand className = "h-4 w-4 sm:h-5 sm: w-5" />
234
235
) }
235
236
</ button >
236
237
</ TooltipTrigger >
237
- < TooltipContent side = "bottom" >
238
+ < TooltipContent side = "bottom" >
238
239
< p > { isFullScreen ? 'Exit Fullscreen' : 'Fullscreen' } </ p >
239
240
</ TooltipContent >
240
241
</ Tooltip >
241
242
</ TooltipProvider >
242
243
< button
243
244
onClick = { compileAndExecute }
244
- className = "flex items-center justify-center gap-2 px-4 py-2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors duration-200 shadow-sm"
245
+ className = "flex items-center justify-center gap-1 sm:gap- 2 px-2 sm:px- 4 py-1 sm:py- 2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors duration-200 shadow-sm text-xs sm:text -sm"
245
246
>
246
- < Play size = { 18 } />
247
+ < Play className = "w-4 h-4 sm:w-5 sm:h-5" />
247
248
Run
248
249
</ button >
249
250
</ div >
250
251
</ div >
251
- < div className = "flex-1 p-4" >
252
+ < div className = "flex-1 p-2 sm:p- 4" >
252
253
< Editor
253
254
height = "100%"
254
255
defaultLanguage = "javascript"
255
256
theme = "vs-dark"
256
257
value = { code }
257
258
onChange = { handleEditorChange }
258
259
options = { {
259
- minimap : { enabled : true } ,
260
- fontSize : 14 ,
261
- padding : { top : 24 , bottom : 24 } ,
260
+ minimap : { enabled : window . innerWidth > 768 } ,
261
+ fontSize : window . innerWidth < 640 ? 12 : 14 ,
262
+ padding : { top : 16 , bottom : 16 } ,
262
263
wordWrap : "on" ,
263
264
automaticLayout : true ,
264
265
scrollBeyondLastLine : false ,
@@ -275,26 +276,26 @@ const Index = () => {
275
276
< ResizableHandle withHandle />
276
277
277
278
< ResizablePanel defaultSize = { 50 } >
278
- < div className = "h-full flex flex-col p-6" >
279
- < div className = "flex items-center mb-4" >
280
- < div className = "flex items-center gap-2" >
281
- < div className = "w-2 h-2 rounded-full bg-green-500" > </ div >
282
- < h2 className = "text-lg font-semibold flex items-center justify-center gap-1" >
279
+ < div className = "h-full flex flex-col p-3 sm:p- 6" >
280
+ < div className = "flex items-center mb-2 sm:mb- 4" >
281
+ < div className = "flex items-center gap-1 sm:gap- 2" >
282
+ < div className = "w-1.5 h-1.5 sm:w-2 sm: h-2 rounded-full bg-green-500" > </ div >
283
+ < h2 className = "text-sm sm:text- lg font-semibold flex items-center justify-center gap-1" >
283
284
Console Output
284
285
</ h2 >
285
286
</ div >
286
287
< button
287
- className = "ml-auto text-sm text-muted-foreground hover:text-foreground"
288
+ className = "ml-auto text-xs sm:text- sm text-muted-foreground hover:text-foreground"
288
289
onClick = { clearOutput }
289
290
>
290
291
Clear
291
292
</ button >
292
293
</ div >
293
- < div className = "flex-1 font-mono bg-black p-6 rounded overflow-auto border shadow-inner" >
294
+ < div className = "flex-1 font-mono bg-black p-3 sm:p- 6 rounded overflow-auto border shadow-inner" >
294
295
{ error ? (
295
- < div className = "text-destructive" > { error } </ div >
296
+ < div className = "text-destructive text-xs sm:text-sm " > { error } </ div >
296
297
) : (
297
- < pre className = "whitespace-pre-wrap text-green-500" >
298
+ < pre className = "whitespace-pre-wrap text-green-500 text-xs sm:text-sm " >
298
299
{ output }
299
300
</ pre >
300
301
) }
0 commit comments