fix command page buttons
This commit is contained in:
parent
4c1c23bd27
commit
0cf7408225
1
TODO.md
1
TODO.md
@ -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
4
package-lock.json
generated
@ -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",
|
||||||
|
|||||||
@ -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": {
|
||||||
|
|||||||
@ -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();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user