Spaces:
Running
Running
Upload index (6).html
Browse files- index (6).html +1329 -0
index (6).html
ADDED
@@ -0,0 +1,1329 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html lang="ko">
|
3 |
+
<head>
|
4 |
+
<meta charset="UTF-8">
|
5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
+
<title>์นํฐ ํธ์ง ์คํ๋์ค Pro</title>
|
7 |
+
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100;300;400;500;700;900&family=Black+Han+Sans&family=Jua&family=Do+Hyeon&family=Sunflower:wght@300;500;700&family=Cute+Font&family=Gamja+Flower&family=Hi+Melody&family=Nanum+Pen+Script&family=Stylish&family=Single+Day&family=Gaegu:wght@300;400;700&display=swap" rel="stylesheet">
|
8 |
+
<style>
|
9 |
+
* {
|
10 |
+
margin: 0;
|
11 |
+
padding: 0;
|
12 |
+
box-sizing: border-box;
|
13 |
+
}
|
14 |
+
|
15 |
+
body {
|
16 |
+
font-family: 'Noto Sans KR', sans-serif;
|
17 |
+
background: #1a1a1a;
|
18 |
+
color: #fff;
|
19 |
+
overflow: hidden;
|
20 |
+
}
|
21 |
+
|
22 |
+
.container {
|
23 |
+
display: flex;
|
24 |
+
height: 100vh;
|
25 |
+
}
|
26 |
+
|
27 |
+
/* ์ข์ธก ํด๋ฐ */
|
28 |
+
.toolbar {
|
29 |
+
width: 320px;
|
30 |
+
background: #2a2a2a;
|
31 |
+
padding: 20px;
|
32 |
+
overflow-y: auto;
|
33 |
+
border-right: 1px solid #444;
|
34 |
+
}
|
35 |
+
|
36 |
+
.toolbar::-webkit-scrollbar {
|
37 |
+
width: 8px;
|
38 |
+
}
|
39 |
+
|
40 |
+
.toolbar::-webkit-scrollbar-track {
|
41 |
+
background: #1a1a1a;
|
42 |
+
}
|
43 |
+
|
44 |
+
.toolbar::-webkit-scrollbar-thumb {
|
45 |
+
background: #4a9eff;
|
46 |
+
border-radius: 4px;
|
47 |
+
}
|
48 |
+
|
49 |
+
.toolbar h2 {
|
50 |
+
font-size: 18px;
|
51 |
+
margin-bottom: 20px;
|
52 |
+
color: #fff;
|
53 |
+
border-bottom: 2px solid #4a9eff;
|
54 |
+
padding-bottom: 10px;
|
55 |
+
}
|
56 |
+
|
57 |
+
.tool-section {
|
58 |
+
margin-bottom: 30px;
|
59 |
+
}
|
60 |
+
|
61 |
+
.tool-section h3 {
|
62 |
+
font-size: 14px;
|
63 |
+
margin-bottom: 15px;
|
64 |
+
color: #aaa;
|
65 |
+
text-transform: uppercase;
|
66 |
+
}
|
67 |
+
|
68 |
+
/* ํ์ผ ์
๋ก๋ ์์ญ */
|
69 |
+
.file-upload {
|
70 |
+
border: 2px dashed #4a9eff;
|
71 |
+
border-radius: 8px;
|
72 |
+
padding: 20px;
|
73 |
+
text-align: center;
|
74 |
+
cursor: pointer;
|
75 |
+
transition: all 0.3s;
|
76 |
+
margin-bottom: 20px;
|
77 |
+
}
|
78 |
+
|
79 |
+
.file-upload:hover {
|
80 |
+
background: rgba(74, 158, 255, 0.1);
|
81 |
+
border-color: #6ab7ff;
|
82 |
+
}
|
83 |
+
|
84 |
+
.file-upload input {
|
85 |
+
display: none;
|
86 |
+
}
|
87 |
+
|
88 |
+
/* ํ์ผ ๋ฆฌ์คํธ */
|
89 |
+
.file-list {
|
90 |
+
background: #333;
|
91 |
+
border-radius: 8px;
|
92 |
+
padding: 10px;
|
93 |
+
margin-top: 10px;
|
94 |
+
max-height: 150px;
|
95 |
+
overflow-y: auto;
|
96 |
+
}
|
97 |
+
|
98 |
+
.file-item {
|
99 |
+
font-size: 12px;
|
100 |
+
color: #aaa;
|
101 |
+
padding: 3px 0;
|
102 |
+
border-bottom: 1px solid #444;
|
103 |
+
}
|
104 |
+
|
105 |
+
.file-item:last-child {
|
106 |
+
border-bottom: none;
|
107 |
+
}
|
108 |
+
|
109 |
+
/* ์ปดํฌ๋ํธ ๋ฒํผ๋ค */
|
110 |
+
.component-grid {
|
111 |
+
display: grid;
|
112 |
+
grid-template-columns: repeat(3, 1fr);
|
113 |
+
gap: 8px;
|
114 |
+
}
|
115 |
+
|
116 |
+
.component-btn {
|
117 |
+
background: #3a3a3a;
|
118 |
+
border: 1px solid #555;
|
119 |
+
border-radius: 8px;
|
120 |
+
padding: 10px;
|
121 |
+
cursor: pointer;
|
122 |
+
transition: all 0.3s;
|
123 |
+
text-align: center;
|
124 |
+
color: #fff;
|
125 |
+
}
|
126 |
+
|
127 |
+
.component-btn:hover {
|
128 |
+
background: #4a4a4a;
|
129 |
+
border-color: #4a9eff;
|
130 |
+
transform: translateY(-2px);
|
131 |
+
}
|
132 |
+
|
133 |
+
.component-btn svg {
|
134 |
+
width: 35px;
|
135 |
+
height: 35px;
|
136 |
+
margin-bottom: 3px;
|
137 |
+
}
|
138 |
+
|
139 |
+
.component-btn span {
|
140 |
+
display: block;
|
141 |
+
font-size: 11px;
|
142 |
+
}
|
143 |
+
|
144 |
+
/* ์์ฑ ํธ์ง ํจ๋ */
|
145 |
+
.properties-panel {
|
146 |
+
background: #333;
|
147 |
+
border-radius: 8px;
|
148 |
+
padding: 15px;
|
149 |
+
margin-top: 20px;
|
150 |
+
}
|
151 |
+
|
152 |
+
.property-group {
|
153 |
+
margin-bottom: 15px;
|
154 |
+
}
|
155 |
+
|
156 |
+
.property-group label {
|
157 |
+
display: block;
|
158 |
+
font-size: 12px;
|
159 |
+
color: #aaa;
|
160 |
+
margin-bottom: 5px;
|
161 |
+
}
|
162 |
+
|
163 |
+
.property-group input,
|
164 |
+
.property-group select,
|
165 |
+
.property-group textarea {
|
166 |
+
width: 100%;
|
167 |
+
padding: 8px;
|
168 |
+
background: #2a2a2a;
|
169 |
+
border: 1px solid #444;
|
170 |
+
border-radius: 4px;
|
171 |
+
color: #fff;
|
172 |
+
}
|
173 |
+
|
174 |
+
.color-picker {
|
175 |
+
display: grid;
|
176 |
+
grid-template-columns: repeat(6, 1fr);
|
177 |
+
gap: 5px;
|
178 |
+
}
|
179 |
+
|
180 |
+
.color-option {
|
181 |
+
width: 35px;
|
182 |
+
height: 35px;
|
183 |
+
border-radius: 4px;
|
184 |
+
cursor: pointer;
|
185 |
+
border: 2px solid transparent;
|
186 |
+
}
|
187 |
+
|
188 |
+
.color-option.selected {
|
189 |
+
border-color: #4a9eff;
|
190 |
+
box-shadow: 0 0 10px rgba(74, 158, 255, 0.5);
|
191 |
+
}
|
192 |
+
|
193 |
+
/* ๋ฉ์ธ ์์
์์ญ */
|
194 |
+
.workspace {
|
195 |
+
flex: 1;
|
196 |
+
display: flex;
|
197 |
+
flex-direction: column;
|
198 |
+
background: #1a1a1a;
|
199 |
+
}
|
200 |
+
|
201 |
+
.workspace-header {
|
202 |
+
background: #2a2a2a;
|
203 |
+
padding: 15px 20px;
|
204 |
+
border-bottom: 1px solid #444;
|
205 |
+
display: flex;
|
206 |
+
justify-content: space-between;
|
207 |
+
align-items: center;
|
208 |
+
}
|
209 |
+
|
210 |
+
.workspace-tools {
|
211 |
+
display: flex;
|
212 |
+
gap: 10px;
|
213 |
+
}
|
214 |
+
|
215 |
+
.tool-btn {
|
216 |
+
background: #3a3a3a;
|
217 |
+
border: 1px solid #555;
|
218 |
+
border-radius: 6px;
|
219 |
+
padding: 8px 16px;
|
220 |
+
color: #fff;
|
221 |
+
cursor: pointer;
|
222 |
+
transition: all 0.3s;
|
223 |
+
}
|
224 |
+
|
225 |
+
.tool-btn:hover {
|
226 |
+
background: #4a4a4a;
|
227 |
+
border-color: #4a9eff;
|
228 |
+
}
|
229 |
+
|
230 |
+
.tool-btn.primary {
|
231 |
+
background: #4a9eff;
|
232 |
+
border-color: #4a9eff;
|
233 |
+
}
|
234 |
+
|
235 |
+
.tool-btn.primary:hover {
|
236 |
+
background: #6ab7ff;
|
237 |
+
}
|
238 |
+
|
239 |
+
.tool-btn.secondary {
|
240 |
+
background: #28a745;
|
241 |
+
border-color: #28a745;
|
242 |
+
}
|
243 |
+
|
244 |
+
.tool-btn.secondary:hover {
|
245 |
+
background: #5cbf5c;
|
246 |
+
}
|
247 |
+
|
248 |
+
/* ์บ๋ฒ์ค ์์ญ */
|
249 |
+
.canvas-container {
|
250 |
+
flex: 1;
|
251 |
+
overflow: auto;
|
252 |
+
padding: 20px;
|
253 |
+
display: flex;
|
254 |
+
justify-content: center;
|
255 |
+
background: #222;
|
256 |
+
}
|
257 |
+
|
258 |
+
.canvas-wrapper {
|
259 |
+
position: relative;
|
260 |
+
background: white;
|
261 |
+
box-shadow: 0 10px 40px rgba(0,0,0,0.5);
|
262 |
+
min-height: 800px;
|
263 |
+
width: 700px;
|
264 |
+
}
|
265 |
+
|
266 |
+
/* ์ด๋ฏธ์ง ์ปจํ
์ด๋ */
|
267 |
+
.image-container {
|
268 |
+
position: relative;
|
269 |
+
width: 100%;
|
270 |
+
}
|
271 |
+
|
272 |
+
.image-number {
|
273 |
+
position: absolute;
|
274 |
+
left: -40px;
|
275 |
+
top: 10px;
|
276 |
+
background: #4a9eff;
|
277 |
+
color: white;
|
278 |
+
width: 30px;
|
279 |
+
height: 30px;
|
280 |
+
border-radius: 50%;
|
281 |
+
display: flex;
|
282 |
+
align-items: center;
|
283 |
+
justify-content: center;
|
284 |
+
font-weight: bold;
|
285 |
+
font-size: 14px;
|
286 |
+
z-index: 10;
|
287 |
+
box-shadow: 0 2px 5px rgba(0,0,0,0.3);
|
288 |
+
}
|
289 |
+
|
290 |
+
.webtoon-image {
|
291 |
+
width: 100%;
|
292 |
+
display: block;
|
293 |
+
margin-bottom: 20px;
|
294 |
+
}
|
295 |
+
|
296 |
+
/* ๋๋๊ทธ ๊ฐ๋ฅํ ์ปดํฌ๋ํธ */
|
297 |
+
.draggable-component {
|
298 |
+
position: absolute;
|
299 |
+
cursor: move;
|
300 |
+
user-select: none;
|
301 |
+
}
|
302 |
+
|
303 |
+
.draggable-component.selected {
|
304 |
+
outline: 2px solid #4a9eff;
|
305 |
+
z-index: 100;
|
306 |
+
}
|
307 |
+
|
308 |
+
.draggable-component .resize-handle {
|
309 |
+
position: absolute;
|
310 |
+
width: 10px;
|
311 |
+
height: 10px;
|
312 |
+
background: #4a9eff;
|
313 |
+
border: 1px solid #fff;
|
314 |
+
display: none;
|
315 |
+
}
|
316 |
+
|
317 |
+
.draggable-component.selected .resize-handle {
|
318 |
+
display: block;
|
319 |
+
}
|
320 |
+
|
321 |
+
.resize-handle.nw { top: -5px; left: -5px; cursor: nw-resize; }
|
322 |
+
.resize-handle.ne { top: -5px; right: -5px; cursor: ne-resize; }
|
323 |
+
.resize-handle.sw { bottom: -5px; left: -5px; cursor: sw-resize; }
|
324 |
+
.resize-handle.se { bottom: -5px; right: -5px; cursor: se-resize; }
|
325 |
+
|
326 |
+
/* ๋งํ์ ์คํ์ผ๋ค */
|
327 |
+
.speech-bubble {
|
328 |
+
background: white;
|
329 |
+
border: 2px solid black;
|
330 |
+
border-radius: 20px;
|
331 |
+
padding: 30px 15px 15px 15px;
|
332 |
+
min-width: 100px;
|
333 |
+
min-height: 50px;
|
334 |
+
position: relative;
|
335 |
+
width: 100%;
|
336 |
+
height: 100%;
|
337 |
+
}
|
338 |
+
|
339 |
+
.speech-bubble-tail {
|
340 |
+
position: absolute;
|
341 |
+
bottom: -10px;
|
342 |
+
left: 20px;
|
343 |
+
width: 0;
|
344 |
+
height: 0;
|
345 |
+
border-left: 10px solid transparent;
|
346 |
+
border-right: 10px solid transparent;
|
347 |
+
border-top: 10px solid black;
|
348 |
+
}
|
349 |
+
|
350 |
+
.speech-bubble-tail::after {
|
351 |
+
content: '';
|
352 |
+
position: absolute;
|
353 |
+
bottom: 3px;
|
354 |
+
left: -10px;
|
355 |
+
width: 0;
|
356 |
+
height: 0;
|
357 |
+
border-left: 10px solid transparent;
|
358 |
+
border-right: 10px solid transparent;
|
359 |
+
border-top: 10px solid white;
|
360 |
+
}
|
361 |
+
|
362 |
+
.thought-bubble {
|
363 |
+
background: white;
|
364 |
+
border: 2px solid black;
|
365 |
+
border-radius: 50%;
|
366 |
+
padding: 40px 20px 20px 20px;
|
367 |
+
min-width: 120px;
|
368 |
+
min-height: 80px;
|
369 |
+
position: relative;
|
370 |
+
width: 100%;
|
371 |
+
height: 100%;
|
372 |
+
}
|
373 |
+
|
374 |
+
.thought-bubble-dots {
|
375 |
+
position: absolute;
|
376 |
+
bottom: -25px;
|
377 |
+
left: 20px;
|
378 |
+
}
|
379 |
+
|
380 |
+
.thought-dot {
|
381 |
+
position: absolute;
|
382 |
+
background: white;
|
383 |
+
border: 2px solid black;
|
384 |
+
border-radius: 50%;
|
385 |
+
}
|
386 |
+
|
387 |
+
.thought-dot.large {
|
388 |
+
width: 20px;
|
389 |
+
height: 20px;
|
390 |
+
}
|
391 |
+
|
392 |
+
.thought-dot.small {
|
393 |
+
width: 12px;
|
394 |
+
height: 12px;
|
395 |
+
left: -5px;
|
396 |
+
top: 10px;
|
397 |
+
}
|
398 |
+
|
399 |
+
.shout-bubble {
|
400 |
+
background: white;
|
401 |
+
border: 3px solid black;
|
402 |
+
padding: 30px 15px 15px 15px;
|
403 |
+
min-width: 100px;
|
404 |
+
min-height: 50px;
|
405 |
+
position: relative;
|
406 |
+
width: 100%;
|
407 |
+
height: 100%;
|
408 |
+
clip-path: polygon(10% 0%, 90% 0%, 100% 10%, 100% 90%, 90% 100%, 10% 100%, 0% 90%, 0% 10%);
|
409 |
+
}
|
410 |
+
|
411 |
+
.narration-box {
|
412 |
+
background: rgba(0, 0, 0, 0.85);
|
413 |
+
border: 2px solid white;
|
414 |
+
padding: 30px 15px 15px 15px;
|
415 |
+
min-width: 150px;
|
416 |
+
min-height: 40px;
|
417 |
+
width: 100%;
|
418 |
+
height: 100%;
|
419 |
+
}
|
420 |
+
|
421 |
+
.narration-box .component-text {
|
422 |
+
color: white !important;
|
423 |
+
}
|
424 |
+
|
425 |
+
.text-box {
|
426 |
+
background: white;
|
427 |
+
border: 2px solid black;
|
428 |
+
padding: 20px 10px 10px 10px;
|
429 |
+
min-width: 100px;
|
430 |
+
min-height: 40px;
|
431 |
+
width: 100%;
|
432 |
+
height: 100%;
|
433 |
+
}
|
434 |
+
|
435 |
+
.transparent-box {
|
436 |
+
background: rgba(255, 255, 255, 0.8);
|
437 |
+
border: 1px dashed #999;
|
438 |
+
padding: 20px 10px 10px 10px;
|
439 |
+
min-width: 100px;
|
440 |
+
min-height: 40px;
|
441 |
+
width: 100%;
|
442 |
+
height: 100%;
|
443 |
+
}
|
444 |
+
|
445 |
+
.action-effect {
|
446 |
+
background: transparent;
|
447 |
+
border: none;
|
448 |
+
padding: 20px 10px 10px 10px;
|
449 |
+
min-width: 80px;
|
450 |
+
min-height: 40px;
|
451 |
+
width: 100%;
|
452 |
+
height: 100%;
|
453 |
+
font-weight: bold;
|
454 |
+
text-shadow: 2px 2px 0 white, -2px -2px 0 white, 2px -2px 0 white, -2px 2px 0 white;
|
455 |
+
}
|
456 |
+
|
457 |
+
.emotion-bubble {
|
458 |
+
background: #ffeb3b;
|
459 |
+
border: 2px solid black;
|
460 |
+
border-radius: 15px;
|
461 |
+
padding: 20px 10px 10px 10px;
|
462 |
+
min-width: 80px;
|
463 |
+
min-height: 40px;
|
464 |
+
width: 100%;
|
465 |
+
height: 100%;
|
466 |
+
}
|
467 |
+
|
468 |
+
.whisper-bubble {
|
469 |
+
background: #f0f0f0;
|
470 |
+
border: 1px dashed #666;
|
471 |
+
border-radius: 15px;
|
472 |
+
padding: 20px 10px 10px 10px;
|
473 |
+
min-width: 100px;
|
474 |
+
min-height: 40px;
|
475 |
+
width: 100%;
|
476 |
+
height: 100%;
|
477 |
+
opacity: 0.9;
|
478 |
+
}
|
479 |
+
|
480 |
+
.gradient-box {
|
481 |
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
482 |
+
border: 2px solid white;
|
483 |
+
border-radius: 10px;
|
484 |
+
padding: 30px 15px 15px 15px;
|
485 |
+
min-width: 100px;
|
486 |
+
min-height: 40px;
|
487 |
+
width: 100%;
|
488 |
+
height: 100%;
|
489 |
+
}
|
490 |
+
|
491 |
+
.gradient-box .component-text {
|
492 |
+
color: white !important;
|
493 |
+
}
|
494 |
+
|
495 |
+
.component-text {
|
496 |
+
width: 100%;
|
497 |
+
height: 100%;
|
498 |
+
border: none;
|
499 |
+
background: transparent;
|
500 |
+
resize: none;
|
501 |
+
outline: none;
|
502 |
+
font-family: inherit;
|
503 |
+
font-size: 14px;
|
504 |
+
color: black;
|
505 |
+
text-align: center;
|
506 |
+
padding: 5px;
|
507 |
+
overflow: visible;
|
508 |
+
line-height: 1.4;
|
509 |
+
}
|
510 |
+
|
511 |
+
/* ๋ก๋ฉ ์ธ๋์ผ์ดํฐ */
|
512 |
+
.loading {
|
513 |
+
display: none;
|
514 |
+
position: fixed;
|
515 |
+
top: 50%;
|
516 |
+
left: 50%;
|
517 |
+
transform: translate(-50%, -50%);
|
518 |
+
background: rgba(0,0,0,0.9);
|
519 |
+
padding: 30px;
|
520 |
+
border-radius: 10px;
|
521 |
+
z-index: 1000;
|
522 |
+
text-align: center;
|
523 |
+
}
|
524 |
+
|
525 |
+
.loading.active {
|
526 |
+
display: block;
|
527 |
+
}
|
528 |
+
|
529 |
+
.loading-spinner {
|
530 |
+
border: 3px solid #f3f3f3;
|
531 |
+
border-top: 3px solid #4a9eff;
|
532 |
+
border-radius: 50%;
|
533 |
+
width: 40px;
|
534 |
+
height: 40px;
|
535 |
+
animation: spin 1s linear infinite;
|
536 |
+
margin: 0 auto 10px;
|
537 |
+
}
|
538 |
+
|
539 |
+
@keyframes spin {
|
540 |
+
0% { transform: rotate(0deg); }
|
541 |
+
100% { transform: rotate(360deg); }
|
542 |
+
}
|
543 |
+
|
544 |
+
/* ์ด๋ฏธ์ง ๊ฐ๊ฒฉ ์กฐ์ */
|
545 |
+
.spacing-control {
|
546 |
+
display: flex;
|
547 |
+
align-items: center;
|
548 |
+
gap: 10px;
|
549 |
+
}
|
550 |
+
|
551 |
+
.spacing-control input[type="range"] {
|
552 |
+
flex: 1;
|
553 |
+
}
|
554 |
+
|
555 |
+
.spacing-value {
|
556 |
+
width: 50px;
|
557 |
+
text-align: center;
|
558 |
+
}
|
559 |
+
|
560 |
+
/* ๊ฐ๋ณ ์ ์ฅ ์
๋ ฅ */
|
561 |
+
.save-individual {
|
562 |
+
display: flex;
|
563 |
+
gap: 5px;
|
564 |
+
margin-top: 10px;
|
565 |
+
}
|
566 |
+
|
567 |
+
.save-individual input {
|
568 |
+
width: 60px;
|
569 |
+
}
|
570 |
+
|
571 |
+
.save-individual button {
|
572 |
+
flex: 1;
|
573 |
+
padding: 5px;
|
574 |
+
background: #28a745;
|
575 |
+
border: none;
|
576 |
+
border-radius: 4px;
|
577 |
+
color: white;
|
578 |
+
cursor: pointer;
|
579 |
+
}
|
580 |
+
|
581 |
+
.save-individual button:hover {
|
582 |
+
background: #5cbf5c;
|
583 |
+
}
|
584 |
+
</style>
|
585 |
+
</head>
|
586 |
+
<body>
|
587 |
+
<div class="container">
|
588 |
+
<!-- ์ข์ธก ํด๋ฐ -->
|
589 |
+
<div class="toolbar">
|
590 |
+
<h2>๐จ ์นํฐ ํธ์ง ๋๊ตฌ</h2>
|
591 |
+
|
592 |
+
<!-- ํ์ผ ์
๋ก๋ -->
|
593 |
+
<div class="tool-section">
|
594 |
+
<h3>๐ ์ด๋ฏธ์ง ์
๋ก๋</h3>
|
595 |
+
<div class="file-upload" onclick="document.getElementById('fileInput').click()">
|
596 |
+
<svg width="40" height="40" fill="#4a9eff">
|
597 |
+
<rect x="5" y="10" width="30" height="25" fill="none" stroke="currentColor" stroke-width="2"/>
|
598 |
+
<polyline points="15,25 20,20 25,25" fill="none" stroke="currentColor" stroke-width="2"/>
|
599 |
+
<line x1="20" y1="20" x2="20" y2="30" stroke="currentColor" stroke-width="2"/>
|
600 |
+
</svg>
|
601 |
+
<p>ํด๋ฆญํ์ฌ ์ด๋ฏธ์ง ์ ํ</p>
|
602 |
+
<p style="font-size: 11px; color: #888; margin-top: 5px;">ํ์ผ๋ช
๊ธฐ์ค ์๋ ์ ๋ ฌ (1.jpg, 2.jpg...)</p>
|
603 |
+
<input type="file" id="fileInput" multiple accept="image/*">
|
604 |
+
</div>
|
605 |
+
<div id="fileList"></div>
|
606 |
+
|
607 |
+
<!-- ์ด๋ฏธ์ง ๊ฐ๊ฒฉ ์กฐ์ -->
|
608 |
+
<div class="property-group">
|
609 |
+
<label>์ด๋ฏธ์ง ๊ฐ๊ฒฉ</label>
|
610 |
+
<div class="spacing-control">
|
611 |
+
<input type="range" id="imageSpacing" min="0" max="100" value="20" onchange="updateImageSpacing()">
|
612 |
+
<span class="spacing-value" id="spacingValue">20px</span>
|
613 |
+
</div>
|
614 |
+
</div>
|
615 |
+
|
616 |
+
<!-- ๊ฐ๋ณ ์ด๋ฏธ์ง ์ ์ฅ -->
|
617 |
+
<div class="property-group">
|
618 |
+
<label>๊ฐ๋ณ ์ด๋ฏธ์ง ์ ์ฅ</label>
|
619 |
+
<div class="save-individual">
|
620 |
+
<input type="number" id="imageNumber" placeholder="๋ฒํธ" min="1">
|
621 |
+
<button onclick="exportSingleImage()">์ ์ฅ</button>
|
622 |
+
</div>
|
623 |
+
</div>
|
624 |
+
</div>
|
625 |
+
|
626 |
+
<!-- ์ปดํฌ๋ํธ -->
|
627 |
+
<div class="tool-section">
|
628 |
+
<h3>๐ฌ ๋งํ์ & ํจ๊ณผ</h3>
|
629 |
+
<div class="component-grid">
|
630 |
+
<div class="component-btn" onclick="addComponent('speech')">
|
631 |
+
<svg viewBox="0 0 100 100" fill="none" stroke="white" stroke-width="2">
|
632 |
+
<ellipse cx="50" cy="40" rx="40" ry="30"/>
|
633 |
+
<path d="M 30 55 L 25 75 L 40 55"/>
|
634 |
+
</svg>
|
635 |
+
<span>๋งํ์ </span>
|
636 |
+
</div>
|
637 |
+
<div class="component-btn" onclick="addComponent('thought')">
|
638 |
+
<svg viewBox="0 0 100 100" fill="none" stroke="white" stroke-width="2">
|
639 |
+
<ellipse cx="50" cy="40" rx="35" ry="25"/>
|
640 |
+
<circle cx="30" cy="65" r="8"/>
|
641 |
+
<circle cx="20" cy="75" r="5"/>
|
642 |
+
</svg>
|
643 |
+
<span>์๊ฐํ์ </span>
|
644 |
+
</div>
|
645 |
+
<div class="component-btn" onclick="addComponent('shout')">
|
646 |
+
<svg viewBox="0 0 100 100" fill="none" stroke="white" stroke-width="3">
|
647 |
+
<polygon points="50,10 90,30 85,70 50,90 15,70 10,30"/>
|
648 |
+
</svg>
|
649 |
+
<span>์ธ์นจํ์ </span>
|
650 |
+
</div>
|
651 |
+
<div class="component-btn" onclick="addComponent('whisper')">
|
652 |
+
<svg viewBox="0 0 100 100" fill="none" stroke="white" stroke-width="1" stroke-dasharray="3,3">
|
653 |
+
<ellipse cx="50" cy="45" rx="35" ry="25"/>
|
654 |
+
</svg>
|
655 |
+
<span>์์ญ์</span>
|
656 |
+
</div>
|
657 |
+
<div class="component-btn" onclick="addComponent('emotion')">
|
658 |
+
<svg viewBox="0 0 100 100" fill="#ffeb3b" stroke="white" stroke-width="2">
|
659 |
+
<ellipse cx="50" cy="45" rx="35" ry="25"/>
|
660 |
+
</svg>
|
661 |
+
<span>๊ฐ์ ํํ</span>
|
662 |
+
</div>
|
663 |
+
<div class="component-btn" onclick="addComponent('action')">
|
664 |
+
<svg viewBox="0 0 100 100" fill="none" stroke="white" stroke-width="2">
|
665 |
+
<text x="50" y="50" text-anchor="middle" font-size="30" fill="white">!</text>
|
666 |
+
</svg>
|
667 |
+
<span>ํจ๊ณผ์</span>
|
668 |
+
</div>
|
669 |
+
<div class="component-btn" onclick="addComponent('narration')">
|
670 |
+
<svg viewBox="0 0 100 100" fill="#333" stroke="white" stroke-width="2">
|
671 |
+
<rect x="15" y="30" width="70" height="40"/>
|
672 |
+
</svg>
|
673 |
+
<span>๋๋ ์ด์
</span>
|
674 |
+
</div>
|
675 |
+
<div class="component-btn" onclick="addComponent('box')">
|
676 |
+
<svg viewBox="0 0 100 100" fill="none" stroke="white" stroke-width="2">
|
677 |
+
<rect x="20" y="30" width="60" height="40"/>
|
678 |
+
</svg>
|
679 |
+
<span>ํ
์คํธ๋ฐ์ค</span>
|
680 |
+
</div>
|
681 |
+
<div class="component-btn" onclick="addComponent('transparent')">
|
682 |
+
<svg viewBox="0 0 100 100" fill="none" stroke="white" stroke-width="2" stroke-dasharray="5,5">
|
683 |
+
<rect x="20" y="30" width="60" height="40"/>
|
684 |
+
</svg>
|
685 |
+
<span>ํฌ๋ช
๋ฐ์ค</span>
|
686 |
+
</div>
|
687 |
+
<div class="component-btn" onclick="addComponent('gradient')">
|
688 |
+
<svg viewBox="0 0 100 100">
|
689 |
+
<defs>
|
690 |
+
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="100%">
|
691 |
+
<stop offset="0%" style="stop-color:#667eea;stop-opacity:1" />
|
692 |
+
<stop offset="100%" style="stop-color:#764ba2;stop-opacity:1" />
|
693 |
+
</linearGradient>
|
694 |
+
</defs>
|
695 |
+
<rect x="20" y="30" width="60" height="40" fill="url(#grad1)" stroke="white" stroke-width="2"/>
|
696 |
+
</svg>
|
697 |
+
<span>๊ทธ๋ผ๋์ธํธ</span>
|
698 |
+
</div>
|
699 |
+
</div>
|
700 |
+
</div>
|
701 |
+
|
702 |
+
<!-- ์์ฑ ํธ์ง -->
|
703 |
+
<div class="tool-section">
|
704 |
+
<h3>โ๏ธ ์์ฑ ํธ์ง</h3>
|
705 |
+
<div class="properties-panel">
|
706 |
+
<div class="property-group">
|
707 |
+
<label>ํฐํธ</label>
|
708 |
+
<select id="fontSelect" onchange="updateSelectedComponent()">
|
709 |
+
<optgroup label="๊ธฐ๋ณธ ํฐํธ">
|
710 |
+
<option value="Arial">Arial</option>
|
711 |
+
<option value="Verdana">Verdana</option>
|
712 |
+
<option value="Georgia">Georgia</option>
|
713 |
+
<option value="'Times New Roman'">Times New Roman</option>
|
714 |
+
<option value="'Courier New'">Courier New</option>
|
715 |
+
<option value="'Comic Sans MS'">Comic Sans MS</option>
|
716 |
+
</optgroup>
|
717 |
+
<optgroup label="ํ๊ธ ํฐํธ">
|
718 |
+
<option value="'Noto Sans KR'">๋
ธํ ์ฐ์ค</option>
|
719 |
+
<option value="'Black Han Sans'">๊ฒ์๊ณ ๋</option>
|
720 |
+
<option value="'Jua'">์ฃผ์</option>
|
721 |
+
<option value="'Do Hyeon'">๋ํ</option>
|
722 |
+
<option value="'Sunflower'">ํด๋ฐ๋ผ๊ธฐ</option>
|
723 |
+
<option value="'Cute Font'">๊ท์ฌ์ด ๊ธ๊ผด</option>
|
724 |
+
<option value="'Gamja Flower'">๊ฐ์๊ฝ</option>
|
725 |
+
<option value="'Hi Melody'">ํ์ด ๋ฉ๋ก๋</option>
|
726 |
+
<option value="'Nanum Pen Script'">๋๋ํ</option>
|
727 |
+
<option value="'Stylish'">์คํ์ผ๋ฆฌ์</option>
|
728 |
+
<option value="'Single Day'">์ฑ๊ธ๋ฐ์ด</option>
|
729 |
+
<option value="'Gaegu'">๊ฐ๊ตฌ์์ด</option>
|
730 |
+
</optgroup>
|
731 |
+
</select>
|
732 |
+
</div>
|
733 |
+
<div class="property-group">
|
734 |
+
<label>๊ธ์ ํฌ๊ธฐ</label>
|
735 |
+
<input type="number" id="fontSizeInput" value="14" min="8" max="72" onchange="updateSelectedComponent()">
|
736 |
+
</div>
|
737 |
+
<div class="property-group">
|
738 |
+
<label>๊ธ์ ๊ตต๊ธฐ</label>
|
739 |
+
<select id="fontWeightSelect" onchange="updateSelectedComponent()">
|
740 |
+
<option value="100">์์ฃผ ์๊ฒ</option>
|
741 |
+
<option value="300">์๊ฒ</option>
|
742 |
+
<option value="400" selected>๋ณดํต</option>
|
743 |
+
<option value="500">์ฝ๊ฐ ๊ตต๊ฒ</option>
|
744 |
+
<option value="700">๊ตต๊ฒ</option>
|
745 |
+
<option value="900">์์ฃผ ๊ตต๊ฒ</option>
|
746 |
+
</select>
|
747 |
+
</div>
|
748 |
+
<div class="property-group">
|
749 |
+
<label>๊ธ์ ์์</label>
|
750 |
+
<div class="color-picker">
|
751 |
+
<div class="color-option selected" style="background: black" onclick="selectColor(this, 'black')"></div>
|
752 |
+
<div class="color-option" style="background: white; border: 1px solid #ccc;" onclick="selectColor(this, 'white')"></div>
|
753 |
+
<div class="color-option" style="background: #ff0000" onclick="selectColor(this, '#ff0000')"></div>
|
754 |
+
<div class="color-option" style="background: #ff6b6b" onclick="selectColor(this, '#ff6b6b')"></div>
|
755 |
+
<div class="color-option" style="background: #0066ff" onclick="selectColor(this, '#0066ff')"></div>
|
756 |
+
<div class="color-option" style="background: #4ecdc4" onclick="selectColor(this, '#4ecdc4')"></div>
|
757 |
+
<div class="color-option" style="background: #00b300" onclick="selectColor(this, '#00b300')"></div>
|
758 |
+
<div class="color-option" style="background: #95e1d3" onclick="selectColor(this, '#95e1d3')"></div>
|
759 |
+
<div class="color-option" style="background: #ffe100" onclick="selectColor(this, '#ffe100')"></div>
|
760 |
+
<div class="color-option" style="background: #ff9800" onclick="selectColor(this, '#ff9800')"></div>
|
761 |
+
<div class="color-option" style="background: #9c27b0" onclick="selectColor(this, '#9c27b0')"></div>
|
762 |
+
<div class="color-option" style="background: #ff00ff" onclick="selectColor(this, '#ff00ff')"></div>
|
763 |
+
</div>
|
764 |
+
</div>
|
765 |
+
<div class="property-group">
|
766 |
+
<label>ํ
์คํธ</label>
|
767 |
+
<textarea id="textInput" rows="3" placeholder="ํ
์คํธ ์
๋ ฅ..." onkeyup="updateSelectedComponent()"></textarea>
|
768 |
+
</div>
|
769 |
+
</div>
|
770 |
+
</div>
|
771 |
+
</div>
|
772 |
+
|
773 |
+
<!-- ๋ฉ์ธ ์์
์์ญ -->
|
774 |
+
<div class="workspace">
|
775 |
+
<div class="workspace-header">
|
776 |
+
<h1 style="font-size: 20px;">๐จ ์นํฐ ํธ์ง ์คํ๋์ค Pro</h1>
|
777 |
+
<div class="workspace-tools">
|
778 |
+
<button class="tool-btn" onclick="deleteSelected()">๐๏ธ ์ ํ ์ญ์ </button>
|
779 |
+
<button class="tool-btn" onclick="clearAll()">๐ ์ ์ฒด ์ด๊ธฐํ</button>
|
780 |
+
<button class="tool-btn primary" onclick="exportSingleImage()">๐พ ์ด๋ฏธ์ง ์ ์ฅ</button>
|
781 |
+
</div>
|
782 |
+
</div>
|
783 |
+
|
784 |
+
<div class="canvas-container">
|
785 |
+
<div class="canvas-wrapper" id="canvas">
|
786 |
+
<!-- ์
๋ก๋๋ ์ด๋ฏธ์ง์ ์ปดํฌ๋ํธ๋ค์ด ์ฌ๊ธฐ์ ์ถ๊ฐ๋ฉ๋๋ค -->
|
787 |
+
</div>
|
788 |
+
</div>
|
789 |
+
</div>
|
790 |
+
</div>
|
791 |
+
|
792 |
+
<div class="loading" id="loading">
|
793 |
+
<div class="loading-spinner"></div>
|
794 |
+
<p>์ฒ๋ฆฌ ์ค...</p>
|
795 |
+
</div>
|
796 |
+
|
797 |
+
<!-- html2canvas ๋ผ์ด๋ธ๋ฌ๋ฆฌ -->
|
798 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
|
799 |
+
|
800 |
+
<script>
|
801 |
+
let selectedComponent = null;
|
802 |
+
let isDragging = false;
|
803 |
+
let isResizing = false;
|
804 |
+
let dragOffset = { x: 0, y: 0 };
|
805 |
+
let componentCounter = 0;
|
806 |
+
let selectedColor = 'black';
|
807 |
+
let uploadedImages = [];
|
808 |
+
|
809 |
+
// ์์ฐ์ค๋ฌ์ด ์ ๋ ฌ ํจ์ (์ซ์๊ฐ ํฌํจ๋ ํ์ผ๋ช
์ ๋ ฌ)
|
810 |
+
function naturalSort(a, b) {
|
811 |
+
// ํ์ผ๋ช
์์ ์ซ์ ์ถ์ถ
|
812 |
+
const extractNumber = (filename) => {
|
813 |
+
const match = filename.match(/(\d+)/);
|
814 |
+
return match ? parseInt(match[1]) : 0;
|
815 |
+
};
|
816 |
+
|
817 |
+
const aNum = extractNumber(a.name);
|
818 |
+
const bNum = extractNumber(b.name);
|
819 |
+
|
820 |
+
// ์ซ์๋ก ๋น๊ต
|
821 |
+
if (aNum !== bNum) {
|
822 |
+
return aNum - bNum;
|
823 |
+
}
|
824 |
+
|
825 |
+
// ์ซ์๊ฐ ๊ฐ์ผ๋ฉด ์ ์ฒด ํ์ผ๋ช
์ผ๋ก ๋น๊ต
|
826 |
+
return a.name.localeCompare(b.name);
|
827 |
+
}
|
828 |
+
|
829 |
+
// ํ์ผ ์
๋ก๋ ์ฒ๋ฆฌ
|
830 |
+
document.getElementById('fileInput').addEventListener('change', async function(e) {
|
831 |
+
const files = Array.from(e.target.files);
|
832 |
+
|
833 |
+
// ์์ฐ์ค๋ฌ์ด ์ ๋ ฌ (1.jpg, 2.jpg, 10.jpg ์์๋ก)
|
834 |
+
files.sort(naturalSort);
|
835 |
+
|
836 |
+
const canvas = document.getElementById('canvas');
|
837 |
+
|
838 |
+
// ๊ธฐ์กด ์ด๋ฏธ์ง ์ ๊ฑฐ
|
839 |
+
canvas.querySelectorAll('.image-container').forEach(container => container.remove());
|
840 |
+
uploadedImages = [];
|
841 |
+
|
842 |
+
// ํ์ผ ๋ฆฌ์คํธ HTML
|
843 |
+
let fileListHTML = '<div class="file-list">';
|
844 |
+
|
845 |
+
// ๋ชจ๋ ์ด๋ฏธ์ง๋ฅผ ์์๋๋ก ๋ก๋ํ๊ธฐ ์ํ Promise ๋ฐฐ์ด
|
846 |
+
const loadPromises = files.map((file, index) => {
|
847 |
+
return new Promise((resolve) => {
|
848 |
+
if (file.type.startsWith('image/')) {
|
849 |
+
const reader = new FileReader();
|
850 |
+
|
851 |
+
reader.onload = function(event) {
|
852 |
+
resolve({
|
853 |
+
index: index,
|
854 |
+
src: event.target.result,
|
855 |
+
name: file.name
|
856 |
+
});
|
857 |
+
};
|
858 |
+
|
859 |
+
reader.readAsDataURL(file);
|
860 |
+
} else {
|
861 |
+
resolve(null);
|
862 |
+
}
|
863 |
+
});
|
864 |
+
});
|
865 |
+
|
866 |
+
// ๋ชจ๋ ์ด๋ฏธ์ง ๋ก๋ ์๋ฃ ํ ์์๋๋ก ์ถ๊ฐ
|
867 |
+
const loadedImages = await Promise.all(loadPromises);
|
868 |
+
|
869 |
+
loadedImages.forEach((imageData, index) => {
|
870 |
+
if (imageData) {
|
871 |
+
// ์ด๋ฏธ์ง ์ปจํ
์ด๋ ์์ฑ
|
872 |
+
const container = document.createElement('div');
|
873 |
+
container.className = 'image-container';
|
874 |
+
container.id = 'image-container-' + (index + 1);
|
875 |
+
|
876 |
+
// ๋๋ฒ๋ง ํ์
|
877 |
+
const numberLabel = document.createElement('div');
|
878 |
+
numberLabel.className = 'image-number';
|
879 |
+
numberLabel.textContent = index + 1;
|
880 |
+
|
881 |
+
// ์ด๋ฏธ์ง ์์ฑ
|
882 |
+
const img = document.createElement('img');
|
883 |
+
img.src = imageData.src;
|
884 |
+
img.className = 'webtoon-image';
|
885 |
+
img.alt = imageData.name;
|
886 |
+
img.id = 'webtoon-image-' + (index + 1);
|
887 |
+
|
888 |
+
container.appendChild(numberLabel);
|
889 |
+
container.appendChild(img);
|
890 |
+
|
891 |
+
// ์ด๋ฏธ์ง๋ฅผ ์์๋๋ก ์ถ๊ฐ
|
892 |
+
canvas.appendChild(container);
|
893 |
+
|
894 |
+
// ์
๋ก๋๋ ์ด๋ฏธ์ง ์ ๋ณด ์ ์ฅ
|
895 |
+
uploadedImages.push({
|
896 |
+
id: index + 1,
|
897 |
+
name: imageData.name,
|
898 |
+
element: img
|
899 |
+
});
|
900 |
+
|
901 |
+
// ํ์ผ ๋ฆฌ์คํธ์ ์ถ๊ฐ
|
902 |
+
fileListHTML += `<div class="file-item">${index + 1}. ${imageData.name}</div>`;
|
903 |
+
}
|
904 |
+
});
|
905 |
+
|
906 |
+
fileListHTML += '</div>';
|
907 |
+
|
908 |
+
// ํ์ผ ๋ฆฌ์คํธ ํ์
|
909 |
+
const fileList = document.getElementById('fileList');
|
910 |
+
fileList.innerHTML = '<p style="font-size: 12px; color: #4a9eff; margin-bottom: 10px;">โ
์
๋ก๋๋ ํ์ผ: ' + files.length + '๊ฐ</p>' + fileListHTML;
|
911 |
+
|
912 |
+
updateImageSpacing();
|
913 |
+
});
|
914 |
+
|
915 |
+
// ์ด๋ฏธ์ง ๊ฐ๊ฒฉ ์
๋ฐ์ดํธ
|
916 |
+
function updateImageSpacing() {
|
917 |
+
const spacing = document.getElementById('imageSpacing').value;
|
918 |
+
document.getElementById('spacingValue').textContent = spacing + 'px';
|
919 |
+
|
920 |
+
document.querySelectorAll('.webtoon-image').forEach(img => {
|
921 |
+
img.style.marginBottom = spacing + 'px';
|
922 |
+
});
|
923 |
+
}
|
924 |
+
|
925 |
+
// ์ปดํฌ๋ํธ ์ถ๊ฐ
|
926 |
+
function addComponent(type) {
|
927 |
+
const canvas = document.getElementById('canvas');
|
928 |
+
const component = document.createElement('div');
|
929 |
+
component.className = 'draggable-component';
|
930 |
+
component.id = 'component-' + componentCounter++;
|
931 |
+
|
932 |
+
// ์บ๋ฒ์ค์ ์คํฌ๋กค ์์น๋ฅผ ๊ณ ๋ คํ ์ด๊ธฐ ์์น
|
933 |
+
const canvasRect = canvas.getBoundingClientRect();
|
934 |
+
const scrollTop = document.querySelector('.canvas-container').scrollTop;
|
935 |
+
|
936 |
+
component.style.left = '50px';
|
937 |
+
component.style.top = (scrollTop + 50) + 'px';
|
938 |
+
component.style.width = '150px';
|
939 |
+
component.style.height = '80px';
|
940 |
+
|
941 |
+
let innerContent = '';
|
942 |
+
|
943 |
+
switch(type) {
|
944 |
+
case 'speech':
|
945 |
+
innerContent = `
|
946 |
+
<div class="speech-bubble">
|
947 |
+
<textarea class="component-text" placeholder="๋์ฌ ์
๋ ฅ..."></textarea>
|
948 |
+
<div class="speech-bubble-tail"></div>
|
949 |
+
</div>`;
|
950 |
+
break;
|
951 |
+
case 'thought':
|
952 |
+
innerContent = `
|
953 |
+
<div class="thought-bubble">
|
954 |
+
<textarea class="component-text" placeholder="์๊ฐ ์
๋ ฅ..."></textarea>
|
955 |
+
<div class="thought-bubble-dots">
|
956 |
+
<div class="thought-dot large"></div>
|
957 |
+
<div class="thought-dot small"></div>
|
958 |
+
</div>
|
959 |
+
</div>`;
|
960 |
+
break;
|
961 |
+
case 'shout':
|
962 |
+
innerContent = `
|
963 |
+
<div class="shout-bubble">
|
964 |
+
<textarea class="component-text" placeholder="์ธ์นจ!" style="font-weight: bold;"></textarea>
|
965 |
+
</div>`;
|
966 |
+
break;
|
967 |
+
case 'whisper':
|
968 |
+
innerContent = `
|
969 |
+
<div class="whisper-bubble">
|
970 |
+
<textarea class="component-text" placeholder="์์ญ์..." style="font-style: italic;"></textarea>
|
971 |
+
</div>`;
|
972 |
+
break;
|
973 |
+
case 'emotion':
|
974 |
+
innerContent = `
|
975 |
+
<div class="emotion-bubble">
|
976 |
+
<textarea class="component-text" placeholder="โฅ โช โ
"></textarea>
|
977 |
+
</div>`;
|
978 |
+
break;
|
979 |
+
case 'action':
|
980 |
+
innerContent = `
|
981 |
+
<div class="action-effect">
|
982 |
+
<textarea class="component-text" placeholder="์ฟต!" style="font-size: 24px; font-weight: bold;"></textarea>
|
983 |
+
</div>`;
|
984 |
+
break;
|
985 |
+
case 'narration':
|
986 |
+
innerContent = `
|
987 |
+
<div class="narration-box">
|
988 |
+
<textarea class="component-text" placeholder="๋๋ ์ด์
..."></textarea>
|
989 |
+
</div>`;
|
990 |
+
break;
|
991 |
+
case 'box':
|
992 |
+
innerContent = `
|
993 |
+
<div class="text-box">
|
994 |
+
<textarea class="component-text" placeholder="ํ
์คํธ ์
๋ ฅ..."></textarea>
|
995 |
+
</div>`;
|
996 |
+
break;
|
997 |
+
case 'transparent':
|
998 |
+
innerContent = `
|
999 |
+
<div class="transparent-box">
|
1000 |
+
<textarea class="component-text" placeholder="ํ
์คํธ ์
๋ ฅ..."></textarea>
|
1001 |
+
</div>`;
|
1002 |
+
break;
|
1003 |
+
case 'gradient':
|
1004 |
+
innerContent = `
|
1005 |
+
<div class="gradient-box">
|
1006 |
+
<textarea class="component-text" placeholder="ํน์ ํจ๊ณผ!"></textarea>
|
1007 |
+
</div>`;
|
1008 |
+
break;
|
1009 |
+
}
|
1010 |
+
|
1011 |
+
component.innerHTML = innerContent + `
|
1012 |
+
<div class="resize-handle nw"></div>
|
1013 |
+
<div class="resize-handle ne"></div>
|
1014 |
+
<div class="resize-handle sw"></div>
|
1015 |
+
<div class="resize-handle se"></div>
|
1016 |
+
`;
|
1017 |
+
|
1018 |
+
canvas.appendChild(component);
|
1019 |
+
|
1020 |
+
// ์ด๋ฒคํธ ๋ฆฌ์ค๋ ์ถ๊ฐ
|
1021 |
+
component.addEventListener('mousedown', startDrag);
|
1022 |
+
|
1023 |
+
// ํ
์คํธ ์์ญ ํด๋ฆญ ์ ๋๋๊ทธ ๋ฐฉ์ง
|
1024 |
+
const textArea = component.querySelector('.component-text');
|
1025 |
+
if (textArea) {
|
1026 |
+
textArea.addEventListener('mousedown', function(e) {
|
1027 |
+
e.stopPropagation();
|
1028 |
+
});
|
1029 |
+
textArea.addEventListener('click', function(e) {
|
1030 |
+
e.stopPropagation();
|
1031 |
+
selectComponent(component);
|
1032 |
+
});
|
1033 |
+
}
|
1034 |
+
|
1035 |
+
// ๋ฆฌ์ฌ์ด์ฆ ํธ๋ค ์ด๋ฒคํธ
|
1036 |
+
component.querySelectorAll('.resize-handle').forEach(handle => {
|
1037 |
+
handle.addEventListener('mousedown', startResize);
|
1038 |
+
});
|
1039 |
+
|
1040 |
+
// ์๋ ์ ํ
|
1041 |
+
selectComponent(component);
|
1042 |
+
}
|
1043 |
+
|
1044 |
+
// ์ปดํฌ๋ํธ ์ ํ
|
1045 |
+
function selectComponent(component) {
|
1046 |
+
// ์ด์ ์ ํ ํด์
|
1047 |
+
document.querySelectorAll('.draggable-component').forEach(c => {
|
1048 |
+
c.classList.remove('selected');
|
1049 |
+
});
|
1050 |
+
|
1051 |
+
// ์๋ก์ด ์ปดํฌ๋ํธ ์ ํ
|
1052 |
+
component.classList.add('selected');
|
1053 |
+
selectedComponent = component;
|
1054 |
+
|
1055 |
+
// ์์ฑ ํจ๋ ์
๋ฐ์ดํธ
|
1056 |
+
const textArea = component.querySelector('.component-text');
|
1057 |
+
if (textArea) {
|
1058 |
+
document.getElementById('textInput').value = textArea.value;
|
1059 |
+
document.getElementById('fontSizeInput').value = parseInt(textArea.style.fontSize) || 14;
|
1060 |
+
document.getElementById('fontSelect').value = textArea.style.fontFamily || "'Noto Sans KR'";
|
1061 |
+
document.getElementById('fontWeightSelect').value = textArea.style.fontWeight || '400';
|
1062 |
+
}
|
1063 |
+
}
|
1064 |
+
|
1065 |
+
// ๋๋๊ทธ ์์
|
1066 |
+
function startDrag(e) {
|
1067 |
+
if (e.target.classList.contains('resize-handle')) return;
|
1068 |
+
if (e.target.classList.contains('component-text')) return;
|
1069 |
+
|
1070 |
+
const component = e.currentTarget;
|
1071 |
+
selectComponent(component);
|
1072 |
+
|
1073 |
+
isDragging = true;
|
1074 |
+
|
1075 |
+
const rect = component.getBoundingClientRect();
|
1076 |
+
|
1077 |
+
dragOffset.x = e.clientX - rect.left;
|
1078 |
+
dragOffset.y = e.clientY - rect.top;
|
1079 |
+
|
1080 |
+
// ๋๋๊ทธ ์ค ํฌ์ธํฐ ์ด๋ฒคํธ ๋นํ์ฑํ
|
1081 |
+
component.style.pointerEvents = 'none';
|
1082 |
+
|
1083 |
+
document.addEventListener('mousemove', drag);
|
1084 |
+
document.addEventListener('mouseup', stopDrag);
|
1085 |
+
|
1086 |
+
e.preventDefault();
|
1087 |
+
}
|
1088 |
+
|
1089 |
+
// ๋๋๊ทธ ์ค
|
1090 |
+
function drag(e) {
|
1091 |
+
if (!isDragging || !selectedComponent) return;
|
1092 |
+
|
1093 |
+
const canvas = document.getElementById('canvas');
|
1094 |
+
const canvasRect = canvas.getBoundingClientRect();
|
1095 |
+
const containerScrollTop = document.querySelector('.canvas-container').scrollTop;
|
1096 |
+
|
1097 |
+
let newX = e.clientX - canvasRect.left - dragOffset.x;
|
1098 |
+
let newY = e.clientY - canvasRect.top - dragOffset.y + containerScrollTop;
|
1099 |
+
|
1100 |
+
// ์บ๋ฒ์ค ๋ฒ์ ๋ด๋ก ์ ํ
|
1101 |
+
newX = Math.max(0, Math.min(newX, canvas.offsetWidth - selectedComponent.offsetWidth));
|
1102 |
+
newY = Math.max(0, newY);
|
1103 |
+
|
1104 |
+
selectedComponent.style.left = newX + 'px';
|
1105 |
+
selectedComponent.style.top = newY + 'px';
|
1106 |
+
|
1107 |
+
e.preventDefault();
|
1108 |
+
}
|
1109 |
+
|
1110 |
+
// ๋๋๊ทธ ์ข
๋ฃ
|
1111 |
+
function stopDrag(e) {
|
1112 |
+
if (selectedComponent) {
|
1113 |
+
selectedComponent.style.pointerEvents = 'auto';
|
1114 |
+
}
|
1115 |
+
isDragging = false;
|
1116 |
+
document.removeEventListener('mousemove', drag);
|
1117 |
+
document.removeEventListener('mouseup', stopDrag);
|
1118 |
+
|
1119 |
+
e.preventDefault();
|
1120 |
+
}
|
1121 |
+
|
1122 |
+
// ๋ฆฌ์ฌ์ด์ฆ ์์
|
1123 |
+
function startResize(e) {
|
1124 |
+
e.stopPropagation();
|
1125 |
+
isResizing = true;
|
1126 |
+
|
1127 |
+
const handle = e.target;
|
1128 |
+
const component = handle.parentElement;
|
1129 |
+
selectComponent(component);
|
1130 |
+
|
1131 |
+
const startX = e.clientX;
|
1132 |
+
const startY = e.clientY;
|
1133 |
+
const startWidth = component.offsetWidth;
|
1134 |
+
const startHeight = component.offsetHeight;
|
1135 |
+
const startLeft = component.offsetLeft;
|
1136 |
+
const startTop = component.offsetTop;
|
1137 |
+
|
1138 |
+
function resize(e) {
|
1139 |
+
if (!isResizing) return;
|
1140 |
+
|
1141 |
+
const dx = e.clientX - startX;
|
1142 |
+
const dy = e.clientY - startY;
|
1143 |
+
|
1144 |
+
if (handle.classList.contains('se')) {
|
1145 |
+
component.style.width = Math.max(80, startWidth + dx) + 'px';
|
1146 |
+
component.style.height = Math.max(40, startHeight + dy) + 'px';
|
1147 |
+
} else if (handle.classList.contains('sw')) {
|
1148 |
+
component.style.width = Math.max(80, startWidth - dx) + 'px';
|
1149 |
+
component.style.height = Math.max(40, startHeight + dy) + 'px';
|
1150 |
+
component.style.left = Math.min(startLeft + dx, startLeft + startWidth - 80) + 'px';
|
1151 |
+
} else if (handle.classList.contains('ne')) {
|
1152 |
+
component.style.width = Math.max(80, startWidth + dx) + 'px';
|
1153 |
+
component.style.height = Math.max(40, startHeight - dy) + 'px';
|
1154 |
+
component.style.top = Math.min(startTop + dy, startTop + startHeight - 40) + 'px';
|
1155 |
+
} else if (handle.classList.contains('nw')) {
|
1156 |
+
component.style.width = Math.max(80, startWidth - dx) + 'px';
|
1157 |
+
component.style.height = Math.max(40, startHeight - dy) + 'px';
|
1158 |
+
component.style.left = Math.min(startLeft + dx, startLeft + startWidth - 80) + 'px';
|
1159 |
+
component.style.top = Math.min(startTop + dy, startTop + startHeight - 40) + 'px';
|
1160 |
+
}
|
1161 |
+
}
|
1162 |
+
|
1163 |
+
function stopResize() {
|
1164 |
+
isResizing = false;
|
1165 |
+
document.removeEventListener('mousemove', resize);
|
1166 |
+
document.removeEventListener('mouseup', stopResize);
|
1167 |
+
}
|
1168 |
+
|
1169 |
+
document.addEventListener('mousemove', resize);
|
1170 |
+
document.addEventListener('mouseup', stopResize);
|
1171 |
+
}
|
1172 |
+
|
1173 |
+
// ์ ํ๋ ์ปดํฌ๋ํธ ์
๋ฐ์ดํธ
|
1174 |
+
function updateSelectedComponent() {
|
1175 |
+
if (!selectedComponent) return;
|
1176 |
+
|
1177 |
+
const textArea = selectedComponent.querySelector('.component-text');
|
1178 |
+
if (textArea) {
|
1179 |
+
textArea.value = document.getElementById('textInput').value;
|
1180 |
+
textArea.style.fontSize = document.getElementById('fontSizeInput').value + 'px';
|
1181 |
+
textArea.style.fontFamily = document.getElementById('fontSelect').value;
|
1182 |
+
textArea.style.fontWeight = document.getElementById('fontWeightSelect').value;
|
1183 |
+
textArea.style.color = selectedColor;
|
1184 |
+
}
|
1185 |
+
}
|
1186 |
+
|
1187 |
+
// ์์ ์ ํ
|
1188 |
+
function selectColor(element, color) {
|
1189 |
+
document.querySelectorAll('.color-option').forEach(opt => {
|
1190 |
+
opt.classList.remove('selected');
|
1191 |
+
});
|
1192 |
+
element.classList.add('selected');
|
1193 |
+
selectedColor = color;
|
1194 |
+
updateSelectedComponent();
|
1195 |
+
}
|
1196 |
+
|
1197 |
+
// ์ ํ๋ ์ปดํฌ๋ํธ ์ญ์
|
1198 |
+
function deleteSelected() {
|
1199 |
+
if (selectedComponent) {
|
1200 |
+
selectedComponent.remove();
|
1201 |
+
selectedComponent = null;
|
1202 |
+
document.getElementById('textInput').value = '';
|
1203 |
+
}
|
1204 |
+
}
|
1205 |
+
|
1206 |
+
// ์ ์ฒด ์ด๊ธฐํ
|
1207 |
+
function clearAll() {
|
1208 |
+
if (confirm('๋ชจ๋ ์ปดํฌ๋ํธ๋ฅผ ์ญ์ ํ์๊ฒ ์ต๋๊น?')) {
|
1209 |
+
document.querySelectorAll('.draggable-component').forEach(c => c.remove());
|
1210 |
+
selectedComponent = null;
|
1211 |
+
document.getElementById('textInput').value = '';
|
1212 |
+
}
|
1213 |
+
}
|
1214 |
+
|
1215 |
+
// ์ ์ฒด ์ด๋ฏธ์ง ์ ์ฅ ๊ธฐ๋ฅ ์ ๊ฑฐ๋จ
|
1216 |
+
|
1217 |
+
// ๊ฐ๋ณ ์ด๋ฏธ์ง ์ ์ฅ
|
1218 |
+
function exportSingleImage() {
|
1219 |
+
const imageNumber = parseInt(document.getElementById('imageNumber').value);
|
1220 |
+
|
1221 |
+
if (!imageNumber || imageNumber < 1) {
|
1222 |
+
alert('โ ๏ธ ์ ์ฅํ ์ด๋ฏธ์ง ๋ฒํธ๋ฅผ ์
๋ ฅํด์ฃผ์ธ์.');
|
1223 |
+
return;
|
1224 |
+
}
|
1225 |
+
|
1226 |
+
const imageContainer = document.getElementById('image-container-' + imageNumber);
|
1227 |
+
|
1228 |
+
if (!imageContainer) {
|
1229 |
+
alert('โ ๏ธ ' + imageNumber + '๋ฒ ์ด๋ฏธ์ง๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.');
|
1230 |
+
return;
|
1231 |
+
}
|
1232 |
+
|
1233 |
+
const loading = document.getElementById('loading');
|
1234 |
+
loading.classList.add('active');
|
1235 |
+
|
1236 |
+
// ์ ํ ํด์ ๋ฐ ๋ฒํธ ์จ๊ธฐ๊ธฐ
|
1237 |
+
document.querySelectorAll('.draggable-component').forEach(c => {
|
1238 |
+
c.classList.remove('selected');
|
1239 |
+
});
|
1240 |
+
|
1241 |
+
const numberLabel = imageContainer.querySelector('.image-number');
|
1242 |
+
if (numberLabel) numberLabel.style.display = 'none';
|
1243 |
+
|
1244 |
+
// ์์ ์ปจํ
์ด๋ ์์ฑ
|
1245 |
+
const tempContainer = document.createElement('div');
|
1246 |
+
tempContainer.style.position = 'relative';
|
1247 |
+
tempContainer.style.width = imageContainer.offsetWidth + 'px';
|
1248 |
+
tempContainer.style.background = 'white';
|
1249 |
+
|
1250 |
+
// ์ด๋ฏธ์ง ๋ณต์ฌ
|
1251 |
+
const imgClone = imageContainer.querySelector('.webtoon-image').cloneNode(true);
|
1252 |
+
imgClone.style.marginBottom = '0';
|
1253 |
+
tempContainer.appendChild(imgClone);
|
1254 |
+
|
1255 |
+
// ํด๋น ์ด๋ฏธ์ง ์์ ์ปดํฌ๋ํธ๋ค๋ง ๋ณต์ฌ
|
1256 |
+
const imageRect = imageContainer.getBoundingClientRect();
|
1257 |
+
const canvasRect = document.getElementById('canvas').getBoundingClientRect();
|
1258 |
+
const imageTop = imageContainer.offsetTop;
|
1259 |
+
const imageBottom = imageTop + imageContainer.offsetHeight;
|
1260 |
+
|
1261 |
+
document.querySelectorAll('.draggable-component').forEach(component => {
|
1262 |
+
const compTop = parseInt(component.style.top);
|
1263 |
+
const compBottom = compTop + component.offsetHeight;
|
1264 |
+
|
1265 |
+
// ์ปดํฌ๋ํธ๊ฐ ์ด๋ฏธ์ง ์์ญ ๋ด์ ์๋์ง ํ์ธ
|
1266 |
+
if (compTop < imageBottom && compBottom > imageTop) {
|
1267 |
+
const compClone = component.cloneNode(true);
|
1268 |
+
compClone.classList.remove('selected');
|
1269 |
+
compClone.style.top = (compTop - imageTop) + 'px';
|
1270 |
+
tempContainer.appendChild(compClone);
|
1271 |
+
}
|
1272 |
+
});
|
1273 |
+
|
1274 |
+
// ์์๋ก DOM์ ์ถ๊ฐ (๋ณด์ด์ง ์๊ฒ)
|
1275 |
+
tempContainer.style.position = 'absolute';
|
1276 |
+
tempContainer.style.left = '-9999px';
|
1277 |
+
document.body.appendChild(tempContainer);
|
1278 |
+
|
1279 |
+
html2canvas(tempContainer, {
|
1280 |
+
backgroundColor: '#ffffff',
|
1281 |
+
scale: 2,
|
1282 |
+
useCORS: true,
|
1283 |
+
logging: false
|
1284 |
+
}).then(function(canvas) {
|
1285 |
+
// ์ด๋ฏธ์ง ๋ค์ด๋ก๋
|
1286 |
+
const link = document.createElement('a');
|
1287 |
+
link.download = 'webtoon_' + imageNumber + '_' + new Date().getTime() + '.png';
|
1288 |
+
link.href = canvas.toDataURL('image/png');
|
1289 |
+
link.click();
|
1290 |
+
|
1291 |
+
// ์์ ์ปจํ
์ด๋ ์ ๊ฑฐ
|
1292 |
+
document.body.removeChild(tempContainer);
|
1293 |
+
|
1294 |
+
// ๋ฒํธ ๋ค์ ํ์
|
1295 |
+
if (numberLabel) numberLabel.style.display = 'flex';
|
1296 |
+
|
1297 |
+
loading.classList.remove('active');
|
1298 |
+
|
1299 |
+
// ์ฑ๊ณต ๋ฉ์์ง
|
1300 |
+
alert('โ
' + imageNumber + '๋ฒ ์ด๋ฏธ์ง๊ฐ ์ฑ๊ณต์ ์ผ๋ก ์ ์ฅ๋์์ต๋๋ค!');
|
1301 |
+
}).catch(function(error) {
|
1302 |
+
document.body.removeChild(tempContainer);
|
1303 |
+
if (numberLabel) numberLabel.style.display = 'flex';
|
1304 |
+
loading.classList.remove('active');
|
1305 |
+
console.error('Error:', error);
|
1306 |
+
alert('โ ๏ธ ์ด๋ฏธ์ง ์ ์ฅ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค.');
|
1307 |
+
});
|
1308 |
+
}
|
1309 |
+
|
1310 |
+
// ์บ๋ฒ์ค ํด๋ฆญ ์ด๋ฒคํธ (๋น ๊ณต๊ฐ ํด๋ฆญ ์ ์ ํ ํด์ )
|
1311 |
+
document.getElementById('canvas').addEventListener('click', function(e) {
|
1312 |
+
if (e.target === this || e.target.classList.contains('webtoon-image')) {
|
1313 |
+
document.querySelectorAll('.draggable-component').forEach(c => {
|
1314 |
+
c.classList.remove('selected');
|
1315 |
+
});
|
1316 |
+
selectedComponent = null;
|
1317 |
+
document.getElementById('textInput').value = '';
|
1318 |
+
}
|
1319 |
+
});
|
1320 |
+
|
1321 |
+
// ํค๋ณด๋ ๋จ์ถํค
|
1322 |
+
document.addEventListener('keydown', function(e) {
|
1323 |
+
if (e.key === 'Delete' && selectedComponent) {
|
1324 |
+
deleteSelected();
|
1325 |
+
}
|
1326 |
+
});
|
1327 |
+
</script>
|
1328 |
+
</body>
|
1329 |
+
</html>
|