feat(rflows): fix text-click drag, smart source labels, Pay by buttons
- Prevent foreignObject HTML clicks from starting node drag (select + inline edit instead)
- New source nodes get personalized "{username}'s stream to {flowName}" label
- Replace source type <select> dropdowns with clickable "Pay by" button grid
in ICP panel, editor panel, and source modal
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
a28eb88140
commit
f24fee942b
|
|
@ -576,6 +576,30 @@
|
|||
.source-type-btn:hover { border-color: var(--rs-bg-surface-raised); background: var(--rs-bg-surface); }
|
||||
.source-type-btn--active { border-color: #10b981; background: var(--rflows-source-hover-bg, #064e3b); color: var(--rflows-source-text, #6ee7b7); }
|
||||
|
||||
/* Pay-by button grid (ICP - compact) */
|
||||
.icp-pay-by { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; margin-top: 4px; }
|
||||
.icp-pay-btn {
|
||||
display: flex; align-items: center; justify-content: center; gap: 4px;
|
||||
padding: 6px 4px; border-radius: 6px; border: 1.5px solid var(--rs-border-strong);
|
||||
background: var(--rs-bg-page); color: var(--rs-text-secondary); cursor: pointer;
|
||||
transition: all 0.15s; font-size: 10px; font-weight: 500;
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
}
|
||||
.icp-pay-btn:hover { border-color: var(--rs-bg-surface-raised); background: var(--rs-bg-surface); }
|
||||
.icp-pay-btn--active { border-color: #10b981; background: var(--rflows-source-hover-bg, #064e3b); color: var(--rflows-source-text, #6ee7b7); }
|
||||
|
||||
/* Pay-by button grid (editor panel - larger) */
|
||||
.editor-pay-by { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; margin-top: 4px; }
|
||||
.editor-pay-btn {
|
||||
display: flex; flex-direction: column; align-items: center; gap: 4px;
|
||||
padding: 10px 6px; border-radius: 8px; border: 2px solid var(--rs-border-strong);
|
||||
background: var(--rs-bg-page); color: var(--rs-text-secondary); cursor: pointer;
|
||||
transition: all 0.15s; font-size: 11px; font-weight: 500;
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
}
|
||||
.editor-pay-btn:hover { border-color: var(--rs-bg-surface-raised); background: var(--rs-bg-surface); }
|
||||
.editor-pay-btn--active { border-color: #10b981; background: var(--rflows-source-hover-bg, #064e3b); color: var(--rflows-source-text, #6ee7b7); }
|
||||
|
||||
/* Node hover tooltip */
|
||||
.flows-node-tooltip {
|
||||
position: absolute; z-index: 30; pointer-events: none;
|
||||
|
|
|
|||
|
|
@ -1343,6 +1343,13 @@ class FolkFlowsApp extends HTMLElement {
|
|||
this.selectedEdgeKey = null;
|
||||
this.updateSelectionHighlight();
|
||||
|
||||
// If click originated from HTML inside foreignObject, open inline edit but skip drag
|
||||
const target = e.target as Element;
|
||||
if (target instanceof HTMLElement && target.closest("foreignObject")) {
|
||||
this.enterInlineEdit(nodeId);
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare drag (but don't start until threshold exceeded)
|
||||
nodeDragStarted = false;
|
||||
this.draggingNodeId = nodeId;
|
||||
|
|
@ -2769,10 +2776,12 @@ class FolkFlowsApp extends HTMLElement {
|
|||
<input class="icp-input" data-icp-field="label" value="${this.esc(d.label)}"/></div>
|
||||
<div class="icp-field"><label class="icp-label">Flow Rate ($/mo)</label>
|
||||
<input class="icp-input" data-icp-field="flowRate" type="number" value="${d.flowRate}"/></div>
|
||||
<div class="icp-field"><label class="icp-label">Source Type</label>
|
||||
<select class="icp-select" data-icp-field="sourceType">
|
||||
${["card", "safe_wallet", "ridentity", "unconfigured"].map((t) => `<option value="${t}" ${d.sourceType === t ? "selected" : ""}>${t}</option>`).join("")}
|
||||
</select></div>`;
|
||||
<div class="icp-field"><label class="icp-label">Pay by</label>
|
||||
<div class="icp-pay-by">
|
||||
<button class="icp-pay-btn ${d.sourceType === "card" ? "icp-pay-btn--active" : ""}" data-icp-source-type="card">💳 Card</button>
|
||||
<button class="icp-pay-btn ${d.sourceType === "safe_wallet" ? "icp-pay-btn--active" : ""}" data-icp-source-type="safe_wallet">🔒 Wallet</button>
|
||||
<button class="icp-pay-btn ${d.sourceType === "ridentity" ? "icp-pay-btn--active" : ""}" data-icp-source-type="ridentity">👤 EncryptID</button>
|
||||
</div></div>`;
|
||||
if (d.sourceType === "card") {
|
||||
html += `<button class="icp-fund-btn" data-icp-action="fund">Fund with Card</button>`;
|
||||
}
|
||||
|
|
@ -3124,6 +3133,19 @@ class FolkFlowsApp extends HTMLElement {
|
|||
});
|
||||
});
|
||||
|
||||
// Pay-by buttons (source nodes)
|
||||
overlay.querySelectorAll("[data-icp-source-type]").forEach((btn) => {
|
||||
btn.addEventListener("click", (e: Event) => {
|
||||
e.stopPropagation();
|
||||
(node.data as SourceNodeData).sourceType = (btn as HTMLElement).dataset.icpSourceType as any;
|
||||
const body = overlay.querySelector(".icp-body") as HTMLElement;
|
||||
if (body) body.innerHTML = this.renderInlineConfigContent(node);
|
||||
this.attachInlineConfigFieldListeners(overlay, node);
|
||||
this.redrawNodeOnly(node);
|
||||
this.redrawEdges();
|
||||
});
|
||||
});
|
||||
|
||||
// Range sliders
|
||||
overlay.querySelectorAll("[data-icp-range]").forEach((el) => {
|
||||
const input = el as HTMLInputElement;
|
||||
|
|
@ -3326,10 +3348,12 @@ class FolkFlowsApp extends HTMLElement {
|
|||
<input class="editor-input" data-field="label" value="${this.esc(d.label)}"/></div>
|
||||
<div class="editor-field"><label class="editor-label">Flow Rate ($/mo)</label>
|
||||
<input class="editor-input" data-field="flowRate" type="number" value="${d.flowRate}"/></div>
|
||||
<div class="editor-field"><label class="editor-label">Source Type</label>
|
||||
<select class="editor-select" data-field="sourceType">
|
||||
${["card", "safe_wallet", "ridentity", "unconfigured"].map((t) => `<option value="${t}" ${d.sourceType === t ? "selected" : ""}>${t}</option>`).join("")}
|
||||
</select></div>`;
|
||||
<div class="editor-field"><label class="editor-label">Pay by</label>
|
||||
<div class="editor-pay-by">
|
||||
<button class="editor-pay-btn ${d.sourceType === "card" ? "editor-pay-btn--active" : ""}" data-editor-source-type="card">💳<span>Card</span></button>
|
||||
<button class="editor-pay-btn ${d.sourceType === "safe_wallet" ? "editor-pay-btn--active" : ""}" data-editor-source-type="safe_wallet">🔒<span>Wallet</span></button>
|
||||
<button class="editor-pay-btn ${d.sourceType === "ridentity" ? "editor-pay-btn--active" : ""}" data-editor-source-type="ridentity">👤<span>EncryptID</span></button>
|
||||
</div></div>`;
|
||||
if (d.sourceType === "card") {
|
||||
html += `<div class="editor-field" style="margin-top:12px">
|
||||
<button class="editor-btn fund-card-btn" data-action="fund-with-card"
|
||||
|
|
@ -3765,6 +3789,16 @@ class FolkFlowsApp extends HTMLElement {
|
|||
this.openUserOnRamp(node.id);
|
||||
}
|
||||
});
|
||||
|
||||
// Pay-by buttons (source editor)
|
||||
panel.querySelectorAll("[data-editor-source-type]").forEach((btn) => {
|
||||
btn.addEventListener("click", () => {
|
||||
(node.data as SourceNodeData).sourceType = (btn as HTMLElement).dataset.editorSourceType as any;
|
||||
this.drawCanvasContent();
|
||||
this.scheduleSave();
|
||||
this.openEditor(node.id);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ─── Node hover tooltip ──────────────────────────────
|
||||
|
|
@ -4051,7 +4085,7 @@ class FolkFlowsApp extends HTMLElement {
|
|||
<button class="flows-modal__close" data-modal-action="close">×</button>
|
||||
</div>
|
||||
<div style="margin-bottom:16px">
|
||||
<div style="font-size:11px;font-weight:600;color:var(--rs-text-secondary);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:8px">Source Type</div>
|
||||
<div style="font-size:11px;font-weight:600;color:var(--rs-text-secondary);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:8px">Pay by</div>
|
||||
<div class="source-type-grid">
|
||||
${["card", "safe_wallet", "ridentity"].map((t) => `
|
||||
<button class="source-type-btn ${d.sourceType === t ? "source-type-btn--active" : ""}" data-source-type="${t}">
|
||||
|
|
@ -4152,7 +4186,11 @@ class FolkFlowsApp extends HTMLElement {
|
|||
const id = `${type}-${Date.now().toString(36)}`;
|
||||
let data: any;
|
||||
if (type === "source") {
|
||||
data = { label: "New Source", flowRate: 1000, sourceType: "card", targetAllocations: [] } as SourceNodeData;
|
||||
const username = getUsername();
|
||||
const defaultLabel = username
|
||||
? `${username}'s stream to ${this.flowName || "Flow"}`
|
||||
: `Stream to ${this.flowName || "Flow"}`;
|
||||
data = { label: defaultLabel, flowRate: 1000, sourceType: "card", targetAllocations: [] } as SourceNodeData;
|
||||
} else if (type === "funnel") {
|
||||
data = {
|
||||
label: "New Funnel", currentValue: 0, desiredOutflow: 5000,
|
||||
|
|
|
|||
Loading…
Reference in New Issue