Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 39 additions & 11 deletions packages/struktolab/src/editor/struktolab-editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = `
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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());
Expand All @@ -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);
Expand All @@ -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();
Expand Down
8 changes: 7 additions & 1 deletion platforms/web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -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); }

Expand Down Expand Up @@ -109,7 +112,10 @@
<img src="/logo.svg" alt="StruktoLab Logo" width="32" height="32" />
<h1>Strukto<span>Lab</span></h1>
<div class="spacer"></div>
<button id="share-btn" title="Copy shareable URL to clipboard">πŸ”— Share</button>
<button id="share-btn" title="Copy shareable URL to clipboard">
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 14a4.5 4.5 0 0 0 6.4 0l3-3a4.5 4.5 0 0 0-6.4-6.4l-1 1M14 10a4.5 4.5 0 0 0-6.4 0l-3 3a4.5 4.5 0 0 0 6.4 6.4l1-1"/></svg>
<span id="share-label">Share</span>
</button>
</header>

<div class="container">
Expand Down
8 changes: 4 additions & 4 deletions platforms/web/src/app/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
});

Expand Down
Loading