@@ -82,6 +82,7 @@ export function LearningMapEditor({
8282 const [ settings , setSettings ] = useState < Settings > ( parsedRoadmap . settings ) ;
8383 const [ showGrid , setShowGrid ] = useState ( false ) ;
8484 const [ clipboard , setClipboard ] = useState < { nodes : Node < NodeData > [ ] ; edges : Edge [ ] } | null > ( null ) ;
85+ const [ lastMousePosition , setLastMousePosition ] = useState < { x : number ; y : number } | null > ( null ) ;
8586
8687 // Use language from settings if available, otherwise use prop
8788 const effectiveLanguage = settings ?. language || language ;
@@ -98,6 +99,7 @@ export function LearningMapEditor({
9899 { action : t . shortcuts . togglePreviewMode , shortcut : "Ctrl+P" } ,
99100 { action : t . shortcuts . toggleDebugMode , shortcut : "Ctrl+D" } ,
100101 { action : t . shortcuts . selectMultipleNodes , shortcut : "Ctrl+Click or Shift+Drag" } ,
102+ { action : t . shortcuts . selectAllNodes , shortcut : "Ctrl+A" } ,
101103 { action : t . shortcuts . showHelp , shortcut : "Ctrl+? or Help Button" } ,
102104 { action : t . shortcuts . zoomIn , shortcut : "Ctrl++" } ,
103105 { action : t . shortcuts . zoomOut , shortcut : "Ctrl+-" } ,
@@ -306,12 +308,16 @@ export function LearningMapEditor({
306308
307309 const addNewNode = useCallback (
308310 ( type : "task" | "topic" | "image" | "text" ) => {
309- const centerPos = screenToFlowPosition ( { x : window . innerWidth / 2 , y : window . innerHeight / 2 } ) ;
311+ // Use last mouse position if available, otherwise use center of screen
312+ const position = lastMousePosition
313+ ? screenToFlowPosition ( lastMousePosition )
314+ : screenToFlowPosition ( { x : window . innerWidth / 2 , y : window . innerHeight / 2 } ) ;
315+
310316 if ( type === "task" ) {
311317 const newNode : Node < NodeData > = {
312318 id : `node${ nextNodeId } ` ,
313319 type,
314- position : centerPos ,
320+ position,
315321 data : {
316322 label : t . newTask ,
317323 summary : "" ,
@@ -324,7 +330,7 @@ export function LearningMapEditor({
324330 const newNode : Node < NodeData > = {
325331 id : `node${ nextNodeId } ` ,
326332 type,
327- position : centerPos ,
333+ position,
328334 data : {
329335 label : t . newTopic ,
330336 summary : "" ,
@@ -339,7 +345,7 @@ export function LearningMapEditor({
339345 id : `background-node${ nextNodeId } ` ,
340346 type,
341347 zIndex : - 2 ,
342- position : centerPos ,
348+ position,
343349 data : {
344350 src : "" ,
345351 } ,
@@ -350,7 +356,7 @@ export function LearningMapEditor({
350356 const newNode : Node < TextNodeData > = {
351357 id : `background-node${ nextNodeId } ` ,
352358 type,
353- position : centerPos ,
359+ position,
354360 zIndex : - 1 ,
355361 data : {
356362 text : t . backgroundTextDefault ,
@@ -363,7 +369,7 @@ export function LearningMapEditor({
363369 }
364370 setSaved ( false ) ;
365371 } ,
366- [ nextNodeId , screenToFlowPosition , setNodes , setSaved , t ]
372+ [ nextNodeId , lastMousePosition , screenToFlowPosition , setNodes , setSaved , t ]
367373 ) ;
368374
369375 const handleSave = useCallback ( ( ) => {
@@ -679,13 +685,28 @@ export function LearningMapEditor({
679685 }
680686 } , [ setNodes , setEdges , setNextNodeId , setSaved , t ] ) ;
681687
688+ const handleSelectAll = useCallback ( ( ) => {
689+ setSelectedNodeIds ( nodes . map ( n => n . id ) ) ;
690+ } , [ nodes , setSelectedNodeIds ] ) ;
691+
682692 const handleSelectionChange : OnSelectionChangeFunc = useCallback (
683693 ( { nodes : selectedNodes } ) => {
684694 setSelectedNodeIds ( selectedNodes . map ( n => n . id ) ) ;
685695 } ,
686696 [ setSelectedNodeIds ]
687697 ) ;
688698
699+ // Track mouse position for node placement
700+ useEffect ( ( ) => {
701+ const handleMouseMove = ( e : MouseEvent ) => {
702+ setLastMousePosition ( { x : e . clientX , y : e . clientY } ) ;
703+ } ;
704+ window . addEventListener ( "mousemove" , handleMouseMove ) ;
705+ return ( ) => {
706+ window . removeEventListener ( "mousemove" , handleMouseMove ) ;
707+ } ;
708+ } , [ ] ) ;
709+
689710 useEffect ( ( ) => {
690711 const handleKeyDown = ( e : KeyboardEvent ) => {
691712 //save shortcut
@@ -764,7 +785,6 @@ export function LearningMapEditor({
764785 handleZoomToSelection ( ) ;
765786 }
766787
767- console . log ( e ) ;
768788 // Toggle grid shortcut
769789 if ( ( e . ctrlKey || e . metaKey ) && e . code === "Backslash" ) {
770790 e . preventDefault ( ) ;
@@ -790,6 +810,11 @@ export function LearningMapEditor({
790810 e . preventDefault ( ) ;
791811 handlePaste ( ) ;
792812 }
813+ // Select all shortcut
814+ if ( ( e . ctrlKey || e . metaKey ) && e . key . toLowerCase ( ) === 'a' && ! e . shiftKey ) {
815+ e . preventDefault ( ) ;
816+ handleSelectAll ( ) ;
817+ }
793818
794819 // Dismiss with Escape
795820 if ( helpOpen && e . key === 'Escape' ) {
@@ -802,7 +827,7 @@ export function LearningMapEditor({
802827 } ;
803828 } , [ handleSave , handleUndo , handleRedo , addNewNode , helpOpen , setHelpOpen , togglePreviewMode , toggleDebugMode ,
804829 handleZoomIn , handleZoomOut , handleResetZoom , handleFitView , handleZoomToSelection , handleToggleGrid ,
805- handleResetMap , handleCut , handleCopy , handlePaste ] ) ;
830+ handleResetMap , handleCut , handleCopy , handlePaste , handleSelectAll ] ) ;
806831
807832 return (
808833 < >
@@ -822,6 +847,7 @@ export function LearningMapEditor({
822847 onDownlad = { handleDownload }
823848 onOpen = { handleOpen }
824849 onShare = { handleShare }
850+ onReset = { handleResetMap }
825851 language = { effectiveLanguage }
826852 />
827853 { previewMode && < LearningMap roadmapData = { roadmapState } language = { effectiveLanguage } /> }
0 commit comments