|
5 | 5 |
|
6 | 6 | import type { Editor } from "@graphite/editor";
|
7 | 7 | import type { Node } from "@graphite/messages.svelte";
|
8 |
| - import type { FrontendNodeWire, FrontendNode, FrontendGraphInput, FrontendGraphOutput, FrontendGraphDataType, WirePath } from "@graphite/messages.svelte"; |
| 8 | + import { type FrontendNodeWire, type FrontendNode, type FrontendGraphInput, FrontendGraphOutput, type FrontendGraphDataType, type WirePath } from "@graphite/messages.svelte"; |
9 | 9 | import type { NodeGraphState } from "@graphite/state-providers/node-graph";
|
10 | 10 | import type { IconName } from "@graphite/utility-functions/icons";
|
11 | 11 |
|
|
142 | 142 |
|
143 | 143 | function resolveWire(wire: FrontendNodeWire): { nodeOutput: SVGSVGElement; nodeInput: SVGSVGElement } | undefined {
|
144 | 144 | const wireStartNodeIdIndex = nodeIndexes.get(wire.wireStart.nodeId!);
|
145 |
| - let nodeOutputConnectors = outputs[wireStartNodeIdIndex]; |
| 145 | + let nodeOutputConnectors = outputs[wireStartNodeIdIndex] ?? undefined; |
146 | 146 | if (nodeOutputConnectors === undefined && wire.wireStart.nodeId === undefined) {
|
147 | 147 | nodeOutputConnectors = outputs[0];
|
148 | 148 | }
|
|
151 | 151 | if (nodeOutput === undefined) return undefined;
|
152 | 152 |
|
153 | 153 | const wireEndNodeIdIndex = nodeIndexes.get(wire.wireEnd.nodeId!);
|
154 |
| - let nodeInputConnectors = inputs[wireEndNodeIdIndex] || undefined; |
| 154 | + let nodeInputConnectors = inputs[wireEndNodeIdIndex] ?? undefined; |
155 | 155 | if (nodeInputConnectors === undefined && wire.wireEnd.nodeId === undefined) {
|
156 | 156 | nodeInputConnectors = inputs[0];
|
157 | 157 | }
|
|
640 | 640 |
|
641 | 641 | $effect.pre(() => {
|
642 | 642 | if (inputs.length && outputs.length && $nodeGraph.nodes) {
|
643 |
| - refreshWires(inputs, outputs) |
| 643 | + refreshWires() |
644 | 644 | }
|
645 | 645 | })
|
646 | 646 |
|
|
753 | 753 | <!-- Import and Export ports -->
|
754 | 754 | <div class="imports-and-exports" style:transform-origin={`0 0`} style:transform={`translate(${$nodeGraph.transform.x}px, ${$nodeGraph.transform.y}px) scale(${$nodeGraph.transform.scale})`}>
|
755 | 755 | {#each $nodeGraph.imports as { outputMetadata, position }, index}
|
756 |
| - <svg |
757 |
| - xmlns="http://www.w3.org/2000/svg" |
758 |
| - viewBox="0 0 8 8" |
759 |
| - class="port" |
760 |
| - data-port="output" |
761 |
| - data-datatype={outputMetadata.dataType} |
762 |
| - style:--data-color={`var(--color-data-${outputMetadata.dataType.toLowerCase()})`} |
763 |
| - style:--data-color-dim={`var(--color-data-${outputMetadata.dataType.toLowerCase()}-dim)`} |
764 |
| - style:--offset-left={position.x / 24} |
765 |
| - style:--offset-top={position.y / 24} |
766 |
| - bind:this={outputs[0][index]} |
767 |
| - > |
768 |
| - <title>{`${dataTypeTooltip(outputMetadata)}\n\n${outputConnectedToText(outputMetadata)}`}</title> |
769 |
| - {#if outputMetadata.connectedTo !== undefined} |
770 |
| - <path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" /> |
771 |
| - {:else} |
772 |
| - <path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color-dim)" /> |
773 |
| - {/if} |
774 |
| - </svg> |
775 |
| - |
| 756 | + {@render port("port", "output", outputs, 0, index, outputMetadata, position.x / 24, position.y / 24)} |
776 | 757 | <div
|
777 | 758 | class="edit-import-export import"
|
778 | 759 | onpointerenter={() => (hoveringImportIndex = index)}
|
|
828 | 809 | </div>
|
829 | 810 | {/if}
|
830 | 811 | {#each $nodeGraph.exports as { inputMetadata, position }, index}
|
831 |
| - <svg |
832 |
| - xmlns="http://www.w3.org/2000/svg" |
833 |
| - viewBox="0 0 8 8" |
834 |
| - class="port" |
835 |
| - data-port="input" |
836 |
| - data-datatype={inputMetadata.dataType} |
837 |
| - style:--data-color={`var(--color-data-${inputMetadata.dataType.toLowerCase()})`} |
838 |
| - style:--data-color-dim={`var(--color-data-${inputMetadata.dataType.toLowerCase()}-dim)`} |
839 |
| - style:--offset-left={position.x / 24} |
840 |
| - style:--offset-top={position.y / 24} |
841 |
| - bind:this={inputs[0][index]} |
842 |
| - > |
843 |
| - <title>{`${dataTypeTooltip(inputMetadata)}\n\n${inputConnectedToText(inputMetadata)}`}</title> |
844 |
| - {#if inputMetadata.connectedTo !== undefined} |
845 |
| - <path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" /> |
846 |
| - {:else} |
847 |
| - <path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color-dim)" /> |
848 |
| - {/if} |
849 |
| - </svg> |
| 812 | + {@render port("port", "input", inputs, 0, index, inputMetadata, position.x / 24, position.y / 24)} |
850 | 813 | <div
|
851 | 814 | class="edit-import-export export"
|
852 | 815 | onpointerenter={() => (hoveringExportIndex = index)}
|
|
991 | 954 | <!-- Layer input port (from left) -->
|
992 | 955 | {#if node.exposedInputs.length > 0}
|
993 | 956 | <div class="input ports">
|
994 |
| - <svg |
995 |
| - xmlns="http://www.w3.org/2000/svg" |
996 |
| - viewBox="0 0 8 8" |
997 |
| - class="port" |
998 |
| - data-port="input" |
999 |
| - data-datatype={stackDataInput.dataType} |
1000 |
| - style:--data-color={`var(--color-data-${stackDataInput.dataType.toLowerCase()})`} |
1001 |
| - style:--data-color-dim={`var(--color-data-${stackDataInput.dataType.toLowerCase()}-dim)`} |
1002 |
| - bind:this={inputs[nodeIndex + 1][1]} |
1003 |
| - > |
1004 |
| - <title>{`${dataTypeTooltip(stackDataInput)}\n\n${validTypesText(stackDataInput)}\n\n${inputConnectedToText(stackDataInput)}`}</title> |
1005 |
| - {#if stackDataInput.connectedTo !== undefined} |
1006 |
| - <path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" /> |
1007 |
| - {:else} |
1008 |
| - <path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color-dim)" /> |
1009 |
| - {/if} |
1010 |
| - </svg> |
| 957 | + {@render port("port", "input", inputs, nodeIndex + 1, 1, stackDataInput)} |
1011 | 958 | </div>
|
1012 | 959 | {/if}
|
1013 | 960 | <div class="details">
|
|
1098 | 1045 | <!-- Input ports -->
|
1099 | 1046 | <div class="input ports">
|
1100 | 1047 | {#if node.primaryInput?.dataType}
|
1101 |
| - <svg |
1102 |
| - xmlns="http://www.w3.org/2000/svg" |
1103 |
| - viewBox="0 0 8 8" |
1104 |
| - class="port primary-port" |
1105 |
| - data-port="input" |
1106 |
| - data-datatype={node.primaryInput?.dataType} |
1107 |
| - style:--data-color={`var(--color-data-${node.primaryInput.dataType.toLowerCase()})`} |
1108 |
| - style:--data-color-dim={`var(--color-data-${node.primaryInput.dataType.toLowerCase()}-dim)`} |
1109 |
| - bind:this={inputs[nodeIndex + 1][0]} |
1110 |
| - > |
1111 |
| - <title>{`${dataTypeTooltip(node.primaryInput)}\n\n${validTypesText(node.primaryInput)}\n\n${inputConnectedToText(node.primaryInput)}`}</title> |
1112 |
| - {#if node.primaryInput.connectedTo !== undefined} |
1113 |
| - <path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" /> |
1114 |
| - {:else} |
1115 |
| - <path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color-dim)" /> |
1116 |
| - {/if} |
1117 |
| - </svg> |
| 1048 | + {@render port("port primary-port", "input", inputs, nodeIndex + 1, 0, node.primaryInput)} |
1118 | 1049 | {/if}
|
1119 | 1050 | {#each node.exposedInputs as secondary, index}
|
1120 | 1051 | {#if index < node.exposedInputs.length}
|
1121 |
| - <svg |
1122 |
| - xmlns="http://www.w3.org/2000/svg" |
1123 |
| - viewBox="0 0 8 8" |
1124 |
| - class="port" |
1125 |
| - data-port="input" |
1126 |
| - data-datatype={secondary.dataType} |
1127 |
| - style:--data-color={`var(--color-data-${secondary.dataType.toLowerCase()})`} |
1128 |
| - style:--data-color-dim={`var(--color-data-${secondary.dataType.toLowerCase()}-dim)`} |
1129 |
| - bind:this={inputs[nodeIndex + 1][index + (node.primaryInput ? 1 : 0)]} |
1130 |
| - > |
1131 |
| - <title>{`${dataTypeTooltip(secondary)}\n\n${validTypesText(secondary)}\n\n${inputConnectedToText(secondary)}`}</title> |
1132 |
| - {#if secondary.connectedTo !== undefined} |
1133 |
| - <path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" /> |
1134 |
| - {:else} |
1135 |
| - <path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color-dim)" /> |
1136 |
| - {/if} |
1137 |
| - </svg> |
| 1052 | + {@render port("port", "input", inputs, nodeIndex + 1, index + (node.primaryInput ? 1 : 0), secondary)} |
1138 | 1053 | {/if}
|
1139 | 1054 | {/each}
|
1140 | 1055 | </div>
|
1141 | 1056 | <!-- Output ports -->
|
1142 | 1057 | <div class="output ports">
|
1143 |
| - {#if node.primaryOutput} |
1144 |
| - <svg |
1145 |
| - xmlns="http://www.w3.org/2000/svg" |
1146 |
| - viewBox="0 0 8 8" |
1147 |
| - class="port primary-port" |
1148 |
| - data-port="output" |
1149 |
| - data-datatype={node.primaryOutput.dataType} |
1150 |
| - style:--data-color={`var(--color-data-${node.primaryOutput.dataType.toLowerCase()})`} |
1151 |
| - style:--data-color-dim={`var(--color-data-${node.primaryOutput.dataType.toLowerCase()}-dim)`} |
1152 |
| - bind:this={outputs[nodeIndex + 1][0]} |
1153 |
| - > |
1154 |
| - <title>{`${dataTypeTooltip(node.primaryOutput)}\n\n${outputConnectedToText(node.primaryOutput)}`}</title> |
1155 |
| - {#if node.primaryOutput.connectedTo !== undefined} |
1156 |
| - <path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" /> |
1157 |
| - {:else} |
1158 |
| - <path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color-dim)" /> |
1159 |
| - {/if} |
1160 |
| - </svg> |
1161 |
| - {/if} |
| 1058 | + {@render port("port primary-port", "output", outputs, nodeIndex + 1, 0, node.primaryOutput)} |
1162 | 1059 | {#each node.exposedOutputs as secondary, outputIndex}
|
1163 |
| - <svg |
1164 |
| - xmlns="http://www.w3.org/2000/svg" |
1165 |
| - viewBox="0 0 8 8" |
1166 |
| - class="port" |
1167 |
| - data-port="output" |
1168 |
| - data-datatype={secondary.dataType} |
1169 |
| - style:--data-color={`var(--color-data-${secondary.dataType.toLowerCase()})`} |
1170 |
| - style:--data-color-dim={`var(--color-data-${secondary.dataType.toLowerCase()}-dim)`} |
1171 |
| - bind:this={outputs[nodeIndex + 1][outputIndex + (node.primaryOutput ? 1 : 0)]} |
1172 |
| - > |
1173 |
| - <title>{`${dataTypeTooltip(secondary)}\n\n${outputConnectedToText(secondary)}`}</title> |
1174 |
| - {#if secondary.connectedTo !== undefined} |
1175 |
| - <path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" /> |
1176 |
| - {:else} |
1177 |
| - <path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color-dim)" /> |
1178 |
| - {/if} |
1179 |
| - </svg> |
| 1060 | + {@render port("port", "output", outputs, nodeIndex + 1, outputIndex + (node.primaryOutput ? 1 : 0), secondary)} |
1180 | 1061 | {/each}
|
1181 | 1062 | </div>
|
1182 | 1063 | <svg class="border-mask" width="0" height="0">
|
|
1206 | 1087 | ></div>
|
1207 | 1088 | {/if}
|
1208 | 1089 |
|
| 1090 | +{#snippet port(className: string, dataPort: string, ref: SVGSVGElement[][], x: number, y: number, node?: FrontendGraphInput | FrontendGraphOutput, offsetLeft?: number, offsetTop?: number)} |
| 1091 | + {#if node} |
| 1092 | + {@const color = node.dataType.toLowerCase()} |
| 1093 | + <svg |
| 1094 | + xmlns="http://www.w3.org/2000/svg" |
| 1095 | + viewBox="0 0 8 8" |
| 1096 | + class={className} |
| 1097 | + data-port={dataPort} |
| 1098 | + data-datatype={node.dataType} |
| 1099 | + style:--data-color={`var(--color-data-${color})`} |
| 1100 | + style:--data-color-dim={`var(--color-data-${color}-dim)`} |
| 1101 | + style:--offset-left={offsetLeft} |
| 1102 | + style:--offset-top={offsetTop} |
| 1103 | + bind:this={ref[x][y]} |
| 1104 | + > |
| 1105 | + {#if node instanceof FrontendGraphOutput} |
| 1106 | + <title>{`${dataTypeTooltip(node)}\n\n${outputConnectedToText(node)}`}</title> |
| 1107 | + {:else} |
| 1108 | + <title>{`${dataTypeTooltip(node)}\n\n${validTypesText(node)}\n\n${inputConnectedToText(node)}`}</title> |
| 1109 | + {/if} |
| 1110 | + {#if node.connectedTo !== undefined} |
| 1111 | + <path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" /> |
| 1112 | + {:else} |
| 1113 | + <path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color-dim)" /> |
| 1114 | + {/if} |
| 1115 | + </svg> |
| 1116 | + {/if} |
| 1117 | +{/snippet} |
| 1118 | + |
1209 | 1119 | <style lang="scss" global>
|
1210 | 1120 | .graph {
|
1211 | 1121 | position: relative;
|
|
0 commit comments