fix command page buttons

This commit is contained in:
Franz Rolfsvaag 2026-06-17 21:32:24 +02:00
parent 4c1c23bd27
commit 0cf7408225
5 changed files with 113 additions and 86 deletions

View File

@ -125,6 +125,7 @@ This file tracks larger Lumi work that cannot safely be completed in one pass. K
## Done ## Done
- 2026-06-17: Fixed custom command Edit buttons and `/commands` Copy Link / expand buttons with delegated handlers, clipboard fallback, and v0.1.5 patch bump.
- 2026-06-17: Fixed repo-based core updates deleting `data/update-cache/repo` during apply, added a verification guard, and bumped core package version to v0.1.4. - 2026-06-17: Fixed repo-based core updates deleting `data/update-cache/repo` during apply, added a verification guard, and bumped core package version to v0.1.4.
- 2026-06-17: Bumped core package version to v0.1.3. - 2026-06-17: Bumped core package version to v0.1.3.
- 2026-06-17: Completed homepage hero embed pass for Discord widgets, YouTube video playback options, external embed fallback/sandbox controls, admin validation, platform-specific fields, and Test preview behavior. - 2026-06-17: Completed homepage hero embed pass for Discord widgets, YouTube video playback options, external embed fallback/sandbox controls, admin validation, platform-specific fields, and Test preview behavior.

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "lumi-bot", "name": "lumi-bot",
"version": "0.1.4", "version": "0.1.5",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "lumi-bot", "name": "lumi-bot",
"version": "0.1.4", "version": "0.1.5",
"dependencies": { "dependencies": {
"adm-zip": "^0.5.12", "adm-zip": "^0.5.12",
"better-sqlite3": "^11.5.0", "better-sqlite3": "^11.5.0",

View File

@ -1,6 +1,6 @@
{ {
"name": "lumi-bot", "name": "lumi-bot",
"version": "0.1.4", "version": "0.1.5",
"private": true, "private": true,
"type": "commonjs", "type": "commonjs",
"scripts": { "scripts": {

View File

@ -57,35 +57,36 @@
} }
}); });
const editToggles = Array.from( const selectorEscape = (value) => {
document.querySelectorAll("[data-edit-toggle]") if (window.CSS?.escape) return CSS.escape(value);
); return String(value || "").replace(/["\\]/g, "\\$&");
if (editToggles.length) { };
const editRows = Array.from(document.querySelectorAll("[data-edit-row]"));
const updateToggleStates = () => { const updateEditToggleStates = () => {
editToggles.forEach((button) => { document.querySelectorAll("[data-edit-toggle]").forEach((button) => {
const key = button.dataset.editToggle; const key = button.dataset.editToggle;
const row = editRows.find((item) => item.dataset.editRow === key); const row = key ? document.querySelector(`[data-edit-row="${selectorEscape(key)}"]`) : null;
const isOpen = row?.classList.contains("is-open"); const isOpen = row?.classList.contains("is-open");
button.setAttribute("aria-expanded", isOpen ? "true" : "false"); button.setAttribute("aria-expanded", isOpen ? "true" : "false");
}); });
}; };
editToggles.forEach((button) => { document.addEventListener("click", (event) => {
button.addEventListener("click", () => { const button = event.target.closest("[data-edit-toggle]");
if (!button) return;
event.preventDefault();
const key = button.dataset.editToggle; const key = button.dataset.editToggle;
const target = editRows.find((item) => item.dataset.editRow === key); const target = key ? document.querySelector(`[data-edit-row="${selectorEscape(key)}"]`) : null;
const willOpen = target ? !target.classList.contains("is-open") : false; const willOpen = target ? !target.classList.contains("is-open") : false;
editRows.forEach((row) => { document.querySelectorAll("[data-edit-row].is-open").forEach((row) => {
row.classList.remove("is-open"); row.classList.remove("is-open");
}); });
if (target && willOpen) { if (target && willOpen) {
target.classList.add("is-open"); target.classList.add("is-open");
} }
updateToggleStates(); updateEditToggleStates();
}); });
}); updateEditToggleStates();
}
document.querySelectorAll("[data-table]").forEach((table) => { document.querySelectorAll("[data-table]").forEach((table) => {
const tbody = table.tBodies[0]; const tbody = table.tBodies[0];
@ -198,8 +199,11 @@
setGroupExpanded(group, false); setGroupExpanded(group, false);
}); });
tbody.querySelectorAll("[data-command-toggle]").forEach((button) => { tbody.addEventListener("click", (event) => {
button.addEventListener("click", (event) => { const button = event.target.closest("[data-command-toggle]");
if (!button || !tbody.contains(button)) {
return;
}
event.preventDefault(); event.preventDefault();
const rootRow = button.closest("tr"); const rootRow = button.closest("tr");
if (!rootRow) { if (!rootRow) {
@ -213,7 +217,6 @@
const expanded = rootRow.dataset.expanded === "true"; const expanded = rootRow.dataset.expanded === "true";
setGroupExpanded(group, !expanded); setGroupExpanded(group, !expanded);
}); });
});
revealAnchorRow(); revealAnchorRow();
window.addEventListener("hashchange", () => { window.addEventListener("hashchange", () => {
@ -864,8 +867,31 @@
}); });
} }
document.querySelectorAll("[data-copy]").forEach((button) => { const copyText = async (text) => {
button.addEventListener("click", async () => { if (navigator.clipboard?.writeText && window.isSecureContext) {
await navigator.clipboard.writeText(text);
return true;
}
const tempInput = document.createElement("textarea");
tempInput.value = text;
tempInput.setAttribute("readonly", "");
tempInput.style.position = "fixed";
tempInput.style.left = "-9999px";
tempInput.style.top = "0";
document.body.appendChild(tempInput);
tempInput.focus();
tempInput.select();
try {
return document.execCommand("copy");
} finally {
tempInput.remove();
}
};
document.addEventListener("click", async (event) => {
const button = event.target.closest("[data-copy]");
if (!button) return;
event.preventDefault();
const text = button.getAttribute("data-copy") || ""; const text = button.getAttribute("data-copy") || "";
if (!text) { if (!text) {
return; return;
@ -873,41 +899,24 @@
const label = button.querySelector("[data-copy-label]"); const label = button.querySelector("[data-copy-label]");
const originalLabel = label ? label.textContent : ""; const originalLabel = label ? label.textContent : "";
const markCopied = () => { const markCopyResult = (copied) => {
button.classList.add("copied"); button.classList.toggle("copied", copied);
button.classList.toggle("copy-failed", !copied);
if (label) { if (label) {
label.textContent = "Copied"; label.textContent = copied ? "Copied" : "Copy failed";
} }
window.setTimeout(() => { window.setTimeout(() => {
button.classList.remove("copied"); button.classList.remove("copied", "copy-failed");
if (label) { if (label) {
label.textContent = originalLabel; label.textContent = originalLabel;
} }
}, 1200); }, copied ? 1200 : 1800);
}; };
try { try {
if (navigator.clipboard && navigator.clipboard.writeText) { markCopyResult(await copyText(text));
await navigator.clipboard.writeText(text);
markCopied();
return;
}
} catch { } catch {
// Fall back to legacy copy. markCopyResult(false);
} }
const tempInput = document.createElement("input");
tempInput.value = text;
document.body.appendChild(tempInput);
tempInput.select();
try {
document.execCommand("copy");
markCopied();
} catch {
// Ignore copy errors.
} finally {
tempInput.remove();
}
});
}); });
})(); })();

View File

@ -777,6 +777,23 @@ body {
border-radius: 999px; border-radius: 999px;
} }
.copy-pill.copy-failed {
border-color: var(--danger);
}
.copy-pill.copy-failed::after {
content: "Copy failed";
position: absolute;
top: -10px;
right: -6px;
background: var(--danger);
color: white;
font-size: 0.65rem;
padding: 2px 6px;
border-radius: 999px;
white-space: nowrap;
}
.copy-link { .copy-link {
min-width: 96px; min-width: 96px;
justify-content: center; justify-content: center;