diff --git a/apps/obsidian/src/components/canvas/utils/convertToDiscourseNode.ts b/apps/obsidian/src/components/canvas/utils/convertToDiscourseNode.ts index dac54ff07..16d6fd738 100644 --- a/apps/obsidian/src/components/canvas/utils/convertToDiscourseNode.ts +++ b/apps/obsidian/src/components/canvas/utils/convertToDiscourseNode.ts @@ -57,13 +57,13 @@ export const convertToDiscourseNode = async ( } }; -const convertTextShapeToNode = async ({ +const convertTextShapeToNode = ({ editor, shape, nodeType, plugin, canvasFile, -}: ConvertToDiscourseNodeArgs): Promise => { +}: ConvertToDiscourseNodeArgs): TLShapeId | undefined => { const text = renderPlaintextFromRichText( editor, (shape as TLTextShape).props.richText, @@ -79,31 +79,54 @@ const convertTextShapeToNode = async ({ return undefined; } - const createdFile = await createDiscourseNodeFile({ + let shapeId: TLShapeId | undefined; + + const modal = new ModifyNodeModal(plugin.app, { + nodeTypes: plugin.settings.nodeTypes, plugin, - nodeType, - text: text.trim(), - }); + initialNodeType: nodeType, + initialTitle: text.trim(), + onSubmit: async ({ + nodeType: selectedNodeType, + title, + selectedExistingNode, + }) => { + try { + const file = + selectedExistingNode ?? + (await createDiscourseNodeFile({ + plugin, + nodeType: selectedNodeType, + text: title, + })); + + if (!file) { + throw new Error("Failed to create discourse node file"); + } - if (!createdFile) { - throw new Error("Failed to create discourse node file"); - } + shapeId = await createDiscourseNodeShape({ + editor, + shape, + createdFile: file, + nodeType: selectedNodeType, + plugin, + canvasFile, + }); - const shapeId = await createDiscourseNodeShape({ - editor, - shape, - createdFile, - nodeType, - plugin, - canvasFile, + showToast({ + severity: "success", + title: "Shape Converted", + description: `Converted text to ${selectedNodeType.name}`, + targetCanvasId: canvasFile.path, + }); + } catch (error) { + console.error("Error creating node from text:", error); + throw error; + } + }, }); - showToast({ - severity: "success", - title: "Shape Converted", - description: `Converted text to ${nodeType.name}`, - targetCanvasId: canvasFile.path, - }); + modal.open(); return shapeId; }; @@ -129,28 +152,35 @@ const convertImageShapeToNode = async ({ plugin, initialNodeType: nodeType, initialTitle: "", - onSubmit: async ({ nodeType: selectedNodeType, title }) => { + onSubmit: async ({ + nodeType: selectedNodeType, + title, + selectedExistingNode, + }) => { try { - const createdFile = await createDiscourseNodeFile({ - plugin, - nodeType: selectedNodeType, - text: title, - }); - - if (!createdFile) { + const file = + selectedExistingNode ?? + (await createDiscourseNodeFile({ + plugin, + nodeType: selectedNodeType, + text: title, + })); + + if (!file) { throw new Error("Failed to create discourse node file"); } let imageSrc: string | undefined; if (imageFile) { - await embedImageInNode(createdFile, imageFile, plugin); + await embedImageInNode(file, imageFile, plugin); + imageSrc = plugin.app.vault.getResourcePath(imageFile); } shapeId = await createDiscourseNodeShape({ editor, shape, - createdFile, + createdFile: file, nodeType: selectedNodeType, plugin, canvasFile, diff --git a/apps/website/content/obsidian/core-features/canvas.md b/apps/website/content/obsidian/core-features/canvas.md index 9334e9295..bb3fab9bb 100644 --- a/apps/website/content/obsidian/core-features/canvas.md +++ b/apps/website/content/obsidian/core-features/canvas.md @@ -47,6 +47,15 @@ Or click on the canvas icon at the top right corner ![Create discourse node](/docs/obsidian/create-discourse-node.gif) +### Converting text and image shapes into discourse nodes + +You can convert a tldraw text or image shape into a discourse node directly from the canvas: + +1. Right-click on a text or image shape +2. Choose a node type from the "Convert to" submenu +3. A modal opens pre-filled with the text content (or an empty title for images) — edit the title if needed +4. Click "Confirm" to create the discourse node; the original shape is replaced + ### Adding existing nodes **Using node search**