@@ -16,12 +16,22 @@ import {
1616 IRectNodeComponent ,
1717 INodeComponent ,
1818 getSelectedNode ,
19+ renderElement ,
20+ createJSXElement ,
21+ NodeTaskFactory ,
22+ transformCameraSpaceToWorldSpace ,
23+ getPointerPos ,
24+ pointerDown ,
1925} from '@devhelpr/visual-programming-system' ;
2026import {
2127 getFollowNodeExecution ,
2228 setFollowNodeExecution ,
2329} from '../follow-path/followNodeExecution' ;
24- import { NodeInfo } from '@devhelpr/web-flow-executor' ;
30+ import {
31+ canvasNodeTaskRegistryLabels ,
32+ getNodeFactoryNames ,
33+ NodeInfo ,
34+ } from '@devhelpr/web-flow-executor' ;
2535import { createInputDialog } from '../utils/create-input-dialog' ;
2636
2737export class NodeSidebarMenuComponent extends Component <
@@ -42,12 +52,14 @@ export class NodeSidebarMenuComponent extends Component<
4252 followNodeExecution : HTMLButtonElement | null = null ;
4353 apikeysButton : HTMLButtonElement | null = null ;
4454 showDependencyConnections = false ;
55+ getNodeFactory : ( name : string ) => NodeTaskFactory < NodeInfo > ;
4556
4657 constructor (
4758 parent : BaseComponent | null ,
4859 props : AppNavComponentsProps < NodeInfo >
4960 ) {
5061 super ( parent , props ) ;
62+ this . getNodeFactory = props . getNodeFactory ;
5163 this . template = createTemplate (
5264 `<div class="z-20 flex flex-col absolute right-0 top-1/2 bg-slate-700 -translate-y-1/2 p-[4px] rounded-l-lg">
5365 <button title="Node properties" class="${ navBarButtonNomargin } flex w-[32px] h-[32px] mb-1"><span class="icon icon-tune text-[16px]"></span></button>
@@ -131,6 +143,61 @@ export class NodeSidebarMenuComponent extends Component<
131143 this . apikeysButton
132144 ) ;
133145 this . rootElement . append ( this . element ) ;
146+ let taskbar : HTMLElement | null = null ;
147+ let taskbarContainer : HTMLElement | null = null ;
148+ renderElement (
149+ < div
150+ class = { `taskbar-container transition-transform z-[1050] flex flex-col absolute left-0 top-[58px] max-h-[calc(100vh-108px)] bg-slate-700 p-[4px] rounded-l-lg overflow-y-scroll` }
151+ getElement = { ( element : HTMLElement ) => {
152+ taskbarContainer = element ;
153+ } }
154+ >
155+ < div
156+ class = { `overflow-visible flex flex-col ` }
157+ getElement = { ( element : HTMLElement ) => {
158+ taskbar = element ;
159+
160+ const nodeTasks = getNodeFactoryNames ( ) ;
161+ nodeTasks . forEach ( ( nodeTask ) => {
162+ //const factory = this.getNodeFactory(nodeTask);
163+ //let categoryName = 'Default';
164+ // if (factory) {
165+ // const node = factory(canvasUpdated);
166+ // if (allowedNodeTasks.indexOf(node.name) < 0) {
167+ // return;
168+ // }
169+ // categoryName = node.category || 'uncategorized';
170+ // }
171+ const label =
172+ canvasNodeTaskRegistryLabels [ nodeTask ] || nodeTask ;
173+
174+ renderElement (
175+ < div
176+ class = { `cursor-pointer border border-white border-solid rounded px-4 py-2 text-white` }
177+ pointerdown = { ( event : PointerEvent ) => {
178+ this . startDragNode (
179+ event ,
180+ taskbar ,
181+ taskbarContainer ,
182+ nodeTask
183+ ) ;
184+ } }
185+ >
186+ { label }
187+ </ div > ,
188+ taskbar
189+ ) ;
190+ } ) ;
191+ } }
192+ > </ div >
193+ </ div > ,
194+ this . rootElement
195+ ) ;
196+ this . rootElement . addEventListener ( 'pointerup' , ( _event ) => {
197+ if ( taskbarContainer ) {
198+ taskbarContainer . classList . remove ( '-translate-x-[100%]' ) ;
199+ }
200+ } ) ;
134201 }
135202 }
136203 this . isMounted = true ;
@@ -144,6 +211,65 @@ export class NodeSidebarMenuComponent extends Component<
144211 this . isMounted = false ;
145212 }
146213
214+ startDragNode = (
215+ event : PointerEvent ,
216+ taskbar : HTMLElement | null ,
217+ taskbarContainer : HTMLElement | null ,
218+ nodeType : string
219+ ) => {
220+ const factory = this . getNodeFactory ( nodeType ) ;
221+ const canvasApp = this . props . getCanvasApp ( ) ;
222+
223+ if ( factory && canvasApp && taskbar && taskbarContainer ) {
224+ const { pointerXPos, pointerYPos, rootX, rootY } = getPointerPos (
225+ canvasApp . canvas . domElement as HTMLElement ,
226+ canvasApp . rootElement ,
227+ event
228+ ) ;
229+ const { x, y } = transformCameraSpaceToWorldSpace (
230+ pointerXPos ,
231+ pointerYPos - ( window ?. visualViewport ?. offsetTop ?? 0 )
232+ ) ;
233+
234+ taskbarContainer . classList . add ( '-translate-x-[100%]' ) ;
235+ const nodeTask = factory ( this . props . canvasUpdated , canvasApp . theme ) ;
236+ const nodeInfo = undefined ;
237+ const node = nodeTask . createVisualNode (
238+ canvasApp ,
239+ x ,
240+ y ,
241+ undefined ,
242+ undefined ,
243+ undefined ,
244+ undefined ,
245+ undefined ,
246+ undefined ,
247+ nodeInfo
248+ ) ;
249+ if ( node && node . nodeInfo ) {
250+ const elementRect = (
251+ node . domElement as unknown as HTMLElement | SVGElement
252+ ) . getBoundingClientRect ( ) ;
253+
254+ const rect = transformCameraSpaceToWorldSpace (
255+ elementRect . x - rootX ,
256+ elementRect . y - rootY
257+ ) ;
258+ // TODO : IMPROVE THIS
259+ ( node . nodeInfo as any ) . taskType = nodeType ;
260+ ( node . domElement as HTMLElement ) . setPointerCapture ( event . pointerId ) ;
261+
262+ pointerDown (
263+ x - rect . x + ( node . width ?? 0 ) / 2 ,
264+ y - rect . y + ( node . height ?? 0 ) / 2 ,
265+ node ,
266+ canvasApp . canvas ,
267+ canvasApp . interactionStateMachine
268+ ) ;
269+ }
270+ }
271+ } ;
272+
147273 onClickSettingsNode = ( event : Event ) => {
148274 event . preventDefault ( ) ;
149275 const nodeInfo = this . getSelectedNodeInfo ( ) ;
@@ -437,5 +563,6 @@ export const NodeSidebarMenuComponents = (
437563 setIsStoring : props . setIsStoring ,
438564 showPopup : props . showPopup ,
439565 executeCommand : props . executeCommand ,
566+ getNodeFactory : props . getNodeFactory ,
440567 } ) ;
441568} ;
0 commit comments