Add playground example loader
This commit is contained in:
@@ -1,26 +1,9 @@
|
||||
import init, { evaluateProject } from '../wasm/decodal_wasm.js';
|
||||
import { highlightDecodal } from '../lib/highlight.js';
|
||||
import { playgroundExamples } from './playground-examples.js';
|
||||
|
||||
const STORAGE_KEY = 'decodal-playground-project-v1';
|
||||
|
||||
const starterFiles = {
|
||||
'main.dcdl': `let
|
||||
schema = import "./schemas/service.dcdl";
|
||||
in
|
||||
schema.Service & {
|
||||
name = "api";
|
||||
port = 9000 + 443;
|
||||
tags = ["web"] ++ ["prod"];
|
||||
feature.enable = 9000 + 443 > 9000 && true;
|
||||
}
|
||||
`,
|
||||
'schemas/service.dcdl': `Service = {
|
||||
name = String;
|
||||
port = Int & > 443 default 8443;
|
||||
feature.enable = Bool default true;
|
||||
};
|
||||
`,
|
||||
};
|
||||
const starterProject = playgroundExamples[0];
|
||||
|
||||
const source = document.getElementById('source');
|
||||
const sourceHighlight = document.getElementById('source-highlight');
|
||||
@@ -31,9 +14,19 @@ const fileTree = document.getElementById('file-tree');
|
||||
const activeFile = document.getElementById('active-file');
|
||||
const newFile = document.getElementById('new-file');
|
||||
const deleteFile = document.getElementById('delete-file');
|
||||
const exampleSelect = document.getElementById('example-select');
|
||||
const loadExample = document.getElementById('load-example');
|
||||
|
||||
const project = loadProject();
|
||||
|
||||
for (const example of playgroundExamples) {
|
||||
const option = document.createElement('option');
|
||||
option.value = example.id;
|
||||
option.textContent = example.title;
|
||||
exampleSelect.append(option);
|
||||
}
|
||||
exampleSelect.value = starterProject.id;
|
||||
|
||||
setActiveFile(project.activePath);
|
||||
renderFileTree();
|
||||
updateHighlight();
|
||||
@@ -49,7 +42,11 @@ function loadProject() {
|
||||
} catch (_error) {
|
||||
// Fall back to the starter project.
|
||||
}
|
||||
return { files: { ...starterFiles }, activePath: 'main.dcdl' };
|
||||
return { files: cloneFiles(starterProject.files), activePath: starterProject.activePath };
|
||||
}
|
||||
|
||||
function cloneFiles(files) {
|
||||
return Object.fromEntries(Object.entries(files).map(([path, source]) => [path, source]));
|
||||
}
|
||||
|
||||
function normalizeFiles(files) {
|
||||
@@ -65,6 +62,17 @@ function saveProject() {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(project));
|
||||
}
|
||||
|
||||
function loadExampleProject(exampleId) {
|
||||
const example = playgroundExamples.find((item) => item.id === exampleId) ?? starterProject;
|
||||
project.files = cloneFiles(example.files);
|
||||
project.activePath = example.activePath;
|
||||
exampleSelect.value = example.id;
|
||||
setActiveFile(project.activePath);
|
||||
output.textContent = '';
|
||||
output.classList.remove('error');
|
||||
execute();
|
||||
}
|
||||
|
||||
function normalizePath(path) {
|
||||
const parts = [];
|
||||
for (const part of String(path).replaceAll('\\', '/').split('/')) {
|
||||
@@ -165,6 +173,12 @@ try {
|
||||
}
|
||||
|
||||
run.addEventListener('click', execute);
|
||||
loadExample.addEventListener('click', () => {
|
||||
const example = playgroundExamples.find((item) => item.id === exampleSelect.value);
|
||||
if (!example) return;
|
||||
if (!confirm(`Load example "${example.title}"? This replaces the current virtual files.`)) return;
|
||||
loadExampleProject(example.id);
|
||||
});
|
||||
newFile.addEventListener('click', () => {
|
||||
const path = normalizePath(prompt('New virtual file path', 'schemas/types.dcdl') ?? '');
|
||||
if (!path) return;
|
||||
@@ -172,7 +186,7 @@ newFile.addEventListener('click', () => {
|
||||
setActiveFile(path);
|
||||
return;
|
||||
}
|
||||
project.files[path] = path.endsWith('.dcdl') ? '' : '// Decodal source\n';
|
||||
project.files[path] = 'value = "new";\n';
|
||||
setActiveFile(path);
|
||||
});
|
||||
deleteFile.addEventListener('click', () => {
|
||||
|
||||
Reference in New Issue
Block a user