ui: align node sockets and widen resource cards
This commit is contained in:
parent
97b174ac6e
commit
67d6bc6b71
|
|
@ -2,16 +2,28 @@
|
|||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
// Attribution term under AGPL-3.0 section 7(b): see LICENSE-ADDENDUM.
|
||||
|
||||
import { ChangeDetectionStrategy, Component, HostBinding, Input } from "@angular/core";
|
||||
import {
|
||||
AfterViewInit,
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
ElementRef,
|
||||
HostBinding,
|
||||
inject,
|
||||
Input,
|
||||
OnDestroy
|
||||
} from "@angular/core";
|
||||
|
||||
@Component({
|
||||
template: ``,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class CustomSocket {
|
||||
export class CustomSocket implements AfterViewInit, OnDestroy {
|
||||
@Input() data!: any;
|
||||
@Input() emit!: any;
|
||||
@Input() rendered!: any;
|
||||
private readonly element = inject<ElementRef<HTMLElement>>(ElementRef);
|
||||
private resizeObserver: ResizeObserver | null = null;
|
||||
private renderFrame: number | null = null;
|
||||
private side: "input" | "output" = "input";
|
||||
private kind: "data" | "dependency" | "resource" = "data";
|
||||
|
||||
|
|
@ -19,10 +31,18 @@ export class CustomSocket {
|
|||
return this.data.name;
|
||||
}
|
||||
|
||||
@HostBinding("style.width") w = "15px";
|
||||
@HostBinding("style.height") h = "15px";
|
||||
@HostBinding("style.width")
|
||||
get width() {
|
||||
return this.kind === "resource" ? "9px" : "8px";
|
||||
}
|
||||
|
||||
@HostBinding("style.height")
|
||||
get height() {
|
||||
return this.kind === "resource" ? "100%" : "26px";
|
||||
}
|
||||
|
||||
@HostBinding("style.display") d = "block";
|
||||
@HostBinding("style.borderRadius") br = "4px";
|
||||
@HostBinding("style.borderRadius") br = "999px";
|
||||
@HostBinding("style.border") border = "1px solid rgba(255,255,255,0.9)";
|
||||
@HostBinding("style.cursor") get cursor() {
|
||||
return this.data?.__readonly === true ? "default" : "crosshair";
|
||||
|
|
@ -73,6 +93,29 @@ export class CustomSocket {
|
|||
ngOnChanges(): void {
|
||||
this.side = this.resolveSocketSide();
|
||||
this.kind = this.resolveSocketKind();
|
||||
requestAnimationFrame(() => this.rendered());
|
||||
this.schedulePositionRefresh();
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
if (typeof ResizeObserver === "undefined") return;
|
||||
this.resizeObserver = new ResizeObserver(() => this.schedulePositionRefresh());
|
||||
this.resizeObserver.observe(this.element.nativeElement);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.resizeObserver?.disconnect();
|
||||
if (this.renderFrame !== null) cancelAnimationFrame(this.renderFrame);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rete stores the socket's DOM centre. Resource sockets change height when their card opens, so
|
||||
* that position must be published again after every real size change.
|
||||
*/
|
||||
private schedulePositionRefresh(): void {
|
||||
if (this.renderFrame !== null) cancelAnimationFrame(this.renderFrame);
|
||||
this.renderFrame = requestAnimationFrame(() => {
|
||||
this.renderFrame = null;
|
||||
this.rendered?.();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -425,7 +425,7 @@
|
|||
.container-node__port-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
gap: 0;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
|
|
@ -433,6 +433,19 @@
|
|||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.container-node__socket {
|
||||
position: relative;
|
||||
flex: 0 0 0;
|
||||
width: 0;
|
||||
left: -18px;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.container-node__socket--right {
|
||||
left: auto;
|
||||
right: -18px;
|
||||
}
|
||||
|
||||
.container-node__port-label {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
.llm-node {
|
||||
position: relative;
|
||||
width: 280px;
|
||||
width: 340px;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
border-radius: 16px;
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
inset: 0;
|
||||
margin: auto;
|
||||
z-index: 9991;
|
||||
width: 280px;
|
||||
width: 340px;
|
||||
max-width: calc(100vw - 32px);
|
||||
height: fit-content;
|
||||
max-height: calc(100vh - 32px);
|
||||
|
|
@ -586,21 +586,24 @@
|
|||
}
|
||||
|
||||
.llm-row-input {
|
||||
grid-template-columns: 16px 1fr;
|
||||
gap: 6px;
|
||||
grid-template-columns: 0 minmax(0, 1fr);
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.llm-row-output {
|
||||
grid-template-columns: 1fr 16px;
|
||||
gap: 6px;
|
||||
grid-template-columns: minmax(0, 1fr) 0;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.llm-socket {
|
||||
position: relative;
|
||||
left: -16px;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.llm-socket-right {
|
||||
left: auto;
|
||||
right: -16px;
|
||||
justify-self: end;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@
|
|||
|
||||
.resource-card {
|
||||
position: relative;
|
||||
width: 250px;
|
||||
width: 340px;
|
||||
box-sizing: border-box;
|
||||
padding: 12px 16px 12px 12px;
|
||||
border: 1.5px solid #99f6e4;
|
||||
border-left: 5px solid #0d9488;
|
||||
|
|
@ -26,7 +27,7 @@
|
|||
}
|
||||
|
||||
.resource-card--open {
|
||||
width: 320px;
|
||||
width: 340px;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
.llm-node {
|
||||
position: relative;
|
||||
width: 280px;
|
||||
width: 340px;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
border-radius: 16px;
|
||||
|
|
@ -495,21 +495,24 @@ button.llm-node-bias-summary:focus-visible {
|
|||
}
|
||||
|
||||
.llm-row-input {
|
||||
grid-template-columns: 16px 1fr;
|
||||
gap: 6px;
|
||||
grid-template-columns: 0 minmax(0, 1fr);
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.llm-row-output {
|
||||
grid-template-columns: 1fr 16px;
|
||||
gap: 6px;
|
||||
grid-template-columns: minmax(0, 1fr) 0;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.llm-socket {
|
||||
position: relative;
|
||||
left: -16px;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.llm-socket-right {
|
||||
left: auto;
|
||||
right: -16px;
|
||||
justify-self: end;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -124,12 +124,10 @@ export async function createEditor(
|
|||
|
||||
render.addPreset(
|
||||
Presets.classic.setup({
|
||||
// Rete pushes an output's anchor 12px past its socket, for a small handle on a node's side.
|
||||
// A resource's handle is a bar along its right edge: its links start from the bar itself.
|
||||
// Every socket is a bar centred on the node border, so the connection starts from the bar's
|
||||
// actual DOM centre. The Rete default would push the anchor another 12px past it.
|
||||
socketPositionWatcher: getDOMSocketPosition<HFSchemes, any>({
|
||||
offset: (position, _nodeId, side, key) => key === FLOW_RESOURCE_PORT_KEY
|
||||
? position
|
||||
: { x: position.x + 12 * (side === 'input' ? -1 : 1), y: position.y }
|
||||
offset: (position) => position
|
||||
}),
|
||||
customize: {
|
||||
node(context: any) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue