diff --git a/index.html b/index.html
index 63a278b..0875d00 100644
--- a/index.html
+++ b/index.html
@@ -25,7 +25,16 @@
-
+
+
+
+
+
+
Save JavaScript
+
Export as HTML
+
+
+
diff --git a/index.js b/index.js
index d4da91e..b2b45d2 100644
--- a/index.js
+++ b/index.js
@@ -46,6 +46,9 @@ editor.setValue(sessionStorage.getItem("code") ?? editor.getValue(), -1);
const runButton = document.querySelector("#run-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 sessionSaveDebounce = new Debounce(1000);
@@ -61,15 +64,81 @@ runButton.onclick = (ev) => {
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) => {
- const code = editor.getValue();
- const element = document.createElement("a");
- element.setAttribute("href", `data:text/javascript;charset=utf-8,${encodeURIComponent(code)}`);
- const filename = prompt("Filename?")
- element.setAttribute("download", filename.endsWith(".js") ? filename : `${filename}.js`);
- element.style.display = "none";
- document.body.appendChild(element);
- element.click();
- document.body.removeChild(element);
+ if (saveButton.classList.contains("active")) {
+ saveButton.classList.remove("active");
+
+ saveDropdown.style.display = "none";
+ } else {
+ saveButton.classList.add("active");
+
+ saveDropdown.style.display = "block";
+ }
};
+
+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 = `
+
+
+
+
+
+ Game
+
+
+
+
+
+
+
+`;
+
+ downloadFile(html, "text/html", ".html");
+};
+
diff --git a/lib.js b/lib.js
index 582e588..1e14ca7 100644
--- a/lib.js
+++ b/lib.js
@@ -24,7 +24,10 @@ export function drawRect(x, y, width, height, color) {
}
export function println(msg) {
- consoleCode.textContent += `${msg}\n`;
+ if (consoleCode)
+ consoleCode.textContent += `${msg}\n`;
+ else
+ console.log(msg);
}
export function startGameLoop(loopFunction) {
diff --git a/style.css b/style.css
index 1c4062b..d71954b 100644
--- a/style.css
+++ b/style.css
@@ -54,6 +54,7 @@ div#buttons {
display: flex;
flex: row;
justify-content: space-between;
+ align-items: flex-start;
gap: 5px;
}
@@ -129,6 +130,33 @@ div#buttons > * > button {
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 {
background-color: #4FC3F7;
border: none;
@@ -139,6 +167,10 @@ button {
transition-duration: 200ms;
}
+button.active {
+ background-color: #0288D1;
+}
+
button:hover {
box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.2);
}