Files
fiddle/public/js/embed.js
root e41c3e7dc4 Add browse dashboard, tags, visibility control, export, QR sharing, and embed mode
- Browse dashboard at / with search, framework filter, tag pills, and pagination
- Tags system with autocomplete datalist and per-fiddle tag management
- Listed/unlisted toggle for visibility control (unlisted still accessible via direct URL)
- Export standalone HTML with inlined CSS/JS and framework CDN tags
- QR code modal for sharing fiddle URLs
- Embed mode at /embed/:id for minimal preview-only rendering
- Extract shared loadScript() utility from 4 files into utils.js
- Database schema: listed column, tags and fiddle_tags tables with index
2026-02-26 14:19:52 -06:00

83 lines
2.3 KiB
JavaScript

import { loadFiddle } from './api.js';
import { getFrameworkRuntime } from './js-preprocessors.js';
const MODE_MAP = {
javascript: 'html-css-js',
typescript: 'typescript',
react: 'react',
'react-ts': 'react-ts',
vue: 'vue',
svelte: 'svelte',
};
async function init() {
// Extract fiddle ID from URL: /embed/:id
const match = location.pathname.match(/^\/embed\/([a-zA-Z0-9_-]+)$/);
if (!match) {
document.body.innerHTML = '<div class="embed-error">Invalid embed URL</div>';
return;
}
// Theme
const params = new URLSearchParams(location.search);
if (params.get('theme') === 'dark') document.body.classList.add('dark');
try {
const fiddle = await loadFiddle(match[1]);
const mode = MODE_MAP[fiddle.js_type] || 'html-css-js';
const runtime = getFrameworkRuntime(mode);
// For embed, we compile client-side using the same preprocessors
const { compileCss } = await import('./preprocessors.js');
const { compileJs } = await import('./js-preprocessors.js');
const compiledCss = await compileCss(fiddle.css, fiddle.css_type || 'css');
const result = await compileJs(fiddle.js, mode);
const allCss = result.extraCss ? `${compiledCss}\n${result.extraCss}` : compiledCss;
let bodyContent;
if (mode === 'vue' || mode === 'svelte') {
bodyContent = fiddle.html ? `${fiddle.html}\n${runtime.bodyHtml}` : runtime.bodyHtml;
} else if (runtime.bodyHtml) {
bodyContent = `${fiddle.html}\n${runtime.bodyHtml}`;
} else {
bodyContent = fiddle.html;
}
let scripts = '';
if (result.js) {
if (result.isModule) {
scripts = `<script type="module">\n${escapeScriptClose(result.js)}\n<\/script>`;
} else {
for (const url of runtime.scripts) {
scripts += `<script src="${url}"><\/script>\n`;
}
scripts += `<script>\n${escapeScriptClose(result.js)}\n<\/script>`;
}
}
const doc = `<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>${allCss}</style>
</head>
<body>
${bodyContent}
${scripts}
</body>
</html>`;
document.getElementById('preview-frame').srcdoc = doc;
} catch (e) {
document.body.innerHTML = `<div class="embed-error">Failed to load fiddle: ${e.message}</div>`;
}
}
function escapeScriptClose(code) {
return code.replace(/<\/script/gi, '<\\/script');
}
init();