@@ -6,12 +6,16 @@ import {
66 Vec ,
77 Box ,
88 createShapeId ,
9+ FONT_FAMILIES ,
910} from "tldraw" ;
1011import { DiscourseNode } from "~/utils/getDiscourseNodes" ;
1112import { formatHexColor } from "~/components/settings/DiscourseNodeCanvasSettings" ;
1213import { getRelationColor } from "./DiscourseRelationShape/DiscourseRelationUtil" ;
1314import { useAtom } from "@tldraw/state" ;
1415import { TOOL_ARROW_ICON_SVG , NODE_COLOR_ICON_SVG } from "~/icons" ;
16+ import { getDiscourseNodeColors } from "~/utils/getDiscourseNodeColors" ;
17+ import { DEFAULT_WIDTH , DEFAULT_HEIGHT } from "./Tldraw" ;
18+ import { DEFAULT_STYLE_PROPS , FONT_SIZES } from "./DiscourseNodeUtil" ;
1519
1620export type DiscourseGraphPanelProps = {
1721 nodes : DiscourseNode [ ] ;
@@ -30,6 +34,8 @@ type DragState =
3034 type : "node" | "relation" ;
3135 id : string ;
3236 text : string ;
37+ backgroundColor : string ;
38+ textColor : string ;
3339 color : string ;
3440 } ;
3541 startPosition : Vec ;
@@ -40,6 +46,8 @@ type DragState =
4046 type : "node" | "relation" ;
4147 id : string ;
4248 text : string ;
49+ backgroundColor : string ;
50+ textColor : string ;
4351 color : string ;
4452 } ;
4553 currentPosition : Vec ;
@@ -72,20 +80,32 @@ const DiscourseGraphPanel = ({
7280 ) ;
7381
7482 const panelItems = useMemo ( ( ) => {
75- const nodeItems = nodes . map ( ( node ) => ( {
76- type : "node" as const ,
77- id : node . type ,
78- text : node . text ,
79- color : formatHexColor ( node . canvasSettings . color ) || "black" ,
80- shortcut : node . shortcut ,
81- } ) ) ;
82-
83- const relationItems = uniqueRelations . map ( ( relation , index ) => ( {
84- type : "relation" as const ,
85- id : relation ,
86- text : relation ,
87- color : getRelationColor ( relation , index ) ,
88- } ) ) ;
83+ const nodeItems = nodes . map ( ( node ) => {
84+ const { backgroundColor, textColor } = getDiscourseNodeColors ( {
85+ nodeType : node . type ,
86+ } ) ;
87+ return {
88+ type : "node" as const ,
89+ id : node . type ,
90+ text : node . text ,
91+ backgroundColor : backgroundColor ,
92+ textColor : textColor ,
93+ color : formatHexColor ( node . canvasSettings . color ) || "black" ,
94+ shortcut : node . shortcut ,
95+ } ;
96+ } ) ;
97+
98+ const relationItems = uniqueRelations . map ( ( relation , index ) => {
99+ const color = getRelationColor ( relation , index ) ;
100+ return {
101+ type : "relation" as const ,
102+ id : relation ,
103+ text : relation ,
104+ backgroundColor : color ,
105+ textColor : "black" ,
106+ color : color ,
107+ } ;
108+ } ) ;
89109
90110 return [ ...nodeItems , ...relationItems ] ;
91111 } , [ nodes , uniqueRelations ] ) ;
@@ -108,6 +128,10 @@ const DiscourseGraphPanel = ({
108128 break ;
109129 }
110130 case "pointing_item" : {
131+ // Relations should not be draggable
132+ if ( current . item . type === "relation" ) {
133+ break ;
134+ }
111135 const dist = Vec . Dist ( screenPoint , current . startPosition ) ;
112136 if ( dist > 10 ) {
113137 dragState . set ( {
@@ -153,14 +177,16 @@ const DiscourseGraphPanel = ({
153177 case "dragging" : {
154178 // When dragging ends, create the shape at the drop position
155179 const pagePoint = editor . screenToPage ( current . currentPosition ) ;
180+ const offsetX = DEFAULT_WIDTH / 2 ;
181+ const offsetY = DEFAULT_HEIGHT / 2 ;
156182
157183 if ( current . item . type === "node" ) {
158184 const shapeId = createShapeId ( ) ;
159185 editor . createShape ( {
160186 id : shapeId ,
161187 type : current . item . id ,
162- x : pagePoint . x ,
163- y : pagePoint . y ,
188+ x : pagePoint . x - offsetX ,
189+ y : pagePoint . y - offsetY ,
164190 props : { fontFamily : "sans" , size : "s" } ,
165191 } ) ;
166192 editor . setEditingShape ( shapeId ) ;
@@ -198,8 +224,12 @@ const DiscourseGraphPanel = ({
198224 startPosition,
199225 } ) ;
200226
201- target . addEventListener ( "pointermove" , handlePointerMove ) ;
202- document . addEventListener ( "keydown" , handleKeyDown ) ;
227+ // Relations should not be draggable, only clickable
228+ // So we don't add the pointermove listener for relations
229+ if ( item . type !== "relation" ) {
230+ target . addEventListener ( "pointermove" , handlePointerMove ) ;
231+ document . addEventListener ( "keydown" , handleKeyDown ) ;
232+ }
203233 } ;
204234
205235 const handleKeyDown = ( e : KeyboardEvent ) => {
@@ -228,6 +258,11 @@ const DiscourseGraphPanel = ({
228258
229259 const state = useValue ( "dragState" , ( ) => dragState . get ( ) , [ dragState ] ) ;
230260
261+ const zoomLevel = Math . max (
262+ 0.5 ,
263+ useValue ( "clipboardZoomLevel" , ( ) => editor . getZoomLevel ( ) , [ editor ] ) ,
264+ ) ;
265+
231266 // Drag preview management
232267 useQuickReactor (
233268 "drag-image-style" ,
@@ -244,39 +279,46 @@ const DiscourseGraphPanel = ({
244279 break ;
245280 }
246281 case "dragging" : {
282+ // Relations should not be draggable
283+ if ( current . item . type === "relation" ) {
284+ imageRef . style . display = "none" ;
285+ break ;
286+ }
247287 const panelContainerRect = panelContainerRef . getBoundingClientRect ( ) ;
248288 const box = new Box (
249289 panelContainerRect . x ,
250290 panelContainerRect . y ,
251291 panelContainerRect . width ,
252292 panelContainerRect . height ,
253293 ) ;
254- const viewportScreenBounds = editor . getViewportScreenBounds ( ) ;
294+
295+ const zoomLevel = Math . max ( 0.5 , editor . getZoomLevel ( ) ) ;
296+ const height = DEFAULT_HEIGHT * zoomLevel ;
297+ const width = DEFAULT_WIDTH * zoomLevel ;
255298 const isInside = Box . ContainsPoint ( box , current . currentPosition ) ;
256299 if ( isInside ) {
257300 imageRef . style . display = "none" ;
258301 } else {
259- imageRef . style . display = "block" ;
260- imageRef . style . position = "absolute" ;
302+ const viewportScreenBounds = editor . getViewportScreenBounds ( ) ;
303+ imageRef . style . display = "flex" ;
304+ imageRef . style . position = "fixed" ;
261305 imageRef . style . pointerEvents = "none" ;
262306 imageRef . style . left = "0px" ;
263307 imageRef . style . top = "0px" ;
264- imageRef . style . transform = `translate(${ current . currentPosition . x - viewportScreenBounds . x - 25 } px, ${ current . currentPosition . y - viewportScreenBounds . y - 25 } px)` ;
265- imageRef . style . width = "50px" ;
266- imageRef . style . height = "50px" ;
267- imageRef . style . fontSize = "40px" ;
268- imageRef . style . display = "flex" ;
269- imageRef . style . alignItems = "center" ;
270- imageRef . style . justifyContent = "center" ;
271- imageRef . style . borderRadius = "8px" ;
272- imageRef . style . backgroundColor = current . item . color ;
273- imageRef . style . color = "white" ;
274- imageRef . style . fontWeight = "bold" ;
308+ imageRef . style . transform = `translate(${ current . currentPosition . x - viewportScreenBounds . x - width / 2 } px, ${ current . currentPosition . y - viewportScreenBounds . y - height / 2 } px)` ;
309+ imageRef . style . width = `${ width } px` ;
310+ imageRef . style . height = `${ height } px` ;
311+ imageRef . style . zIndex = "9999" ;
312+ imageRef . style . borderRadius = `${ 16 * zoomLevel } px` ;
313+ imageRef . style . backgroundColor = current . item . backgroundColor ;
314+ imageRef . style . color = current . item . textColor ;
315+ imageRef . className =
316+ "roamjs-tldraw-node pointer-events-none flex fixed items-center justify-center overflow-hidden" ;
275317 }
276318 }
277319 }
278320 } ,
279- [ dragState ] ,
321+ [ dragState , editor ] ,
280322 ) ;
281323
282324 // If it's a node tool, show only that node
@@ -384,15 +426,11 @@ const DiscourseGraphPanel = ({
384426 { state . name === "dragging" && (
385427 < div
386428 style = { {
387- backgroundColor : state . item . color ,
388- color : "white" ,
389- fontWeight : "bold" ,
390- borderRadius : "8px" ,
391- display : "flex" ,
392- alignItems : "center" ,
393- justifyContent : "center" ,
394- width : "100%" ,
395- height : "100%" ,
429+ ...DEFAULT_STYLE_PROPS ,
430+ maxWidth : "" ,
431+ fontFamily : FONT_FAMILIES . sans ,
432+ fontSize : `${ FONT_SIZES . s * zoomLevel } px` ,
433+ padding : `0px` ,
396434 } }
397435 >
398436 { state . item . text }
0 commit comments