Allow saving both as JS and HTML
This commit is contained in:
parent
4d885903b0
commit
61050f58d9
@ -25,7 +25,16 @@
|
|||||||
<a href="docs/index.html" target="_blank">
|
<a href="docs/index.html" target="_blank">
|
||||||
<button>🤓 Docs</button>
|
<button>🤓 Docs</button>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
<div class="dropdown-wrapper">
|
||||||
<button id="save-button">💾 Save/Export</button>
|
<button id="save-button">💾 Save/Export</button>
|
||||||
|
|
||||||
|
<div id="save-dropdown" class="dropdown-content">
|
||||||
|
<div id="save-js" class="dropdown-option">Save JavaScript</div>
|
||||||
|
<div id="save-html" class="dropdown-option">Export as HTML</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button id="run-button">▶️ Run</button>
|
<button id="run-button">▶️ Run</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
87
index.js
87
index.js
@ -46,6 +46,9 @@ editor.setValue(sessionStorage.getItem("code") ?? editor.getValue(), -1);
|
|||||||
|
|
||||||
const runButton = document.querySelector("#run-button");
|
const runButton = document.querySelector("#run-button");
|
||||||
const saveButton = document.querySelector("#save-button");
|
const saveButton = document.querySelector("#save-button");
|
||||||
|
const saveDropdown = document.querySelector("#save-dropdown");
|
||||||
|
const saveJsButton = document.querySelector("#save-js");
|
||||||
|
const saveHtmlButton = document.querySelector("#save-html");
|
||||||
const consoleCode = document.querySelector("#console-code");
|
const consoleCode = document.querySelector("#console-code");
|
||||||
|
|
||||||
const sessionSaveDebounce = new Debounce(1000);
|
const sessionSaveDebounce = new Debounce(1000);
|
||||||
@ -61,15 +64,81 @@ runButton.onclick = (ev) => {
|
|||||||
runButton.textContent = "⚙️ Running...";
|
runButton.textContent = "⚙️ Running...";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function downloadFile(content, mime, extension) {
|
||||||
|
const filename = prompt("Filename?");
|
||||||
|
|
||||||
|
const element = document.createElement("a");
|
||||||
|
|
||||||
|
element.href = `data:${mime};charset=utf-8,${encodeURIComponent(content)}`;
|
||||||
|
element.download = filename.endsWith(extension) ? filename : filename + extension;
|
||||||
|
element.style.display = "none";
|
||||||
|
|
||||||
|
document.body.appendChild(element);
|
||||||
|
|
||||||
|
element.click();
|
||||||
|
|
||||||
|
document.body.removeChild(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
function minifyJs(code) {
|
||||||
|
return code
|
||||||
|
.replace(/[\s\n]+/g, " ")
|
||||||
|
.replace(/;\s+/g, ";");
|
||||||
|
}
|
||||||
|
|
||||||
saveButton.onclick = (ev) => {
|
saveButton.onclick = (ev) => {
|
||||||
const code = editor.getValue();
|
if (saveButton.classList.contains("active")) {
|
||||||
const element = document.createElement("a");
|
saveButton.classList.remove("active");
|
||||||
element.setAttribute("href", `data:text/javascript;charset=utf-8,${encodeURIComponent(code)}`);
|
|
||||||
const filename = prompt("Filename?")
|
saveDropdown.style.display = "none";
|
||||||
element.setAttribute("download", filename.endsWith(".js") ? filename : `${filename}.js`);
|
} else {
|
||||||
element.style.display = "none";
|
saveButton.classList.add("active");
|
||||||
document.body.appendChild(element);
|
|
||||||
element.click();
|
saveDropdown.style.display = "block";
|
||||||
document.body.removeChild(element);
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
saveJsButton.onclick = (ev) => {
|
||||||
|
downloadFile(editor.getValue(), "text/javascript", ".js");
|
||||||
|
};
|
||||||
|
|
||||||
|
saveHtmlButton.onclick = async (ev) => {
|
||||||
|
const js = editor.getValue().split("\n").map(line => " ".repeat(12) + line).join("\n");
|
||||||
|
let lib = await (await fetch("./lib.js")).text();
|
||||||
|
lib = minifyJs(lib);
|
||||||
|
|
||||||
|
const html = `
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="generator" content="karlkoder playground">
|
||||||
|
<title>Game</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script type="importmap">
|
||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"lib": "data:text/javascript,${encodeURIComponent(lib)}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script type="module">
|
||||||
|
${js}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<canvas width="480" height="360"></canvas>
|
||||||
|
</body>
|
||||||
|
</html>`;
|
||||||
|
|
||||||
|
downloadFile(html, "text/html", ".html");
|
||||||
|
};
|
||||||
|
|
||||||
|
3
lib.js
3
lib.js
@ -24,7 +24,10 @@ export function drawRect(x, y, width, height, color) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function println(msg) {
|
export function println(msg) {
|
||||||
|
if (consoleCode)
|
||||||
consoleCode.textContent += `${msg}\n`;
|
consoleCode.textContent += `${msg}\n`;
|
||||||
|
else
|
||||||
|
console.log(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function startGameLoop(loopFunction) {
|
export function startGameLoop(loopFunction) {
|
||||||
|
32
style.css
32
style.css
@ -54,6 +54,7 @@ div#buttons {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex: row;
|
flex: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,6 +130,33 @@ div#buttons > * > button {
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dropdown-wrapper {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-content {
|
||||||
|
display: none;
|
||||||
|
background-color: white;
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-option {
|
||||||
|
padding: 5px 10px;
|
||||||
|
font-family: sans-serif;
|
||||||
|
color: #424242;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-option:hover {
|
||||||
|
background-color: #EEE;
|
||||||
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
background-color: #4FC3F7;
|
background-color: #4FC3F7;
|
||||||
border: none;
|
border: none;
|
||||||
@ -139,6 +167,10 @@ button {
|
|||||||
transition-duration: 200ms;
|
transition-duration: 200ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button.active {
|
||||||
|
background-color: #0288D1;
|
||||||
|
}
|
||||||
|
|
||||||
button:hover {
|
button:hover {
|
||||||
box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.2);
|
box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.2);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user