Showing
30 changed files
with
1021 additions
and
0 deletions
.babelrc
0 → 100644
.browserlistrc.js
0 → 100644
1 | +export const browserslist = ["defaults"]; |
.gitignore
0 → 100644
1 | +# Config | ||
2 | +!config/default.json | ||
3 | +!config/development.json.sample | ||
4 | +config/*.json | ||
5 | + | ||
6 | +# Next | ||
7 | +.next | ||
8 | +out | ||
9 | + | ||
10 | +# Logs | ||
11 | +npm-debug.log* | ||
12 | + | ||
13 | +# NPM | ||
14 | +node_modules/ | ||
15 | + | ||
16 | +# Transpiled code | ||
17 | +dist | ||
18 | +out | ||
19 | +.out | ||
20 | + | ||
21 | +# Dev tools | ||
22 | +.DS_Store | ||
23 | +.vscode | ||
24 | +.idea | ||
25 | +*.swp | ||
26 | +*.bak | ||
27 | + | ||
28 | +node_modules.nosync/ | ||
29 | +*.env.* | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
.prettierrc
0 → 100644
gif-generator/.gitignore
0 → 100644
gif-generator/examples/tui/black-theme.js
0 → 100644
1 | +var blackTheme = { | ||
2 | + 'common.bi.image': 'https://uicdn.toast.com/toastui/img/tui-image-editor-bi.png', | ||
3 | + 'common.bisize.width': '251px', | ||
4 | + 'common.bisize.height': '21px', | ||
5 | + 'common.backgroundImage': 'none', | ||
6 | + 'common.backgroundColor': '#1e1e1e', | ||
7 | + 'common.border': '0px', | ||
8 | + | ||
9 | + // header | ||
10 | + 'header.backgroundImage': 'none', | ||
11 | + 'header.backgroundColor': 'transparent', | ||
12 | + 'header.border': '0px', | ||
13 | + | ||
14 | + // load button | ||
15 | + 'loadButton.backgroundColor': '#fff', | ||
16 | + 'loadButton.border': '1px solid #ddd', | ||
17 | + 'loadButton.color': '#222', | ||
18 | + 'loadButton.fontFamily': "'Noto Sans', sans-serif", | ||
19 | + 'loadButton.fontSize': '12px', | ||
20 | + | ||
21 | + // download button | ||
22 | + 'downloadButton.backgroundColor': '#fdba3b', | ||
23 | + 'downloadButton.border': '1px solid #fdba3b', | ||
24 | + 'downloadButton.color': '#fff', | ||
25 | + 'downloadButton.fontFamily': "'Noto Sans', sans-serif", | ||
26 | + 'downloadButton.fontSize': '12px', | ||
27 | + | ||
28 | + // main icons | ||
29 | + 'menu.normalIcon.color': '#8a8a8a', | ||
30 | + 'menu.activeIcon.color': '#555555', | ||
31 | + 'menu.disabledIcon.color': '#434343', | ||
32 | + 'menu.hoverIcon.color': '#e9e9e9', | ||
33 | + 'menu.iconSize.width': '24px', | ||
34 | + 'menu.iconSize.height': '24px', | ||
35 | + | ||
36 | + // submenu icons | ||
37 | + 'submenu.normalIcon.color': '#8a8a8a', | ||
38 | + 'submenu.activeIcon.color': '#e9e9e9', | ||
39 | + 'submenu.iconSize.width': '32px', | ||
40 | + 'submenu.iconSize.height': '32px', | ||
41 | + | ||
42 | + // submenu primary color | ||
43 | + 'submenu.backgroundColor': '#1e1e1e', | ||
44 | + 'submenu.partition.color': '#3c3c3c', | ||
45 | + | ||
46 | + // submenu labels | ||
47 | + 'submenu.normalLabel.color': '#8a8a8a', | ||
48 | + 'submenu.normalLabel.fontWeight': 'lighter', | ||
49 | + 'submenu.activeLabel.color': '#fff', | ||
50 | + 'submenu.activeLabel.fontWeight': 'lighter', | ||
51 | + | ||
52 | + // checkbox style | ||
53 | + 'checkbox.border': '0px', | ||
54 | + 'checkbox.backgroundColor': '#fff', | ||
55 | + | ||
56 | + // range style | ||
57 | + 'range.pointer.color': '#fff', | ||
58 | + 'range.bar.color': '#666', | ||
59 | + 'range.subbar.color': '#d1d1d1', | ||
60 | + | ||
61 | + 'range.disabledPointer.color': '#414141', | ||
62 | + 'range.disabledBar.color': '#282828', | ||
63 | + 'range.disabledSubbar.color': '#414141', | ||
64 | + | ||
65 | + 'range.value.color': '#fff', | ||
66 | + 'range.value.fontWeight': 'lighter', | ||
67 | + 'range.value.fontSize': '11px', | ||
68 | + 'range.value.border': '1px solid #353535', | ||
69 | + 'range.value.backgroundColor': '#151515', | ||
70 | + 'range.title.color': '#fff', | ||
71 | + 'range.title.fontWeight': 'lighter', | ||
72 | + | ||
73 | + // colorpicker style | ||
74 | + 'colorpicker.button.border': '1px solid #1e1e1e', | ||
75 | + 'colorpicker.title.color': '#fff', | ||
76 | +}; |
gif-generator/examples/tui/index.html
0 → 100644
1 | +<!DOCTYPE html> | ||
2 | +<html> | ||
3 | + <head> | ||
4 | + <meta charset="UTF-8" /> | ||
5 | + <title>TUI Example</title> | ||
6 | + <link | ||
7 | + type="text/css" | ||
8 | + href="https://uicdn.toast.com/tui-color-picker/v2.2.6/tui-color-picker.css" | ||
9 | + rel="stylesheet" | ||
10 | + /> | ||
11 | + <link type="text/css" href="./tui-image-editor.css" rel="stylesheet" /> | ||
12 | + <style> | ||
13 | + @import url(http://fonts.googleapis.com/css?family=Noto+Sans); | ||
14 | + html, | ||
15 | + body { | ||
16 | + height: 100%; | ||
17 | + margin: 0; | ||
18 | + } | ||
19 | + </style> | ||
20 | + </head> | ||
21 | + <body> | ||
22 | + <div id="tui-image-editor-container"></div> | ||
23 | + <script | ||
24 | + type="text/javascript" | ||
25 | + src="https://api-storage.cloud.toast.com/v1/AUTH_e18353c4ea5746c097143946d0644e61/toast-ui-cdn/tui-image-editor/v3.11.0/example/fabric-v4.2.0.js" | ||
26 | + ></script> | ||
27 | + <script | ||
28 | + type="text/javascript" | ||
29 | + src="https://uicdn.toast.com/tui.code-snippet/v1.5.0/tui-code-snippet.min.js" | ||
30 | + ></script> | ||
31 | + <script | ||
32 | + type="text/javascript" | ||
33 | + src="https://uicdn.toast.com/tui-color-picker/v2.2.6/tui-color-picker.js" | ||
34 | + ></script> | ||
35 | + <script | ||
36 | + type="text/javascript" | ||
37 | + src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.3/FileSaver.min.js" | ||
38 | + ></script> | ||
39 | + <script type="text/javascript" src="./tui-image-editor.js"></script> | ||
40 | + <script type="text/javascript" src="./black-theme.js"></script> | ||
41 | + <script type="text/javascript" src="../../dist/gif-generator.js"></script> | ||
42 | + <script> | ||
43 | + // Image editor | ||
44 | + var imageEditor = new tui.ImageEditor("#tui-image-editor-container", { | ||
45 | + includeUI: { | ||
46 | + loadImage: { | ||
47 | + path: "./sampleImage2.png", | ||
48 | + name: "SampleImage", | ||
49 | + }, | ||
50 | + theme: blackTheme, // or whiteTheme | ||
51 | + initMenu: "filter", | ||
52 | + menuBarPosition: "bottom", | ||
53 | + }, | ||
54 | + cssMaxWidth: 700, | ||
55 | + cssMaxHeight: 500, | ||
56 | + usageStatistics: false, | ||
57 | + }); | ||
58 | + window.onresize = function () { | ||
59 | + imageEditor.ui.resizeEditor(); | ||
60 | + }; | ||
61 | + | ||
62 | + let gifGenerator; | ||
63 | + setTimeout(function () { | ||
64 | + gifGenerator = new GifGenerator(imageEditor._graphics.getCanvas()); | ||
65 | + }, 1000); | ||
66 | + </script> | ||
67 | + </body> | ||
68 | +</html> |
gif-generator/examples/tui/sampleImage2.png
0 → 100644
1.32 MB
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
gif-generator/package-lock.json
0 → 100644
This diff could not be displayed because it is too large.
gif-generator/package.json
0 → 100644
1 | +{ | ||
2 | + "name": "gif-generator", | ||
3 | + "version": "1.0.0", | ||
4 | + "description": "", | ||
5 | + "main": "index.js", | ||
6 | + "scripts": { | ||
7 | + "start": "webpack -w", | ||
8 | + "build": "webpack" | ||
9 | + }, | ||
10 | + "author": "", | ||
11 | + "license": "ISC", | ||
12 | + "devDependencies": { | ||
13 | + "@babel/cli": "^7.13.14", | ||
14 | + "@babel/core": "^7.13.15", | ||
15 | + "@babel/preset-env": "^7.13.15", | ||
16 | + "babel-loader": "^8.2.2", | ||
17 | + "fabric": "^4.4.0", | ||
18 | + "webpack": "^5.31.0", | ||
19 | + "webpack-cli": "^4.6.0" | ||
20 | + }, | ||
21 | + "dependencies": { | ||
22 | + "@babel/plugin-proposal-class-properties": "^7.13.0", | ||
23 | + "gifencoder": "^2.0.1", | ||
24 | + "stream": "0.0.2" | ||
25 | + } | ||
26 | +} |
gif-generator/src/index.js
0 → 100644
1 | +import GIF from "gifencoder"; | ||
2 | + | ||
3 | +class GifGenerator { | ||
4 | + constructor(canvas) { | ||
5 | + this.canvas = canvas; | ||
6 | + this.width = canvas.getWidth(); | ||
7 | + this.height = canvas.getHeight(); | ||
8 | + this.gif = new GIF(this.width, this.height); | ||
9 | + | ||
10 | + this.gif.start(); | ||
11 | + this.gif.setTransparent(null); | ||
12 | + this.gif.setRepeat(0); | ||
13 | + this.gif.setQuality(10); | ||
14 | + } | ||
15 | + | ||
16 | + addFrame(delay = 0) { | ||
17 | + this.gif.setDelay(delay); | ||
18 | + this.gif.addFrame(this.canvas.getContext()); | ||
19 | + } | ||
20 | + | ||
21 | + render() { | ||
22 | + this.gif.finish(); | ||
23 | + const byte = new Uint8Array(this.gif.out.data); | ||
24 | + | ||
25 | + return new Blob([byte], { type: "image/gif" }); | ||
26 | + } | ||
27 | +} | ||
28 | + | ||
29 | +window.GifGenerator = GifGenerator; |
gif-generator/webpack.config.js
0 → 100644
1 | +const path = require('path'); | ||
2 | + | ||
3 | +module.exports = { | ||
4 | + entry: './src/index.js', | ||
5 | + output: { | ||
6 | + path: __dirname + '/dist', | ||
7 | + filename: 'gif-generator.js', | ||
8 | + sourceMapFilename: 'gif-generator.map', | ||
9 | + }, | ||
10 | + module: { | ||
11 | + rules: [ | ||
12 | + { | ||
13 | + test: /\.js$/, | ||
14 | + include: [ | ||
15 | + path.resolve(__dirname, 'src/js') | ||
16 | + ], | ||
17 | + exclude: /node_modules/, | ||
18 | + use: { | ||
19 | + loader: 'babel-loader', | ||
20 | + options: { | ||
21 | + presets: ['@babel/preset-env'], | ||
22 | + plugins: ['@babel/plugin-proposal-class-properties'] | ||
23 | + } | ||
24 | + } | ||
25 | + } | ||
26 | + ] | ||
27 | + }, | ||
28 | + devtool: 'source-map', | ||
29 | + mode: 'development' | ||
30 | +}; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
next-env.d.ts
0 → 100644
next.config.js
0 → 100644
1 | +/* eslint-disable @typescript-eslint/no-var-requires */ | ||
2 | +const withBundleAnalyzer = require("@next/bundle-analyzer")({ | ||
3 | + enabled: process.env.ANALYZE === "true", | ||
4 | +}); | ||
5 | + | ||
6 | +module.exports = withBundleAnalyzer({ | ||
7 | + target: "serverless", | ||
8 | + env: { | ||
9 | + BASE_URL: process.env.BASE_URL, | ||
10 | + }, | ||
11 | + | ||
12 | + webpack(conf) { | ||
13 | + conf.module.rules.push({ | ||
14 | + test: /\.svg$/, | ||
15 | + use: [ | ||
16 | + { | ||
17 | + loader: "@svgr/webpack", | ||
18 | + options: { | ||
19 | + svgoConfig: { | ||
20 | + plugins: [ | ||
21 | + { | ||
22 | + // Enable figma's wrong mask-type attribute work | ||
23 | + removeRasterImages: false, | ||
24 | + removeStyleElement: false, | ||
25 | + removeUnknownsAndDefaults: false, | ||
26 | + // Enable svgr's svg to fill the size | ||
27 | + removeViewBox: false, | ||
28 | + }, | ||
29 | + ], | ||
30 | + }, | ||
31 | + }, | ||
32 | + }, | ||
33 | + ], | ||
34 | + }); | ||
35 | + // 절대경로 | ||
36 | + conf.resolve.modules.push(__dirname); | ||
37 | + return conf; | ||
38 | + }, | ||
39 | +}); |
package.json
0 → 100644
1 | +{ | ||
2 | + "name": "website", | ||
3 | + "version": "0.1.0", | ||
4 | + "private": true, | ||
5 | + "dependencies": { | ||
6 | + "@next/bundle-analyzer": "^10.0.7", | ||
7 | + "@testing-library/jest-dom": "^5.11.4", | ||
8 | + "@testing-library/react": "^11.1.0", | ||
9 | + "@testing-library/user-event": "^12.1.10", | ||
10 | + "next": "^10.0.5", | ||
11 | + "react": "^17.0.2", | ||
12 | + "react-dom": "^17.0.2", | ||
13 | + "styled-components": "^5.2.3", | ||
14 | + "styled-reset": "^4.3.4", | ||
15 | + "tui-image-editor": "3.14.2", | ||
16 | + "@toast-ui/react-image-editor": "3.14.2", | ||
17 | + "web-vitals": "^1.0.1" | ||
18 | + }, | ||
19 | + "devDependencies": { | ||
20 | + "@babel/core": "^7.13.10", | ||
21 | + "@babel/plugin-syntax-dynamic-import": "^7.8.3", | ||
22 | + "@svgr/webpack": "^5.5.0", | ||
23 | + "@types/node": "^14.14.22", | ||
24 | + "@types/react": "^17.0.0", | ||
25 | + "@types/react-dom": "^17.0.0", | ||
26 | + "@types/react-window": "^1.8.2", | ||
27 | + "@types/styled-components": "^5.1.7", | ||
28 | + "@typescript-eslint/eslint-plugin": "^4.14.1", | ||
29 | + "@typescript-eslint/eslint-plugin-tslint": "^4.14.1", | ||
30 | + "@typescript-eslint/parser": "^4.14.1", | ||
31 | + "babel-loader": "^8.2.2", | ||
32 | + "eslint": "^7.18.0", | ||
33 | + "eslint-config-airbnb-typescript": "^12.3.1", | ||
34 | + "eslint-config-prettier": "^8.1.0", | ||
35 | + "eslint-plugin-import": "^2.22.1", | ||
36 | + "eslint-plugin-jsx-a11y": "^6.4.1", | ||
37 | + "eslint-plugin-react": "^7.22.0", | ||
38 | + "eslint-plugin-react-hooks": "^4.2.0", | ||
39 | + "prettier": "^2.2.1", | ||
40 | + "typescript": "^4.1.3" | ||
41 | + }, | ||
42 | + "scripts": { | ||
43 | + "dev": "next", | ||
44 | + "debug": "NODE_OPTIONS='--inspect' next dev", | ||
45 | + "build": "next build", | ||
46 | + "start": "next start", | ||
47 | + "export": "next export", | ||
48 | + "type-check": "tsc", | ||
49 | + "eslint": "eslint .", | ||
50 | + "analyze": "ANALYZE=true next build" | ||
51 | + }, | ||
52 | + "eslintConfig": { | ||
53 | + "extends": [ | ||
54 | + "react-app", | ||
55 | + "react-app/jest" | ||
56 | + ] | ||
57 | + }, | ||
58 | + "browserslist": { | ||
59 | + "production": [ | ||
60 | + ">0.2%", | ||
61 | + "not dead", | ||
62 | + "not op_mini all" | ||
63 | + ], | ||
64 | + "development": [ | ||
65 | + "last 1 chrome version", | ||
66 | + "last 1 firefox version", | ||
67 | + "last 1 safari version" | ||
68 | + ] | ||
69 | + } | ||
70 | +} |
src/components/Header.tsx
0 → 100644
1 | +import styled from "styled-components"; | ||
2 | + | ||
3 | +const Header = () => { | ||
4 | + return <Container>Gif Generator</Container>; | ||
5 | +}; | ||
6 | + | ||
7 | +const Container = styled.div` | ||
8 | + position: fixed; | ||
9 | + top: 0; | ||
10 | + left: 0; | ||
11 | + width: 100%; | ||
12 | + padding: 1.5rem; | ||
13 | + background-color: white; | ||
14 | + box-shadow: ${({ theme }) => theme.boxShadow.normal}; | ||
15 | + text-align: center; | ||
16 | + font-size: 1.6rem; | ||
17 | + font-weight: 500; | ||
18 | + font-style: italic; | ||
19 | +`; | ||
20 | + | ||
21 | +export default Header; |
src/components/Image.tsx
0 → 100644
1 | +import dynamic from "next/dynamic"; | ||
2 | +import { useState } from "react"; | ||
3 | +import styled from "styled-components"; | ||
4 | + | ||
5 | +const ToastEditor = dynamic(() => import("components/ToastEditor"), { | ||
6 | + ssr: false, | ||
7 | +}); | ||
8 | +const Image = ({ previewURL, setPreviewURL }) => { | ||
9 | + const [file, setFile] = useState(undefined); | ||
10 | + console.log("previewURL", previewURL); | ||
11 | + | ||
12 | + // const uploadImage = (file) => { | ||
13 | + // if (!file) { | ||
14 | + // return; | ||
15 | + // } | ||
16 | + // }; | ||
17 | + | ||
18 | + // const selectImg = (e) => { | ||
19 | + // const reader = new FileReader(); | ||
20 | + // const targetFile = e.target.files[0]; | ||
21 | + // setFile(targetFile); | ||
22 | + // // uploadImage(targetFile); | ||
23 | + | ||
24 | + // reader.onloadend = () => { | ||
25 | + // setPreviewURL(reader.result); | ||
26 | + // }; | ||
27 | + | ||
28 | + // reader.readAsDataURL(targetFile); | ||
29 | + // }; | ||
30 | + | ||
31 | + // const [isEditorOpened, setIsEditorOpened] = useState(false); | ||
32 | + // const handleEditor = () => { | ||
33 | + // setIsEditorOpened(true); | ||
34 | + // }; | ||
35 | + | ||
36 | + return ( | ||
37 | + <> | ||
38 | + <Container> | ||
39 | + <ImgBox> | ||
40 | + {/* <div onClick={handleEditor}>asdf</div> */} | ||
41 | + {/* {file === undefined ? ( */} | ||
42 | + <> | ||
43 | + {/* <div className="sub-flex"> | ||
44 | + <BlankBox /> | ||
45 | + <div>Click to add a photo</div> | ||
46 | + <input | ||
47 | + type="file" | ||
48 | + style={{ | ||
49 | + position: "absolute", | ||
50 | + top: 0, | ||
51 | + paddingLeft: 0, | ||
52 | + zIndex: 0, | ||
53 | + width: "90%", | ||
54 | + height: "100%", | ||
55 | + border: "none", | ||
56 | + cursor: "pointer", | ||
57 | + outline: "none", | ||
58 | + }} | ||
59 | + onChange={selectImg} | ||
60 | + /> | ||
61 | + </div> | ||
62 | + <div className="sub-flex">Open Image Editor</div> */} | ||
63 | + </> | ||
64 | + {/* ) : ( */} | ||
65 | + <img | ||
66 | + id="image" | ||
67 | + alt={""} | ||
68 | + style={{ | ||
69 | + objectFit: "cover", | ||
70 | + display: "flex", | ||
71 | + maxHeight: "90%", | ||
72 | + maxWidth: "90%", | ||
73 | + }} | ||
74 | + src={previewURL as string} | ||
75 | + /> | ||
76 | + {/* )} */} | ||
77 | + </ImgBox> | ||
78 | + {/* <Menu /> */} | ||
79 | + </Container> | ||
80 | + {/* {isEditorOpened && <ToastEditor {...{ setPreviewURL, setIsImgAdded }} />} */} | ||
81 | + </> | ||
82 | + ); | ||
83 | +}; | ||
84 | + | ||
85 | +const Menu = () => { | ||
86 | + return ( | ||
87 | + <div style={{ width: "15rem", marginLeft: "2rem" }}> | ||
88 | + <Box /> | ||
89 | + <Box /> | ||
90 | + <Box /> | ||
91 | + <Box /> | ||
92 | + </div> | ||
93 | + ); | ||
94 | +}; | ||
95 | + | ||
96 | +const Container = styled.div` | ||
97 | + width: 100%; | ||
98 | + display: flex; | ||
99 | + justify-content: center; | ||
100 | + margin-top: 10rem; | ||
101 | +`; | ||
102 | +const ImgBox = styled.div` | ||
103 | + position: relative; | ||
104 | + width: 90%; | ||
105 | + /* height: 30rem; */ | ||
106 | + background-color: white; | ||
107 | + box-shadow: ${({ theme }) => theme.boxShadow.normal}; | ||
108 | + border-radius: 2rem; | ||
109 | + margin-top: 2rem; | ||
110 | + display: flex; | ||
111 | + align-items: center; | ||
112 | + justify-content: center; | ||
113 | + font-size: 1rem; | ||
114 | + display: flex; | ||
115 | + /* flex: 0.6; */ | ||
116 | + padding: 1rem 0; | ||
117 | + /* .sub-flex { | ||
118 | + position: relative; | ||
119 | + width: 100%; | ||
120 | + height: 100%; | ||
121 | + display: flex; | ||
122 | + align-items: center; | ||
123 | + justify-content: center; | ||
124 | + :first-child { | ||
125 | + border-right: 1px solid ${({ theme }) => theme.color.gray}; | ||
126 | + } | ||
127 | + } */ | ||
128 | +`; | ||
129 | + | ||
130 | +const Box = styled.div` | ||
131 | + width: 100%; | ||
132 | + height: 10rem; | ||
133 | + margin-top: 2rem; | ||
134 | + border-radius: 1rem; | ||
135 | + background-color: white; | ||
136 | + box-shadow: ${({ theme }) => theme.boxShadow.normal}; | ||
137 | +`; | ||
138 | +const BlankBox = styled.div` | ||
139 | + z-index: 1; | ||
140 | + position: absolute; | ||
141 | + top: 0; | ||
142 | + width: 90%; | ||
143 | + height: 50px; | ||
144 | + background-color: white; | ||
145 | +`; | ||
146 | + | ||
147 | +export default Image; |
src/components/ToastEditor/index.tsx
0 → 100644
1 | +/// <reference path="react-image-editor.d.ts" /> | ||
2 | +import ImageEditor from "@toast-ui/react-image-editor"; | ||
3 | +import { useEffect, useState } from "react"; | ||
4 | +import styled from "styled-components"; | ||
5 | +import "tui-image-editor/dist/tui-image-editor.css"; | ||
6 | + | ||
7 | +const ToastEditor = ({ setPreviewURL, setIsImgAdded, setIsEditorOpened }) => { | ||
8 | + // const [lowerCanvas, setLowerCanvas] = useState<HTMLCanvasElement>(); | ||
9 | + // const [upperCanvas, setUpperCanvas] = useState<HTMLCanvasElement>(); | ||
10 | + // // console.log( | ||
11 | + // // document.getElementsByClassName("lower-canvas")[0]?.toDataURL("image/png") | ||
12 | + // // ); | ||
13 | + // console.log("s"); | ||
14 | + | ||
15 | + // // const [upperCanvas, setUpperCanvas] = useState( | ||
16 | + // // document.getElementsByClassName("upper-canvas ")[0] | ||
17 | + // // ); | ||
18 | + | ||
19 | + // useEffect(() => { | ||
20 | + // window?.addEventListener("click", () => { | ||
21 | + // setLowerCanvas( | ||
22 | + // document.getElementsByClassName("lower-canvas")[0] as HTMLCanvasElement | ||
23 | + // ); | ||
24 | + // setUpperCanvas( | ||
25 | + // document.getElementsByClassName("upper-canvas")[0] as HTMLCanvasElement | ||
26 | + // ); | ||
27 | + // }); | ||
28 | + // }, []); | ||
29 | + | ||
30 | + // useEffect(() => { | ||
31 | + // const img = lowerCanvas?.toDataURL("image/png"); | ||
32 | + // const uploaded = document.getElementById("image"); | ||
33 | + // console.log(uploaded); | ||
34 | + // // let w = window.open(); | ||
35 | + // // if (w?.window) w.document.body.innerHTML = "<img src='" + img + "'>"; | ||
36 | + // const image = new Image(); | ||
37 | + // // image.onload = function () { | ||
38 | + // // lowerCanvas.width = uploaded.clientWidth; | ||
39 | + // // lowerCanvas.height = uploaded.clientHeight; | ||
40 | + // // lowerCanvas?.getContext("2d").drawImage(image, 0, 0); | ||
41 | + // // }; | ||
42 | + // image.src = previewURL; | ||
43 | + // console.log("b"); | ||
44 | + // if (lowerCanvas?.getContext&&upperCanvas?.getContext) { | ||
45 | + // image.onload = function () { | ||
46 | + | ||
47 | + // lowerCanvas.width = 1000; | ||
48 | + // lowerCanvas.height = 572; | ||
49 | + // upperCanvas.width = 1000; | ||
50 | + // upperCanvas.height = 572; | ||
51 | + // lowerCanvas?.getContext("2d").drawImage(image, 0, 0); | ||
52 | + // }; | ||
53 | + // console.log(lowerCanvas.getContext("2d")); | ||
54 | + // } | ||
55 | + // }, [lowerCanvas?.toDataURL("image/png")]); | ||
56 | + | ||
57 | + const handleEnd = () => { | ||
58 | + const lowerCanvas = document.getElementsByClassName( | ||
59 | + "lower-canvas" | ||
60 | + )[0] as HTMLCanvasElement; | ||
61 | + setPreviewURL(lowerCanvas.toDataURL("image/png")); | ||
62 | + console.log("asdf"); | ||
63 | + setIsImgAdded(true); | ||
64 | + setIsEditorOpened(false); | ||
65 | + }; | ||
66 | + | ||
67 | + return ( | ||
68 | + <Container> | ||
69 | + <div onClick={handleEnd} className="upload"> | ||
70 | + Upload | ||
71 | + </div> | ||
72 | + <ImageEditor | ||
73 | + includeUI={{ | ||
74 | + loadImage: { | ||
75 | + // path: 'img/sampleImage.jpg', | ||
76 | + name: "SampleImage", | ||
77 | + }, | ||
78 | + // theme: myTheme, | ||
79 | + menu: ["shape", "filter"], | ||
80 | + initMenu: "filter", | ||
81 | + uiSize: { | ||
82 | + width: "100%", | ||
83 | + height: "700px", | ||
84 | + }, | ||
85 | + menuBarPosition: "bottom", | ||
86 | + }} | ||
87 | + cssMaxHeight={500} | ||
88 | + cssMaxWidth={700} | ||
89 | + selectionStyle={{ | ||
90 | + cornerSize: 20, | ||
91 | + rotatingPointOffset: 70, | ||
92 | + }} | ||
93 | + usageStatistics={true} | ||
94 | + /> | ||
95 | + </Container> | ||
96 | + ); | ||
97 | +}; | ||
98 | + | ||
99 | +const Container = styled.div` | ||
100 | + position: fixed; | ||
101 | + width: 90%; | ||
102 | + top: 10rem; | ||
103 | + border-radius: 1.5rem; | ||
104 | + box-shadow: ${({ theme }) => theme.boxShadow.normal}; | ||
105 | + display: flex; | ||
106 | + flex-direction: column; | ||
107 | + align-items: center; | ||
108 | + .upload { | ||
109 | + font: 800 11.5px Arial; | ||
110 | + position: absolute; | ||
111 | + right: 0; | ||
112 | + top: 0; | ||
113 | + width: 120px; | ||
114 | + height: 40px; | ||
115 | + background: red; | ||
116 | + z-index: 10; | ||
117 | + border-radius: 20px; | ||
118 | + margin: 8px; | ||
119 | + background-color: #fdba3b; | ||
120 | + display: flex; | ||
121 | + align-items: center; | ||
122 | + justify-content: center; | ||
123 | + cursor: pointer; | ||
124 | + } | ||
125 | + .tui-image-editor-container { | ||
126 | + border-radius: 1.5rem; | ||
127 | + } | ||
128 | + .tui-image-editor-container .tui-image-editor-help-menu.top { | ||
129 | + top: 2rem; | ||
130 | + } | ||
131 | +`; | ||
132 | + | ||
133 | +export default ToastEditor; |
1 | +declare module "@toast-ui/react-image-editor"; |
src/pages/_app.tsx
0 → 100644
1 | +import type { AppProps } from "next/app"; | ||
2 | +import Head from "next/head"; | ||
3 | +import { ThemeProvider } from "styled-components"; | ||
4 | +import { GlobalStyle } from "styles/global-style"; | ||
5 | +import { theme } from "styles/theme"; | ||
6 | + | ||
7 | +function MyApp({ Component, pageProps }: AppProps) { | ||
8 | + return ( | ||
9 | + <> | ||
10 | + <Head> | ||
11 | + <meta name="viewport" content="width=device-width, initial-scale=1" /> | ||
12 | + <title>Gif Generator</title> | ||
13 | + </Head> | ||
14 | + <GlobalStyle /> | ||
15 | + <ThemeProvider theme={theme}> | ||
16 | + <Component {...pageProps} /> | ||
17 | + <div id="modal-root" /> | ||
18 | + </ThemeProvider> | ||
19 | + </> | ||
20 | + ); | ||
21 | +} | ||
22 | + | ||
23 | +export default MyApp; |
src/pages/_document.tsx
0 → 100644
1 | +import Document, { | ||
2 | + Html, | ||
3 | + Head, | ||
4 | + Main, | ||
5 | + NextScript, | ||
6 | + DocumentContext, | ||
7 | +} from "next/document"; | ||
8 | +import { ServerStyleSheet } from "styled-components"; | ||
9 | + | ||
10 | +class MyDocument extends Document { | ||
11 | + static async getInitialProps(ctx: DocumentContext) { | ||
12 | + const sheet = new ServerStyleSheet(); | ||
13 | + const originalRenderPage = ctx.renderPage; | ||
14 | + try { | ||
15 | + ctx.renderPage = () => | ||
16 | + originalRenderPage({ | ||
17 | + enhanceApp: (App) => (props) => | ||
18 | + sheet.collectStyles(<App {...props} />), | ||
19 | + }); | ||
20 | + | ||
21 | + const initialProps = await Document.getInitialProps(ctx); | ||
22 | + return { | ||
23 | + ...initialProps, | ||
24 | + styles: ( | ||
25 | + <> | ||
26 | + {initialProps.styles} | ||
27 | + {sheet.getStyleElement()} | ||
28 | + </> | ||
29 | + ), | ||
30 | + }; | ||
31 | + } finally { | ||
32 | + sheet.seal(); | ||
33 | + } | ||
34 | + } | ||
35 | + | ||
36 | + render() { | ||
37 | + return ( | ||
38 | + <Html> | ||
39 | + <Head> | ||
40 | + <meta charSet="utf-8" /> | ||
41 | + <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /> | ||
42 | + <meta property="og:title" content="네이버 예약" /> | ||
43 | + <link rel="preconnect" href="https://fonts.gstatic.com" /> | ||
44 | + <link | ||
45 | + href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100;300;400;500;700;900&display=swap" | ||
46 | + rel="preload" | ||
47 | + as="style" | ||
48 | + /> | ||
49 | + <link | ||
50 | + href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100;300;400;500;700;900&display=swap" | ||
51 | + rel="stylesheet" | ||
52 | + /> | ||
53 | + <script | ||
54 | + type="text/javascript" | ||
55 | + src="https://openapi.map.naver.com/openapi/v3/maps.js?ncpClientId=3ioixdkru3" | ||
56 | + /> | ||
57 | + </Head> | ||
58 | + <body> | ||
59 | + <Main /> | ||
60 | + <NextScript /> | ||
61 | + <script src="libs/code-snippet.min.js"></script> | ||
62 | + <script src="libs/jquery.min.js"></script> | ||
63 | + <script src="libs/fabric.min.js"></script> | ||
64 | + <script src="js/image-editor.js"></script> | ||
65 | + <div id="my-image-editor"> | ||
66 | + <canvas></canvas> | ||
67 | + </div> | ||
68 | + </body> | ||
69 | + </Html> | ||
70 | + ); | ||
71 | + } | ||
72 | +} | ||
73 | + | ||
74 | +export default MyDocument; |
src/pages/index.tsx
0 → 100644
1 | +import Header from "components/Header"; | ||
2 | +import Image from "components/Image"; | ||
3 | +import styled from "styled-components"; | ||
4 | +import dynamic from "next/dynamic"; | ||
5 | +import { useState } from "react"; | ||
6 | + | ||
7 | +const ToastEditor = dynamic(() => import("components/ToastEditor"), { | ||
8 | + ssr: false, | ||
9 | +}); | ||
10 | + | ||
11 | +const Index = () => { | ||
12 | + const [isEditorOpened, setIsEditorOpened] = useState(false); | ||
13 | + const [previewURL, setPreviewURL] = useState<string | ArrayBuffer>(""); | ||
14 | + const [isImgAdded, setIsImgAdded] = useState(false); | ||
15 | + | ||
16 | + return ( | ||
17 | + <Container> | ||
18 | + <Header /> | ||
19 | + | ||
20 | + {!isImgAdded ? ( | ||
21 | + <div | ||
22 | + style={{ | ||
23 | + height: "80vh", | ||
24 | + width: "100%", | ||
25 | + display: "flex", | ||
26 | + alignItems: "center", | ||
27 | + justifyContent: "center", | ||
28 | + }} | ||
29 | + > | ||
30 | + <button | ||
31 | + className="open-button" | ||
32 | + onClick={() => setIsEditorOpened(true)} | ||
33 | + > | ||
34 | + Open Image Editor | ||
35 | + </button> | ||
36 | + </div> | ||
37 | + ) : ( | ||
38 | + !isEditorOpened && ( | ||
39 | + <> | ||
40 | + <div style={{ position: "fixed", top: "5rem" }}> | ||
41 | + <button | ||
42 | + className="open-button" | ||
43 | + onClick={() => setIsEditorOpened(true)} | ||
44 | + > | ||
45 | + Change Image | ||
46 | + </button> | ||
47 | + </div> | ||
48 | + <Image {...{ previewURL, setPreviewURL }} /> | ||
49 | + </> | ||
50 | + ) | ||
51 | + )} | ||
52 | + {isEditorOpened && ( | ||
53 | + <ToastEditor {...{ setPreviewURL, setIsImgAdded, setIsEditorOpened }} /> | ||
54 | + )} | ||
55 | + </Container> | ||
56 | + ); | ||
57 | +}; | ||
58 | + | ||
59 | +const Container = styled.div` | ||
60 | + display: flex; | ||
61 | + flex-direction: column; | ||
62 | + align-items: center; | ||
63 | + .open-button { | ||
64 | + margin-top: 3rem; | ||
65 | + padding: 0.5rem 2rem; | ||
66 | + display: flex; | ||
67 | + align-items: center; | ||
68 | + transition: 0.3s; | ||
69 | + :hover { | ||
70 | + font-size: 1.1rem; | ||
71 | + transition: 0.3s; | ||
72 | + } | ||
73 | + ::before { | ||
74 | + width: 2.315rem; | ||
75 | + content: "+"; | ||
76 | + font-size: 2rem; | ||
77 | + margin-right: 1rem; | ||
78 | + box-shadow: ${({ theme }) => theme.boxShadow.normal}; | ||
79 | + border-radius: 50%; | ||
80 | + } | ||
81 | + } | ||
82 | +`; | ||
83 | + | ||
84 | +export default Index; |
src/styles/global-style.ts
0 → 100644
1 | +import { createGlobalStyle } from "styled-components"; | ||
2 | +import { reset } from "styled-reset"; | ||
3 | +import { media } from "./theme"; | ||
4 | + | ||
5 | +export const GlobalStyle = createGlobalStyle` | ||
6 | + ${reset} | ||
7 | + :focus { | ||
8 | + outline: none; | ||
9 | + border: none; | ||
10 | + } | ||
11 | + div[role="button"] { | ||
12 | + cursor: pointer; | ||
13 | + } | ||
14 | + ::-webkit-scrollbar { | ||
15 | + display: none; | ||
16 | + } | ||
17 | + html{ | ||
18 | + -webkit-text-size-adjust: none; | ||
19 | + font-family: -apple-system,BlinkMacSystemFont,helvetica,Apple SD Gothic Neo,sans-serif; | ||
20 | + font-display: fallback; | ||
21 | + ${media.tablet}{ | ||
22 | + font-size: 10px; | ||
23 | + } | ||
24 | + -ms-overflow-style: none; | ||
25 | + scrollbar-width: none; | ||
26 | + } | ||
27 | + button { | ||
28 | + background: none; | ||
29 | + padding: 0; | ||
30 | + border: none; | ||
31 | + cursor: pointer; | ||
32 | + &:disabled { | ||
33 | + cursor: default; | ||
34 | + fill: #f2f3f4; | ||
35 | + } | ||
36 | + } | ||
37 | + | ||
38 | + .pc-tablet-only { | ||
39 | + display: block; | ||
40 | + ${media.mobile} { | ||
41 | + display: none; | ||
42 | + } | ||
43 | + } | ||
44 | + .tablet-mobile-only{ | ||
45 | + display: none; | ||
46 | + ${media.tablet}{ | ||
47 | + display:block; | ||
48 | + } | ||
49 | + } | ||
50 | + .mobile-only { | ||
51 | + display: none; | ||
52 | + ${media.mobile} { | ||
53 | + display: block; | ||
54 | + } | ||
55 | + } | ||
56 | +`; |
src/styles/styled.d.ts
0 → 100644
1 | +import "styled-components"; | ||
2 | + | ||
3 | +declare module "styled-components" { | ||
4 | + export interface DefaultTheme { | ||
5 | + color: { | ||
6 | + purple: "#8661de"; | ||
7 | + blue: "#00bac7"; | ||
8 | + gray: "#f6f6f6"; | ||
9 | + green: "#07b495"; | ||
10 | + lightGreen: "#99ecdd"; | ||
11 | + darkGray: "#54595d"; | ||
12 | + }; | ||
13 | + boxShadow: { | ||
14 | + normal: "0 3px 8px 0 rgb(0 0 0 / 10%)"; | ||
15 | + purple: "0 3px 8px 0 #d6c9ff"; | ||
16 | + blue: "0 3px 8px 0 #b3e2e6"; | ||
17 | + }; | ||
18 | + } | ||
19 | +} |
src/styles/theme.ts
0 → 100644
1 | +import { DefaultTheme } from "styled-components"; | ||
2 | + | ||
3 | +export const theme: DefaultTheme = { | ||
4 | + color: { | ||
5 | + purple: "#8661de", | ||
6 | + blue: "#00bac7", | ||
7 | + gray: "#f6f6f6", | ||
8 | + green: "#07b495", | ||
9 | + lightGreen: "#99ecdd", | ||
10 | + darkGray: "#54595d", | ||
11 | + }, | ||
12 | + boxShadow: { | ||
13 | + normal: "0 3px 8px 0 rgb(0 0 0 / 10%)", | ||
14 | + purple: "0 3px 8px 0 #d6c9ff", | ||
15 | + blue: "0 3px 8px 0 #b3e2e6", | ||
16 | + }, | ||
17 | +}; | ||
18 | + | ||
19 | +const customMediaQuery = (maxWidth: number): string => | ||
20 | + `@media (max-width: ${maxWidth}px)`; | ||
21 | + | ||
22 | +export const media = { | ||
23 | + custom: customMediaQuery, | ||
24 | + pc: customMediaQuery(1440), | ||
25 | + tablet: customMediaQuery(768), | ||
26 | + mobile: customMediaQuery(576), | ||
27 | +}; |
tsconfig.json
0 → 100644
1 | +{ | ||
2 | + "compilerOptions": { | ||
3 | + "target": "es5", | ||
4 | + "lib": [ | ||
5 | + "dom", | ||
6 | + "dom.iterable", | ||
7 | + "esnext" | ||
8 | + ], | ||
9 | + "allowJs": true, | ||
10 | + "skipLibCheck": true, | ||
11 | + "strict": false, | ||
12 | + "forceConsistentCasingInFileNames": true, | ||
13 | + "noEmit": true, | ||
14 | + "esModuleInterop": true, | ||
15 | + "module": "esnext", | ||
16 | + "moduleResolution": "node", | ||
17 | + "resolveJsonModule": true, | ||
18 | + "isolatedModules": true, | ||
19 | + "jsx": "preserve", | ||
20 | + "baseUrl": "src", | ||
21 | + "rootDir": "src", | ||
22 | + }, | ||
23 | + "include": [ | ||
24 | + "next-env.d.ts", | ||
25 | + "**/*.ts", | ||
26 | + "**/*.tsx", | ||
27 | + "next.config.js", | ||
28 | + "custom.d.ts", | ||
29 | + "styled.d.ts", | ||
30 | + "src/styles", | ||
31 | + "src/pages", | ||
32 | + "public", | ||
33 | + "**/*.scss", | ||
34 | + "src/components", | ||
35 | + "resources", | ||
36 | + ], | ||
37 | + "exclude": [ | ||
38 | + "node_modules", | ||
39 | + ] | ||
40 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
yarn-error.log
0 → 100644
This diff could not be displayed because it is too large.
yarn.lock
0 → 100644
This diff could not be displayed because it is too large.
-
Please register or login to post a comment