From c38abaf99f04899e5cc7f7733eb347fbcd99e496 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Wed, 20 Apr 2022 04:26:29 +0000 Subject: [PATCH] separate IDE mode --- static/css/index.css | 32 +++- static/src/folders.js | 281 +++++++++++++++++++++++++++++++++++ static/src/index.js | 153 +++---------------- static/src/service-worker.js | 1 + templates/index.html | 37 ++++- 5 files changed, 361 insertions(+), 143 deletions(-) create mode 100644 static/src/folders.js diff --git a/static/css/index.css b/static/css/index.css index 20e8e39..d50e1d0 100644 --- a/static/css/index.css +++ b/static/css/index.css @@ -83,6 +83,12 @@ select:hover { cursor: pointer; } +.menu-bar a[title="Settings"] { + float: right; + color: var(--foreground-color); + padding-top: 4px; +} + #folder-view { width: calc(var(--folder-width) - var(--divider-size)); float: left; @@ -294,30 +300,44 @@ select:hover { position: relative; cursor: pointer; transition: all 200ms; - /* border-left: 2px solid var(--active-color); */ padding-left: 4px; } -.folder-item:hover { +.folder-item.file.active { background-color: var(--light-background-color); } +.folder-item:not(.active):hover { + background-color: var(--active-color); +} + +.folder-item > .folder-item-button { + opacity: 0; + float: right; + transition: all 200ms; +} + +.folder-item:hover > .folder-item-button { + opacity: 1; +} + .folder { position: relative; left: 32px; - overflow-x: hidden; + width: calc(100% - 32px); overflow-y: auto; + overflow-x: hidden; } -.folder.root { +.folder-root { left: 0px !important; overflow-y: auto; overflow-x: hidden; height: 100%; - max-height: calc(100vh - var(--menu-bar-height) - var(--tab-line-height)); /* subtract the padding */ + max-height: calc(100vh - var(--menu-bar-height) * 2 - var(--tab-line-height) - 12px); /* subtract the padding */ } -.folder.root > .folder-item { +.folder-root > .folder-item { border-left: none !important; } diff --git a/static/src/folders.js b/static/src/folders.js new file mode 100644 index 0000000..5dc1e03 --- /dev/null +++ b/static/src/folders.js @@ -0,0 +1,281 @@ + +// Experimental Folder System +/* + { + "name": "Examples", + "type": "dir", + "state": "open", + "elems": [ + { + "name": "example 1", + "type": "file", + }, + { + "name": "example 2", + "type": "file", + }, + { + "name": "example 3", + "type": "file", + }, + { + "name": "Built ins", + "type": "dir", + "state": "open", + "elems": [ + { + "name": "example 1", + "type": "file", + }, + { + "name": "example 2", + "type": "file", + }, + { + "name": "example 3", + "type": "file", + }, + ], + }, + ], + }, + { + "name": "Built ins", + "type": "dir", + "state": "open", + "elems": [ + { + "name": "example 1", + "type": "file", + }, + { + "name": "example 2", + "type": "file", + }, + { + "name": "example 3", + "type": "file", + }, + ], + }, +] +*/ + +class FolderSystem { + constructor() { + this.folders = []; + } + + create_directory(path) { + let parts = path.split("/"); + let name = parts.at(-1); + + let root = this.folders; + for (let part of parts.slice(0, parts.length - 1)) { + let matches = root.filter((x) => x.name == part); + if (matches.length == 0) { + root.push({ + name: part, + type: "dir", + state: "closed", + elems: [], + }); + root = root[root.length - 1].elems; + + } else { + root = matches[0].elems; + } + } + + for (let elem of root) { + if (elem.name == name) return elem; + } + + root.push({ + name, + type: "dir", + state: "closed", + elems: [], + }) + + return root[root.length - 1]; + } + + lookup(path) { + let parts = path.split("/"); + + let root = this.folders; + for (let part of parts) { + if (!Array.isArray(root)) return null; + + let elems = root.filter((x) => x.name == part); + if (elems.length != 1) return null; + + root = elems[0]; + if (root.type == "dir") { + root = root.elems; + } + } + + return root; + } + + build_folder_view(onclick, selector=".folder-root") { + let $root = $(selector); + + let build = (t, name) => { + let output = ""; + switch (t.type) { + case "dir": { + output += `
+ + ${t.name} + + +
`; + + t.elems.sort((a, b) => { + let av = a.type == "dir" ? 0 : 1; + let bv = b.type == "dir" ? 0 : 1; + + if (av == bv) { + return a.name < b.name ? -1 : 1; + } else { + return av - bv; + } + }) + + output += `
`; + for (let i of t.elems) { + output += build(i, name + "/" + i.name); + } + output += `
`; + + break; + } + + case "file": { + output += `
+ + ${t.name} + + +
`; + break; + } + } + + return output; + } + + let root_html = ""; + for (let elem of this.folders) { + root_html += build(elem, elem.name); + } + + $root.html(root_html); + $root.find(".folder-item").click(onclick); + } + + save() { + localStorage["filesystem"] = JSON.stringify(this.folders); + } + + restore() { + if ("filesystem" in localStorage) { + this.folders = JSON.parse(localStorage["filesystem"]); + return true; + } + + return false; + } +} + + +async function enable_ide_mode() { + $("#simple-menubar").addClass("hidden"); + $("#ide-menubar").removeClass("hidden"); + $("#folder-view").removeClass("hidden"); + $("#main-horizontal-divider").removeClass("hidden"); + $(":root").css("--folder-width", localStorage.getItem("folder-width")); + + folders = new FolderSystem(); + folders.restore(); + + if (folders.lookup("Examples") == null) { + await populate_examples_folder(); + } + + await populate_simple_saved_folder(); + + folders.save(); + folders.build_folder_view(folder_item_click); +} + +function disable_ide_mode() { + $("#simple-menubar").removeClass("hidden"); + $("#ide-menubar").addClass("hidden"); + $("#folder-view").addClass("hidden"); + $("#main-horizontal-divider").addClass("hidden"); + $(":root").css("--folder-width", "0px"); +} + +async function populate_examples_folder() { + let examples = await fetch(ROOT_ENDPOINT + "/list_examples").then(x => x.json()) + let example_dir = folders.create_directory("Examples"); + for (let ex of examples) { + let example_code = await fetch(`${ROOT_ENDPOINT}/example?example=${ex}`).then(x => x.text()); + example_dir.elems.push({ + name: ex, + type: "file", + contents: example_code + }) + } +} + +async function populate_simple_saved_folder() { + let folder_name = "Simple Mode Saves"; + + let saved_dir = folders.create_directory(folder_name); + for (let item in localStorage) { + if (/saved_/.test(item)) { + let item_name = item.substring(6); + + let existing_item = folders.lookup(folder_name + "/" + item_name); + if (existing_item) { + existing_item.contents = localStorage[item]; + + } else { + saved_dir.elems.push({ + name: item_name, + type: "file", + contents: localStorage[item], + }); + } + } + } +} + +function folder_item_click(e) { + let $target = $(e.target); + + if ($target.hasClass("file")) { + let editor = ace.edit("code-editor"); + let filename = $target.attr("data-filename"); + let file = folders.lookup(filename); + editor.setValue(file.contents); + editor.clearSelection(); + } + + if ($target.hasClass("directory")) { + if ($target.hasClass("open")) { + $target.removeClass("open").addClass("closed"); + $target.children("i").removeClass("fa-folder-open").addClass("fa-folder"); + $target.next().addClass("hidden"); + } else { + $target.removeClass("closed").addClass("open"); + $target.children("i").removeClass("fa-folder").addClass("fa-folder-open"); + $target.next().removeClass("hidden"); + } + } +} \ No newline at end of file diff --git a/static/src/index.js b/static/src/index.js index a5f4e77..dfdeaa8 100644 --- a/static/src/index.js +++ b/static/src/index.js @@ -5,6 +5,7 @@ let ui_theme = "dark"; let input_shared_buffer = new SharedArrayBuffer(1024 * Uint8Array.BYTES_PER_ELEMENT); let canvas_shared_buffer = new SharedArrayBuffer(7 * Int32Array.BYTES_PER_ELEMENT); +let folders = null; async function clear_output() { let elem = document.getElementById('code-result'); @@ -124,12 +125,12 @@ async function kill_code() { } function update_running_msg() { - let elem = document.getElementById('run-button'); + let elem = $('.run-button'); if (wasm_worker == null) { - elem.innerHTML = ""; + elem.html(""); } else { - elem.innerHTML = ""; + elem.html(""); } } @@ -183,6 +184,21 @@ function change_ui_theme(value) { persist_settings(); } +function change_ui_mode(value) { + let elem = document.getElementById('ui-mode'); + if (value == null) { + value = elem.value; + } else { + document.querySelector(`#ui-mode option[value="${value}"]`).selected = true; + } + + if (value == "ide") { + enable_ide_mode(); + } else { + disable_ide_mode(); + } +} + function persist_settings() { localStorage["editor_theme"] = editor_theme; localStorage["editor_keybind_mode"] = editor_keybind_mode; @@ -285,18 +301,18 @@ async function request_permalink() { function load_split_sizes() { let $root = $(":root"); - $root.css("--folder-width", localStorage.getItem("folder-width")); $root.css("--top-half-height", localStorage.getItem("top-half-height")); $root.css("--left-half-width", localStorage.getItem("left-half-width")); + $root.css("--folder-width", "0px"); } function save_split_sizes() { let $root = $(":root"); - localStorage.setItem("folder-width", $root.css("--folder-width")); localStorage.setItem("top-half-height", $root.css("--top-half-height")); localStorage.setItem("left-half-width", $root.css("--left-half-width")); } + window.onload = () => { if ('serviceWorker' in navigator) { navigator.serviceWorker.register("/playground/static/src/service-worker.js", { @@ -313,7 +329,7 @@ window.onload = () => { populate_examples(); load_settings(); - // build_folder_view(); + change_ui_mode("ide"); make_resizer("main-horizontal-divider", "--folder-width", "", (e) => { save_split_sizes(); @@ -336,127 +352,4 @@ window.onload = () => { $("#save-filename").on('keyup', (ev) => { if (ev.keyCode === 13) save_to_local_storage() }); $("#load-filename").on('keyup', (ev) => { if (ev.keyCode === 13) load_from_local_storage() }); -}; - -// Experimental Folder System -/* -let folders = [ - { - "name": "Examples", - "type": "dir", - "state": "open", - "elems": [ - { - "name": "example 1", - "type": "file", - }, - { - "name": "example 2", - "type": "file", - }, - { - "name": "example 3", - "type": "file", - }, - { - "name": "Built ins", - "type": "dir", - "state": "open", - "elems": [ - { - "name": "example 1", - "type": "file", - }, - { - "name": "example 2", - "type": "file", - }, - { - "name": "example 3", - "type": "file", - }, - ], - }, - ], - }, - { - "name": "Built ins", - "type": "dir", - "state": "open", - "elems": [ - { - "name": "example 1", - "type": "file", - }, - { - "name": "example 2", - "type": "file", - }, - { - "name": "example 3", - "type": "file", - }, - ], - }, -] - -function build_folder_view() { - let $root = $(".folder.root"); - - let build = (t) => { - let output = ""; - switch (t.type) { - case "dir": { - output += `
- - ${t.name}
`; - - if (t.state == "open") { - output += `
`; - for (let i of t.elems) { - output += build(i); - } - output += `
`; - } - - break; - } - - case "file": { - output += `
${t.name}
`; - break; - } - } - - return output; - } - - let root_html = ""; - for (let elem of folders) { - root_html += build(elem); - } - - $root.html(root_html); - $(".folder-item").click(folder_item_click); -} - -function folder_item_click(e) { - let $target = $(e.target); - console.log($target); - - if ($target.hasClass("file")) { - } - - if ($target.hasClass("directory")) { - if ($target.hasClass("open")) { - $target.removeClass("open").addClass("closed"); - $target.children("i").removeClass("fa-folder-open").addClass("fa-folder"); - $target.next().addClass("hidden"); - } else { - $target.removeClass("closed").addClass("open"); - $target.children("i").removeClass("fa-folder").addClass("fa-folder-open"); - $target.next().removeClass("hidden"); - } - } -} -*/ \ No newline at end of file +}; \ No newline at end of file diff --git a/static/src/service-worker.js b/static/src/service-worker.js index c9564c6..b1780a4 100644 --- a/static/src/service-worker.js +++ b/static/src/service-worker.js @@ -10,6 +10,7 @@ const precacheResources = [ '/playground/static/src/resizer.js', '/playground/static/src/storage.js', '/playground/static/src/canvas.js', + '/playground/static/src/folders.js', '/playground/static/src/index.js', '/playground/static/vendor/ace/ace.js', '/playground/static/vendor/jquery/jquery.min.js', diff --git a/templates/index.html b/templates/index.html index 7b49e1f..6b18f7f 100644 --- a/templates/index.html +++ b/templates/index.html @@ -16,6 +16,7 @@ + @@ -23,15 +24,14 @@ -