Add interactive graph editor connections: port-based edges, drag-connect, and detach
- Add visible typed ports on graph nodes (colored dots for each edge type) - Route edges to specific port positions instead of node center - Drag from output port to compatible input port to create/change connections - Right-click edge context menu with Disconnect option - Delete key detaches selected edge - Mark nested edges (composite layers, zones) as non-editable with dotted style - Add resolve_ref helper for empty-string sentinel to clear reference fields - Apply resolve_ref across all storage stores for consistent detach support - Add connection mapping module (graph-connections.js) with API field resolution - Add i18n keys for connection operations (en/ru/zh) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -336,32 +336,40 @@
|
||||
/* ── Ports ── */
|
||||
|
||||
.graph-port {
|
||||
stroke: var(--bg-color);
|
||||
stroke-width: 2;
|
||||
opacity: 0.85;
|
||||
transition: r 0.15s, opacity 0.15s;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.graph-node:hover .graph-port {
|
||||
r: 5;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Port output cursor: draggable */
|
||||
.graph-port-out {
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.graph-port circle {
|
||||
fill: var(--bg-secondary);
|
||||
stroke: var(--text-muted);
|
||||
stroke-width: 1.5;
|
||||
r: 5;
|
||||
transition: fill 0.15s, stroke 0.15s, r 0.15s;
|
||||
/* Port interaction states during connection drag */
|
||||
.graph-port-compatible {
|
||||
r: 6 !important;
|
||||
opacity: 1 !important;
|
||||
cursor: pointer;
|
||||
filter: drop-shadow(0 0 3px currentColor);
|
||||
}
|
||||
|
||||
.graph-port:hover circle {
|
||||
fill: var(--primary-color);
|
||||
stroke: var(--primary-color);
|
||||
r: 6;
|
||||
.graph-port-incompatible {
|
||||
opacity: 0.15 !important;
|
||||
}
|
||||
|
||||
.graph-port.connected circle {
|
||||
fill: var(--text-secondary);
|
||||
stroke: var(--text-secondary);
|
||||
}
|
||||
|
||||
.graph-port-label {
|
||||
fill: var(--text-muted);
|
||||
font-size: 9px;
|
||||
font-family: 'DM Sans', sans-serif;
|
||||
.graph-port-drop-target {
|
||||
r: 7 !important;
|
||||
stroke: var(--primary-color) !important;
|
||||
stroke-width: 3 !important;
|
||||
filter: drop-shadow(0 0 6px var(--primary-color));
|
||||
}
|
||||
|
||||
/* ── Edges ── */
|
||||
@@ -398,6 +406,12 @@
|
||||
opacity: 0.12;
|
||||
}
|
||||
|
||||
/* Nested edges (composite layers, zones) — not drag-editable */
|
||||
.graph-edge-nested {
|
||||
stroke-dasharray: 2 2;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
/* Edge type colors */
|
||||
.graph-edge-picture { stroke: #42A5F5; color: #42A5F5; }
|
||||
.graph-edge-colorstrip { stroke: #66BB6A; color: #66BB6A; }
|
||||
@@ -433,6 +447,47 @@
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* ── Edge context menu ── */
|
||||
|
||||
.graph-edge-menu {
|
||||
position: absolute;
|
||||
z-index: 40;
|
||||
background: var(--card-bg);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 16px var(--shadow-color);
|
||||
padding: 4px;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.graph-edge-menu-item {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--text-color);
|
||||
font-size: 0.85rem;
|
||||
font-family: inherit;
|
||||
text-align: left;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: background 0.1s;
|
||||
}
|
||||
|
||||
.graph-edge-menu-item:hover {
|
||||
background: var(--bg-secondary);
|
||||
}
|
||||
|
||||
.graph-edge-menu-item.danger {
|
||||
color: var(--danger-color);
|
||||
}
|
||||
|
||||
.graph-edge-menu-item.danger:hover {
|
||||
background: var(--danger-color);
|
||||
color: var(--primary-contrast);
|
||||
}
|
||||
|
||||
/* ── Hover overlay (action buttons) ── */
|
||||
|
||||
.graph-node-overlay {
|
||||
|
||||
Reference in New Issue
Block a user