diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 0d36402..0295583 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -19,6 +19,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-scripts": "5.0.1", + "react-svg": "^16.1.19", "web-vitals": "^2.1.4" } }, @@ -4000,6 +4001,16 @@ "url": "https://github.com/sponsors/gregberge" } }, + "node_modules/@tanem/svg-injector": { + "version": "10.1.60", + "resolved": "https://registry.npmjs.org/@tanem/svg-injector/-/svg-injector-10.1.60.tgz", + "integrity": "sha512-yzdF0f7TZI7MrMieJLu5VYEJuL0WneFCabLvBfpNWDoWikzQPW8V9tpEqHa2A4kKJDiXUzsIoqtPEvGj9xsPgQ==", + "dependencies": { + "@babel/runtime": "^7.22.5", + "content-type": "^1.0.5", + "tslib": "^2.6.0" + } + }, "node_modules/@testing-library/dom": { "version": "9.3.1", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.1.tgz", @@ -15092,6 +15103,21 @@ } } }, + "node_modules/react-svg": { + "version": "16.1.19", + "resolved": "https://registry.npmjs.org/react-svg/-/react-svg-16.1.19.tgz", + "integrity": "sha512-WchBqQ8LooWpEp3JM7F9cJxPzrMLmd2fTD5NbzkDHeJAMuqUeD9QtOEDNPgRstPeh0aMEV2j8WwNXSXFRMuy3g==", + "dependencies": { + "@babel/runtime": "^7.22.6", + "@tanem/svg-injector": "^10.1.60", + "@types/prop-types": "^15.7.5", + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", diff --git a/frontend/package.json b/frontend/package.json index ce67c8d..f314d7e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -14,6 +14,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-scripts": "5.0.1", + "react-svg": "^16.1.19", "web-vitals": "^2.1.4" }, "scripts": { diff --git a/frontend/src/App.js b/frontend/src/App.js index 7e778bb..065cad3 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1,4 +1,6 @@ -import React, { useState } from 'react'; +import React, { useRef, useState } from 'react'; +import { renderToString } from 'react-dom/server'; +import { ReactSVG } from 'react-svg'; import { Button, TextField, Box, CircularProgress, AppBar, Toolbar, Typography, Container, Grid, Paper, Link, IconButton } from '@mui/material'; import LinkedInIcon from '@mui/icons-material/LinkedIn'; import TwitterIcon from '@mui/icons-material/Twitter'; @@ -41,17 +43,18 @@ function App() { const [description, setDescription] = useState(''); const [isLoading, setIsLoading] = useState(false); const [svgData, setSvgData] = useState(null); + const svgRef = useRef(null); const handleDesignClick = async () => { setIsLoading(true); try { - const response = await axios.post('/call_prompt', + const response = await axios.post('/call_prompt', { input: description, }, { - headers: {"Content-Type": "application/json"}, + headers: { "Content-Type": "application/json" }, redirect: 'follow' } ); @@ -66,9 +69,28 @@ function App() { }; // Creating a Blob from SVG data - const svgBlob = new Blob([svgData], {type: 'image/svg+xml;charset=utf-8'}); + const svgBlob = new Blob([svgData], { type: 'image/svg+xml;charset=utf-8' }); const svgUrl = URL.createObjectURL(svgBlob); + const downloadPNG = () => { + const svgString = renderToString(svgRef.current); + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + const img = new Image(); + + img.src = `data:image/svg+xml;base64,${btoa(svgString)}`; + img.onload = () => { + canvas.width = img.width; + canvas.height = img.height; + ctx.drawImage(img, 0, 0); + const pngUrl = canvas.toDataURL(); + const link = document.createElement('a'); + link.href = pngUrl; + link.download = 'diagram.png'; + link.click(); + }; + }; + return ( - {isLoading ? :
} + {isLoading ? : } @@ -121,9 +143,14 @@ function App() { {!isLoading && svgData && ( - - Download Diagram - + <> + + Download Diagram (SVG) + + + )}