이정민

Merge branch 'feat/web' into develop

......@@ -9,6 +9,7 @@
"@testing-library/user-event": "^12.1.10",
"@toast-ui/react-image-editor": "3.14.2",
"@types/fabric": "^4.2.5",
"axios": "^0.21.1",
"fabric": "^4.4.0",
"next": "^10.0.5",
"react": "^17.0.2",
......
import axios from "axios";
const baseURL = "https://9davbjzey4.execute-api.ap-northeast-2.amazonaws.com";
export const postGif = async (formData) => {
console.log("file", formData);
const { data } = await axios.post(baseURL, formData);
return data;
};
export const getGif = async (id) => {
const { data } = await axios.get(baseURL, {
params: {
id: id,
},
});
return data;
};
import { useEffect, useRef, useState } from "react";
import { fabric } from "fabric";
import styled from "styled-components";
import { GifGenerator } from "gif-generator/src";
import ImageEditor from "@toast-ui/react-image-editor";
import TuiImageEditor from "tui-image-editor";
import "gif-generator/dist/gif-generator";
import { postGif } from "api";
declare global {
interface Window {
GifGenerator: any;
}
}
const GifEditor = ({ previewURL }) => {
const [canvas, setCanvas] = useState<HTMLCanvasElement>();
const [gifGenerator, setGifGenerator] = useState(null);
const [imageEditor, setImageEditor] = useState(null);
const rootEl = useRef();
const [download, setDownload] = useState(null);
const [blob, setBlob] = useState(null);
const [isMakeStarted, setIsMakeStarted] = useState(false);
const [isUploadLoading, setIsUploadLoading] = useState(false);
const [viewLink, setViewLink] = useState(null);
useEffect(() => {
if (window) {
setCanvas(
document.getElementsByClassName(
"tui-image-editor-container"
)[0] as HTMLCanvasElement
setImageEditor(
new TuiImageEditor(rootEl.current, {
includeUI: {
loadImage: {
path: previewURL,
name: "SampleImage",
},
uiSize: {
width: "100%",
height: "600px",
},
menu: ["draw", "text"],
menuBarPosition: "bottom",
},
cssMaxWidth: 500,
cssMaxHeight: 700,
usageStatistics: false,
})
);
}
}, []);
console.log(
"asdf",
document.getElementsByClassName("tui-image-editor-container")
);
console.log("canvas", canvas);
console.log('useref',useRef.arguments)
useEffect(()=>{
if(canvas)setGifGenerator(new GifGenerator(canvas._graphics.getCanvas()));
}, [canvas])
// useEffect(() => {
// // const img = lowerCanvas?.toDataURL("image/png");
// // const uploaded = document.getElementById("image");
// // console.log(uploaded);
// // let w = window.open();
// // if (w?.window) w.document.body.innerHTML = "<img src='" + img + "'>";
// const image = new Image();
// // image.onload = function () {
// // lowerCanvas.width = uploaded.clientWidth;
// // lowerCanvas.height = uploaded.clientHeight;
// // lowerCanvas?.getContext("2d").drawImage(image, 0, 0);
// // };
// image.src = previewURL;
// console.log("canvascontext", canvas?.getContext);
// if (canvas?.getContext) {
// console.log('왜안돼')
// image.onload = function () {
// canvas.width = 1000;
// canvas.height = 572;
// canvas?.getContext("2d").drawImage(image, 0, 0);
// };
// // console.log(canvas.getContext("2d"));
// }
// }, [canvas]);
useEffect(() => {
if (imageEditor) {
console.log(imageEditor._graphics.getCanvas().getObjects());
}
}, [imageEditor]);
const render = () => {
const makeGif = () => {
setIsMakeStarted(true);
const gifGenerator = new window.GifGenerator(
imageEditor._graphics.getCanvas()
);
gifGenerator.make().then(
(blob) => {
window.open(window.URL.createObjectURL(blob));
setBlob(blob);
setDownload(window.URL.createObjectURL(blob));
},
(error) => {
alert(error);
......@@ -64,44 +68,58 @@ const GifEditor = ({ previewURL }) => {
);
};
const handleUpload = async () => {
setIsUploadLoading(true);
const file = new File([blob], "new_gif.gif");
const formData = new FormData();
formData.append("gif", file);
const res = await postGif(formData);
console.log(res);
setIsUploadLoading(false);
setViewLink(
`https://gif-generator.s3.ap-northeast-2.amazonaws.com//gif/${res.id}.gif`
);
};
return (
<Container>
<div onClick={render} className="upload">
Save
<>
<Wrapper>
{((isMakeStarted && !download) || isUploadLoading) && (
<>
<div className="background" />
<div className="download">loading...</div>
</>
)}
{!isUploadLoading && viewLink && (
<div className="download" style={{ zIndex: 200 }}>
<a href={viewLink}>{viewLink}</a>
</div>
<ImageEditor
includeUI={{
loadImage: {
path: previewURL,
name: "SampleImage",
},
menu: ["draw", "text"],
initMenu: "draw",
uiSize: {
width: "100%",
height: "600px",
},
menuBarPosition: "bottom",
}}
cssMaxHeight={500}
cssMaxWidth={700}
selectionStyle={{
cornerSize: 20,
rotatingPointOffset: 70,
}}
usageStatistics={true}
/>
<div className="alert">Please select a photo.</div>
</Container>
// <Container>
// <ImgBox>
// <canvas id="gif-canvas" />
// </ImgBox>
// </Container>
)}
{download && !isUploadLoading && (
<>
<div className="background" />
<div className="download">
<div className="download__btn">
<a href={download} download="new_gif.gif">
Download a File
</a>
</div>
<div className="download__btn">
<div onClick={handleUpload}>Upload to Server</div>
</div>
</div>
</>
)}
<div onClick={makeGif} className="make">
Make a Gif
</div>
<div ref={rootEl} />
</Wrapper>
</>
);
};
const Container = styled.div`
const Wrapper = styled.div`
position: fixed;
width: 90%;
top: 10rem;
......@@ -110,7 +128,11 @@ const Container = styled.div`
display: flex;
flex-direction: column;
align-items: center;
.upload {
a {
color: black;
text-decoration: none;
}
.make {
font: 800 11.5px Arial;
position: absolute;
right: 0;
......@@ -127,11 +149,30 @@ const Container = styled.div`
justify-content: center;
cursor: pointer;
}
.alert {
.background {
position: fixed;
border-radius: 0.5rem;
transition: 1s;
top: 7rem;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background-color: black;
opacity: 0.7;
z-index: 100;
}
.download {
position: absolute;
top: 15rem;
z-index: 100;
display: flex;
background-color: white;
padding: 1.5rem 2rem;
border-radius: 2rem;
&__btn {
cursor: pointer;
:last-child {
margin-left: 1rem;
}
}
}
.tui-image-editor-container {
border-radius: 1.5rem;
......@@ -143,6 +184,9 @@ const Container = styled.div`
.tui-image-editor-header-logo {
display: none;
}
.tui-image-editor-header-buttons {
display: none;
}
`;
export default GifEditor;
......
import dynamic from "next/dynamic";
import { useState } from "react";
import styled from "styled-components";
const ToastEditor = dynamic(() => import("components/ToastEditor"), {
ssr: false,
});
const Image = ({ previewURL, setPreviewURL }) => {
const [file, setFile] = useState(undefined);
// console.log("previewURL", previewURL);
// const uploadImage = (file) => {
// if (!file) {
// return;
// }
// };
// const selectImg = (e) => {
// const reader = new FileReader();
// const targetFile = e.target.files[0];
// setFile(targetFile);
// // uploadImage(targetFile);
// reader.onloadend = () => {
// setPreviewURL(reader.result);
// };
// reader.readAsDataURL(targetFile);
// };
// const [isEditorOpened, setIsEditorOpened] = useState(false);
// const handleEditor = () => {
// setIsEditorOpened(true);
// };
return (
<>
<Container>
<ImgBox>
{/* <div onClick={handleEditor}>asdf</div> */}
{/* {file === undefined ? ( */}
<>
{/* <div className="sub-flex">
<BlankBox />
<div>Click to add a photo</div>
<input
type="file"
style={{
position: "absolute",
top: 0,
paddingLeft: 0,
zIndex: 0,
width: "90%",
height: "100%",
border: "none",
cursor: "pointer",
outline: "none",
}}
onChange={selectImg}
/>
</div>
<div className="sub-flex">Open Image Editor</div> */}
</>
{/* ) : ( */}
<img
id="image"
alt={""}
style={{
objectFit: "cover",
display: "flex",
maxHeight: "90%",
maxWidth: "90%",
}}
src={previewURL as string}
/>
{/* )} */}
</ImgBox>
{/* <Menu /> */}
</Container>
{/* {isEditorOpened && <ToastEditor {...{ setPreviewURL, setIsImgAdded }} />} */}
</>
);
};
const Menu = () => {
return (
<div style={{ width: "15rem", marginLeft: "2rem" }}>
<Box />
<Box />
<Box />
<Box />
</div>
);
};
const Container = styled.div`
width: 100%;
display: flex;
justify-content: center;
margin-top: 10rem;
`;
const ImgBox = styled.div`
position: relative;
width: 90%;
/* height: 30rem; */
background-color: white;
box-shadow: ${({ theme }) => theme.boxShadow.normal};
border-radius: 2rem;
margin-top: 2rem;
display: flex;
align-items: center;
justify-content: center;
font-size: 1rem;
display: flex;
/* flex: 0.6; */
padding: 1rem 0;
/* .sub-flex {
position: relative;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
:first-child {
border-right: 1px solid ${({ theme }) => theme.color.gray};
}
} */
`;
const Box = styled.div`
width: 100%;
height: 10rem;
margin-top: 2rem;
border-radius: 1rem;
background-color: white;
box-shadow: ${({ theme }) => theme.boxShadow.normal};
`;
export default Image;
/// <reference path="react-image-editor.d.ts" />
import ImageEditor from "@toast-ui/react-image-editor";
import { useEffect, useState } from "react";
import { useState } from "react";
import styled from "styled-components";
import "tui-image-editor/dist/tui-image-editor.css";
import { GifGenerator } from "gif-generator/src/index";
const ToastEditor = ({ setPreviewURL, setIsImgAdded, setIsEditorOpened }) => {
// const [lowerCanvas, setLowerCanvas] = useState<HTMLCanvasElement>();
// const [upperCanvas, setUpperCanvas] = useState<HTMLCanvasElement>();
// // console.log(
// // document.getElementsByClassName("lower-canvas")[0]?.toDataURL("image/png")
// // );
// console.log("s");
// // const [upperCanvas, setUpperCanvas] = useState(
// // document.getElementsByClassName("upper-canvas ")[0]
// // );
// useEffect(() => {
// window?.addEventListener("click", () => {
// setLowerCanvas(
// document.getElementsByClassName("lower-canvas")[0] as HTMLCanvasElement
// );
// setUpperCanvas(
// document.getElementsByClassName("upper-canvas")[0] as HTMLCanvasElement
// );
// });
// }, []);
// useEffect(() => {
// const img = lowerCanvas?.toDataURL("image/png");
// const uploaded = document.getElementById("image");
// console.log(uploaded);
// // let w = window.open();
// // if (w?.window) w.document.body.innerHTML = "<img src='" + img + "'>";
// const image = new Image();
// // image.onload = function () {
// // lowerCanvas.width = uploaded.clientWidth;
// // lowerCanvas.height = uploaded.clientHeight;
// // lowerCanvas?.getContext("2d").drawImage(image, 0, 0);
// // };
// image.src = previewURL;
// console.log("b");
// if (lowerCanvas?.getContext&&upperCanvas?.getContext) {
// image.onload = function () {
// lowerCanvas.width = 1000;
// lowerCanvas.height = 572;
// upperCanvas.width = 1000;
// upperCanvas.height = 572;
// lowerCanvas?.getContext("2d").drawImage(image, 0, 0);
// };
// console.log(lowerCanvas.getContext("2d"));
// }
// }, [lowerCanvas?.toDataURL("image/png")]);
const [alertIsShown, setAlertIsShown] = useState(false);
const handleEnd = () => {
......@@ -76,43 +26,16 @@ const ToastEditor = ({ setPreviewURL, setIsImgAdded, setIsEditorOpened }) => {
}
};
// console.log('asdf',document
// .getElementsByClassName("tui-image-editor-container"))
// window.GifGenerator = GifGenerator;
// let gifGenerator;
// setTimeout(function () {
// gifGenerator = new GifGenerator(
// document
// .getElementsByClassName("tui-image-editor-container")
// ._graphics.getCanvas()
// );
// }, 1000);
// function render() {
// gifGenerator.make().then(
// (blob) => {
// window.open(window.URL.createObjectURL(blob));
// },
// (error) => {
// alert(error);
// }
// );
// }
return (
<Container>
<div onClick={handleEnd} className="upload">
Upload
<div onClick={handleEnd} className="move">
Move to Gif
</div>
<ImageEditor
includeUI={{
loadImage: {
// path: 'img/sampleImage.jpg',
name: "SampleImage",
},
// theme: myTheme,
initMenu: "filter",
uiSize: {
width: "100%",
height: "600px",
......@@ -143,7 +66,7 @@ const Container = styled.div`
display: flex;
flex-direction: column;
align-items: center;
.upload {
.move {
font: 800 11.5px Arial;
position: absolute;
right: 0;
......
......@@ -51,7 +51,7 @@ export class GifGenerator {
const objs = [];
fabricObjs.map((fabricObj) => {
if (fabricObj instanceof fabric.Path) {
if (fabricObj.path !== undefined) {
objs.push(new Component.Brush(fabricObj));
this.canvas.remove(fabricObj);
} else if (fabricObj.text !== undefined) {
......
import { useRouter } from "next/dist/client/router";
const Detail = () => {
const id = useRouter().query.id;
return (
<div>
<img
src={`https://9davbjzey4.execute-api.ap-northeast-2.amazonaws.com/?id=${id}`}
/>
</div>
);
};
export default Detail;
import Header from "components/Header";
import Image from "components/Image";
import styled from "styled-components";
import dynamic from "next/dynamic";
import { useState } from "react";
......
......@@ -1856,6 +1856,13 @@ axe-core@^4.0.2:
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.1.2.tgz#7cf783331320098bfbef620df3b3c770147bc224"
integrity sha512-V+Nq70NxKhYt89ArVcaNL9FDryB3vQOd+BFXZIfO3RP6rwtj+2yqqqdHEkacutglPaZLkJeuXKCjCJDMGPtPqg==
axios@^0.21.1:
version "0.21.1"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
dependencies:
follow-redirects "^1.10.0"
axobject-query@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
......@@ -3184,6 +3191,11 @@ flatted@^3.1.0:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.1.tgz#c4b489e80096d9df1dfc97c79871aea7c617c469"
integrity sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==
follow-redirects@^1.10.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.1.tgz#d9114ded0a1cfdd334e164e6662ad02bfd91ff43"
integrity sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==
foreach@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
......