From dd56bf3153c8e00acb41b638783606d6fc051640 Mon Sep 17 00:00:00 2001 From: "matti.bat" <138713607+mattibat@users.noreply.github.com> Date: Thu, 29 Oct 2026 15:27:35 +0100 Subject: [PATCH] Draw the toolbar icons as SVG instead of emoji --- .../src/editor/struktolab-editor.js | 50 +++++++++++++++---- platforms/web/index.html | 8 ++- platforms/web/src/app/main.js | 8 +-- 3 files changed, 50 insertions(+), 16 deletions(-) diff --git a/packages/struktolab/src/editor/struktolab-editor.js b/packages/struktolab/src/editor/struktolab-editor.js index e807bec..cb8801f 100644 --- a/packages/struktolab/src/editor/struktolab-editor.js +++ b/packages/struktolab/src/editor/struktolab-editor.js @@ -166,6 +166,34 @@ const TOOLBAR_ITEMS = [ { type: "TryCatchNode", label: "Try/Catch", icon: "⚡" }, ]; +/** Emoji look different on every system and are missing on some, so the toolbar draws its own. */ +const ICON_PATHS = { + undo: "M9 15 4 10l5-5M4 10h11a5 5 0 0 1 0 10h-3", + redo: "M15 15l5-5-5-5M20 10H9a5 5 0 0 0 0 10h3", + view: "M4 6h9M17 6h3M15 4v4M4 12h3M11 12h9M9 10v4M4 18h11M19 18h1M17 16v4", + save: "M5 3h11l5 5v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2zM7 3v5h8V3M7 21v-7h10v7", + load: "M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z", + png: "M5 3h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2zM21 15l-5-5L5 21M7.5 9a1.5 1.5 0 1 0 3 0a1.5 1.5 0 1 0-3 0", + svg: "M4 17C6 9 18 9 20 17M2.5 17h3v3h-3zM18.5 17h3v3h-3zM6 6h12M10.5 4.5h3v3h-3z", +}; + +function icon(name) { + const svgNS = "http://www.w3.org/2000/svg"; + const svg = document.createElementNS(svgNS, "svg"); + svg.setAttribute("viewBox", "0 0 24 24"); + svg.setAttribute("width", "16"); + svg.setAttribute("height", "16"); + svg.setAttribute("fill", "none"); + svg.setAttribute("stroke", "currentColor"); + svg.setAttribute("stroke-width", "2"); + svg.setAttribute("stroke-linecap", "round"); + svg.setAttribute("stroke-linejoin", "round"); + const path = document.createElementNS(svgNS, "path"); + path.setAttribute("d", ICON_PATHS[name]); + svg.appendChild(path); + return svg; +} + /* ── CSS ───────────────────────────────────────────────────── */ const STYLES = ` @@ -223,9 +251,9 @@ button { } /* Every icon gets the same box. - Left to itself each glyph contributes its own line box — ⚙ is 16px tall, 💾 - 17, ↶ 20, 🖼 22 — so the buttons came out five different heights, with PNG - the odd one out. A fixed box means the glyph no longer sets the height. */ + Left to itself each glyph of the insert menu contributes its own line box, + so the buttons came out different heights. A fixed box means the glyph no + longer sets the height. */ button .icon { flex: none; display: inline-flex; @@ -739,7 +767,7 @@ class StruktolabEditor extends HTMLElement { const iconEl = document.createElement("span"); iconEl.className = "icon"; iconEl.setAttribute("aria-hidden", "true"); - iconEl.textContent = icon; + iconEl.append(icon); const labelEl = document.createElement("span"); labelEl.className = "label"; labelEl.textContent = label; @@ -768,15 +796,15 @@ class StruktolabEditor extends HTMLElement { _buildToolbar() { /* History */ const history = this._group("history"); - this._undoBtn = this._button("↶", this._t("undo"), this._t("undoTitle"), () => this.undo()); - this._redoBtn = this._button("↷", this._t("redo"), this._t("redoTitle"), () => this.redo()); + this._undoBtn = this._button(icon("undo"), this._t("undo"), this._t("undoTitle"), () => this.undo()); + this._redoBtn = this._button(icon("redo"), this._t("redo"), this._t("redoTitle"), () => this.redo()); history.append(this._undoBtn, this._redoBtn); this._historyGroup = history; this._historySep = this._separator(); /* View settings, behind one button */ const view = this._group("view"); - const viewBtn = this._button("⚙", this._t("view"), this._t("viewTitle")); + const viewBtn = this._button(icon("view"), this._t("view"), this._t("viewTitle")); viewBtn.setAttribute("aria-haspopup", "true"); viewBtn.setAttribute("aria-expanded", "false"); viewBtn.addEventListener("click", () => this._toggleViewPopover()); @@ -788,10 +816,10 @@ class StruktolabEditor extends HTMLElement { /* Files and export */ const file = this._group("file"); - this._saveBtn = this._button("💾", this._t("save"), this._t("saveTitle"), () => + this._saveBtn = this._button(icon("save"), this._t("save"), this._t("saveTitle"), () => this._downloadJSON(), ); - this._loadBtn = this._button("📂", this._t("load"), this._t("loadTitle"), () => + this._loadBtn = this._button(icon("load"), this._t("load"), this._t("loadTitle"), () => this._triggerLoadJSON(), ); file.append(this._saveBtn, this._loadBtn); @@ -804,8 +832,8 @@ class StruktolabEditor extends HTMLElement { file.appendChild(this._fileInput); file.append( - this._button("🖼", "PNG", this._t("pngTitle"), () => this._downloadImage("png")), - this._button("📐", "SVG", this._t("svgTitle"), () => this._downloadImage("svg")), + this._button(icon("png"), "PNG", this._t("pngTitle"), () => this._downloadImage("png")), + this._button(icon("svg"), "SVG", this._t("svgTitle"), () => this._downloadImage("svg")), ); this._updateHistoryButtons(); diff --git a/platforms/web/index.html b/platforms/web/index.html index be62395..aa63980 100644 --- a/platforms/web/index.html +++ b/platforms/web/index.html @@ -39,6 +39,9 @@ cursor: pointer; font-size: 13px; font-family: inherit; + display: inline-flex; + align-items: center; + gap: 6px; } header button:hover { background: rgba(255,255,255,0.2); } @@ -109,7 +112,10 @@ StruktoLab Logo

StruktoLab

- +
diff --git a/platforms/web/src/app/main.js b/platforms/web/src/app/main.js index e802a03..40ca40d 100644 --- a/platforms/web/src/app/main.js +++ b/platforms/web/src/app/main.js @@ -40,10 +40,10 @@ document.getElementById("share-btn").addEventListener("click", () => { if (!hash) return; const url = window.location.origin + window.location.pathname + "#" + hash; navigator.clipboard.writeText(url).then(() => { - const btn = document.getElementById("share-btn"); - const orig = btn.textContent; - btn.textContent = "✓ Copied!"; - setTimeout(() => { btn.textContent = orig; }, 2000); + const label = document.getElementById("share-label"); + const orig = label.textContent; + label.textContent = "✓ Copied!"; + setTimeout(() => { label.textContent = orig; }, 2000); }); });