Skip to content

Commit dd2b08d

Browse files
authored
Merge pull request #7 from nullscript-lang/dev
Clean up playground component: remove all comments and improve code s…
2 parents 5c6b060 + 2fe72ef commit dd2b08d

7 files changed

Lines changed: 30 additions & 84 deletions

File tree

.vitepress/components/playground.vue

Lines changed: 22 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
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"
@@ -41,7 +40,6 @@
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>
@@ -61,7 +59,7 @@
6159
<script setup>
6260
import { computed, onMounted, ref } from "vue";
6361
64-
const nullscriptCode = ref(`// Write your NullScript code here...
62+
const nullScriptCode = ref(`// Write your NullScript code here...
6563
run greet(name) {
6664
return \`Hello, \${name}! Welcome to NullScript! 🎭\`;
6765
}
@@ -72,25 +70,14 @@ speak.say(message);`);
7270
const javascriptCode = ref("");
7371
const consoleOutput = ref("// Execution results will appear here...");
7472
75-
// Computed property to check if input is empty
7673
const 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
8479
async 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
10490
async 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
11698
function 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
184161
function captureConsoleOutput() {
185162
const output = [];
186163
const originalLog = console.log;
@@ -233,26 +210,22 @@ function captureConsoleOutput() {
233210
};
234211
}
235212
236-
// Transpile code
237213
async 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
267239
function 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
313280
function 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
323288
async 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
347310
let transpileTimeout;
348311
function debouncedTranspile() {
349312
clearTimeout(transpileTimeout);
350313
transpileTimeout = setTimeout(() => transpile(), 500);
351314
}
352315
353-
// Initialize
354316
onMounted(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;

.vitepress/config.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,6 @@ export default defineConfig({
5252
logo: {
5353
src: "/logo.png",
5454
alt: "NullScript Logo",
55-
style: {
56-
borderRadius: "10%",
57-
},
5855
},
5956
nav: [
6057
{ text: "Guide", link: "/guide/introduction" },

.vitepress/theme/custom.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300..700&display=swap');
2+
13
:root {
24
--vp-c-brand-1: #f7df1e;
35
--vp-c-brand-2: #e6c800;
@@ -7,6 +9,9 @@
79
--vp-button-brand-hover-text: #000;
810
--vp-code-bg: #f7df1e;
911
--vp-code-color: #000;
12+
13+
--vp-font-family-base: "Space Grotesk", sans-serif;
14+
--vp-font-family-mono: "Space Grotesk", sans-serif;
1015
}
1116

1217
.dark {

0 commit comments

Comments
 (0)