Initial commit: code playground with multi-framework support

Express + SQLite backend with Monaco editor frontend.
Supports HTML/CSS/JS, TypeScript, React (JSX/TSX), Vue SFC,
and Svelte with live preview, console output, save/fork/share.

Includes CSS preprocessors (SCSS, Less), framework-specific
compilation (Babel, TypeScript, Svelte compiler), and
CDN-loaded runtime libraries for preview rendering.
This commit is contained in:
root
2026-02-26 08:12:39 -06:00
commit 463b563423
14 changed files with 2550 additions and 0 deletions

View File

@@ -0,0 +1,54 @@
let sassLoaded = false;
let lessLoaded = false;
function loadScript(src) {
return new Promise((resolve, reject) => {
if (document.querySelector(`script[src="${src}"]`)) { resolve(); return; }
const savedDefine = window.define;
window.define = undefined;
const s = document.createElement('script');
s.src = src;
s.onload = () => { window.define = savedDefine; resolve(); };
s.onerror = () => { window.define = savedDefine; reject(new Error(`Failed to load ${src}`)); };
document.head.appendChild(s);
});
}
async function ensureSass() {
if (sassLoaded) return;
await loadScript('https://cdnjs.cloudflare.com/ajax/libs/sass.js/0.11.1/sass.sync.min.js');
sassLoaded = true;
}
async function ensureLess() {
if (lessLoaded) return;
window.less = { env: 'production' };
await loadScript('https://cdnjs.cloudflare.com/ajax/libs/less.js/4.2.0/less.min.js');
lessLoaded = true;
}
export async function compileCss(code, type) {
if (type === 'css') return code;
if (type === 'scss') {
await ensureSass();
return new Promise((resolve, reject) => {
Sass.compile(code, (result) => {
if (result.status === 0) resolve(result.text);
else reject(new Error(result.formatted || result.message));
});
});
}
if (type === 'less') {
await ensureLess();
try {
const result = await less.render(code);
return result.css;
} catch (e) {
throw new Error(e.message);
}
}
return code;
}