runlab 0.1.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/app.js +256 -0
- package/dist/app/core/editor.js +120 -0
- package/dist/app/core/navbar.js +154 -0
- package/dist/app/fileExplorer/FSNode.js +10 -0
- package/dist/app/fileExplorer/File.js +12 -0
- package/dist/app/fileExplorer/FileExplorer.js +405 -0
- package/dist/app/fileExplorer/Folder.js +12 -0
- package/dist/app/terminal/commands.js +117 -0
- package/dist/app/terminal/terminal.js +126 -0
- package/dist/index.js +45 -13
- package/package.json +36 -10
- package/dist/runlab.wasm +0 -0
- package/dist/wasm_exec.js +0 -575
package/dist/app/app.js
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { createEditor } from "./core/editor.js";
|
|
2
|
+
import { createNavbar } from "./core/navbar.js";
|
|
3
|
+
import { FileExplorer } from "./fileExplorer/FileExplorer.js";
|
|
4
|
+
import { createTerminal } from "./terminal/terminal.js";
|
|
5
|
+
|
|
6
|
+
export function generateContainer(parentId,w,h) {
|
|
7
|
+
const container = document.createElement("div");
|
|
8
|
+
container.id = "runlab-container";
|
|
9
|
+
Object.assign(container.style, {
|
|
10
|
+
width: w + "px",
|
|
11
|
+
height: h + "px",
|
|
12
|
+
border: "1px solid #000",
|
|
13
|
+
display: "flex",
|
|
14
|
+
justifyContent: "center",
|
|
15
|
+
alignItems: "center",
|
|
16
|
+
overflow: "hidden"
|
|
17
|
+
});
|
|
18
|
+
document.getElementById(parentId).appendChild(container);
|
|
19
|
+
gridTemplate("runlab-container", w, h);
|
|
20
|
+
createEditor("runlab-editor","");
|
|
21
|
+
|
|
22
|
+
// View and Editor toggle
|
|
23
|
+
const editor = document.getElementById("runlab-editor");
|
|
24
|
+
const overlay = document.createElement("div");
|
|
25
|
+
overlay.id = "runlab-view";
|
|
26
|
+
Object.assign(overlay.style, {
|
|
27
|
+
position: "absolute",
|
|
28
|
+
inset: "0",
|
|
29
|
+
backgroundColor: "#303030"
|
|
30
|
+
});
|
|
31
|
+
editor.style.position = "relative";
|
|
32
|
+
editor.appendChild(overlay);
|
|
33
|
+
|
|
34
|
+
const viewContent = document.createElement("iframe");
|
|
35
|
+
viewContent.id = "runlab-view-content";
|
|
36
|
+
Object.assign(viewContent.style, {
|
|
37
|
+
width: "100%",
|
|
38
|
+
height: "100%",
|
|
39
|
+
border: "none",
|
|
40
|
+
backgroundColor: "rgba(255, 255, 255, 0.8)"
|
|
41
|
+
});
|
|
42
|
+
document.getElementById("runlab-view").appendChild(viewContent);
|
|
43
|
+
|
|
44
|
+
const fe = new FileExplorer("runlab-file-explorer");
|
|
45
|
+
const root = fe.getRoot();
|
|
46
|
+
setFileExplorerNode(fe);
|
|
47
|
+
createNavbar("runlab-navbar");
|
|
48
|
+
|
|
49
|
+
setEditorActive(false); // Start with editor off
|
|
50
|
+
|
|
51
|
+
// ===============================
|
|
52
|
+
|
|
53
|
+
createTerminal("runlab-terminal",root);
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function appendViewContent(codeReturned) {
|
|
58
|
+
const viewContent = document.getElementById("runlab-view-content");
|
|
59
|
+
viewContent.srcdoc = codeReturned;
|
|
60
|
+
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function gridTemplate(parent) {
|
|
64
|
+
const grid = document.createElement('div');
|
|
65
|
+
grid.id = "runlab-grid";
|
|
66
|
+
Object.assign(grid.style, {
|
|
67
|
+
display: 'grid',
|
|
68
|
+
width: "100%",
|
|
69
|
+
height: "100%",
|
|
70
|
+
gridTemplateColumns: "1fr 4fr", // coluna esquerda menor
|
|
71
|
+
gridTemplateRows: "0.15fr 2.5fr 1fr", // top maior, bottom menor
|
|
72
|
+
gap: "2px",
|
|
73
|
+
padding: "2px",
|
|
74
|
+
boxSizing: "border-box",
|
|
75
|
+
backgroundColor: "#303030"
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const navbar = document.createElement("div");
|
|
79
|
+
navbar.id = "runlab-navbar";
|
|
80
|
+
Object.assign(navbar.style, {
|
|
81
|
+
gridColumn: "1 / 3", // ocupa as duas colunas
|
|
82
|
+
gridRow: "1 / 2", // fica na linha 1
|
|
83
|
+
border: "1px solid #09090b"
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
//Left
|
|
87
|
+
const fileExplorer = document.createElement("div");
|
|
88
|
+
fileExplorer.id = "runlab-file-explorer";
|
|
89
|
+
Object.assign(fileExplorer.style, {
|
|
90
|
+
gridColumn: "1 / 2",
|
|
91
|
+
gridRow: "2 / 4", // ocupa a linha 2 e 3
|
|
92
|
+
border: "1px solid #09090b"
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
//Right Top
|
|
96
|
+
const editor = document.createElement("div");
|
|
97
|
+
editor.id = "runlab-editor";
|
|
98
|
+
Object.assign(editor.style, {
|
|
99
|
+
gridColumn: "2 / 3",
|
|
100
|
+
gridRow: "2 / 3", // linha logo após a navbar
|
|
101
|
+
border: "1px solid #09090b",
|
|
102
|
+
width: "100%",
|
|
103
|
+
height: "100%",
|
|
104
|
+
overflow: "hidden"
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Right Bottom
|
|
108
|
+
const terminal = document.createElement("div");
|
|
109
|
+
terminal.id = "runlab-terminal";
|
|
110
|
+
Object.assign(terminal.style, {
|
|
111
|
+
gridColumn: "2 / 3",
|
|
112
|
+
gridRow: "3 / 4", // última linha
|
|
113
|
+
width: "100%",
|
|
114
|
+
height: "100%",
|
|
115
|
+
overflow: "hidden",
|
|
116
|
+
border: "1px solid #09090b"
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
grid.appendChild(navbar);
|
|
120
|
+
grid.appendChild(fileExplorer);
|
|
121
|
+
grid.appendChild(editor);
|
|
122
|
+
grid.appendChild(terminal);
|
|
123
|
+
document.getElementById(parent).appendChild(grid);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function setViewActive(status = false){
|
|
127
|
+
|
|
128
|
+
const editorBtn = document.getElementById("runlab-editor-btn");
|
|
129
|
+
const viewBtn = document.getElementById("runlab-view-btn");
|
|
130
|
+
|
|
131
|
+
editorBtn.classList.remove("active");
|
|
132
|
+
viewBtn.classList.remove("active");
|
|
133
|
+
if(status){
|
|
134
|
+
viewBtn.classList.add("active");
|
|
135
|
+
}
|
|
136
|
+
if(!status){
|
|
137
|
+
editorBtn.classList.add("active");
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
[editorBtn, viewBtn].forEach(b => {
|
|
141
|
+
b.style.background = "transparent";
|
|
142
|
+
b.style.color = "#000";
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
if(status){
|
|
146
|
+
document.getElementById("runlab-view").style.display = "block";
|
|
147
|
+
viewBtn.style.background = "#303030";
|
|
148
|
+
viewBtn.style.color = "#fff";
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (!status){
|
|
152
|
+
document.getElementById("runlab-view").style.display = "none";
|
|
153
|
+
editorBtn.style.background = "#303030";
|
|
154
|
+
editorBtn.style.color = "#fff";
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function setEditorActive(status = true){
|
|
159
|
+
const editorWarning = document.createElement("div");
|
|
160
|
+
editorWarning.id = "runlab-editor-warning";
|
|
161
|
+
Object.assign(editorWarning.style, {
|
|
162
|
+
position: "absolute",
|
|
163
|
+
inset: "0",
|
|
164
|
+
display: "flex",
|
|
165
|
+
flexDirection: "column",
|
|
166
|
+
justifyContent: "center",
|
|
167
|
+
alignItems: "center",
|
|
168
|
+
gap: "8px",
|
|
169
|
+
textAlign: "center",
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
//================================ SVG Warning Icon ================================
|
|
173
|
+
const warningImage = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
174
|
+
|
|
175
|
+
warningImage.setAttribute("viewBox", "0 0 128 128");
|
|
176
|
+
warningImage.setAttribute("width", "128");
|
|
177
|
+
warningImage.setAttribute("height", "128");
|
|
178
|
+
warningImage.setAttribute("fill", "none");
|
|
179
|
+
|
|
180
|
+
warningImage.innerHTML = `
|
|
181
|
+
<path
|
|
182
|
+
d="M24 8 H80 L104 32 V112 H24 Z M80 8 V32 H104"
|
|
183
|
+
stroke="currentColor"
|
|
184
|
+
stroke-width="4"
|
|
185
|
+
stroke-linejoin="round"
|
|
186
|
+
/>
|
|
187
|
+
|
|
188
|
+
<rect x="40" y="44" rx="6" ry="6" width="20" height="4"
|
|
189
|
+
fill="currentColor" transform="rotate(-25 36 44)" />
|
|
190
|
+
<rect x="68" y="44" rx="6" ry="6" width="20" height="4"
|
|
191
|
+
fill="currentColor" transform="rotate(25 64 44)" />
|
|
192
|
+
|
|
193
|
+
<circle cx="50" cy="64" r="5" fill="currentColor" />
|
|
194
|
+
<circle cx="78" cy="64" r="5" fill="currentColor" />
|
|
195
|
+
|
|
196
|
+
<rect x="44" y="80" rx="6" ry="6" width="40" height="5"
|
|
197
|
+
fill="currentColor" />
|
|
198
|
+
`;
|
|
199
|
+
|
|
200
|
+
warningImage.style.color = "#aaa";
|
|
201
|
+
|
|
202
|
+
//================================ SVG Warning Text ================================
|
|
203
|
+
|
|
204
|
+
const warningText = document.createElement("p");
|
|
205
|
+
warningText.textContent = "No file selected.";
|
|
206
|
+
warningText.style.color = "#aaa";
|
|
207
|
+
warningText.style.fontSize = "0.9em";
|
|
208
|
+
warningText.style.margin = "0";
|
|
209
|
+
|
|
210
|
+
const warningText2 = document.createElement("p");
|
|
211
|
+
warningText2.textContent =
|
|
212
|
+
"Please create a file using right click on the file explorer at the left container and select it.";
|
|
213
|
+
warningText2.style.color = "#aaa";
|
|
214
|
+
warningText2.style.fontSize = "0.75em";
|
|
215
|
+
warningText2.style.margin = "0";
|
|
216
|
+
|
|
217
|
+
//====================================================================================
|
|
218
|
+
|
|
219
|
+
editorWarning.appendChild(warningImage);
|
|
220
|
+
editorWarning.appendChild(warningText);
|
|
221
|
+
editorWarning.appendChild(warningText2);
|
|
222
|
+
|
|
223
|
+
const editorCodeMirror = document.getElementsByClassName("cm-editor ͼ1 ͼ3 ͼ16")[0];
|
|
224
|
+
|
|
225
|
+
if(!status){
|
|
226
|
+
document.getElementById("runlab-editor").appendChild(editorWarning);
|
|
227
|
+
if(editorCodeMirror){
|
|
228
|
+
editorCodeMirror.display = "none";
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if(status){
|
|
233
|
+
const existingWarning = document.getElementById("runlab-editor-warning");
|
|
234
|
+
if(existingWarning){
|
|
235
|
+
existingWarning.remove();
|
|
236
|
+
}
|
|
237
|
+
if(editorCodeMirror){
|
|
238
|
+
editorCodeMirror.display = "block";
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
let feNode = null;
|
|
245
|
+
|
|
246
|
+
function setFileExplorerNode(node) {
|
|
247
|
+
feNode = node;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export function getFeExecutables() {
|
|
251
|
+
return feNode.getExecutables()
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export function getFileNode(file) {
|
|
255
|
+
return feNode.getFileNode(file);
|
|
256
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// Core CM6
|
|
2
|
+
import { EditorState } from "@codemirror/state";
|
|
3
|
+
import { EditorView, keymap } from "@codemirror/view";
|
|
4
|
+
import { Compartment } from "@codemirror/state";
|
|
5
|
+
|
|
6
|
+
// Language
|
|
7
|
+
import { javascript } from "@codemirror/lang-javascript";
|
|
8
|
+
import { html } from "@codemirror/lang-html";
|
|
9
|
+
import { css } from "@codemirror/lang-css";
|
|
10
|
+
import { json } from "@codemirror/lang-json";
|
|
11
|
+
import { markdown } from "@codemirror/lang-markdown";
|
|
12
|
+
import { xml } from "@codemirror/lang-xml";
|
|
13
|
+
import { yaml } from "@codemirror/lang-yaml";
|
|
14
|
+
|
|
15
|
+
// VS Code look & feel
|
|
16
|
+
import { vscodeDark } from "@uiw/codemirror-theme-vscode";
|
|
17
|
+
import { vscodeKeymap } from "@replit/codemirror-vscode-keymap";
|
|
18
|
+
|
|
19
|
+
// IDE features
|
|
20
|
+
import { autocompletion, closeBrackets } from "@codemirror/autocomplete";
|
|
21
|
+
import { foldGutter, codeFolding } from "@codemirror/language";
|
|
22
|
+
|
|
23
|
+
const editors = new Map();
|
|
24
|
+
|
|
25
|
+
let activeFile = null;
|
|
26
|
+
|
|
27
|
+
export const languageCompartment = new Compartment();
|
|
28
|
+
|
|
29
|
+
export function setActiveFile(file) {
|
|
30
|
+
activeFile = file;
|
|
31
|
+
let navbarFileName = document.getElementById("runlab-navbar-active-file-name")
|
|
32
|
+
if (navbarFileName) {
|
|
33
|
+
navbarFileName.textContent = file ? `${file.name}.${file.ext}` : "";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function getActiveFile() {
|
|
38
|
+
return activeFile;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function getCurrentCode() {
|
|
42
|
+
const activeFile = getActiveFile();
|
|
43
|
+
return activeFile ? activeFile.content : "";
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function getCurrentExtension() {
|
|
47
|
+
const activeFile = getActiveFile();
|
|
48
|
+
return activeFile ? activeFile.ext : "";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function languageFromExtension(ext) {
|
|
52
|
+
switch (ext) {
|
|
53
|
+
case "txt": return [];
|
|
54
|
+
case "md": return markdown();
|
|
55
|
+
case "json": return json();
|
|
56
|
+
case "yaml": return yaml();
|
|
57
|
+
case "yml": return yaml();
|
|
58
|
+
case "toml":return [];
|
|
59
|
+
case "html":return html();
|
|
60
|
+
case "xml":return xml();
|
|
61
|
+
case "css":return css();
|
|
62
|
+
case "js":return javascript({ typescript: false });
|
|
63
|
+
case "ts":return javascript({ typescript: true });
|
|
64
|
+
case "lua":return [];
|
|
65
|
+
default:return [];
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function createEditor(parentId, initialCode = "") {
|
|
70
|
+
const parent = document.getElementById(parentId);
|
|
71
|
+
if (!parent) throw new Error(`Elemento #${parentId} não encontrado`);
|
|
72
|
+
|
|
73
|
+
const state = EditorState.create({
|
|
74
|
+
doc: initialCode,
|
|
75
|
+
extensions: [
|
|
76
|
+
keymap.of(vscodeKeymap),
|
|
77
|
+
vscodeDark,
|
|
78
|
+
languageCompartment.of(languageFromExtension(getActiveFile() ? getActiveFile().ext : "")),
|
|
79
|
+
autocompletion(),
|
|
80
|
+
closeBrackets(),
|
|
81
|
+
codeFolding(),
|
|
82
|
+
foldGutter(),
|
|
83
|
+
EditorView.updateListener.of(update => {
|
|
84
|
+
if (update.docChanged) {
|
|
85
|
+
const file = getActiveFile();
|
|
86
|
+
if (file) {
|
|
87
|
+
file.content = update.state.doc.toString();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
]
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const view = new EditorView({
|
|
95
|
+
state,
|
|
96
|
+
parent
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
editors.set(parentId, view);
|
|
100
|
+
return view;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function updateEditorContentById(parentId, content) {
|
|
104
|
+
const view = editors.get(parentId);
|
|
105
|
+
if (!view) {
|
|
106
|
+
console.warn(`Editor ${parentId} não inicializado`);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const langFactory = languageFromExtension(getActiveFile() ? getActiveFile().ext : "");
|
|
111
|
+
|
|
112
|
+
view.dispatch({
|
|
113
|
+
effects: languageCompartment.reconfigure(langFactory),
|
|
114
|
+
changes: {
|
|
115
|
+
from: 0,
|
|
116
|
+
to: view.state.doc.length,
|
|
117
|
+
insert: content
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { sendCode } from "../../index.js";
|
|
2
|
+
import { setViewActive } from "../app.js";
|
|
3
|
+
import { getCurrentCode, getCurrentExtension } from "./editor.js";
|
|
4
|
+
import Swal from "sweetalert2";
|
|
5
|
+
|
|
6
|
+
export function createNavbar(parentId) {
|
|
7
|
+
const navbar = document.createElement("nav");
|
|
8
|
+
navbar.id = "runlab-navbar-div";
|
|
9
|
+
Object.assign(navbar.style, {
|
|
10
|
+
width: "100%",
|
|
11
|
+
height: "100%"
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
// ========== Menu Items ==========
|
|
15
|
+
|
|
16
|
+
const ul = document.createElement("ul");
|
|
17
|
+
Object.assign(ul.style, {
|
|
18
|
+
listStyleType: "none",
|
|
19
|
+
margin: "0",
|
|
20
|
+
padding: "0",
|
|
21
|
+
display: "flex",
|
|
22
|
+
alignItems: "center",
|
|
23
|
+
width: "100%"
|
|
24
|
+
});
|
|
25
|
+
navbar.appendChild(ul);
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
// ========== Left Menu Items ==========
|
|
29
|
+
|
|
30
|
+
const leftGroup = document.createElement("div");
|
|
31
|
+
Object.assign(leftGroup.style, {
|
|
32
|
+
display: "flex",
|
|
33
|
+
alignItems: "center"
|
|
34
|
+
});
|
|
35
|
+
ul.appendChild(leftGroup);
|
|
36
|
+
|
|
37
|
+
const menuItems = ["Run", "Help"];
|
|
38
|
+
menuItems.forEach(item => {
|
|
39
|
+
const li = document.createElement("li");
|
|
40
|
+
li.textContent = item;
|
|
41
|
+
|
|
42
|
+
Object.assign(li.style, {
|
|
43
|
+
marginRight: "15px",
|
|
44
|
+
marginLeft: "15px",
|
|
45
|
+
padding: "10px 14px",
|
|
46
|
+
cursor: "pointer",
|
|
47
|
+
color: "#fff"
|
|
48
|
+
});
|
|
49
|
+
if (item === "Run") {
|
|
50
|
+
li.addEventListener("click", () => {
|
|
51
|
+
sendCode(getCurrentCode(),getCurrentExtension());
|
|
52
|
+
setViewActive(true);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
if (item === "Help") {
|
|
56
|
+
li.addEventListener("click", () => {
|
|
57
|
+
Swal.fire({
|
|
58
|
+
title: "RunLab Help",
|
|
59
|
+
html: `
|
|
60
|
+
<p>RunLab is a web-based code editor and runtime environment.</p>
|
|
61
|
+
<p>Here's how to use it:</p>
|
|
62
|
+
<ul style="text-align: left;">
|
|
63
|
+
<li><strong>File Explorer:</strong> Use the file explorer to create, open, and manage your project files. Start it by right clicking on the left container.</li>
|
|
64
|
+
<li><strong>Editor:</strong> Write your code in the editor pane. It supports multiple file types. To use it you should click on a file.</li>
|
|
65
|
+
<li><strong>View:</strong> After writing your code, click the "Run" button in the navbar to execute it. The output will be displayed in the view pane.</li>
|
|
66
|
+
<li><strong>Terminal:</strong> You can run terminal commands in the terminal pane.</li>
|
|
67
|
+
</ul>
|
|
68
|
+
<p>Available terminal commands:</p>
|
|
69
|
+
<ul style="text-align: left;">
|
|
70
|
+
<li><span style="font-weight: bold;">ls</span>: List directory contents</li>
|
|
71
|
+
<li><span style="font-weight: bold;">cd</span>: Change directory</li>
|
|
72
|
+
<li><span style="font-weight: bold;">clear</span>: Clear the terminal</li>
|
|
73
|
+
<li><span style="font-weight: bold;">pwd</span>: Print current directory</li>
|
|
74
|
+
<li><span style="font-weight: bold;">run</span>: Run a file (e.g., run script.js)</li>
|
|
75
|
+
<li><span style="font-weight: bold;">help | h</span>: Show help message</li>
|
|
76
|
+
</ul>
|
|
77
|
+
`,
|
|
78
|
+
width: 700,
|
|
79
|
+
confirmButtonText: "Got it!"
|
|
80
|
+
})
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
leftGroup.appendChild(li);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// ========== Append navbar ==========
|
|
88
|
+
|
|
89
|
+
document.getElementById(parentId).appendChild(navbar);
|
|
90
|
+
|
|
91
|
+
// ========== ActiveFile Name ==========
|
|
92
|
+
const activeFileName = document.createElement("li");
|
|
93
|
+
activeFileName.id = "runlab-navbar-active-file-name";
|
|
94
|
+
|
|
95
|
+
Object.assign(activeFileName.style, {
|
|
96
|
+
margin: "0 auto",
|
|
97
|
+
padding: "10px 14px",
|
|
98
|
+
fontWeight: "600",
|
|
99
|
+
color: "#FFDE21",
|
|
100
|
+
whiteSpace: "nowrap"
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
ul.appendChild(activeFileName);
|
|
104
|
+
// ========== Editor/View Toggle ==========
|
|
105
|
+
|
|
106
|
+
const toggleLi = document.createElement("li");
|
|
107
|
+
Object.assign(toggleLi.style, {
|
|
108
|
+
|
|
109
|
+
padding: "4px 10px"
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const toggle = document.createElement("div");
|
|
113
|
+
Object.assign(toggle.style, {
|
|
114
|
+
display: "grid",
|
|
115
|
+
gridTemplateColumns: "1fr 1fr",
|
|
116
|
+
width: "180px",
|
|
117
|
+
height: "28px",
|
|
118
|
+
border: "2px solid #09090b",
|
|
119
|
+
borderRadius: "8px",
|
|
120
|
+
overflow: "hidden",
|
|
121
|
+
background: "#e5e7eb",
|
|
122
|
+
fontFamily: "sans-serif",
|
|
123
|
+
marginLeft: "20px"
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const editorBtn = document.createElement("button");
|
|
127
|
+
editorBtn.id = "runlab-editor-btn";
|
|
128
|
+
editorBtn.textContent = "Editor";
|
|
129
|
+
editorBtn.classList.add("active");
|
|
130
|
+
|
|
131
|
+
const viewBtn = document.createElement("button");
|
|
132
|
+
viewBtn.id = "runlab-view-btn";
|
|
133
|
+
viewBtn.textContent = "View";
|
|
134
|
+
|
|
135
|
+
[editorBtn, viewBtn].forEach(btn => {
|
|
136
|
+
Object.assign(btn.style, {
|
|
137
|
+
border: "none",
|
|
138
|
+
cursor: "pointer",
|
|
139
|
+
fontWeight: "500",
|
|
140
|
+
transition: "0.2s",
|
|
141
|
+
color: "#000"
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
toggle.append(editorBtn, viewBtn);
|
|
146
|
+
toggleLi.appendChild(toggle);
|
|
147
|
+
ul.appendChild(toggleLi);
|
|
148
|
+
|
|
149
|
+
//Initialize with editor active
|
|
150
|
+
setViewActive(false);
|
|
151
|
+
|
|
152
|
+
editorBtn.onclick = () => setViewActive(false);
|
|
153
|
+
viewBtn.onclick = () => setViewActive(true);
|
|
154
|
+
}
|