11<template >
22 <div class =" playground-container" >
3- <!-- Input Section - Full Width -->
43 <div class =" input-section" >
54 <h3 >🎭 NullScript Code</h3 >
65 <textarea
7- v-model =" nullscriptCode "
6+ v-model =" nullScriptCode "
87 @input =" debouncedTranspile"
98 placeholder =" // Write your NullScript code here..."
109 class =" code-input"
4140 </div >
4241 </div >
4342
44- <!-- Output Section - Horizontal Layout -->
4543 <div class =" output-container" >
4644 <div class =" output-panel" >
4745 <h3 >⚡ JavaScript Output</h3 >
6159<script setup>
6260import { computed , onMounted , ref } from " vue" ;
6361
64- const nullscriptCode = ref (` // Write your NullScript code here...
62+ const nullScriptCode = ref (` // Write your NullScript code here...
6563run greet(name) {
6664 return \` Hello, \$ {name}! Welcome to NullScript! 🎭\` ;
6765}
@@ -72,25 +70,14 @@ speak.say(message);`);
7270const javascriptCode = ref (" " );
7371const consoleOutput = ref (" // Execution results will appear here..." );
7472
75- // Computed property to check if input is empty
7673const isInputEmpty = computed (() => {
77- return ! nullscriptCode .value .trim ();
74+ return ! nullScriptCode .value .trim ();
7875});
7976
80- // NullScript compiler status
81- let compilerStatus = " checking" ; // 'checking', 'available', 'unavailable'
77+ let compilerStatus = " checking" ;
8278
83- // Check if we can use server-side compilation
8479async function checkCompilerAvailability () {
8580 try {
86- // In the future, we could check for a compilation API endpoint:
87- // const response = await fetch('/api/nullscript/compile', { method: 'HEAD' })
88- // if (response.ok) {
89- // compilerStatus = 'available'
90- // return true
91- // }
92-
93- // For now, we use the fallback keyword mapping approach
9481 compilerStatus = " unavailable" ;
9582 console .info (" Using client-side keyword mapping for transpilation" );
9683 return false ;
@@ -100,19 +87,14 @@ async function checkCompilerAvailability() {
10087 }
10188}
10289
103- // Transpile NullScript to JavaScript
10490async function transpileNullScript (code ) {
105- // If we haven't checked compiler availability yet
10691 if (compilerStatus === " checking" ) {
10792 await checkCompilerAvailability ();
10893 }
10994
110- // For now, always use fallback transpilation
111- // In the future, this could be extended to use a server-side compilation API
11295 return fallbackTranspile (code);
11396}
11497
115- // Fallback transpilation using keyword mappings
11698function fallbackTranspile (code ) {
11799 const keywordMappings = {
118100 " run " : " function " ,
@@ -155,20 +137,16 @@ function fallbackTranspile(code) {
155137 " pull(" : " fetch(" ,
156138 };
157139
158- // Remove single-line comments (// ...)
159140 let jsCode = code .replace (/ \/\/ . * $ / gm , " " );
160141
161- // Remove multi-line comments (/* ... */)
162142 jsCode = jsCode .replace (/ \/\* [\s\S ] *? \*\/ / g , " " );
163143
164- // Clean up empty lines and excessive whitespace
165144 jsCode = jsCode
166145 .split (" \n " )
167146 .map ((line ) => line .trim ())
168147 .filter ((line ) => line .length > 0 )
169148 .join (" \n " );
170149
171- // Apply keyword mappings
172150 for (const [nullscript , javascript ] of Object .entries (keywordMappings)) {
173151 const regex = new RegExp (
174152 nullscript .replace (/ [. *+?^${}()|[\]\\ ] / g , " \\ $&" ),
@@ -180,7 +158,6 @@ function fallbackTranspile(code) {
180158 return jsCode;
181159}
182160
183- // Capture console output
184161function captureConsoleOutput () {
185162 const output = [];
186163 const originalLog = console .log ;
@@ -233,26 +210,22 @@ function captureConsoleOutput() {
233210 };
234211}
235212
236- // Transpile code
237213async function transpile () {
238- // Return early if input is empty (button should be disabled)
239214 if (isInputEmpty .value ) return ;
240215
241216 try {
242- const code = nullscriptCode .value .trim ();
217+ const code = nullScriptCode .value .trim ();
243218 if (! code) {
244219 javascriptCode .value = " // No code to transpile" ;
245220 return ;
246221 }
247222
248- // Show loading state
249223 const compilerType =
250224 compilerStatus === " available"
251225 ? " official NullScript compiler"
252226 : " keyword mapping" ;
253227 consoleOutput .value = ` <span class="info">🔄 Transpiling with ${ compilerType} ...</span>` ;
254228
255- // Use the real NullScript compiler
256229 const result = await transpileNullScript (code);
257230 javascriptCode .value = result;
258231 consoleOutput .value =
@@ -263,9 +236,7 @@ async function transpile() {
263236 }
264237}
265238
266- // Run transpiled code
267239function runCode () {
268- // Return early if input is empty (button should be disabled)
269240 if (isInputEmpty .value ) return ;
270241
271242 if (! javascriptCode .value .trim ()) {
@@ -279,12 +250,9 @@ function runCode() {
279250 try {
280251 consoleOutput .value = " " ;
281252
282- // Execute code using Function constructor (safer than eval)
283- // eslint-disable-next-line no-new-func
284253 const executeCode = new Function (javascriptCode .value );
285254 executeCode ();
286255
287- // Display captured output
288256 const output = capture .getOutput ();
289257 if (output .length === 0 ) {
290258 consoleOutput .value =
@@ -309,19 +277,15 @@ function runCode() {
309277 }
310278}
311279
312- // Clear all
313280function clearAll () {
314- // Return early if input is empty (button should be disabled)
315281 if (isInputEmpty .value ) return ;
316282
317- nullscriptCode .value = " " ;
283+ nullScriptCode .value = " " ;
318284 javascriptCode .value = " // Transpiled JavaScript will appear here..." ;
319285 consoleOutput .value = " // Execution results will appear here..." ;
320286}
321287
322- // Copy JavaScript code
323288async function copyJavaScript () {
324- // Return early if input is empty (button should be disabled)
325289 if (isInputEmpty .value ) return ;
326290
327291 if (! javascriptCode .value .trim ()) {
@@ -343,19 +307,14 @@ async function copyJavaScript() {
343307 }
344308}
345309
346- // Debounced transpile
347310let transpileTimeout;
348311function debouncedTranspile () {
349312 clearTimeout (transpileTimeout);
350313 transpileTimeout = setTimeout (() => transpile (), 500 );
351314}
352315
353- // Initialize
354316onMounted (async () => {
355- // Check compiler availability first
356317 await checkCompilerAvailability ();
357-
358- // Then transpile the initial code
359318 await transpile ();
360319});
361320 </script >
@@ -369,22 +328,19 @@ onMounted(async () => {
369328 min-height : 500px ;
370329}
371330
372- /* Tablet breakpoint */
373331@media (max-width : 1024px ) {
374332 .playground-container {
375333 gap : 15px ;
376334 }
377335}
378336
379- /* Mobile breakpoint */
380337@media (max-width : 768px ) {
381338 .playground-container {
382339 gap : 20px ;
383340 margin : 15px 0 ;
384341 }
385342}
386343
387- /* Small mobile breakpoint */
388344@media (max-width : 480px ) {
389345 .playground-container {
390346 margin : 10px 0 ;
@@ -398,15 +354,13 @@ onMounted(async () => {
398354 width : 100% ;
399355}
400356
401- /* Output container with vertical layout */
402357.output-container {
403358 display : flex ;
404359 flex-direction : column ;
405360 gap : 40px ;
406361 width : 100% ;
407362}
408363
409- /* Individual output panels */
410364.output-panel {
411365 width : 100% ;
412366 display : flex ;
@@ -443,7 +397,6 @@ onMounted(async () => {
443397 box-sizing : border-box ;
444398}
445399
446- /* Responsive textarea height */
447400@media (max-width : 768px ) {
448401 .code-input {
449402 height : 250px ;
@@ -491,7 +444,6 @@ onMounted(async () => {
491444 border : 1px solid var (--vp-c-border ) !important ;
492445}
493446
494- /* Responsive button sizing */
495447@media (max-width : 640px ) {
496448 .btn {
497449 padding : 10px 14px ;
@@ -516,12 +468,13 @@ onMounted(async () => {
516468
517469.btn-primary {
518470 background : var (--vp-c-brand );
519- color : white ;
471+ color : #000 ;
520472 border : 1px solid var (--vp-c-border );
521473}
522474
523475.btn-primary :hover:not (:disabled ) {
524- background : var (--vp-c-brand-dark );
476+ background : #e6c800 ;
477+ transition : all 0.2s ;
525478}
526479
527480.btn-success {
@@ -532,16 +485,18 @@ onMounted(async () => {
532485
533486.btn-success :hover:not (:disabled ) {
534487 background : #059669 ;
488+ transition : all 0.2s ;
535489}
536490
537491.btn-secondary {
538- background : var ( --vp-c-bg-mute ) ;
539- color : var ( --vp-c-text-1 ) ;
540- border : 1px solid var ( --vp-c-border ) ;
492+ background : red ;
493+ color : white ;
494+ border : 1px solid red ;
541495}
542496
543497.btn-secondary :hover:not (:disabled ) {
544- background : var (--vp-c-bg-soft );
498+ background : #b91c1c ;
499+ transition : all 0.2s ;
545500}
546501
547502.btn-info {
@@ -552,13 +507,14 @@ onMounted(async () => {
552507
553508.btn-info :hover:not (:disabled ) {
554509 background : #2563eb ;
510+ transition : all 0.2s ;
555511}
556512
557513.code-output ,
558514.console-output {
559515 width : 100% ;
560516 min-height : 200px ;
561- height : 200px ; /* Fixed height for consistency */
517+ height : 200px ;
562518 font-family : " Monaco" , " Menlo" , " Ubuntu Mono" , " Courier New" , monospace ;
563519 font-size : 14px ;
564520 border : 2px solid var (--vp-c-border );
@@ -567,18 +523,17 @@ onMounted(async () => {
567523 background : var (--vp-c-bg-soft );
568524 color : var (--vp-c-text-1 );
569525 overflow-x : auto ;
570- overflow-y : auto ; /* Allow vertical scrolling */
526+ overflow-y : auto ;
571527 white-space : pre-wrap ;
572528 line-height : 1.5 ;
573- margin-bottom : 0 ; /* Remove bottom margin for consistent gap */
529+ margin-bottom : 0 ;
574530 box-sizing : border-box ;
575531}
576532
577- /* Responsive output areas */
578533@media (max-width : 768px ) {
579534 .code-output ,
580535 .console-output {
581- height : 150px ; /* Fixed height for mobile */
536+ height : 150px ;
582537 min-height : 150px ;
583538 }
584539}
@@ -613,19 +568,17 @@ onMounted(async () => {
613568 color : #3b82f6 ;
614569}
615570
616- /* Touch-friendly improvements */
617571@media (hover : none) and (pointer: coarse) {
618572 .btn {
619573 padding : 12px 16px ;
620- font-size : 16px ; /* Prevent zoom on iOS */
574+ font-size : 16px ;
621575 }
622576
623577 .code-input {
624- font-size : 16px ; /* Prevent zoom on iOS */
578+ font-size : 16px ;
625579 }
626580}
627581
628- /* Landscape mobile optimization */
629582@media (max-width : 768px ) and (orientation : landscape ) {
630583 .code-input {
631584 height : 180px ;
@@ -637,7 +590,6 @@ onMounted(async () => {
637590 }
638591}
639592
640- /* Very small screens */
641593@media (max-width : 320px ) {
642594 .playground-container {
643595 margin : 5px 0 ;
0 commit comments