diff --git a/editor/src/messages/portfolio/portfolio_message.rs b/editor/src/messages/portfolio/portfolio_message.rs index 763d73b629..5faa6c28a5 100644 --- a/editor/src/messages/portfolio/portfolio_message.rs +++ b/editor/src/messages/portfolio/portfolio_message.rs @@ -108,6 +108,10 @@ pub enum PortfolioMessage { mouse: Option<(f64, f64)>, parent_and_insert_index: Option<(LayerNodeIdentifier, usize)>, }, + ImportSvgAsNewDocument { + name: Option, + svg: String, + }, PrevDocument, SetActivePanel { panel: PanelType, diff --git a/editor/src/messages/portfolio/portfolio_message_handler.rs b/editor/src/messages/portfolio/portfolio_message_handler.rs index 4e70ceb68c..03126b67e5 100644 --- a/editor/src/messages/portfolio/portfolio_message_handler.rs +++ b/editor/src/messages/portfolio/portfolio_message_handler.rs @@ -865,6 +865,21 @@ impl MessageHandler> for Portfolio }); } } + PortfolioMessage::ImportSvgAsNewDocument { name, svg } => { + // Create a new document explicitly + responses.add(PortfolioMessage::NewDocumentWithName { name: name.clone().unwrap_or(DEFAULT_DOCUMENT_NAME.into()) }); + + responses.add(DocumentMessage::PasteSvg { + name, + svg, + mouse: None, + parent_and_insert_index: None, + }); + + // After graph runs, wrap contents in artboard and zoom to fit + responses.add(DeferMessage::AfterGraphRun { messages: vec![DocumentMessage::WrapContentInArtboard { place_artboard_at_origin: true }.into()] }); + responses.add(DeferMessage::AfterNavigationReady { messages: vec![DocumentMessage::ZoomCanvasToFitAll.into()] }); + } PortfolioMessage::PrevDocument => { if let Some(active_document_id) = self.active_document_id { let len = self.document_ids.len(); diff --git a/frontend/src/components/panels/Document.svelte b/frontend/src/components/panels/Document.svelte index c259c9ba74..cbc6133f7f 100644 --- a/frontend/src/components/panels/Document.svelte +++ b/frontend/src/components/panels/Document.svelte @@ -23,6 +23,8 @@ import { updateBoundsOfViewports } from "@graphite/utility-functions/viewports"; import EyedropperPreview, { ZOOM_WINDOW_DIMENSIONS } from "@graphite/components/floating-menus/EyedropperPreview.svelte"; + import MenuList from "@graphite/components/floating-menus/MenuList.svelte"; + import FloatingMenu from "@graphite/components/layout/FloatingMenu.svelte"; import LayoutCol from "@graphite/components/layout/LayoutCol.svelte"; import LayoutRow from "@graphite/components/layout/LayoutRow.svelte"; import Graph from "@graphite/components/views/Graph.svelte"; @@ -94,6 +96,17 @@ $: canvasWidthScaledRoundedToEven = canvasWidthScaled && (canvasWidthScaled % 2 === 1 ? canvasWidthScaled + 1 : canvasWidthScaled); $: canvasHeightScaledRoundedToEven = canvasHeightScaled && (canvasHeightScaled % 2 === 1 ? canvasHeightScaled + 1 : canvasHeightScaled); + // Menu shown when an SVG is dropped on to the canvas + let svgDropMenu: { open: boolean; x: number; y: number; name: string; svg: string } = { open: false, x: 0, y: 0, name: "", svg: "" }; + + function importSvgAsNewDocument(name: string, svg: string) { + const handleWithImport = editor.handle as unknown as { importSvgAsNewDocument?: (name: string | undefined, svg: string) => void }; + handleWithImport.importSvgAsNewDocument?.(name, svg); + } + function importSvgAsLayerAt(x: number, y: number, name: string, svg: string) { + editor.handle.pasteSvg(name, svg, x, y); + } + $: toolShelfTotalToolsAndSeparators = ((layoutGroup) => { if (!isWidgetSpanRow(layoutGroup)) return undefined; @@ -141,7 +154,13 @@ if (file.type.includes("svg")) { const svgData = await file.text(); - editor.handle.pasteSvg(file.name, svgData, x, y); + // Menu shown at drop location + if (typeof x === "number" && typeof y === "number") { + svgDropMenu = { open: true, x, y, name: file.name, svg: svgData }; + } else { + //Paste normally + editor.handle.pasteSvg(file.name, svgData, x, y); + } return; } @@ -597,6 +616,34 @@ +{#if svgDropMenu.open} + + { + importSvgAsLayerAt(svgDropMenu.x, svgDropMenu.y, svgDropMenu.name, svgDropMenu.svg); + svgDropMenu.open = false; + }, + }, + { + label: "Import as New Document", + value: "document", + action: () => { + importSvgAsNewDocument(svgDropMenu.name, svgDropMenu.svg); + svgDropMenu.open = false; + }, + }, + ], + ]} + /> + +{/if} +