feat: remove code output footer, move actions to top bar, download .ll

- Remove global-toolbar (footer with code display) entirely
- Move Generate, Save, Load, New, Tests buttons to algorithm pane toolbar
- Replace prog.generateCode() with prog.generateAndDownload() — creates
  a Blob from the IR and triggers a program.ll download via a temp <a>
- Remove copyCode function from helpers.js (no longer needed)
- Remove global-toolbar and .code-output CSS rules
- Add .action-btn styling for the text buttons in pane-toolbar
This commit is contained in:
2026-06-23 20:40:42 +02:00
parent d53f92482d
commit d760c272f2
5 changed files with 38 additions and 73 deletions
+8 -19
View File
@@ -230,9 +230,17 @@ function setupUI() {
const btn = e.target.closest("button");
if (!btn) return;
if (handleBlockAction(btn)) return;
const prog = $id("main-program");
if (btn.dataset.action === "add-section" && typeof enterSectionCreateMode === "function") {
enterSectionCreateMode();
}
if (btn.dataset.action === "generate") prog.generateAndDownload();
if (btn.dataset.action === "save") saveWorkspace();
if (btn.dataset.action === "load") loadWorkspace();
if (btn.dataset.action === "new") newWorkspace();
if (btn.dataset.action === "run-tests") {
if (window.APP_TEST_SUITE) APP_TEST_SUITE.run();
}
});
}
@@ -340,25 +348,6 @@ function setupUI() {
});
}
/* Global toolbar */
const globalToolbar = document.querySelector(".global-toolbar");
if (globalToolbar) {
globalToolbar.addEventListener("click", e => {
const btn = e.target.closest("button");
if (!btn) return;
const prog = $id("main-program");
if (!prog) { showError("Main program element not found"); return; }
if (btn.dataset.action === "generate") prog.generateCode();
if (btn.dataset.action === "save") saveWorkspace();
if (btn.dataset.action === "load") loadWorkspace();
if (btn.dataset.action === "new") newWorkspace();
if (btn.dataset.action === "copy-code") copyCode();
if (btn.dataset.action === "run-tests") {
if (window.APP_TEST_SUITE) APP_TEST_SUITE.run();
}
});
}
/* Tab bar */
const tabBar = document.querySelector(".tab-bar");
if (tabBar) {
-5
View File
@@ -232,11 +232,6 @@ function findDataSource(hook) {
}
/** Copies the generated C code text to the clipboard. */
function copyCode() {
const el = $id("ir-code");
if (el && el.textContent) navigator.clipboard.writeText(el.textContent).catch(() => {});
}
/**
* Escapes special characters for embedding in a C string literal.
* Handles backslash, double-quote, newline, carriage return, and tab.
+7 -12
View File
@@ -374,6 +374,12 @@
<button data-action="add-section" title="draw a logic section">
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" stroke="currentColor" stroke-width="2"><line x1="9" y1="3" x2="9" y2="15"/><line x1="3" y1="9" x2="15" y2="9"/></svg>
</button>
<span class="toolbar-sep"></span>
<button data-action="generate" class="action-btn">Generate</button>
<button data-action="save" class="action-btn">Save</button>
<button data-action="load" class="action-btn">Load</button>
<button data-action="new" class="action-btn">New</button>
<button data-action="run-tests" class="action-btn">Tests</button>
</div>
<div id="draw-area">
<svg id="connections" xmlns="http://www.w3.org/2000/svg">
@@ -438,18 +444,7 @@
</div>
</div>
<!-- Bottom toolbar: code generation button and highlighted output. -->
<div class="global-toolbar">
<button data-action="generate">Generate code</button>
<button data-action="save">Save</button>
<button data-action="load">Load</button>
<button data-action="new">New</button>
<button data-action="copy-code">Copy</button>
<button data-action="run-tests">Tests</button>
<div class="code-output" id="ir-code-container">
<pre><code id="ir-code"></code></pre>
</div>
</div>
<!-- Empty placeholder removed; actions moved to algorithm pane toolbar. -->
<div id="error-overlay" class="error-overlay">
<div class="error-box">
<span class="error-close">&times;</span>
+7 -25
View File
@@ -46,6 +46,12 @@ h1 {
flex-shrink: 0; flex-wrap: wrap;
background: var(--surface); border-bottom: 1px solid var(--border);
}
.pane-toolbar button.action-btn {
padding: 0.3rem 0.6rem; font-size: 0.78rem; font-weight: 500;
background: var(--accent); color: #fff; border: 1px solid var(--accent);
line-height: 1.2;
}
.pane-toolbar button.action-btn:hover { background: #357abd; border-color: #357abd; }
.pane-toolbar button {
padding: 0.3rem; font: inherit; font-size: 0.75rem; cursor: pointer;
background: var(--bg); color: var(--text); border: 1px solid var(--border);
@@ -463,31 +469,7 @@ wc-assign #hook-next[data-direction="out"] {
flex-direction: column;
}
.global-toolbar {
display: flex; gap: 0.25rem; padding: 0.3rem;
align-items: flex-start; flex-shrink: 0;
border-top: 1px solid var(--border); background: var(--surface);
}
.global-toolbar button {
padding: 0.4rem 0.8rem; font: inherit; font-size: 0.8rem; cursor: pointer;
background: var(--accent); color: #fff; border: none; border-radius: 3px;
}
.global-toolbar button:hover { background: #357abd; }
.global-toolbar .code-output {
flex: 1; min-height: 80px; max-height: 50vh; overflow: auto; resize: vertical;
background: var(--bg); border: 1px solid var(--border);
font-family: 'Courier New', monospace; font-size: 0.8rem; line-height: 1.5;
padding: 0.3rem; position: relative;
}
.global-toolbar .code-output pre {
margin: 0; white-space: pre; tab-size: 4;
}
.global-toolbar .code-output code {
display: block;
}
.global-toolbar .code-output code.hljs {
background: transparent; padding: 0;
}
[data-block] {
+16 -12
View File
@@ -208,12 +208,8 @@ class WCProgram extends HTMLElement {
return lines.join("\n");
}
generateCode() {
const outputEl = $id("ir-code");
if (!outputEl) { showError("Missing #ir-code output element"); return; }
_generateIR() {
const { usedQuantities, usedUnits } = this._gatherUsedTypes();
const typeDefs = this._generateTypeDefs(usedQuantities);
const unitDefs = this._generateUnitDefs(usedUnits);
const { boolDefs, scalarDefs, vectorDefs, stringDefs, arrayDefs } = this._generateVariableDeclarations();
@@ -225,24 +221,32 @@ class WCProgram extends HTMLElement {
? CodeGen.emitFlat(firstChild)
: "; no flowchart body\n";
// Collect external function declarations from used libraries
const proccalls = this.querySelectorAll("wc-proccall");
const decls = this._generateLLVMDecls(proccalls);
// Collect string globals
const strPool = CodeGen.getStringPool();
const globals = strPool.map(function (_, i) { return CodeGen.stringGlobal(i); }).join("\n");
// Variable declarations -> alloca instructions in the prologue
const dataSection = (boolDefs || scalarDefs || vectorDefs || stringDefs || arrayDefs)
? [boolDefs, scalarDefs, vectorDefs, stringDefs, arrayDefs]
.filter(Boolean).map(function (s) { return s + "\n"; }).join("")
: "";
const raw = CodeGen.generateIRFile(firstChild, decls, globals, dataSection);
outputEl.textContent = raw;
if (typeof hljs !== "undefined") hljs.highlightElement(outputEl);
outputEl.parentElement.dataset.language = "llvm";
return CodeGen.generateIRFile(firstChild, decls, globals, dataSection);
}
generateAndDownload() {
const ir = this._generateIR();
if (!ir) { showError("No IR to download"); return; }
const blob = new Blob([ir], { type: "text/plain" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "program.ll";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
}