@wewear/virtual-try-on 1.4.1 → 1.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/camera.d.ts +9 -2
- package/dist/components/camera-modal.d.ts +4 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/components/review-modal.d.ts +6 -3
- package/dist/index.d.ts +11 -1
- package/dist/index.esm.js +395 -226
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +395 -226
- package/dist/index.js.map +1 -1
- package/dist/utils.d.ts +0 -1
- package/dist/widget.d.ts +0 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -17,6 +17,49 @@
|
|
|
17
17
|
MODAL: 99999,
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
+
function createPreviewBadge() {
|
|
21
|
+
const badge = document.createElement("div");
|
|
22
|
+
badge.className = CSS_CLASSES.PREVIEW_BADGE;
|
|
23
|
+
badge.innerText = "PREVIEW";
|
|
24
|
+
const styleId = "ww-vto-badge-styles";
|
|
25
|
+
if (!document.getElementById(styleId)) {
|
|
26
|
+
const styles = document.createElement("style");
|
|
27
|
+
styles.id = styleId;
|
|
28
|
+
styles.innerHTML = `
|
|
29
|
+
.${CSS_CLASSES.PREVIEW_BADGE} {
|
|
30
|
+
position: absolute;
|
|
31
|
+
top: 20px;
|
|
32
|
+
right: 20px;
|
|
33
|
+
background: rgba(31, 41, 55, 0.9);
|
|
34
|
+
backdrop-filter: blur(4px);
|
|
35
|
+
-webkit-backdrop-filter: blur(4px);
|
|
36
|
+
color: white;
|
|
37
|
+
padding: 6px 14px;
|
|
38
|
+
border-radius: 6px;
|
|
39
|
+
font-size: 12px;
|
|
40
|
+
font-weight: 600;
|
|
41
|
+
letter-spacing: 0.5px;
|
|
42
|
+
z-index: 10;
|
|
43
|
+
pointer-events: none;
|
|
44
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
45
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
46
|
+
animation: ww-vto-pulse 2s ease-in-out infinite;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@keyframes ww-vto-pulse {
|
|
50
|
+
0%, 100% {
|
|
51
|
+
opacity: 0.9;
|
|
52
|
+
}
|
|
53
|
+
50% {
|
|
54
|
+
opacity: 1;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
`;
|
|
58
|
+
document.head.appendChild(styles);
|
|
59
|
+
}
|
|
60
|
+
return badge;
|
|
61
|
+
}
|
|
62
|
+
|
|
20
63
|
function getPositionStyles(position) {
|
|
21
64
|
switch (position) {
|
|
22
65
|
case "bottom-left":
|
|
@@ -40,39 +83,43 @@
|
|
|
40
83
|
const container = document.createElement("div");
|
|
41
84
|
container.className = `${CSS_CLASSES.BUTTON_CONTAINER} ww-button-group`;
|
|
42
85
|
const positionStyles = getPositionStyles(buttonPosition);
|
|
43
|
-
container.style.cssText = `
|
|
44
|
-
position: absolute;
|
|
45
|
-
${positionStyles}
|
|
46
|
-
display: flex;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
86
|
+
container.style.cssText = `
|
|
87
|
+
position: absolute;
|
|
88
|
+
${positionStyles}
|
|
89
|
+
display: flex;
|
|
90
|
+
gap: 4px;
|
|
91
|
+
border-radius: 100px;
|
|
92
|
+
background: white;
|
|
93
|
+
padding: 4px;
|
|
94
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
95
|
+
z-index: ${Z_INDEX.BUTTON};
|
|
96
|
+
transition: all 0.2s ease;
|
|
52
97
|
`;
|
|
53
98
|
// Camera button
|
|
54
99
|
const cameraButton = document.createElement("button");
|
|
55
100
|
cameraButton.type = "button";
|
|
56
101
|
cameraButton.className = `${CSS_CLASSES.BUTTON} ww-camera-btn`;
|
|
57
102
|
cameraButton.setAttribute("aria-label", "Virtual Try-On");
|
|
58
|
-
cameraButton.style.cssText = `
|
|
59
|
-
display: flex;
|
|
60
|
-
width:
|
|
61
|
-
height:
|
|
62
|
-
cursor: pointer;
|
|
63
|
-
align-items: center;
|
|
64
|
-
justify-content: center;
|
|
65
|
-
border-radius:
|
|
66
|
-
padding:
|
|
67
|
-
border: none;
|
|
68
|
-
background:
|
|
69
|
-
color:
|
|
103
|
+
cameraButton.style.cssText = `
|
|
104
|
+
display: flex;
|
|
105
|
+
width: 40px;
|
|
106
|
+
height: 40px;
|
|
107
|
+
cursor: pointer;
|
|
108
|
+
align-items: center;
|
|
109
|
+
justify-content: center;
|
|
110
|
+
border-radius: 100px;
|
|
111
|
+
padding: 0;
|
|
112
|
+
border: none;
|
|
113
|
+
background: white;
|
|
114
|
+
color: #000000;
|
|
115
|
+
transition: all 0.2s ease;
|
|
116
|
+
flex-shrink: 0;
|
|
70
117
|
`;
|
|
71
|
-
cameraButton.innerHTML = `
|
|
72
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="
|
|
73
|
-
<path d="M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z"></path>
|
|
74
|
-
<circle cx="12" cy="13" r="3"></circle>
|
|
75
|
-
</svg>
|
|
118
|
+
cameraButton.innerHTML = `
|
|
119
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display: block;">
|
|
120
|
+
<path d="M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z"></path>
|
|
121
|
+
<circle cx="12" cy="13" r="3"></circle>
|
|
122
|
+
</svg>
|
|
76
123
|
`;
|
|
77
124
|
cameraButton.onclick = onCameraClick;
|
|
78
125
|
container.appendChild(cameraButton);
|
|
@@ -84,27 +131,30 @@
|
|
|
84
131
|
refreshButton.type = "button";
|
|
85
132
|
refreshButton.className = "ww-refresh-btn";
|
|
86
133
|
refreshButton.setAttribute("aria-label", "Refresh virtual try-on");
|
|
87
|
-
refreshButton.style.cssText = `
|
|
88
|
-
display: flex;
|
|
89
|
-
width:
|
|
90
|
-
height:
|
|
91
|
-
cursor: pointer;
|
|
92
|
-
align-items: center;
|
|
93
|
-
justify-content: center;
|
|
94
|
-
border-radius:
|
|
95
|
-
padding:
|
|
96
|
-
border: none;
|
|
97
|
-
background:
|
|
98
|
-
color:
|
|
134
|
+
refreshButton.style.cssText = `
|
|
135
|
+
display: flex;
|
|
136
|
+
width: 40px;
|
|
137
|
+
height: 40px;
|
|
138
|
+
cursor: pointer;
|
|
139
|
+
align-items: center;
|
|
140
|
+
justify-content: center;
|
|
141
|
+
border-radius: 100px;
|
|
142
|
+
padding: 0;
|
|
143
|
+
border: none;
|
|
144
|
+
background: white;
|
|
145
|
+
color: #333333;
|
|
146
|
+
transition: all 0.2s ease;
|
|
147
|
+
flex-shrink: 0;
|
|
99
148
|
`;
|
|
100
|
-
refreshButton.innerHTML = `
|
|
101
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="
|
|
102
|
-
<path d="M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"></path>
|
|
103
|
-
<path d="M3 3v5h5"></path>
|
|
104
|
-
<path d="M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16"></path>
|
|
105
|
-
<path d="M16 16h5v5"></path>
|
|
106
|
-
</svg>
|
|
149
|
+
refreshButton.innerHTML = `
|
|
150
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display: block;">
|
|
151
|
+
<path d="M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"></path>
|
|
152
|
+
<path d="M3 3v5h5"></path>
|
|
153
|
+
<path d="M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16"></path>
|
|
154
|
+
<path d="M16 16h5v5"></path>
|
|
155
|
+
</svg>
|
|
107
156
|
`;
|
|
157
|
+
refreshButton.onclick = onRefreshClick;
|
|
108
158
|
refreshButton.onclick = onRefreshClick;
|
|
109
159
|
container.appendChild(refreshButton);
|
|
110
160
|
}
|
|
@@ -114,30 +164,48 @@
|
|
|
114
164
|
toggleButton.type = "button";
|
|
115
165
|
toggleButton.className = "ww-toggle-btn";
|
|
116
166
|
toggleButton.setAttribute("aria-label", isShowingVirtualTryOn ? "Show Original Image" : "Show Virtual Try-On");
|
|
117
|
-
toggleButton.style.cssText = `
|
|
118
|
-
display: flex;
|
|
119
|
-
width:
|
|
120
|
-
height:
|
|
121
|
-
cursor: pointer;
|
|
122
|
-
align-items: center;
|
|
123
|
-
justify-content: center;
|
|
124
|
-
border-radius:
|
|
125
|
-
padding:
|
|
126
|
-
border: none;
|
|
127
|
-
background: ${isShowingVirtualTryOn ? "
|
|
128
|
-
color: ${isShowingVirtualTryOn ? "white" : "
|
|
167
|
+
toggleButton.style.cssText = `
|
|
168
|
+
display: flex;
|
|
169
|
+
width: 40px;
|
|
170
|
+
height: 40px;
|
|
171
|
+
cursor: pointer;
|
|
172
|
+
align-items: center;
|
|
173
|
+
justify-content: center;
|
|
174
|
+
border-radius: 100px;
|
|
175
|
+
padding: 0;
|
|
176
|
+
border: none;
|
|
177
|
+
background: ${isShowingVirtualTryOn ? "#333333" : "#e5e7eb"};
|
|
178
|
+
color: ${isShowingVirtualTryOn ? "white" : "#333333"};
|
|
179
|
+
transition: all 0.2s ease;
|
|
180
|
+
flex-shrink: 0;
|
|
129
181
|
`;
|
|
130
|
-
toggleButton.innerHTML = `
|
|
131
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="
|
|
132
|
-
<path d="M3 7V5a2 2 0 0 1 2-2h2"></path>
|
|
133
|
-
<path d="M17 3h2a2 2 0 0 1 2 2v2"></path>
|
|
134
|
-
<path d="M21 17v2a2 2 0 0 1-2 2h-2"></path>
|
|
135
|
-
<path d="M7 21H5a2 2 0 0 1-2-2v-2"></path>
|
|
136
|
-
<path d="M8 14s1.5 2 4 2 4-2 4-2"></path>
|
|
137
|
-
<path d="M9 9h.01"></path>
|
|
138
|
-
<path d="M15 9h.01"></path>
|
|
139
|
-
</svg>
|
|
182
|
+
toggleButton.innerHTML = `
|
|
183
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display: block;">
|
|
184
|
+
<path d="M3 7V5a2 2 0 0 1 2-2h2"></path>
|
|
185
|
+
<path d="M17 3h2a2 2 0 0 1 2 2v2"></path>
|
|
186
|
+
<path d="M21 17v2a2 2 0 0 1-2 2h-2"></path>
|
|
187
|
+
<path d="M7 21H5a2 2 0 0 1-2-2v-2"></path>
|
|
188
|
+
<path d="M8 14s1.5 2 4 2 4-2 4-2"></path>
|
|
189
|
+
<path d="M9 9h.01"></path>
|
|
190
|
+
<path d="M15 9h.01"></path>
|
|
191
|
+
</svg>
|
|
140
192
|
`;
|
|
193
|
+
toggleButton.onmouseover = () => {
|
|
194
|
+
if (isShowingVirtualTryOn) {
|
|
195
|
+
toggleButton.style.background = "#4a4a4a";
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
toggleButton.style.background = "#d1d5db";
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
toggleButton.onmouseout = () => {
|
|
202
|
+
if (isShowingVirtualTryOn) {
|
|
203
|
+
toggleButton.style.background = "#333333";
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
toggleButton.style.background = "#e5e7eb";
|
|
207
|
+
}
|
|
208
|
+
};
|
|
141
209
|
toggleButton.onclick = onToggleClick;
|
|
142
210
|
container.appendChild(toggleButton);
|
|
143
211
|
}
|
|
@@ -164,49 +232,98 @@
|
|
|
164
232
|
function createLoadingOverlay(text = "Processing...") {
|
|
165
233
|
const overlay = document.createElement("div");
|
|
166
234
|
overlay.className = "ww-loading-overlay";
|
|
167
|
-
overlay.style.cssText = `
|
|
168
|
-
position: absolute;
|
|
169
|
-
top: 0;
|
|
170
|
-
left: 0;
|
|
171
|
-
width: 100%;
|
|
172
|
-
height: 100%;
|
|
173
|
-
background
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
235
|
+
overlay.style.cssText = `
|
|
236
|
+
position: absolute;
|
|
237
|
+
top: 0;
|
|
238
|
+
left: 0;
|
|
239
|
+
width: 100%;
|
|
240
|
+
height: 100%;
|
|
241
|
+
background: linear-gradient(135deg, rgba(0, 0, 0, 0.92) 0%, rgba(0, 0, 0, 0.88) 100%);
|
|
242
|
+
backdrop-filter: blur(8px);
|
|
243
|
+
-webkit-backdrop-filter: blur(8px);
|
|
244
|
+
display: flex;
|
|
245
|
+
flex-direction: column;
|
|
246
|
+
align-items: center;
|
|
247
|
+
justify-content: center;
|
|
248
|
+
z-index: ${Z_INDEX.MODAL + 1};
|
|
249
|
+
border-radius: inherit;
|
|
250
|
+
animation: ww-fade-in 0.3s ease;
|
|
180
251
|
`;
|
|
181
252
|
// Add CSS animation to the document if not already added
|
|
182
253
|
if (!document.getElementById("ww-loading-animation")) {
|
|
183
254
|
const style = document.createElement("style");
|
|
184
255
|
style.id = "ww-loading-animation";
|
|
185
|
-
style.textContent = `
|
|
186
|
-
@keyframes ww-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
256
|
+
style.textContent = `
|
|
257
|
+
@keyframes ww-fade-in {
|
|
258
|
+
from { opacity: 0; }
|
|
259
|
+
to { opacity: 1; }
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
@keyframes ww-pulse-logo {
|
|
263
|
+
0%, 100% {
|
|
264
|
+
opacity: 0.8;
|
|
265
|
+
transform: scale(1);
|
|
266
|
+
}
|
|
267
|
+
50% {
|
|
268
|
+
opacity: 1;
|
|
269
|
+
transform: scale(1.05);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
@keyframes ww-spinner-rotate {
|
|
274
|
+
0% { transform: rotate(0deg); }
|
|
275
|
+
100% { transform: rotate(360deg); }
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
@keyframes ww-dot-bounce {
|
|
279
|
+
0%, 80%, 100% {
|
|
280
|
+
transform: scale(0);
|
|
281
|
+
opacity: 0.5;
|
|
282
|
+
}
|
|
283
|
+
40% {
|
|
284
|
+
transform: scale(1);
|
|
285
|
+
opacity: 1;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.ww-loading-logo {
|
|
290
|
+
animation: ww-pulse-logo 2s ease-in-out infinite;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.ww-loading-spinner {
|
|
294
|
+
animation: ww-spinner-rotate 1s linear infinite;
|
|
295
|
+
}
|
|
193
296
|
`;
|
|
194
297
|
document.head.appendChild(style);
|
|
195
298
|
}
|
|
196
|
-
overlay.innerHTML = `
|
|
197
|
-
<div style="display: flex; flex-direction: column; align-items: center; gap:
|
|
198
|
-
<
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
299
|
+
overlay.innerHTML = `
|
|
300
|
+
<div style="display: flex; flex-direction: column; align-items: center; gap: 32px;">
|
|
301
|
+
<div style="position: relative; width: 120px; height: 120px; display: flex; align-items: center; justify-content: center;">
|
|
302
|
+
<!-- Outer spinning circle -->
|
|
303
|
+
<div class="ww-loading-spinner" style="
|
|
304
|
+
position: absolute;
|
|
305
|
+
width: 120px;
|
|
306
|
+
height: 120px;
|
|
307
|
+
border: 3px solid transparent;
|
|
308
|
+
border-top: 3px solid #333333;
|
|
309
|
+
border-right: 3px solid #333333;
|
|
310
|
+
border-radius: 50%;
|
|
311
|
+
"></div>
|
|
312
|
+
|
|
313
|
+
<!-- Logo -->
|
|
314
|
+
<svg class="ww-loading-logo" width="80" height="50" viewBox="0 0 214 135" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
315
|
+
<path d="M102.906 74.8679C102.906 77.9717 101.574 80.7453 98.9104 83.1887C96.6871 85.1918 93.9025 86.6997 90.5566 87.7123C87.695 88.5708 84.6462 89 81.4104 89C73.8821 89 68.0047 87.0189 63.7783 83.0566C59.5519 87.0189 53.6855 89 46.1792 89C42.9434 89 39.9057 88.5708 37.066 87.7123C33.7201 86.6997 30.9245 85.1918 28.6792 83.1887C26.0157 80.7453 24.684 77.9717 24.684 74.8679V41.6509H32.3774V74.8679C32.3774 76.2547 33.489 77.5645 35.7123 78.7972C37.3632 79.7217 39.0692 80.3711 40.8302 80.7453C42.5252 81.1195 44.3082 81.3066 46.1792 81.3066C48.0063 81.3066 49.7673 81.1195 51.4623 80.7453C53.2453 80.3711 54.9623 79.7217 56.6132 78.7972C58.8585 77.5645 59.9811 76.2547 59.9811 74.8679V41.6509H67.6085V74.8679C67.6085 76.2547 68.7311 77.5645 70.9764 78.7972C72.6274 79.7217 74.3443 80.3711 76.1274 80.7453C77.8223 81.1195 79.5833 81.3066 81.4104 81.3066C83.2814 81.3066 85.0755 81.1195 86.7925 80.7453C88.5314 80.3711 90.2264 79.7217 91.8774 78.7972C94.1006 77.5645 95.2123 76.2547 95.2123 74.8679V41.6509H102.906V74.8679ZM189.283 74.8679C189.283 77.9717 187.951 80.7453 185.288 83.1887C183.064 85.1918 180.28 86.6997 176.934 87.7123C174.072 88.5708 171.024 89 167.788 89C160.259 89 154.382 87.0189 150.156 83.0566C145.929 87.0189 140.063 89 132.557 89C129.321 89 126.283 88.5708 123.443 87.7123C120.097 86.6997 117.302 85.1918 115.057 83.1887C112.393 80.7453 111.061 77.9717 111.061 74.8679V41.6509H118.755V74.8679C118.755 76.2547 119.866 77.5645 122.09 78.7972C123.741 79.7217 125.447 80.3711 127.208 80.7453C128.903 81.1195 130.686 81.3066 132.557 81.3066C134.384 81.3066 136.145 81.1195 137.84 80.7453C139.623 80.3711 141.34 79.7217 142.991 78.7972C145.236 77.5645 146.358 76.2547 146.358 74.8679V41.6509H153.986V74.8679C153.986 76.2547 155.108 77.5645 157.354 78.7972C159.005 79.7217 160.722 80.3711 162.505 80.7453C164.2 81.1195 165.961 81.3066 167.788 81.3066C169.659 81.3066 171.453 81.1195 173.17 80.7453C174.909 80.3711 176.604 79.7217 178.255 78.7972C180.478 77.5645 181.59 76.2547 181.59 74.8679V41.6509H189.283V74.8679Z" fill="white"/>
|
|
316
|
+
</svg>
|
|
317
|
+
</div>
|
|
318
|
+
|
|
319
|
+
<div style="font-size: 17px; font-weight: 500; text-align: center; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; color: white; letter-spacing: 0.5px; max-width: 280px;">${text}</div>
|
|
320
|
+
|
|
321
|
+
<div style="display: flex; gap: 10px; margin-top: 4px;">
|
|
322
|
+
<div style="width: 10px; height: 10px; border-radius: 50%; background: #333333; animation: ww-dot-bounce 1.4s ease-in-out infinite;"></div>
|
|
323
|
+
<div style="width: 10px; height: 10px; border-radius: 50%; background: #333333; animation: ww-dot-bounce 1.4s ease-in-out 0.2s infinite;"></div>
|
|
324
|
+
<div style="width: 10px; height: 10px; border-radius: 50%; background: #333333; animation: ww-dot-bounce 1.4s ease-in-out 0.4s infinite;"></div>
|
|
325
|
+
</div>
|
|
326
|
+
</div>
|
|
210
327
|
`;
|
|
211
328
|
return overlay;
|
|
212
329
|
}
|
|
@@ -234,51 +351,6 @@
|
|
|
234
351
|
}
|
|
235
352
|
}
|
|
236
353
|
|
|
237
|
-
function createPreviewBadge() {
|
|
238
|
-
const badge = document.createElement("div");
|
|
239
|
-
badge.className = CSS_CLASSES.PREVIEW_BADGE;
|
|
240
|
-
badge.innerText = "PREVIEW";
|
|
241
|
-
const styleId = "ww-vto-badge-styles";
|
|
242
|
-
if (!document.getElementById(styleId)) {
|
|
243
|
-
const styles = document.createElement("style");
|
|
244
|
-
styles.id = styleId;
|
|
245
|
-
styles.innerHTML = `
|
|
246
|
-
.${CSS_CLASSES.PREVIEW_BADGE} {
|
|
247
|
-
position: absolute;
|
|
248
|
-
top: 16px;
|
|
249
|
-
right: 16px;
|
|
250
|
-
background-color: rgba(0, 0, 0, 0.6);
|
|
251
|
-
color: white;
|
|
252
|
-
padding: 4px 8px;
|
|
253
|
-
border-radius: 4px;
|
|
254
|
-
font-size: 12px;
|
|
255
|
-
font-weight: 600;
|
|
256
|
-
z-index: 10;
|
|
257
|
-
animation: ww-vto-pulse 2s infinite;
|
|
258
|
-
pointer-events: none;
|
|
259
|
-
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
@keyframes ww-vto-pulse {
|
|
263
|
-
0% {
|
|
264
|
-
transform: scale(1);
|
|
265
|
-
opacity: 0.9;
|
|
266
|
-
}
|
|
267
|
-
50% {
|
|
268
|
-
transform: scale(1.05);
|
|
269
|
-
opacity: 1;
|
|
270
|
-
}
|
|
271
|
-
100% {
|
|
272
|
-
transform: scale(1);
|
|
273
|
-
opacity: 0.9;
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
`;
|
|
277
|
-
document.head.appendChild(styles);
|
|
278
|
-
}
|
|
279
|
-
return badge;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
354
|
function showAlert(container, message, type) {
|
|
283
355
|
var _a;
|
|
284
356
|
removeAlert(container); // Remove any existing alert
|
|
@@ -286,42 +358,63 @@
|
|
|
286
358
|
alertDiv.className = `ww-alert ww-alert-${type}`;
|
|
287
359
|
alertDiv.setAttribute("role", "alert" );
|
|
288
360
|
alertDiv.setAttribute("aria-live", "assertive");
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
361
|
+
const bgColor = "linear-gradient(135deg, #fee2e2 0%, #fecaca 100%)"
|
|
362
|
+
;
|
|
363
|
+
const textColor = "#991b1b" ;
|
|
364
|
+
const borderColor = "#f87171" ;
|
|
365
|
+
const iconColor = "#dc2626" ;
|
|
366
|
+
alertDiv.style.cssText = `
|
|
367
|
+
position: absolute;
|
|
368
|
+
top: 24px;
|
|
369
|
+
left: 50%;
|
|
370
|
+
transform: translateX(-50%) translateY(-20px);
|
|
371
|
+
background: ${bgColor};
|
|
372
|
+
color: ${textColor};
|
|
373
|
+
border: 1px solid ${borderColor};
|
|
374
|
+
border-radius: 12px;
|
|
375
|
+
padding: 16px 20px;
|
|
376
|
+
z-index: 9999;
|
|
377
|
+
font-size: 15px;
|
|
378
|
+
font-weight: 500;
|
|
379
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
380
|
+
backdrop-filter: blur(8px);
|
|
381
|
+
-webkit-backdrop-filter: blur(8px);
|
|
382
|
+
display: flex;
|
|
383
|
+
align-items: center;
|
|
384
|
+
gap: 12px;
|
|
385
|
+
min-width: 280px;
|
|
386
|
+
max-width: 90%;
|
|
387
|
+
opacity: 0;
|
|
388
|
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
309
389
|
`;
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
390
|
+
const icon = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="${iconColor}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
391
|
+
<circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/>
|
|
392
|
+
</svg>`
|
|
393
|
+
;
|
|
394
|
+
alertDiv.innerHTML = `
|
|
395
|
+
${icon}
|
|
396
|
+
<span style="flex: 1; line-height: 1.5;">${message}</span>
|
|
397
|
+
<button type="button" aria-label="Close alert"
|
|
398
|
+
style="
|
|
399
|
+
background: none;
|
|
400
|
+
border: none;
|
|
401
|
+
font-size: 22px;
|
|
402
|
+
color: ${textColor};
|
|
403
|
+
cursor: pointer;
|
|
404
|
+
padding: 0;
|
|
405
|
+
line-height: 1;
|
|
406
|
+
opacity: 0.7;
|
|
407
|
+
transition: opacity 0.2s ease;
|
|
408
|
+
width: 24px;
|
|
409
|
+
height: 24px;
|
|
410
|
+
display: flex;
|
|
411
|
+
align-items: center;
|
|
412
|
+
justify-content: center;
|
|
413
|
+
"
|
|
414
|
+
onmouseover="this.style.opacity='1'"
|
|
415
|
+
onmouseout="this.style.opacity='0.7'">
|
|
416
|
+
×
|
|
417
|
+
</button>
|
|
325
418
|
`;
|
|
326
419
|
// Close on button click
|
|
327
420
|
(_a = alertDiv.querySelector("button")) === null || _a === void 0 ? void 0 : _a.addEventListener("click", () => {
|
|
@@ -333,10 +426,16 @@
|
|
|
333
426
|
alertDiv.style.opacity = "1";
|
|
334
427
|
alertDiv.style.transform = "translateX(-50%) translateY(0)";
|
|
335
428
|
});
|
|
429
|
+
// Auto-dismiss after 8 seconds
|
|
430
|
+
setTimeout(() => {
|
|
431
|
+
if (alertDiv.parentElement) {
|
|
432
|
+
fadeOutAndRemove(alertDiv);
|
|
433
|
+
}
|
|
434
|
+
}, 8000);
|
|
336
435
|
}
|
|
337
436
|
function fadeOutAndRemove(element) {
|
|
338
437
|
element.style.opacity = "0";
|
|
339
|
-
element.style.transform = "translateX(-50%) translateY(-
|
|
438
|
+
element.style.transform = "translateX(-50%) translateY(-20px)";
|
|
340
439
|
setTimeout(() => {
|
|
341
440
|
element.remove();
|
|
342
441
|
}, 300);
|
|
@@ -353,7 +452,6 @@
|
|
|
353
452
|
this.originalProductImageUrl = null;
|
|
354
453
|
this.isShowingVirtualTryOn = false;
|
|
355
454
|
this.lastModelImage = null;
|
|
356
|
-
this.cookieCheckInterval = null;
|
|
357
455
|
this.cameraButton = null;
|
|
358
456
|
this.iframeMessageListener = null;
|
|
359
457
|
this.previewBadge = null;
|
|
@@ -443,47 +541,110 @@
|
|
|
443
541
|
removeElements(`.${CSS_CLASSES.MODAL}`);
|
|
444
542
|
const modal = document.createElement("div");
|
|
445
543
|
modal.className = CSS_CLASSES.MODAL;
|
|
446
|
-
modal.style.cssText = `
|
|
447
|
-
position: fixed;
|
|
448
|
-
top: 0;
|
|
449
|
-
left: 0;
|
|
450
|
-
width: 100%;
|
|
451
|
-
height: 100%;
|
|
452
|
-
background
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
544
|
+
modal.style.cssText = `
|
|
545
|
+
position: fixed;
|
|
546
|
+
top: 0;
|
|
547
|
+
left: 0;
|
|
548
|
+
width: 100%;
|
|
549
|
+
height: 100%;
|
|
550
|
+
background: linear-gradient(135deg, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0.7) 100%);
|
|
551
|
+
backdrop-filter: blur(8px);
|
|
552
|
+
-webkit-backdrop-filter: blur(8px);
|
|
553
|
+
display: flex;
|
|
554
|
+
justify-content: center;
|
|
555
|
+
align-items: center;
|
|
556
|
+
z-index: 1000;
|
|
557
|
+
animation: ww-modal-fade-in 0.3s ease;
|
|
457
558
|
`;
|
|
559
|
+
// Add fade-in animation
|
|
560
|
+
if (!document.getElementById("ww-modal-animation")) {
|
|
561
|
+
const style = document.createElement("style");
|
|
562
|
+
style.id = "ww-modal-animation";
|
|
563
|
+
style.textContent = `
|
|
564
|
+
@keyframes ww-modal-fade-in {
|
|
565
|
+
from { opacity: 0; }
|
|
566
|
+
to { opacity: 1; }
|
|
567
|
+
}
|
|
568
|
+
@keyframes ww-modal-scale-in {
|
|
569
|
+
from { transform: scale(0.95); opacity: 0; }
|
|
570
|
+
to { transform: scale(1); opacity: 1; }
|
|
571
|
+
}
|
|
572
|
+
`;
|
|
573
|
+
document.head.appendChild(style);
|
|
574
|
+
}
|
|
575
|
+
const iframeContainer = document.createElement("div");
|
|
576
|
+
iframeContainer.style.cssText = `
|
|
577
|
+
position: relative;
|
|
578
|
+
width: 90%;
|
|
579
|
+
height: 90%;
|
|
580
|
+
max-width: 480px;
|
|
581
|
+
max-height: 720px;
|
|
582
|
+
border-radius: 20px;
|
|
583
|
+
overflow: hidden;
|
|
584
|
+
box-shadow: 0 24px 48px rgba(0, 0, 0, 0.3), 0 12px 24px rgba(0, 0, 0, 0.2);
|
|
585
|
+
animation: ww-modal-scale-in 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
586
|
+
background: white;
|
|
587
|
+
`;
|
|
458
588
|
const iframe = document.createElement("iframe");
|
|
459
589
|
iframe.src = url;
|
|
460
|
-
iframe.style.cssText = `
|
|
461
|
-
width:
|
|
462
|
-
height:
|
|
463
|
-
|
|
464
|
-
max-height: 600px;
|
|
465
|
-
border: none;
|
|
466
|
-
border-radius: 8px;
|
|
590
|
+
iframe.style.cssText = `
|
|
591
|
+
width: 100%;
|
|
592
|
+
height: 100%;
|
|
593
|
+
border: none;
|
|
467
594
|
`;
|
|
468
595
|
const closeButton = document.createElement("button");
|
|
469
|
-
closeButton.
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
596
|
+
closeButton.innerHTML = `
|
|
597
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
598
|
+
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
599
|
+
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
600
|
+
</svg>
|
|
601
|
+
`;
|
|
602
|
+
closeButton.setAttribute("aria-label", "Close modal");
|
|
603
|
+
closeButton.style.cssText = `
|
|
604
|
+
position: absolute;
|
|
605
|
+
top: -48px;
|
|
606
|
+
right: 0;
|
|
607
|
+
background: rgba(255, 255, 255, 0.95);
|
|
608
|
+
backdrop-filter: blur(8px);
|
|
609
|
+
-webkit-backdrop-filter: blur(8px);
|
|
610
|
+
border: none;
|
|
611
|
+
border-radius: 50%;
|
|
612
|
+
width: 40px;
|
|
613
|
+
height: 40px;
|
|
614
|
+
cursor: pointer;
|
|
615
|
+
display: flex;
|
|
616
|
+
align-items: center;
|
|
617
|
+
justify-content: center;
|
|
618
|
+
color: #1f2937;
|
|
619
|
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
620
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
|
|
480
621
|
`;
|
|
622
|
+
closeButton.onmouseover = () => {
|
|
623
|
+
closeButton.style.transform = "scale(1.1) rotate(90deg)";
|
|
624
|
+
closeButton.style.background = "#ef4444";
|
|
625
|
+
closeButton.style.color = "white";
|
|
626
|
+
};
|
|
627
|
+
closeButton.onmouseout = () => {
|
|
628
|
+
closeButton.style.transform = "scale(1) rotate(0deg)";
|
|
629
|
+
closeButton.style.background = "rgba(255, 255, 255, 0.95)";
|
|
630
|
+
closeButton.style.color = "#1f2937";
|
|
631
|
+
};
|
|
481
632
|
closeButton.onclick = () => {
|
|
482
|
-
modal.
|
|
633
|
+
modal.style.opacity = "0";
|
|
634
|
+
iframeContainer.style.transform = "scale(0.95)";
|
|
635
|
+
iframeContainer.style.opacity = "0";
|
|
636
|
+
setTimeout(() => modal.remove(), 300);
|
|
483
637
|
};
|
|
484
|
-
|
|
485
|
-
|
|
638
|
+
iframeContainer.appendChild(iframe);
|
|
639
|
+
iframeContainer.appendChild(closeButton);
|
|
640
|
+
modal.appendChild(iframeContainer);
|
|
486
641
|
document.body.appendChild(modal);
|
|
642
|
+
// Close on backdrop click
|
|
643
|
+
modal.onclick = (e) => {
|
|
644
|
+
if (e.target === modal) {
|
|
645
|
+
closeButton.click();
|
|
646
|
+
}
|
|
647
|
+
};
|
|
487
648
|
}
|
|
488
649
|
/**
|
|
489
650
|
* Sets up listener for messages from the iframe
|
|
@@ -636,6 +797,19 @@
|
|
|
636
797
|
if (!container.hasAttribute("data-ww-original-content")) {
|
|
637
798
|
container.setAttribute("data-ww-original-content", container.innerHTML);
|
|
638
799
|
}
|
|
800
|
+
// Capture and lock container dimensions before replacement to prevent layout shift
|
|
801
|
+
if (!container.hasAttribute("data-ww-container-locked")) {
|
|
802
|
+
const containerRect = container.getBoundingClientRect();
|
|
803
|
+
// Store original dimensions
|
|
804
|
+
container.setAttribute("data-ww-container-width", containerRect.width.toString());
|
|
805
|
+
container.setAttribute("data-ww-container-height", containerRect.height.toString());
|
|
806
|
+
// Lock the container dimensions
|
|
807
|
+
container.style.width = `${containerRect.width}px`;
|
|
808
|
+
container.style.height = `${containerRect.height}px`;
|
|
809
|
+
container.style.minWidth = `${containerRect.width}px`;
|
|
810
|
+
container.style.minHeight = `${containerRect.height}px`;
|
|
811
|
+
container.setAttribute("data-ww-container-locked", "true");
|
|
812
|
+
}
|
|
639
813
|
// Capture original image dimensions before replacement to prevent layout shift
|
|
640
814
|
const originalImg = container.querySelector("img");
|
|
641
815
|
if (originalImg &&
|
|
@@ -726,11 +900,10 @@
|
|
|
726
900
|
else if (originalRectHeight && originalRectHeight !== "0") {
|
|
727
901
|
heightStyle = `${originalRectHeight}px`;
|
|
728
902
|
}
|
|
729
|
-
image.style.cssText = `
|
|
730
|
-
width: ${widthStyle};
|
|
731
|
-
height: ${heightStyle};
|
|
732
|
-
object-fit:
|
|
733
|
-
border-radius: 8px;
|
|
903
|
+
image.style.cssText = `
|
|
904
|
+
width: ${widthStyle};
|
|
905
|
+
height: ${heightStyle};
|
|
906
|
+
object-fit: contain;
|
|
734
907
|
`;
|
|
735
908
|
// Prepend the image to ensure buttons are rendered on top
|
|
736
909
|
container.prepend(image);
|
|
@@ -765,11 +938,7 @@
|
|
|
765
938
|
removeElements(`.${CSS_CLASSES.BUTTON_CONTAINER}`);
|
|
766
939
|
// Remove all modals
|
|
767
940
|
removeElements(`.${CSS_CLASSES.MODAL}`);
|
|
768
|
-
// Clear
|
|
769
|
-
if (this.cookieCheckInterval !== null) {
|
|
770
|
-
clearInterval(this.cookieCheckInterval);
|
|
771
|
-
this.cookieCheckInterval = null;
|
|
772
|
-
}
|
|
941
|
+
// Clear references
|
|
773
942
|
this.cameraButton = null;
|
|
774
943
|
// Remove message listener
|
|
775
944
|
if (this.iframeMessageListener) {
|