From 8e34d6b72afbf50e2b10302da601a022110dc8a5 Mon Sep 17 00:00:00 2001 From: Siklos Date: Fri, 5 Aug 2022 12:10:58 -0400 Subject: [PATCH] Implement export as SVG (#14) Reviewed-on: https://git.siklos-chaneru.duckdns.org/Siklos/svg-layout-designer-react/pulls/14 --- .../FloatingButton/FloatingButton.tsx | 30 ++++++++++++- src/Components/SVG/SVG.tsx | 44 ++++++++++--------- src/Editor.tsx | 43 ++++++++++++++---- src/index.scss | 5 ++- 4 files changed, 90 insertions(+), 32 deletions(-) diff --git a/src/Components/FloatingButton/FloatingButton.tsx b/src/Components/FloatingButton/FloatingButton.tsx index fb5fc1c..544c2bd 100644 --- a/src/Components/FloatingButton/FloatingButton.tsx +++ b/src/Components/FloatingButton/FloatingButton.tsx @@ -1,10 +1,38 @@ import * as React from 'react'; +import { MenuIcon, XIcon } from '@heroicons/react/outline'; interface IFloatingButtonProps { + children: React.ReactNode[] | React.ReactNode + className: string } +const toggleState = ( + isHidden: boolean, + setHidden: React.Dispatch> +) => { + setHidden(!isHidden); +}; + const FloatingButton: React.FC = (props: IFloatingButtonProps) => { - return <>; + const [isHidden, setHidden] = React.useState(true); + const buttonListClasses = isHidden ? 'invisible opacity-0' : 'visible opacity-100'; + const icon = isHidden + ? + : ; + + return ( +
+
+ { props.children } +
+ +
); }; export default FloatingButton; diff --git a/src/Components/SVG/SVG.tsx b/src/Components/SVG/SVG.tsx index c11e39b..bf8704b 100644 --- a/src/Components/SVG/SVG.tsx +++ b/src/Components/SVG/SVG.tsx @@ -18,7 +18,7 @@ interface ISVGState { export class SVG extends React.PureComponent { public state: ISVGState; - public svg: React.RefObject; + public static ID = 'svg'; constructor(props: ISVGProps) { super(props); @@ -29,7 +29,6 @@ export class SVG extends React.PureComponent { } as Value, tool: TOOL_PAN }; - this.svg = React.createRef(); } render() { @@ -49,25 +48,28 @@ export class SVG extends React.PureComponent { } return ( - this.setState({ value })} - tool={this.state.tool} onChangeTool={tool => this.setState({ tool })} - miniatureProps={{ - position: 'left', - background: '#616264', - width: window.innerWidth - 12, - height: 120 - }} - > - - { children } - - - +
+ this.setState({ value })} + tool={this.state.tool} onChangeTool={tool => this.setState({ tool })} + miniatureProps={{ + position: 'left', + background: '#616264', + width: window.innerWidth - 12, + height: 120 + }} + > + + { children } + + + +
+ ); }; } diff --git a/src/Editor.tsx b/src/Editor.tsx index 482b91a..89c38aa 100644 --- a/src/Editor.tsx +++ b/src/Editor.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { UploadIcon } from '@heroicons/react/outline'; +import { UploadIcon, PhotographIcon } from '@heroicons/react/outline'; import './Editor.scss'; import Sidebar from './Components/Sidebar/Sidebar'; import { ElementsSidebar } from './Components/ElementsSidebar/ElementsSidebar'; @@ -9,6 +9,7 @@ import { History } from './Components/History/History'; import { ContainerModel, findContainerById, IContainerModel, MakeIterator } from './Interfaces/ContainerModel'; import Properties from './Interfaces/Properties'; import { IHistoryState } from './App'; +import FloatingButton from './Components/FloatingButton/FloatingButton'; interface IEditorProps { configuration: Configuration, @@ -257,7 +258,7 @@ class Editor extends React.Component { } as IEditorState); } - public SaveEditor() { + public SaveEditorAsJSON() { const exportName = 'state'; const spaces = import.meta.env.DEV ? 4 : 0; const data = JSON.stringify(this.state, getCircularReplacer(), spaces); @@ -270,6 +271,20 @@ class Editor extends React.Component { downloadAnchorNode.remove(); } + public SaveEditorAsSVG() { + const svgWrapper = document.getElementById(SVG.ID) as HTMLElement; + const svg = svgWrapper.querySelector('svg') as SVGSVGElement; + const preface = '\r\n'; + const svgBlob = new Blob([preface, svg.outerHTML], { type: 'image/svg+xml;charset=utf-8' }); + const svgUrl = URL.createObjectURL(svgBlob); + const downloadLink = document.createElement('a'); + downloadLink.href = svgUrl; + downloadLink.download = 'newesttree.svg'; + document.body.appendChild(downloadLink); + downloadLink.click(); + document.body.removeChild(downloadLink); + } + /** * Render the application * @returns {JSX.Element} Rendered JSX element @@ -334,13 +349,23 @@ class Editor extends React.Component { > { current.MainContainer } - + + + + + ); } diff --git a/src/index.scss b/src/index.scss index c7e0d50..ad410c8 100644 --- a/src/index.scss +++ b/src/index.scss @@ -10,9 +10,12 @@ @apply pl-6 pr-6 pt-2 pb-2 w-full } .close-button { - @apply transition-all w-full h-auto p-4 flex + @apply transition-all w-full h-auto p-4 flex } .mainmenu-btn { @apply transition-all bg-blue-100 hover:bg-blue-200 text-blue-700 text-lg font-semibold p-8 rounded-lg } + .floating-btn { + @apply h-full w-full text-white align-middle items-center justify-center + } } \ No newline at end of file