@@ -95,17 +95,17 @@ export const RelationshipEditorWindow: React.FC<RelationshipEditorWindowProps> =
9595
9696 // Initialize position and auto-calculate height based on content
9797 useEffect ( ( ) => {
98- const sidebarWidth = getComputedStyle ( document . documentElement ) . getPropertyValue ( '--sidebar-width' ) || '16rem' ;
99- const sidebarPixels = sidebarWidth === '4rem' ? 64 : 256 ;
100-
101- setPosition ( {
102- x : sidebarPixels + 16 ,
103- y : 180 // Position similar to the old fixed panel
98+ const windowWidth = window . innerWidth ;
99+ const dialogWidth = isExpanded ? 580 : 450 ;
100+
101+ setPosition ( {
102+ x : windowWidth - dialogWidth - 24 ,
103+ y : 100
104104 } ) ;
105-
105+
106106 const contentHeight = calculateContentHeight ( ) ;
107107 setSize ( {
108- width : isExpanded ? 450 : 350 ,
108+ width : dialogWidth ,
109109 height : contentHeight
110110 } ) ;
111111 } , [ isExpanded , isVisible , editingEdge , selectedNodes . size ] ) ;
@@ -120,7 +120,7 @@ export const RelationshipEditorWindow: React.FC<RelationshipEditorWindowProps> =
120120 } ) ;
121121 }
122122 if ( isResizing ) {
123- const minWidth = 350 ;
123+ const minWidth = 450 ;
124124 const minHeight = calculateContentHeight ( ) ; // Use content-based minimum height
125125 const newWidth = Math . max ( minWidth , resizeStart . width + ( e . clientX - resizeStart . x ) ) ;
126126 const newHeight = Math . max ( minHeight , resizeStart . height + ( e . clientY - resizeStart . y ) ) ;
@@ -177,6 +177,20 @@ export const RelationshipEditorWindow: React.FC<RelationshipEditorWindowProps> =
177177 variables : {
178178 where : { id : editingEdge . edge . id } ,
179179 update : { type : newType }
180+ } ,
181+ optimisticResponse : {
182+ __typename : 'Mutation' ,
183+ updateEdges : {
184+ __typename : 'UpdateEdgesMutationResponse' ,
185+ edges : [ {
186+ __typename : 'Edge' ,
187+ id : editingEdge . edge . id ,
188+ type : newType ,
189+ weight : editingEdge . edge . strength || 1.0 ,
190+ source : editingEdge . edge . source ,
191+ target : editingEdge . edge . target
192+ } ]
193+ }
180194 }
181195 } ) ;
182196 showSuccess ( 'Relationship Updated' , 'Edge type changed successfully' ) ;
@@ -196,6 +210,31 @@ export const RelationshipEditorWindow: React.FC<RelationshipEditorWindowProps> =
196210 target : { connect : { where : { node : { id : targetNode . id } } } } ,
197211 weight : 1.0
198212 } ]
213+ } ,
214+ optimisticResponse : {
215+ __typename : 'Mutation' ,
216+ createEdges : {
217+ __typename : 'CreateEdgesMutationResponse' ,
218+ edges : [ {
219+ __typename : 'Edge' ,
220+ id : `temp-${ Date . now ( ) } ` ,
221+ type : newType ,
222+ weight : 1.0 ,
223+ source : {
224+ __typename : 'WorkItem' ,
225+ id : sourceNode . id ,
226+ title : sourceNode . title ,
227+ type : sourceNode . type
228+ } ,
229+ target : {
230+ __typename : 'WorkItem' ,
231+ id : targetNode . id ,
232+ title : targetNode . title ,
233+ type : targetNode . type
234+ } ,
235+ createdAt : new Date ( ) . toISOString ( )
236+ } ]
237+ }
199238 }
200239 } ) ;
201240 showSuccess ( 'Relationship Created' , 'New relationship added successfully' ) ;
@@ -257,10 +296,18 @@ export const RelationshipEditorWindow: React.FC<RelationshipEditorWindowProps> =
257296 // Handle edge delete
258297 const handleDeleteEdge = async ( ) => {
259298 if ( ! editingEdge ) return ;
260-
299+
261300 try {
262301 await deleteEdgeMutation ( {
263- variables : { where : { id : editingEdge . edge . id } }
302+ variables : { where : { id : editingEdge . edge . id } } ,
303+ optimisticResponse : {
304+ __typename : 'Mutation' ,
305+ deleteEdges : {
306+ __typename : 'DeleteInfo' ,
307+ nodesDeleted : 0 ,
308+ relationshipsDeleted : 1
309+ }
310+ }
264311 } ) ;
265312 showSuccess ( 'Relationship Deleted' , 'Edge removed successfully' ) ;
266313 refetchEdges ?.( ) ;
@@ -277,9 +324,22 @@ export const RelationshipEditorWindow: React.FC<RelationshipEditorWindowProps> =
277324 const isEditingMode = ! ! editingEdge ;
278325
279326 return createPortal (
280- < div
327+ < >
328+ < style > { `
329+ @keyframes fadeInScale {
330+ from {
331+ opacity: 0;
332+ transform: scale(0.9);
333+ }
334+ to {
335+ opacity: 1;
336+ transform: scale(1);
337+ }
338+ }
339+ ` } </ style >
340+ < div
281341 ref = { windowRef }
282- className = "fixed bg-white/5 backdrop-blur-xl border border-white/20 rounded-xl shadow-lg overflow-hidden z-50 "
342+ className = "fixed bg-black/90 backdrop-blur-xl border border-white/10 rounded-2xl shadow-2xl overflow-hidden z-[60] "
283343 style = { {
284344 left : `${ position . x } px` ,
285345 top : `${ position . y } px` ,
@@ -291,28 +351,30 @@ export const RelationshipEditorWindow: React.FC<RelationshipEditorWindowProps> =
291351 onClick = { ( e ) => e . stopPropagation ( ) }
292352 >
293353 { /* Header */ }
294- < div
295- className = "flex items-center justify-between p-3 bg-white /10 border-b border-white/10 cursor-move select-none"
354+ < div
355+ className = "flex items-center justify-between p-4 bg-gradient-to-r from-amber-500 /10 to-orange-500/10 border-b border-amber-500/20 cursor-move select-none backdrop-blur-sm "
296356 onMouseDown = { handleDragStart }
297357 >
298358 < div className = "flex items-center space-x-2" >
299- < Zap className = "h-4 w-4 text-amber-400" />
359+ < div className = "p-1.5 bg-amber-500/20 rounded-lg" >
360+ < Zap className = "h-4 w-4 text-amber-400" />
361+ </ div >
300362 < span className = "text-white font-semibold text-sm" >
301363 { isEditingMode ? 'Edit Relationship' : 'Create Relationship' }
302364 </ span >
303365 </ div >
304366 < div className = "flex items-center space-x-1" >
305367 < button
306368 onClick = { ( ) => setIsExpanded ( ! isExpanded ) }
307- className = "p-1 rounded text-gray-400 hover:text-white hover:bg-white/10 transition-colors "
369+ className = "p-1.5 rounded-lg text-gray-400 hover:text-white hover:bg-white/10 transition-all duration-200 "
308370 >
309- { isExpanded ? < Minimize2 className = "h-3 w-3" /> : < Maximize2 className = "h-3 w-3" /> }
371+ { isExpanded ? < Minimize2 className = "h-3.5 w-3.5 " /> : < Maximize2 className = "h-3.5 w-3.5 " /> }
310372 </ button >
311373 < button
312374 onClick = { onClose }
313- className = "p-1 rounded text-gray-400 hover:text-white hover:bg-white/10 transition-colors "
375+ className = "p-1.5 rounded-lg text-gray-400 hover:text-white hover:bg-red-500/20 transition-all duration-200 "
314376 >
315- < X className = "h-3 w-3" />
377+ < X className = "h-3.5 w-3.5 " />
316378 </ button >
317379 </ div >
318380 </ div >
@@ -321,61 +383,129 @@ export const RelationshipEditorWindow: React.FC<RelationshipEditorWindowProps> =
321383 { isExpanded && (
322384 < div className = "p-4 space-y-4" >
323385 { /* Status indicator */ }
324- < div className = "text-center" >
386+ < div className = "text-center space-y-2 " >
325387 { ! canEdit && (
326- < div className = "text-gray-400 text-sm" >
327- Select two nodes or click on an edge to edit relationships
388+ < div className = "space-y-1" >
389+ < div className = "text-gray-300 text-sm font-medium" >
390+ { selectedNodeObjects . length === 0 && 'No nodes selected' }
391+ { selectedNodeObjects . length === 1 && 'One node selected' }
392+ </ div >
393+ < div className = "text-gray-400 text-xs" >
394+ { selectedNodeObjects . length === 0 && 'Select two nodes to create a relationship' }
395+ { selectedNodeObjects . length === 1 && 'Select one more node to create a relationship' }
396+ </ div >
397+ { selectedNodeObjects . length === 1 && (
398+ < div className = "mt-2 inline-block px-3 py-1 bg-white/10 rounded-lg text-white text-xs" >
399+ { selectedNodeObjects [ 0 ] . title }
400+ </ div >
401+ ) }
328402 </ div >
329403 ) }
330404 { canEdit && ! isEditingMode && (
331- < div className = "text-green-400 text-sm" >
332- Ready to create relationship between { selectedNodeObjects . length } selected nodes
405+ < div className = "space-y-2" >
406+ < div className = "text-green-400 text-sm font-medium" >
407+ Ready to create relationship
408+ </ div >
409+ < div className = "flex items-center justify-center gap-2 text-xs" >
410+ < div className = "px-3 py-1 bg-green-500/20 border border-green-500/30 rounded-lg text-green-300" >
411+ { selectedNodeObjects [ 0 ] . title }
412+ </ div >
413+ < span className = "text-gray-400" > →</ span >
414+ < div className = "px-3 py-1 bg-green-500/20 border border-green-500/30 rounded-lg text-green-300" >
415+ { selectedNodeObjects [ 1 ] . title }
416+ </ div >
417+ </ div >
418+ < div className = "text-gray-400 text-xs" >
419+ Select a relationship type below
420+ </ div >
333421 </ div >
334422 ) }
335423 { isEditingMode && (
336- < div className = "text-blue-400 text-sm" >
337- Editing relationship: { ( ( ) => {
338- const sourceId = typeof editingEdge ?. edge . source === 'string'
339- ? editingEdge ?. edge . source
340- : ( editingEdge ?. edge . source as any ) ?. id ;
341- const targetId = typeof editingEdge ?. edge . target === 'string'
342- ? editingEdge ?. edge . target
343- : ( editingEdge ?. edge . target as any ) ?. id ;
344-
345- const sourceTitle = workItems . find ( item => item . id === sourceId ) ?. title || 'Unknown' ;
346- const targetTitle = workItems . find ( item => item . id === targetId ) ?. title || 'Unknown' ;
347-
348- return `${ sourceTitle } → ${ targetTitle } ` ;
349- } ) ( ) }
424+ < div className = "space-y-2" >
425+ < div className = "text-blue-400 text-sm font-medium" >
426+ Editing Relationship
427+ </ div >
428+ < div className = "flex items-center justify-center gap-2 text-xs" >
429+ { ( ( ) => {
430+ const sourceId = typeof editingEdge ?. edge . source === 'string'
431+ ? editingEdge ?. edge . source
432+ : ( editingEdge ?. edge . source as any ) ?. id ;
433+ const targetId = typeof editingEdge ?. edge . target === 'string'
434+ ? editingEdge ?. edge . target
435+ : ( editingEdge ?. edge . target as any ) ?. id ;
436+
437+ const sourceTitle = workItems . find ( item => item . id === sourceId ) ?. title || 'Unknown' ;
438+ const targetTitle = workItems . find ( item => item . id === targetId ) ?. title || 'Unknown' ;
439+
440+ return (
441+ < >
442+ < div className = "px-3 py-1 bg-blue-500/20 border border-blue-500/30 rounded-lg text-blue-300" >
443+ { sourceTitle }
444+ </ div >
445+ < span className = "text-gray-400" > →</ span >
446+ < div className = "px-3 py-1 bg-blue-500/20 border border-blue-500/30 rounded-lg text-blue-300" >
447+ { targetTitle }
448+ </ div >
449+ </ >
450+ ) ;
451+ } ) ( ) }
452+ </ div >
350453 </ div >
351454 ) }
352455 </ div >
353456
354457 { /* Relationship type grid */ }
355458 { canEdit && (
356459 < div >
357- < div className = "text-white text-sm font-medium mb-3" > Relationship Type</ div >
358- < div className = "grid grid-cols-3 gap-2" >
359- { RELATIONSHIP_OPTIONS . map ( ( option ) => {
460+ < div className = "text-white text-sm font-semibold mb-4 flex items-center gap-2" >
461+ < span className = "text-transparent bg-clip-text bg-gradient-to-r from-amber-400 to-orange-400" >
462+ Relationship Type
463+ </ span >
464+ </ div >
465+ < div className = "grid grid-cols-4 gap-2.5" >
466+ { RELATIONSHIP_OPTIONS . map ( ( option , index ) => {
360467 const isSelected = isEditingMode ? editingEdge ?. edge . type === option . type : false ;
468+ const config = getRelationshipConfig ( option . type ) ;
361469 return (
362470 < button
363471 key = { option . type }
364472 onClick = { ( ) => handleRelationshipTypeChange ( option . type ) }
365473 className = { `
366- group relative p-3 rounded-lg border transition-all duration-200
367- ${ isSelected
368- ? 'border-amber-400 bg-amber-400/10 text-amber-400'
369- : 'border-white/20 bg-white/5 text-white hover:border-white/40 hover:bg-white/10'
474+ group relative p-3 rounded-xl border transition-all duration-300 transform
475+ hover:scale-105 hover:z-10
476+ ${ isSelected
477+ ? `border-${ config . color } -400/50 bg-gradient-to-br from-${ config . color } -500/30 via-${ config . color } -500/20 to-${ config . color } -500/10 shadow-lg shadow-${ config . color } -500/20`
478+ : 'border-white/10 bg-gradient-to-br from-white/5 via-white/3 to-transparent hover:border-white/30 hover:from-white/10 hover:via-white/5'
370479 }
371480 ` }
481+ style = { {
482+ animation : `fadeInScale 0.4s ease-out ${ index * 0.03 } s both` ,
483+ ...( isSelected && {
484+ borderColor : `${ config . color === 'blue' ? 'rgb(96 165 250 / 0.5)' :
485+ config . color === 'red' ? 'rgb(248 113 113 / 0.5)' :
486+ config . color === 'green' ? 'rgb(74 222 128 / 0.5)' :
487+ config . color === 'purple' ? 'rgb(192 132 252 / 0.5)' :
488+ config . color === 'orange' ? 'rgb(251 146 60 / 0.5)' :
489+ config . color === 'teal' ? 'rgb(45 212 191 / 0.5)' :
490+ config . color === 'yellow' ? 'rgb(250 204 21 / 0.5)' :
491+ config . color === 'pink' ? 'rgb(244 114 182 / 0.5)' :
492+ config . color === 'indigo' ? 'rgb(129 140 248 / 0.5)' :
493+ config . color === 'cyan' ? 'rgb(103 232 249 / 0.5)' :
494+ 'rgb(156 163 175 / 0.5)' } `
495+ } )
496+ } }
372497 title = { option . description }
373498 >
374- < div className = "flex flex-col items-center space-y-2" >
375- < div className = { `text-lg group-hover:scale-110 transition-transform` } >
499+ { isSelected && (
500+ < div className = "absolute inset-0 rounded-xl bg-gradient-to-br from-white/10 to-transparent opacity-50 animate-pulse" > </ div >
501+ ) }
502+ < div className = "relative flex flex-col items-center space-y-1.5" >
503+ < div className = { `text-lg transition-all duration-300 ${ isSelected ? 'scale-110' : 'group-hover:scale-110' } ` } >
376504 { getRelationshipIconElement ( option . type , "h-5 w-5" ) }
377505 </ div >
378- < span className = "text-xs font-medium text-center leading-tight" >
506+ < span className = { `text-[10px] font-semibold text-center leading-tight transition-colors ${
507+ isSelected ? 'text-white' : 'text-gray-300 group-hover:text-white'
508+ } `} >
379509 { option . label }
380510 </ span >
381511 </ div >
@@ -432,7 +562,8 @@ export const RelationshipEditorWindow: React.FC<RelationshipEditorWindowProps> =
432562 < div className = "absolute bottom-1 right-1 w-2 h-2 border-r-2 border-b-2 border-white/40" > </ div >
433563 </ div >
434564 ) }
435- </ div > ,
565+ </ div >
566+ </ > ,
436567 document . body
437568 ) ;
438569} ;
0 commit comments