Skip to content

Commit ac9588e

Browse files
authored
Merge pull request #21 from TryShape/issue-14-add-export-shape
Issue 14 add export shape
2 parents 4049c6c + a785fec commit ac9588e

7 files changed

Lines changed: 324 additions & 36 deletions

File tree

components/core/App.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ const App = (props) => {
6464
width={300}
6565
/>
6666
) : (
67-
<ShapeList data={ data } />
67+
<ShapeList {...props} data={ data } />
6868
)}
6969
</>
7070
);

components/core/ExportShape.js

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
import React, { useState, useEffect } from "react";
2+
3+
// dynamic from Next.js
4+
import dynamic from "next/dynamic";
5+
6+
// modal
7+
import Modal from "react-bootstrap/Modal";
8+
9+
// button
10+
import Button from "react-bootstrap/Button";
11+
12+
// Clip-Path
13+
const Shape = dynamic(import("react-clip-path"), { ssr: false });
14+
15+
// Toast
16+
import toast from "react-hot-toast";
17+
18+
// html-to-image
19+
import { toPng, toJpeg, toSvg, toCanvas } from "html-to-image";
20+
21+
// downloadjs
22+
import download from "downloadjs";
23+
24+
// misc utilities
25+
import { getShapeId } from "../../utils/misc";
26+
27+
// Radios
28+
import { Radios } from "..";
29+
30+
// Component
31+
const ExportShape = ({ show, setShow, shape }) => {
32+
console.log({ shape });
33+
34+
// state object to hold the export data
35+
const [exportData, setExportData] = useState();
36+
const [loaded, setLoaded] = useState(false);
37+
38+
useEffect(() => {
39+
setExportData({
40+
'name': shape.name,
41+
'type': 'png',
42+
'width': '300',
43+
'height': '300',
44+
'backgroundColor': shape.backgroundColor
45+
});
46+
setLoaded(true);
47+
}, [show])
48+
49+
// Handles the input changes and update
50+
// the state object
51+
const handleChange = (evt) => {
52+
evt.preventDefault();
53+
54+
const name = evt.target.name;
55+
let value =
56+
evt.target.type === "number"
57+
? evt.target.valueAsNumber
58+
: evt.target.value;
59+
60+
if (value < 0) {
61+
return;
62+
}
63+
64+
if (Number.isNaN(value)) {
65+
value = "";
66+
}
67+
68+
setExportData({
69+
...exportData,
70+
[name]: value
71+
});
72+
73+
console.log({exportData});
74+
};
75+
76+
// Export method
77+
const doExport = (id, name) => {
78+
console.log(`Save as ${exportData.type}`);
79+
switch (exportData.type) {
80+
case "png":
81+
exportAsPNG(id, name);
82+
break;
83+
case "jpeg":
84+
exportAsJPEG(id, name);
85+
break;
86+
case "svg":
87+
exportAsSVG(id, name);
88+
break;
89+
default:
90+
exportAsPNG(id, name);
91+
break;
92+
}
93+
};
94+
95+
const exportAsPNG = (id, name) => {
96+
toPng(document.getElementById(id)).then(function (dataUrl) {
97+
console.log(dataUrl);
98+
download(dataUrl, `${name}.png`);
99+
toast.success(`${name}.png has been exported sucessfully!`);
100+
});
101+
};
102+
103+
const exportAsJPEG = (id, name) => {
104+
toJpeg(document.getElementById(id), { quality: 0.95 }).then(function (
105+
dataUrl
106+
) {
107+
console.log(dataUrl);
108+
download(dataUrl, `${name}.jpeg`);
109+
toast.success(`${name}.jpeg has been exported sucessfully!`);
110+
});
111+
};
112+
const exportAsSVG = (id, name) => {
113+
toSvg(document.getElementById(id)).then(function (dataUrl) {
114+
console.log(dataUrl);
115+
download(dataUrl, `${name}.svg`);
116+
toast.success(`${name}.svg has been exported sucessfully!`);
117+
});
118+
};
119+
return (
120+
<>
121+
{loaded && (
122+
<Modal
123+
size="lg"
124+
aria-labelledby="contained-modal-title-vcenter"
125+
show={show}
126+
onHide={() => setShow(false)}
127+
centered
128+
>
129+
<Modal.Header closeButton>
130+
<Modal.Title>Export {exportData.name} </Modal.Title>
131+
</Modal.Header>
132+
<Modal.Body>
133+
<div>
134+
<Shape
135+
name={exportData.name}
136+
formula={shape.formula}
137+
width={`${exportData.width}px`}
138+
height={`${exportData.height}px`}
139+
backgroundColor={exportData.backgroundColor}
140+
id={getShapeId(exportData.name, true)}
141+
/>
142+
</div>
143+
<form>
144+
<div>
145+
<label htmlFor="export-name">Name</label>
146+
<input
147+
type="text"
148+
name="name"
149+
id="export-name"
150+
value={exportData.name}
151+
onChange={handleChange} />
152+
</div>
153+
154+
<div>
155+
<label htmlFor="export-color">Color</label>
156+
<input
157+
type="color"
158+
name="backgroundColor"
159+
id="export-color"
160+
value={exportData.backgroundColor}
161+
onChange={handleChange} />
162+
</div>
163+
164+
<div>
165+
<label htmlFor="export-width">Set a width(in px)</label>
166+
<input
167+
type="range"
168+
min="100"
169+
max="700"
170+
value={exportData.width}
171+
id="export-width"
172+
name="width"
173+
onChange={handleChange} />
174+
175+
<label htmlFor="export-height">Set a height(in px)</label>
176+
<input
177+
type="range"
178+
min="100"
179+
max="700"
180+
value={exportData.height}
181+
id="export-height"
182+
name="height"
183+
onChange={handleChange} />
184+
</div>
185+
186+
<div>
187+
<Radios
188+
groupName="type"
189+
heading="Export as:"
190+
options={[
191+
{ value: "png", displayValue: "png" },
192+
{ value: "jpeg", displayValue: "jpeg" },
193+
{ value: "svg", displayValue: "svg" },
194+
]}
195+
selectedOption={exportData.type}
196+
onValueChange={handleChange}
197+
/>
198+
</div>
199+
</form>
200+
</Modal.Body>
201+
202+
<Modal.Footer>
203+
<Button
204+
onClick={() => doExport(getShapeId(exportData.name, true), exportData.name)}
205+
>
206+
Export
207+
</Button>
208+
</Modal.Footer>
209+
</Modal>
210+
)}
211+
</>
212+
);
213+
};
214+
215+
export default ExportShape;

components/core/Landing.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ const Landing = ({ setOpen, user, setUser }) => {
1515

1616
return(
1717
<div>
18-
<Header setOpen={setOpen} user={user} setUser={setUser} />
1918
<div>
2019
<h1>Landing</h1>
2120
</div>

components/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
export { default as App } from "./core/App";
33
export { default as Landing } from "./core/Landing";
44
export { default as SignInModal } from "./core/SignInModal";
5+
export { default as ExportShape } from "./core/ExportShape";
56

67
// utils
78
export { default as Header } from "./utils/Header";
8-
export { default as ShapeList } from './utils/ShapeList';
9+
export { default as ShapeList } from './utils/ShapeList';
10+
export { default as Radios } from './utils/Radios';

components/utils/Radios.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import React from 'react';
2+
import styled from 'styled-components';
3+
4+
const RadioGroup = styled.div`
5+
margin-top: 5px;
6+
`;
7+
8+
const Radio = styled.span`
9+
margin-right: 24px;
10+
`;
11+
12+
const RadioBtn = props => {
13+
const value = props.value;
14+
const groupName = props.groupName;
15+
const displayValue = props.displayValue;
16+
const onValueChange = props.onValueChange;
17+
const selectedOption = props.selectedOption;
18+
19+
return(
20+
<Radio className="form-radio">
21+
<label>
22+
<input
23+
style={{marginRight: '2px'}}
24+
type="radio"
25+
name={ groupName }
26+
value={ value }
27+
checked={ selectedOption === value }
28+
onChange={ onValueChange }
29+
/>
30+
<span>{ displayValue }</span>
31+
</label>
32+
</Radio>
33+
)
34+
}
35+
36+
const Radios = props => {
37+
38+
const groupName = props.groupName;
39+
const options = props.options;
40+
const onValueChange = props.onValueChange;
41+
const selectedOption = props.selectedOption;
42+
const heading = props.heading;
43+
44+
return(
45+
<>
46+
{ heading && <span>{ heading }</span> } {' '}
47+
<RadioGroup className="form-radio-group">
48+
{
49+
options && options.length > 0 && options.map((option, index) => (
50+
<RadioBtn
51+
key={ index }
52+
groupName={ groupName }
53+
value={ option.value }
54+
displayValue={ option.displayValue }
55+
selectedOption={ selectedOption }
56+
onValueChange={ onValueChange } />
57+
))
58+
}
59+
</RadioGroup>
60+
</>
61+
)
62+
}
63+
64+
export default Radios;

0 commit comments

Comments
 (0)