@primestyleai/tryon 3.0.0 → 3.1.0
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/react/index.js +97 -32
- package/package.json +1 -1
package/dist/react/index.js
CHANGED
|
@@ -187,9 +187,6 @@ function PrimeStyleTryonInner({
|
|
|
187
187
|
const [resultImageUrl, setResultImageUrl] = useState(null);
|
|
188
188
|
const [errorMessage, setErrorMessage] = useState(null);
|
|
189
189
|
const [dragOver, setDragOver] = useState(false);
|
|
190
|
-
const countdownRef = useRef(25);
|
|
191
|
-
const countdownElRef = useRef(null);
|
|
192
|
-
const countdownCircleRef = useRef(null);
|
|
193
190
|
const [sizingMethod, setSizingMethod] = useState(null);
|
|
194
191
|
const [sizingResult, setSizingResult] = useState(null);
|
|
195
192
|
const [sizeGuide, setSizeGuide] = useState(null);
|
|
@@ -202,6 +199,7 @@ function PrimeStyleTryonInner({
|
|
|
202
199
|
const [weightUnit, setWeightUnit] = useState(imperial ? "lbs" : "kg");
|
|
203
200
|
const formRef = useRef({});
|
|
204
201
|
const [formGender, setFormGender] = useState("male");
|
|
202
|
+
const [formKey, setFormKey] = useState(0);
|
|
205
203
|
const [profiles, setProfiles] = useState(() => lsGet("profiles", []));
|
|
206
204
|
const [history, setHistory] = useState(() => lsGet("history", []));
|
|
207
205
|
const [activeProfileId, setActiveProfileId] = useState(null);
|
|
@@ -240,15 +238,33 @@ function PrimeStyleTryonInner({
|
|
|
240
238
|
if (pollingRef.current) clearInterval(pollingRef.current);
|
|
241
239
|
};
|
|
242
240
|
}, [apiUrl]);
|
|
241
|
+
const progressRef = useRef(0);
|
|
242
|
+
const progressBarRef = useRef(null);
|
|
243
|
+
const progressTextRef = useRef(null);
|
|
244
|
+
const progressStatusRef = useRef(null);
|
|
243
245
|
useEffect(() => {
|
|
244
246
|
if (view === "processing") {
|
|
245
|
-
|
|
247
|
+
progressRef.current = 0;
|
|
248
|
+
const statuses = [
|
|
249
|
+
{ at: 0, text: "Preparing your image..." },
|
|
250
|
+
{ at: 15, text: "Analyzing body proportions..." },
|
|
251
|
+
{ at: 30, text: "Matching garment to your photo..." },
|
|
252
|
+
{ at: 50, text: "Generating virtual try-on..." },
|
|
253
|
+
{ at: 75, text: "Refining details..." },
|
|
254
|
+
{ at: 90, text: "Almost there..." }
|
|
255
|
+
];
|
|
246
256
|
const interval = setInterval(() => {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
257
|
+
const p = progressRef.current;
|
|
258
|
+
const increment = p < 30 ? 1.2 : p < 60 ? 0.8 : p < 80 ? 0.4 : p < 95 ? 0.15 : 0;
|
|
259
|
+
progressRef.current = Math.min(p + increment, 95);
|
|
260
|
+
const val = Math.round(progressRef.current);
|
|
261
|
+
if (progressBarRef.current) progressBarRef.current.style.width = `${val}%`;
|
|
262
|
+
if (progressTextRef.current) progressTextRef.current.textContent = `${val}%`;
|
|
263
|
+
if (progressStatusRef.current) {
|
|
264
|
+
const status = [...statuses].reverse().find((s) => val >= s.at);
|
|
265
|
+
if (status) progressStatusRef.current.textContent = status.text;
|
|
266
|
+
}
|
|
267
|
+
}, 200);
|
|
252
268
|
return () => clearInterval(interval);
|
|
253
269
|
}
|
|
254
270
|
}, [view]);
|
|
@@ -385,8 +401,12 @@ function PrimeStyleTryonInner({
|
|
|
385
401
|
});
|
|
386
402
|
if (!completedRef.current) {
|
|
387
403
|
completedRef.current = true;
|
|
404
|
+
progressRef.current = 100;
|
|
405
|
+
if (progressBarRef.current) progressBarRef.current.style.width = "100%";
|
|
406
|
+
if (progressTextRef.current) progressTextRef.current.textContent = "100%";
|
|
407
|
+
if (progressStatusRef.current) progressStatusRef.current.textContent = "Complete!";
|
|
388
408
|
cleanupJob();
|
|
389
|
-
setView("result");
|
|
409
|
+
setTimeout(() => setView("result"), 400);
|
|
390
410
|
onComplete?.({ jobId: update.galleryId, imageUrl: update.imageUrl });
|
|
391
411
|
}
|
|
392
412
|
} else if (update.status === "failed") {
|
|
@@ -541,6 +561,11 @@ function PrimeStyleTryonInner({
|
|
|
541
561
|
if (p.fitPreference) fd.fitPreference = p.fitPreference;
|
|
542
562
|
formRef.current = fd;
|
|
543
563
|
setFormGender(fd.gender || "male");
|
|
564
|
+
if (p.country) setSizingCountry(p.country);
|
|
565
|
+
if (p.sizingUnit) setSizingUnit(p.sizingUnit);
|
|
566
|
+
if (p.heightUnit) setHeightUnit(p.heightUnit);
|
|
567
|
+
if (p.weightUnit) setWeightUnit(p.weightUnit);
|
|
568
|
+
setFormKey((k) => k + 1);
|
|
544
569
|
}, [profiles]);
|
|
545
570
|
const saveProfile = useCallback((name) => {
|
|
546
571
|
const id = activeProfileId || `p_${Date.now()}`;
|
|
@@ -563,6 +588,10 @@ function PrimeStyleTryonInner({
|
|
|
563
588
|
shoeUS: formRef.current.shoeUS,
|
|
564
589
|
shoeUK: formRef.current.shoeUK,
|
|
565
590
|
fitPreference: formRef.current.fitPreference,
|
|
591
|
+
country: sizingCountry,
|
|
592
|
+
sizingUnit,
|
|
593
|
+
heightUnit,
|
|
594
|
+
weightUnit,
|
|
566
595
|
createdAt: Date.now()
|
|
567
596
|
};
|
|
568
597
|
setProfiles((prev) => {
|
|
@@ -576,7 +605,7 @@ function PrimeStyleTryonInner({
|
|
|
576
605
|
});
|
|
577
606
|
setActiveProfileId(id);
|
|
578
607
|
setProfileSaved(true);
|
|
579
|
-
}, [activeProfileId]);
|
|
608
|
+
}, [activeProfileId, sizingCountry, sizingUnit, heightUnit, weightUnit]);
|
|
580
609
|
const saveHistoryEntry = useCallback(() => {
|
|
581
610
|
const entry = {
|
|
582
611
|
id: `h_${Date.now()}`,
|
|
@@ -827,7 +856,11 @@ function PrimeStyleTryonInner({
|
|
|
827
856
|
/* @__PURE__ */ jsx("label", { children: "Sizing region" }),
|
|
828
857
|
/* @__PURE__ */ jsx("select", { className: "ps-tryon-country-select", value: sizingCountry, onChange: (e) => setSizingCountry(e.target.value), children: SIZING_COUNTRIES.map((c) => /* @__PURE__ */ jsx("option", { value: c.code, children: c.label }, c.code)) })
|
|
829
858
|
] }),
|
|
830
|
-
sizingMethod === "exact" && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(UnitToggle, { options: [{ label: "cm", value: "cm" }, { label: "in", value: "in" }], value: sizingUnit, onChange:
|
|
859
|
+
sizingMethod === "exact" && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(UnitToggle, { options: [{ label: "cm", value: "cm" }, { label: "in", value: "in" }], value: sizingUnit, onChange: (v) => {
|
|
860
|
+
setSizingUnit(v);
|
|
861
|
+
setHeightUnit(v === "cm" ? "cm" : "ft");
|
|
862
|
+
setWeightUnit(v === "cm" ? "kg" : "lbs");
|
|
863
|
+
} }) }),
|
|
831
864
|
/* @__PURE__ */ jsxs("div", { className: "ps-tryon-input-row", children: [
|
|
832
865
|
/* @__PURE__ */ jsx("label", { children: "Height" }),
|
|
833
866
|
heightUnit === "ft" ? /* @__PURE__ */ jsxs("div", { className: "ps-tryon-height-ft", children: [
|
|
@@ -883,18 +916,20 @@ function PrimeStyleTryonInner({
|
|
|
883
916
|
"Get My Size & Try On ",
|
|
884
917
|
/* @__PURE__ */ jsx(ArrowRightIcon, {})
|
|
885
918
|
] })
|
|
886
|
-
] }, `form-${formGender}-${sizingUnit}-${heightUnit}-${sizingCountry}`);
|
|
919
|
+
] }, `form-${formGender}-${sizingUnit}-${heightUnit}-${sizingCountry}-${formKey}`);
|
|
887
920
|
}
|
|
888
921
|
function ProcessingView() {
|
|
889
922
|
return /* @__PURE__ */ jsxs("div", { className: "ps-tryon-processing", children: [
|
|
890
|
-
/* @__PURE__ */ jsxs("div", { className: "ps-tryon-
|
|
891
|
-
/* @__PURE__ */
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
] }),
|
|
895
|
-
/* @__PURE__ */ jsx("span", { ref: countdownElRef, className: "ps-tryon-countdown-number", children: "25" })
|
|
923
|
+
/* @__PURE__ */ jsxs("div", { className: "ps-tryon-processing-image-wrap", children: [
|
|
924
|
+
previewUrl && /* @__PURE__ */ jsx("img", { src: previewUrl, alt: "Your photo", className: "ps-tryon-processing-model" }),
|
|
925
|
+
/* @__PURE__ */ jsx("div", { className: "ps-tryon-scan-line" }),
|
|
926
|
+
/* @__PURE__ */ jsx("div", { className: "ps-tryon-scan-overlay" })
|
|
896
927
|
] }),
|
|
897
|
-
/* @__PURE__ */
|
|
928
|
+
/* @__PURE__ */ jsxs("div", { className: "ps-tryon-progress-section", children: [
|
|
929
|
+
/* @__PURE__ */ jsx("div", { className: "ps-tryon-progress-bar-wrap", children: /* @__PURE__ */ jsx("div", { ref: progressBarRef, className: "ps-tryon-progress-bar-fill", style: { width: "0%" } }) }),
|
|
930
|
+
/* @__PURE__ */ jsx("span", { ref: progressTextRef, className: "ps-tryon-progress-pct", children: "0%" })
|
|
931
|
+
] }),
|
|
932
|
+
/* @__PURE__ */ jsx("div", { ref: progressStatusRef, className: cx("ps-tryon-processing-text", cn.processingText), children: "Preparing your image..." }),
|
|
898
933
|
/* @__PURE__ */ jsx("p", { className: cx("ps-tryon-processing-sub", cn.processingSubText), children: "This usually takes 15-25 seconds" })
|
|
899
934
|
] });
|
|
900
935
|
}
|
|
@@ -1324,19 +1359,49 @@ const STYLES = `
|
|
|
1324
1359
|
.ps-tryon-disclaimer { font-size: 11px; color: #666; margin: 4px 0 0; }
|
|
1325
1360
|
|
|
1326
1361
|
/* Processing */
|
|
1327
|
-
.ps-tryon-processing { text-align: center; padding:
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1362
|
+
.ps-tryon-processing { text-align: center; padding: 24px; display: flex; flex-direction: column; align-items: center; }
|
|
1363
|
+
|
|
1364
|
+
.ps-tryon-processing-image-wrap {
|
|
1365
|
+
position: relative; width: 200px; height: 260px; margin: 0 auto 24px;
|
|
1366
|
+
border-radius: 16px; overflow: hidden; border: 2px solid #333;
|
|
1367
|
+
}
|
|
1368
|
+
.ps-tryon-processing-model {
|
|
1369
|
+
width: 100%; height: 100%; object-fit: cover; display: block;
|
|
1370
|
+
}
|
|
1371
|
+
.ps-tryon-scan-overlay {
|
|
1372
|
+
position: absolute; inset: 0;
|
|
1373
|
+
background: linear-gradient(180deg, rgba(187,148,92,0.05) 0%, transparent 40%, transparent 60%, rgba(187,148,92,0.05) 100%);
|
|
1374
|
+
pointer-events: none;
|
|
1375
|
+
}
|
|
1376
|
+
.ps-tryon-scan-line {
|
|
1377
|
+
position: absolute; left: 0; right: 0; height: 3px;
|
|
1378
|
+
background: linear-gradient(90deg, transparent, #bb945c 20%, #d6ba7d 50%, #bb945c 80%, transparent);
|
|
1379
|
+
box-shadow: 0 0 15px rgba(187,148,92,0.6), 0 0 40px rgba(187,148,92,0.2);
|
|
1380
|
+
animation: ps-scan 2.5s ease-in-out infinite;
|
|
1381
|
+
pointer-events: none; z-index: 2;
|
|
1332
1382
|
}
|
|
1333
|
-
@keyframes ps-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1383
|
+
@keyframes ps-scan {
|
|
1384
|
+
0% { top: 0; opacity: 0; }
|
|
1385
|
+
5% { opacity: 1; }
|
|
1386
|
+
95% { opacity: 1; }
|
|
1387
|
+
100% { top: calc(100% - 3px); opacity: 0; }
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
.ps-tryon-progress-section {
|
|
1391
|
+
display: flex; align-items: center; gap: 12px; width: 100%; max-width: 300px; margin-bottom: 16px;
|
|
1392
|
+
}
|
|
1393
|
+
.ps-tryon-progress-bar-wrap {
|
|
1394
|
+
flex: 1; height: 6px; background: #333; border-radius: 3px; overflow: hidden;
|
|
1395
|
+
}
|
|
1396
|
+
.ps-tryon-progress-bar-fill {
|
|
1397
|
+
height: 100%; background: linear-gradient(90deg, #bb945c, #d6ba7d);
|
|
1398
|
+
border-radius: 3px; transition: width 0.3s ease;
|
|
1399
|
+
}
|
|
1400
|
+
.ps-tryon-progress-pct {
|
|
1401
|
+
font-size: 13px; font-weight: 700; color: #bb945c; min-width: 36px; text-align: right;
|
|
1402
|
+
font-variant-numeric: tabular-nums;
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1340
1405
|
@keyframes ps-scale-in { from { opacity: 0; transform: scale(0.8); } to { opacity: 1; transform: scale(1); } }
|
|
1341
1406
|
.ps-tryon-processing-text { font-size: 14px; color: #fff; margin: 0 0 4px; }
|
|
1342
1407
|
.ps-tryon-processing-sub { font-size: 12px; color: #999; margin: 0; }
|