@primestyleai/tryon 5.8.58 → 5.9.1
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/api-client.d.ts +1 -1
- package/dist/{index-J6U0-q_3.js → index-CuIieeOy.js} +2 -1
- package/dist/primestyle-tryon.js +2 -2
- package/dist/react/index.js +392 -61
- package/dist/react/styles.d.ts +1 -1
- package/dist/react/views/MobileScanningView.d.ts +4 -1
- package/dist/react/views/PhotoStepMobile.d.ts +3 -1
- package/dist/react/views/ProcessingView.d.ts +3 -1
- package/dist/storefront/primestyle-tryon.js +393 -61
- package/package.json +1 -4
|
@@ -9296,9 +9296,10 @@ class ApiClient {
|
|
|
9296
9296
|
Authorization: `Bearer ${this.apiKey}`
|
|
9297
9297
|
};
|
|
9298
9298
|
}
|
|
9299
|
-
async submitTryOn(modelImage, garmentImage, fitInfo) {
|
|
9299
|
+
async submitTryOn(modelImage, garmentImage, fitInfo, category) {
|
|
9300
9300
|
const body = { modelImage, garmentImage };
|
|
9301
9301
|
if (fitInfo && fitInfo.length > 0) body.fitInfo = fitInfo;
|
|
9302
|
+
if (category && category !== "apparel") body.category = category;
|
|
9302
9303
|
const res = await fetch(`${this.baseUrl}/api/v1/tryon`, {
|
|
9303
9304
|
method: "POST",
|
|
9304
9305
|
headers: this.headers,
|
|
@@ -10912,12 +10913,22 @@ const STYLES$1 = `
|
|
|
10912
10913
|
}
|
|
10913
10914
|
.ps-tryon-v2-processing-label {
|
|
10914
10915
|
position: absolute; bottom: 1vw; left: 50%; transform: translateX(-50%);
|
|
10915
|
-
z-index: 5; font-size: 0.
|
|
10916
|
-
color:
|
|
10917
|
-
background: rgba(0,0,0,0.
|
|
10918
|
-
padding: 0.
|
|
10916
|
+
z-index: 5; font-size: 0.7vw; font-weight: 600;
|
|
10917
|
+
color: #fff; letter-spacing: 0.05em;
|
|
10918
|
+
background: rgba(0,0,0,0.72); backdrop-filter: blur(10px);
|
|
10919
|
+
padding: 0.6vw 0.9vw; border-radius: 0.6vw;
|
|
10920
|
+
display: flex; flex-direction: column; align-items: center; gap: 0.5vw;
|
|
10921
|
+
min-width: 14vw;
|
|
10922
|
+
box-shadow: 0 0.4vw 1.5vw rgba(0,0,0,0.35);
|
|
10923
|
+
}
|
|
10924
|
+
.ps-tryon-v2-processing-label > span:first-child {
|
|
10919
10925
|
animation: ps-loading-pulse 2s ease-in-out infinite;
|
|
10920
10926
|
}
|
|
10927
|
+
.ps-tryon-v2-processing-label .ps-tryon-progress-ring-track { stroke: rgba(255,255,255,0.18); }
|
|
10928
|
+
.ps-tryon-v2-processing-label .ps-tryon-progress-ring-fill { stroke: var(--ps-accent-light); }
|
|
10929
|
+
.ps-tryon-v2-processing-label .ps-tryon-progress-eta { color: #fff; }
|
|
10930
|
+
.ps-tryon-v2-processing-label .ps-tryon-progress-bar-wrap { background: rgba(255,255,255,0.18); }
|
|
10931
|
+
.ps-tryon-v2-processing-label .ps-tryon-progress-pct { color: var(--ps-accent-light); }
|
|
10921
10932
|
|
|
10922
10933
|
/* "I don't know" link */
|
|
10923
10934
|
.ps-tryon-v2-dontknow {
|
|
@@ -11508,22 +11519,81 @@ const STYLES$1 = `
|
|
|
11508
11519
|
}
|
|
11509
11520
|
|
|
11510
11521
|
.ps-tryon-progress-section {
|
|
11511
|
-
display: flex; align-items: center; gap: 0.63vw; width: 100%; max-width:
|
|
11522
|
+
display: flex; align-items: center; gap: 0.63vw; width: 100%; max-width: 18vw; margin-bottom: 0.83vw;
|
|
11523
|
+
}
|
|
11524
|
+
/* Shared progress layout used inside StageCycler (desktop) and
|
|
11525
|
+
MobileScanningView — row of ring + bar + percent, same tokens. */
|
|
11526
|
+
.ps-tryon-progress-wrap {
|
|
11527
|
+
display: flex; align-items: center; gap: 10px;
|
|
11528
|
+
width: 100%; max-width: 320px; margin-top: 16px;
|
|
11529
|
+
}
|
|
11530
|
+
.ps-tryon-progress-wrap .ps-tryon-progress-bar-wrap {
|
|
11531
|
+
flex: 1; height: 4px; border-radius: 3px; overflow: hidden;
|
|
11532
|
+
position: relative; background: var(--ps-border-color);
|
|
11533
|
+
}
|
|
11534
|
+
.ps-tryon-progress-wrap .ps-tryon-progress-bar-fill {
|
|
11535
|
+
height: 100%; width: 0%;
|
|
11536
|
+
background: linear-gradient(90deg, var(--ps-accent), var(--ps-accent-light));
|
|
11537
|
+
border-radius: 3px; transition: width 0.3s ease;
|
|
11538
|
+
}
|
|
11539
|
+
.ps-tryon-progress-wrap .ps-tryon-progress-pct {
|
|
11540
|
+
font-size: 11px; font-weight: 700; color: var(--ps-accent);
|
|
11541
|
+
min-width: 30px; text-align: right;
|
|
11542
|
+
font-variant-numeric: tabular-nums;
|
|
11512
11543
|
}
|
|
11513
11544
|
.ps-tryon-progress-bar-wrap {
|
|
11514
11545
|
flex: 1; height: 0.31vw; background: var(--ps-border-color); border-radius: 3px; overflow: hidden;
|
|
11546
|
+
position: relative;
|
|
11547
|
+
}
|
|
11548
|
+
.ps-tryon-progress-bar-wrap::after {
|
|
11549
|
+
content: ""; position: absolute; inset: 0;
|
|
11550
|
+
background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.45) 50%, transparent 100%);
|
|
11551
|
+
transform: translateX(-100%);
|
|
11552
|
+
animation: ps-progress-shimmer 2s linear infinite;
|
|
11553
|
+
pointer-events: none;
|
|
11554
|
+
}
|
|
11555
|
+
@keyframes ps-progress-shimmer {
|
|
11556
|
+
0% { transform: translateX(-100%); }
|
|
11557
|
+
100% { transform: translateX(100%); }
|
|
11515
11558
|
}
|
|
11516
11559
|
.ps-tryon-progress-bar-fill {
|
|
11517
11560
|
height: 100%; background: linear-gradient(90deg, var(--ps-accent), var(--ps-accent-light));
|
|
11518
11561
|
border-radius: 3px; transition: width 0.3s ease; width: 0%;
|
|
11562
|
+
position: relative; z-index: 1;
|
|
11519
11563
|
}
|
|
11520
11564
|
.ps-tryon-progress-pct {
|
|
11521
11565
|
font-size: 0.68vw; font-weight: 700; color: var(--ps-accent); min-width: 1.88vw; text-align: right;
|
|
11522
11566
|
font-variant-numeric: tabular-nums;
|
|
11523
11567
|
}
|
|
11524
11568
|
|
|
11569
|
+
/* Circular ETA ring — 48×48 px SVG with a track + progress circle; ETA
|
|
11570
|
+
text centered. strokeDashoffset is driven by the ticker in
|
|
11571
|
+
PrimeStyleTryonInner, so CSS only styles the appearance. */
|
|
11572
|
+
.ps-tryon-progress-ring {
|
|
11573
|
+
position: relative; width: 48px; height: 48px; flex: 0 0 48px;
|
|
11574
|
+
display: flex; align-items: center; justify-content: center;
|
|
11575
|
+
}
|
|
11576
|
+
.ps-tryon-progress-ring svg { transform: rotate(-90deg); }
|
|
11577
|
+
.ps-tryon-progress-ring-track {
|
|
11578
|
+
fill: none; stroke: var(--ps-border-color); stroke-width: 3.5;
|
|
11579
|
+
}
|
|
11580
|
+
.ps-tryon-progress-ring-fill {
|
|
11581
|
+
fill: none; stroke: var(--ps-accent); stroke-width: 3.5;
|
|
11582
|
+
stroke-linecap: round;
|
|
11583
|
+
transition: stroke-dashoffset 0.3s ease;
|
|
11584
|
+
}
|
|
11585
|
+
.ps-tryon-progress-eta {
|
|
11586
|
+
position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
|
|
11587
|
+
font-size: 10px; font-weight: 700; color: var(--ps-accent);
|
|
11588
|
+
font-variant-numeric: tabular-nums; letter-spacing: 0.01em;
|
|
11589
|
+
pointer-events: none;
|
|
11590
|
+
}
|
|
11591
|
+
|
|
11525
11592
|
@keyframes ps-scale-in { from { opacity: 0; transform: scale(0.8); } to { opacity: 1; transform: scale(1); } }
|
|
11526
|
-
.ps-tryon-processing-text {
|
|
11593
|
+
.ps-tryon-processing-text {
|
|
11594
|
+
font-size: 0.73vw; color: var(--ps-text-primary); margin: 0 0 0.21vw;
|
|
11595
|
+
opacity: 1; transition: opacity 0.18s ease;
|
|
11596
|
+
}
|
|
11527
11597
|
.ps-tryon-processing-sub { font-size: 0.63vw; color: var(--ps-text-secondary); margin: 0; }
|
|
11528
11598
|
|
|
11529
11599
|
/* Result — split layout */
|
|
@@ -16836,17 +16906,71 @@ function MobileSkeleton({ landmarks, w: w2, h }) {
|
|
|
16836
16906
|
}
|
|
16837
16907
|
);
|
|
16838
16908
|
}
|
|
16909
|
+
const MSC_TRYON_TARGET_SECONDS = 22;
|
|
16910
|
+
const MSC_RING_RADIUS = 20;
|
|
16911
|
+
const MSC_RING_CIRC = 2 * Math.PI * MSC_RING_RADIUS;
|
|
16912
|
+
function MscTryOnProgress({ t: t2 }) {
|
|
16913
|
+
const startRef = reactExports.useRef(Date.now());
|
|
16914
|
+
const ringRef = reactExports.useRef(null);
|
|
16915
|
+
const barRef = reactExports.useRef(null);
|
|
16916
|
+
const etaRef = reactExports.useRef(null);
|
|
16917
|
+
const pctRef = reactExports.useRef(null);
|
|
16918
|
+
reactExports.useEffect(() => {
|
|
16919
|
+
startRef.current = Date.now();
|
|
16920
|
+
const id2 = setInterval(() => {
|
|
16921
|
+
const elapsed = (Date.now() - startRef.current) / 1e3;
|
|
16922
|
+
const pct = Math.min(95, elapsed / MSC_TRYON_TARGET_SECONDS * 100);
|
|
16923
|
+
const val = Math.round(pct);
|
|
16924
|
+
if (barRef.current) barRef.current.style.width = `${val}%`;
|
|
16925
|
+
if (pctRef.current) pctRef.current.textContent = `${val}%`;
|
|
16926
|
+
if (ringRef.current) ringRef.current.style.strokeDashoffset = String(MSC_RING_CIRC * (1 - pct / 100));
|
|
16927
|
+
if (etaRef.current) {
|
|
16928
|
+
const remaining = Math.max(0, MSC_TRYON_TARGET_SECONDS - Math.floor(elapsed));
|
|
16929
|
+
etaRef.current.textContent = elapsed >= MSC_TRYON_TARGET_SECONDS ? t2("Finalizing...") : `~${remaining}s`;
|
|
16930
|
+
}
|
|
16931
|
+
}, 200);
|
|
16932
|
+
return () => clearInterval(id2);
|
|
16933
|
+
}, [t2]);
|
|
16934
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-progress-wrap", children: [
|
|
16935
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-progress-ring", children: [
|
|
16936
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "48", height: "48", viewBox: "0 0 48 48", "aria-hidden": "true", children: [
|
|
16937
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "24", cy: "24", r: MSC_RING_RADIUS, className: "ps-tryon-progress-ring-track" }),
|
|
16938
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
16939
|
+
"circle",
|
|
16940
|
+
{
|
|
16941
|
+
ref: ringRef,
|
|
16942
|
+
cx: "24",
|
|
16943
|
+
cy: "24",
|
|
16944
|
+
r: MSC_RING_RADIUS,
|
|
16945
|
+
className: "ps-tryon-progress-ring-fill",
|
|
16946
|
+
strokeDasharray: MSC_RING_CIRC,
|
|
16947
|
+
strokeDashoffset: MSC_RING_CIRC
|
|
16948
|
+
}
|
|
16949
|
+
)
|
|
16950
|
+
] }),
|
|
16951
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { ref: etaRef, className: "ps-tryon-progress-eta", children: `~${MSC_TRYON_TARGET_SECONDS}s` })
|
|
16952
|
+
] }),
|
|
16953
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-progress-bar-wrap", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: barRef, className: "ps-tryon-progress-bar-fill" }) }),
|
|
16954
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { ref: pctRef, className: "ps-tryon-progress-pct", children: "0%" })
|
|
16955
|
+
] });
|
|
16956
|
+
}
|
|
16839
16957
|
function MobileScanningView({
|
|
16840
16958
|
previewUrl,
|
|
16841
16959
|
productImage,
|
|
16842
16960
|
bodyLandmarks,
|
|
16843
16961
|
sizingDone,
|
|
16962
|
+
tryOnProcessing,
|
|
16844
16963
|
onSwitchToManual,
|
|
16845
16964
|
t: t2
|
|
16846
16965
|
}) {
|
|
16847
16966
|
const displayImage = previewUrl || productImage || "";
|
|
16848
16967
|
const isPhotoMode = !!previewUrl;
|
|
16849
|
-
const stages =
|
|
16968
|
+
const stages = tryOnProcessing ? [
|
|
16969
|
+
{ title: t2("GENERATING TRY-ON"), desc: t2("Rendering the garment on your photo."), viewfinderText: t2("GENERATING") },
|
|
16970
|
+
{ title: t2("REFINING DETAILS"), desc: t2("Fine-tuning fit, drape and shadows."), viewfinderText: t2("REFINING") },
|
|
16971
|
+
{ title: t2("ALMOST THERE"), desc: t2("Final compositing in progress."), viewfinderText: t2("COMPOSITING") },
|
|
16972
|
+
{ title: t2("FINISHING TOUCHES"), desc: t2("Polishing the result."), viewfinderText: t2("FINISHING") }
|
|
16973
|
+
] : isPhotoMode ? [
|
|
16850
16974
|
{ title: t2("DETECTING POSE"), desc: t2("Identifying body landmarks from your photo."), viewfinderText: t2("DETECTING POSE") },
|
|
16851
16975
|
{ title: t2("SCANNING FRAME"), desc: t2("Our AI is mapping your proportions to calculate the perfect fit."), viewfinderText: t2("SCANNING FRAME") },
|
|
16852
16976
|
{ title: t2("ANALYZING BODY"), desc: t2("Measuring shoulders, chest, waist and hips."), viewfinderText: t2("ANALYZING") },
|
|
@@ -16889,10 +17013,13 @@ function MobileScanningView({
|
|
|
16889
17013
|
),
|
|
16890
17014
|
isPhotoMode && bodyLandmarks && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-msc-pose-wrap", children: /* @__PURE__ */ jsxRuntimeExports.jsx(MobileSkeleton, { landmarks: bodyLandmarks, w: dims.w, h: dims.h }) })
|
|
16891
17015
|
] }),
|
|
16892
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
16893
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
16894
|
-
|
|
16895
|
-
|
|
17016
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msc-stage", children: [
|
|
17017
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msc-stage-slot", children: [
|
|
17018
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-msc-stage-title", children: current.title }),
|
|
17019
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-msc-stage-desc", children: current.desc })
|
|
17020
|
+
] }, stageIdx),
|
|
17021
|
+
tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsx(MscTryOnProgress, { t: t2 })
|
|
17022
|
+
] }),
|
|
16896
17023
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bpm-spacer" }),
|
|
16897
17024
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bpm-bottom", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
16898
17025
|
MobileBottomTabs,
|
|
@@ -17090,6 +17217,62 @@ const SKELETON_CONNECTIONS = [
|
|
|
17090
17217
|
["rightHip", "rightKnee"],
|
|
17091
17218
|
["rightKnee", "rightAnkle"]
|
|
17092
17219
|
];
|
|
17220
|
+
const TRYON_TARGET_SECONDS = 22;
|
|
17221
|
+
const TRYON_RING_RADIUS = 20;
|
|
17222
|
+
const TRYON_RING_CIRC = 2 * Math.PI * TRYON_RING_RADIUS;
|
|
17223
|
+
function TryOnProgress({ t: t2, isActive }) {
|
|
17224
|
+
const startRef = reactExports.useRef(null);
|
|
17225
|
+
const ringRef = reactExports.useRef(null);
|
|
17226
|
+
const barRef = reactExports.useRef(null);
|
|
17227
|
+
const etaRef = reactExports.useRef(null);
|
|
17228
|
+
const pctRef = reactExports.useRef(null);
|
|
17229
|
+
reactExports.useEffect(() => {
|
|
17230
|
+
if (!isActive) {
|
|
17231
|
+
startRef.current = null;
|
|
17232
|
+
return;
|
|
17233
|
+
}
|
|
17234
|
+
startRef.current = Date.now();
|
|
17235
|
+
const id2 = setInterval(() => {
|
|
17236
|
+
const start = startRef.current || Date.now();
|
|
17237
|
+
const elapsed = (Date.now() - start) / 1e3;
|
|
17238
|
+
const pct = Math.min(95, elapsed / TRYON_TARGET_SECONDS * 100);
|
|
17239
|
+
const val = Math.round(pct);
|
|
17240
|
+
if (barRef.current) barRef.current.style.width = `${val}%`;
|
|
17241
|
+
if (pctRef.current) pctRef.current.textContent = `${val}%`;
|
|
17242
|
+
if (ringRef.current) {
|
|
17243
|
+
ringRef.current.style.strokeDashoffset = String(TRYON_RING_CIRC * (1 - pct / 100));
|
|
17244
|
+
}
|
|
17245
|
+
if (etaRef.current) {
|
|
17246
|
+
const remaining = Math.max(0, TRYON_TARGET_SECONDS - Math.floor(elapsed));
|
|
17247
|
+
etaRef.current.textContent = elapsed >= TRYON_TARGET_SECONDS ? t2("Finalizing...") : `~${remaining}s`;
|
|
17248
|
+
}
|
|
17249
|
+
}, 200);
|
|
17250
|
+
return () => clearInterval(id2);
|
|
17251
|
+
}, [isActive, t2]);
|
|
17252
|
+
if (!isActive) return null;
|
|
17253
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-progress-wrap", children: [
|
|
17254
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-progress-ring", children: [
|
|
17255
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "48", height: "48", viewBox: "0 0 48 48", "aria-hidden": "true", children: [
|
|
17256
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "24", cy: "24", r: TRYON_RING_RADIUS, className: "ps-tryon-progress-ring-track" }),
|
|
17257
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
17258
|
+
"circle",
|
|
17259
|
+
{
|
|
17260
|
+
ref: ringRef,
|
|
17261
|
+
cx: "24",
|
|
17262
|
+
cy: "24",
|
|
17263
|
+
r: TRYON_RING_RADIUS,
|
|
17264
|
+
className: "ps-tryon-progress-ring-fill",
|
|
17265
|
+
strokeDasharray: TRYON_RING_CIRC,
|
|
17266
|
+
strokeDashoffset: TRYON_RING_CIRC
|
|
17267
|
+
}
|
|
17268
|
+
)
|
|
17269
|
+
] }),
|
|
17270
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { ref: etaRef, className: "ps-tryon-progress-eta", children: `~${TRYON_TARGET_SECONDS}s` })
|
|
17271
|
+
] }),
|
|
17272
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-progress-bar-wrap", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: barRef, className: "ps-tryon-progress-bar-fill" }) }),
|
|
17273
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { ref: pctRef, className: "ps-tryon-progress-pct", children: "0%" })
|
|
17274
|
+
] });
|
|
17275
|
+
}
|
|
17093
17276
|
function FaceOverlay({
|
|
17094
17277
|
landmarks,
|
|
17095
17278
|
imgWidth,
|
|
@@ -17233,10 +17416,13 @@ function StageCycler({
|
|
|
17233
17416
|
return () => clearInterval(id2);
|
|
17234
17417
|
}, [isDone, active.length]);
|
|
17235
17418
|
const current = active[idx] ?? active[0];
|
|
17236
|
-
return /* @__PURE__ */ jsxRuntimeExports.
|
|
17237
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
17238
|
-
|
|
17239
|
-
|
|
17419
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msc-stage", style: { alignSelf: "center", marginTop: "auto", marginBottom: "auto" }, children: [
|
|
17420
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msc-stage-slot", children: [
|
|
17421
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-msc-stage-title", children: current.title }),
|
|
17422
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-msc-stage-desc", children: current.desc })
|
|
17423
|
+
] }, `${tryOnProcessing ? "t" : "s"}-${idx}`),
|
|
17424
|
+
tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnProgress, { t: t2, isActive: !!tryOnProcessing })
|
|
17425
|
+
] });
|
|
17240
17426
|
}
|
|
17241
17427
|
function SkeletonOverlay({ landmarks, imgWidth, imgHeight }) {
|
|
17242
17428
|
const W2 = imgWidth;
|
|
@@ -18374,6 +18560,7 @@ function SizeResultView({
|
|
|
18374
18560
|
const allDone = hasPhoto ? sizingDone && tryOnDone : sizingDone;
|
|
18375
18561
|
const isMobile = useIsMobile();
|
|
18376
18562
|
const isAccessory = measurementType === "face" || measurementType === "head";
|
|
18563
|
+
const vtoExcluded = measurementType === "foot";
|
|
18377
18564
|
console.log("[PS-SDK] SizeResultView render:", {
|
|
18378
18565
|
hasPhoto,
|
|
18379
18566
|
isSnapProcessing,
|
|
@@ -18411,6 +18598,7 @@ function SizeResultView({
|
|
|
18411
18598
|
previewUrl,
|
|
18412
18599
|
bodyLandmarks: bodyLandmarks ?? null,
|
|
18413
18600
|
sizingDone,
|
|
18601
|
+
tryOnProcessing,
|
|
18414
18602
|
onSwitchToManual: () => setView("body-profile"),
|
|
18415
18603
|
t: t2
|
|
18416
18604
|
}
|
|
@@ -18467,7 +18655,7 @@ function SizeResultView({
|
|
|
18467
18655
|
isMobile: true,
|
|
18468
18656
|
isTryOnImage: !!resultImageUrl,
|
|
18469
18657
|
showLines,
|
|
18470
|
-
onToggleLines: () => setShowLines(!showLines),
|
|
18658
|
+
onToggleLines: isAccessory ? void 0 : () => setShowLines(!showLines),
|
|
18471
18659
|
onImageLoad: handleImgLoad,
|
|
18472
18660
|
overlayNode: resultImageUrl && poseReady && poseLines ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
18473
18661
|
MeasurementOverlay,
|
|
@@ -18541,7 +18729,7 @@ function SizeResultView({
|
|
|
18541
18729
|
},
|
|
18542
18730
|
onClose,
|
|
18543
18731
|
showLines,
|
|
18544
|
-
onToggleLines: () => setShowLines(!showLines),
|
|
18732
|
+
onToggleLines: isAccessory ? void 0 : () => setShowLines(!showLines),
|
|
18545
18733
|
onImageLoad: handleImgLoad,
|
|
18546
18734
|
overlayNode: resultImageUrl && poseReady && poseLines ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
18547
18735
|
MeasurementOverlay,
|
|
@@ -18576,7 +18764,10 @@ function SizeResultView({
|
|
|
18576
18764
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-bg", style: { position: "relative" }, children: [
|
|
18577
18765
|
/* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: tryOnProcessing && previewUrl ? previewUrl : resultImageUrl || productImage, alt: productTitle, className: "ps-tryon-v2-bg-img", onLoad: handleImgLoad }),
|
|
18578
18766
|
tryOnProcessing && bodyLandmarks && /* @__PURE__ */ jsxRuntimeExports.jsx(SkeletonOverlay, { landmarks: bodyLandmarks, imgWidth: imgDims.w, imgHeight: imgDims.h }),
|
|
18579
|
-
tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.
|
|
18767
|
+
tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-processing-label", children: [
|
|
18768
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2("Generating try-on...") }),
|
|
18769
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TryOnProgress, { t: t2, isActive: true })
|
|
18770
|
+
] }),
|
|
18580
18771
|
resultImageUrl && !tryOnProcessing && poseReady && poseLines && /* @__PURE__ */ jsxRuntimeExports.jsx(MeasurementOverlay, { lines: poseLines, fitRows: (() => {
|
|
18581
18772
|
const all = [...sizingResult?.matchDetails || []];
|
|
18582
18773
|
if (sizingResult?.sections) {
|
|
@@ -18593,7 +18784,7 @@ function SizeResultView({
|
|
|
18593
18784
|
}).map((m2) => ({ area: m2.measurement, userNum: parseFloat(m2.userValue) || 0, chartLabel: m2.chartRange || "", fit: m2.fit }));
|
|
18594
18785
|
})(), show: showLines, imgWidth: imgDims.w, imgHeight: imgDims.h }),
|
|
18595
18786
|
resultImageUrl && !tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { position: "absolute", bottom: "0.5vw", left: "0.5vw", zIndex: 3, display: "flex", flexDirection: "column", gap: "0.3vw" }, children: [
|
|
18596
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "ps-tryon-sr-glass-btn", onClick: () => setShowLines(!showLines), children: [
|
|
18787
|
+
!isAccessory && /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "ps-tryon-sr-glass-btn", onClick: () => setShowLines(!showLines), children: [
|
|
18597
18788
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", style: { marginRight: "0.3vw" }, children: [
|
|
18598
18789
|
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "4", y1: "9", x2: "20", y2: "9" }),
|
|
18599
18790
|
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "4", y1: "15", x2: "20", y2: "15" }),
|
|
@@ -18647,7 +18838,7 @@ function SizeResultView({
|
|
|
18647
18838
|
" →"
|
|
18648
18839
|
]
|
|
18649
18840
|
}
|
|
18650
|
-
) :
|
|
18841
|
+
) : vtoExcluded ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
18651
18842
|
"button",
|
|
18652
18843
|
{
|
|
18653
18844
|
className: "ps-tryon-v2-cta",
|
|
@@ -18707,7 +18898,7 @@ function SizeResultView({
|
|
|
18707
18898
|
onBack: resultImageUrl ? onClose || (() => setView("body-profile")) : () => setView("body-profile"),
|
|
18708
18899
|
backLabel: t2("Back"),
|
|
18709
18900
|
internationalSizes: sizingResult?.internationalSizes,
|
|
18710
|
-
onTryOn: resultImageUrl ||
|
|
18901
|
+
onTryOn: resultImageUrl || vtoExcluded ? void 0 : handleSingleTryOn,
|
|
18711
18902
|
continueLabel: resultImageUrl ? t2("Continue Shopping") : void 0,
|
|
18712
18903
|
tryOnProcessing,
|
|
18713
18904
|
productImage: resultImageUrl || productImage,
|
|
@@ -18716,7 +18907,7 @@ function SizeResultView({
|
|
|
18716
18907
|
renderRaw: isAccessory,
|
|
18717
18908
|
isTryOnImage: !!resultImageUrl,
|
|
18718
18909
|
showLines,
|
|
18719
|
-
onToggleLines: () => setShowLines(!showLines),
|
|
18910
|
+
onToggleLines: isAccessory ? void 0 : () => setShowLines(!showLines),
|
|
18720
18911
|
onImageLoad: handleImgLoad,
|
|
18721
18912
|
overlayNode: resultImageUrl && poseReady && poseLines ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
18722
18913
|
MeasurementOverlay,
|
|
@@ -18737,7 +18928,7 @@ function SizeResultView({
|
|
|
18737
18928
|
/* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: resultImageUrl || productImage, alt: productTitle, className: "ps-tryon-v2-bg-img", onLoad: handleImgLoad }),
|
|
18738
18929
|
resultImageUrl && poseReady && poseLines && /* @__PURE__ */ jsxRuntimeExports.jsx(MeasurementOverlay, { lines: poseLines, fitRows: (sizingResult?.matchDetails || []).map((m2) => ({ area: m2.measurement, userNum: parseFloat(m2.userValue) || 0, chartLabel: m2.chartRange || "", fit: m2.fit })), show: showLines, imgWidth: imgDims.w, imgHeight: imgDims.h }),
|
|
18739
18930
|
resultImageUrl && !tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { position: "absolute", bottom: "0.5vw", left: "0.5vw", zIndex: 3, display: "flex", flexDirection: "column", gap: "0.3vw" }, children: [
|
|
18740
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "ps-tryon-sr-glass-btn", onClick: () => setShowLines(!showLines), children: showLines ? t2("Hide Fit") : t2("Show Fit") }),
|
|
18931
|
+
!isAccessory && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "ps-tryon-sr-glass-btn", onClick: () => setShowLines(!showLines), children: showLines ? t2("Hide Fit") : t2("Show Fit") }),
|
|
18741
18932
|
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "ps-tryon-sr-glass-btn", onClick: handleDownload, children: t2("Download") })
|
|
18742
18933
|
] })
|
|
18743
18934
|
] }),
|
|
@@ -18754,7 +18945,7 @@ function SizeResultView({
|
|
|
18754
18945
|
onBack: resultImageUrl ? onClose || (() => setView("body-profile")) : () => setView("body-profile"),
|
|
18755
18946
|
backLabel: t2("Back"),
|
|
18756
18947
|
internationalSizes: sizingResult?.internationalSizes,
|
|
18757
|
-
onTryOn: resultImageUrl ||
|
|
18948
|
+
onTryOn: resultImageUrl || vtoExcluded ? void 0 : handleSingleTryOn,
|
|
18758
18949
|
continueLabel: resultImageUrl ? t2("Continue Shopping") : void 0,
|
|
18759
18950
|
tryOnProcessing,
|
|
18760
18951
|
t: t2,
|
|
@@ -18764,14 +18955,14 @@ function SizeResultView({
|
|
|
18764
18955
|
] });
|
|
18765
18956
|
})()
|
|
18766
18957
|
),
|
|
18767
|
-
showPhotoGuide && !
|
|
18958
|
+
showPhotoGuide && !vtoExcluded && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-chart-overlay", children: isMobile ? (
|
|
18768
18959
|
/* ── Mobile: same layout as the AI-sizing photo step
|
|
18769
18960
|
(PhotoStepMobile) — title + subtitle, large preview,
|
|
18770
18961
|
checklist card, primary CTA + RETAKE secondary. ── */
|
|
18771
18962
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bp-wrapper", style: { padding: "16px 16px 0", background: "var(--ps-bg-primary)" }, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-pm-root", children: [
|
|
18772
18963
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-pm-header", children: [
|
|
18773
18964
|
/* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "ps-pm-title", children: t2("Review your photo") }),
|
|
18774
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ps-pm-subtitle", children: t2("Ensure your full body is visible for the most accurate virtual try-on.") })
|
|
18965
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ps-pm-subtitle", children: measurementType === "face" ? t2("A clear, front-facing face photo — no glasses on — gives us the most accurate try-on.") : measurementType === "head" ? t2("Face the camera with your head and shoulders in frame, leaving space above your head.") : t2("Ensure your full body is visible for the most accurate virtual try-on.") })
|
|
18775
18966
|
] }),
|
|
18776
18967
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
18777
18968
|
"input",
|
|
@@ -18822,11 +19013,19 @@ function SizeResultView({
|
|
|
18822
19013
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-pm-checklist-icon", children: /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "14", height: "14", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z" }) }) }),
|
|
18823
19014
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-pm-checklist-body", children: [
|
|
18824
19015
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-pm-checklist-title", children: t2("Checklist for accuracy") }),
|
|
18825
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
19016
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("ul", { className: "ps-pm-checklist-items", children: measurementType === "face" ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
19017
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: t2("Face the camera directly at eye level") }),
|
|
19018
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: t2("Remove any glasses you're wearing") }),
|
|
19019
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: t2("Good lighting, plain background") })
|
|
19020
|
+
] }) : measurementType === "head" ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
19021
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: t2("Head and shoulders in frame") }),
|
|
19022
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: t2("Leave space above your head") }),
|
|
19023
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: t2("Good lighting, plain background") })
|
|
19024
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
18826
19025
|
/* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: t2("Form-fitting clothing is recommended") }),
|
|
18827
19026
|
/* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: t2("Standing 2-3 meters from camera") }),
|
|
18828
19027
|
/* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: t2("Neutral background with good lighting") })
|
|
18829
|
-
] })
|
|
19028
|
+
] }) })
|
|
18830
19029
|
] })
|
|
18831
19030
|
] }),
|
|
18832
19031
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bpm-spacer" }),
|
|
@@ -18906,7 +19105,7 @@ function SizeResultView({
|
|
|
18906
19105
|
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
18907
19106
|
/* @__PURE__ */ jsxRuntimeExports.jsx(UploadIcon, { size: 32 }),
|
|
18908
19107
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { fontSize: "0.85vw", fontWeight: 600, color: "var(--ps-text-primary)", marginTop: "0.5vw" }, children: t2("Upload your photo") }),
|
|
18909
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { fontSize: "0.6vw", color: "var(--ps-text-muted)", marginTop: "0.2vw" }, children: t2("Click or drag a full-body photo") })
|
|
19108
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { fontSize: "0.6vw", color: "var(--ps-text-muted)", marginTop: "0.2vw" }, children: measurementType === "face" ? t2("Click or drag a close-up face photo") : measurementType === "head" ? t2("Click or drag a head-and-shoulders photo") : t2("Click or drag a full-body photo") })
|
|
18910
19109
|
] }),
|
|
18911
19110
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
18912
19111
|
"input",
|
|
@@ -18931,7 +19130,23 @@ function SizeResultView({
|
|
|
18931
19130
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "#1c9d4c", fontSize: "0.75vw", fontWeight: 700 }, children: "✓" }),
|
|
18932
19131
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "#1c9d4c", fontSize: "0.65vw", fontWeight: 600 }, children: t2("Do") })
|
|
18933
19132
|
] }),
|
|
18934
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
19133
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { fontSize: "0.58vw", color: "var(--ps-text-primary)", lineHeight: 1.8 }, children: measurementType === "face" ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
19134
|
+
t2("Face the camera directly, centered in frame"),
|
|
19135
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
|
|
19136
|
+
t2("Use natural, even lighting (e.g. near a window)"),
|
|
19137
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
|
|
19138
|
+
t2("Keep hair away from your face and ears"),
|
|
19139
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
|
|
19140
|
+
t2("Choose a plain, light background")
|
|
19141
|
+
] }) : measurementType === "head" ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
19142
|
+
t2("Face the camera with head and shoulders in frame"),
|
|
19143
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
|
|
19144
|
+
t2("Leave some space above your head"),
|
|
19145
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
|
|
19146
|
+
t2("Use natural, even lighting"),
|
|
19147
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
|
|
19148
|
+
t2("Choose a plain, light background")
|
|
19149
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
18935
19150
|
t2("Stand facing the camera with your full body in frame"),
|
|
18936
19151
|
/* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
|
|
18937
19152
|
t2("Use natural or even lighting"),
|
|
@@ -18939,14 +19154,30 @@ function SizeResultView({
|
|
|
18939
19154
|
t2("Wear fitted, simple clothing"),
|
|
18940
19155
|
/* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
|
|
18941
19156
|
t2("Stand straight and still, arms relaxed")
|
|
18942
|
-
] })
|
|
19157
|
+
] }) })
|
|
18943
19158
|
] }),
|
|
18944
19159
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { background: "#ffe2e2", borderRadius: "0.5vw", padding: "0.6vw 0.8vw" }, children: [
|
|
18945
19160
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.3vw", marginBottom: "0.3vw" }, children: [
|
|
18946
19161
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "#e7000b", fontSize: "0.75vw", fontWeight: 700 }, children: "✗" }),
|
|
18947
19162
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "#e7000b", fontSize: "0.65vw", fontWeight: 600 }, children: t2("Don't") })
|
|
18948
19163
|
] }),
|
|
18949
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
19164
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { fontSize: "0.58vw", color: "var(--ps-text-primary)", lineHeight: 1.8 }, children: measurementType === "face" ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
19165
|
+
t2("Don't wear sunglasses or a hat in the photo"),
|
|
19166
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
|
|
19167
|
+
t2("Don't tilt or turn your head"),
|
|
19168
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
|
|
19169
|
+
t2("Don't use strong backlighting or flash"),
|
|
19170
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
|
|
19171
|
+
t2("Don't apply filters or edits")
|
|
19172
|
+
] }) : measurementType === "head" ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
19173
|
+
t2("Don't wear a hat in the photo"),
|
|
19174
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
|
|
19175
|
+
t2("Don't crop out the top of your head"),
|
|
19176
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
|
|
19177
|
+
t2("Don't use strong backlighting or flash"),
|
|
19178
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
|
|
19179
|
+
t2("Don't apply filters or edits")
|
|
19180
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
18950
19181
|
t2("Don't wear loose or baggy clothing"),
|
|
18951
19182
|
/* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
|
|
18952
19183
|
t2("Don't sit, pose, or bend"),
|
|
@@ -18954,14 +19185,14 @@ function SizeResultView({
|
|
|
18954
19185
|
t2("Don't take mirror photos or selfies"),
|
|
18955
19186
|
/* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
|
|
18956
19187
|
t2("Don't apply filters or edits")
|
|
18957
|
-
] })
|
|
19188
|
+
] }) })
|
|
18958
19189
|
] }),
|
|
18959
19190
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { background: "rgba(59,130,246,0.08)", border: "1px solid rgba(59,130,246,0.2)", borderRadius: "0.5vw", padding: "0.5vw 0.8vw" }, children: [
|
|
18960
19191
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.3vw", marginBottom: "0.2vw" }, children: [
|
|
18961
19192
|
/* @__PURE__ */ jsxRuntimeExports.jsx(SparkleIcon, { size: 12 }),
|
|
18962
19193
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "var(--ps-accent)", fontSize: "0.65vw", fontWeight: 700 }, children: t2("Pro Tip") })
|
|
18963
19194
|
] }),
|
|
18964
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { fontSize: "0.55vw", color: "var(--ps-text-secondary)", lineHeight: 1.7 }, children: t2("Our AI works best with front-facing, full-body photos in fitted clothing. Better photos = more accurate virtual try-on!") })
|
|
19195
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { fontSize: "0.55vw", color: "var(--ps-text-secondary)", lineHeight: 1.7 }, children: measurementType === "face" ? t2("A clear, well-lit face photo gives the most accurate eyewear try-on.") : measurementType === "head" ? t2("A clear head-and-shoulders photo with space above your head gives the most accurate headwear try-on.") : t2("Our AI works best with front-facing, full-body photos in fitted clothing. Better photos = more accurate virtual try-on!") })
|
|
18965
19196
|
] })
|
|
18966
19197
|
] })
|
|
18967
19198
|
] }),
|
|
@@ -19090,12 +19321,16 @@ function UploadView({
|
|
|
19090
19321
|
}
|
|
19091
19322
|
) });
|
|
19092
19323
|
}
|
|
19324
|
+
const RING_RADIUS = 20;
|
|
19325
|
+
const RING_CIRCUMFERENCE = 2 * Math.PI * RING_RADIUS;
|
|
19093
19326
|
function ProcessingView({
|
|
19094
19327
|
previewUrl,
|
|
19095
19328
|
progressRef,
|
|
19096
19329
|
progressBarRef,
|
|
19097
19330
|
progressTextRef,
|
|
19098
19331
|
progressStatusRef,
|
|
19332
|
+
progressEtaRef,
|
|
19333
|
+
progressRingRef,
|
|
19099
19334
|
cn,
|
|
19100
19335
|
t: t2
|
|
19101
19336
|
}) {
|
|
@@ -19110,6 +19345,16 @@ function ProcessingView({
|
|
|
19110
19345
|
const statusCb = reactExports.useCallback((el2) => {
|
|
19111
19346
|
progressStatusRef.current = el2;
|
|
19112
19347
|
}, []);
|
|
19348
|
+
const etaCb = reactExports.useCallback((el2) => {
|
|
19349
|
+
progressEtaRef.current = el2;
|
|
19350
|
+
}, []);
|
|
19351
|
+
const ringCb = reactExports.useCallback((el2) => {
|
|
19352
|
+
progressRingRef.current = el2;
|
|
19353
|
+
if (el2) {
|
|
19354
|
+
const offset = RING_CIRCUMFERENCE * (1 - Math.round(progressRef.current) / 100);
|
|
19355
|
+
el2.style.strokeDashoffset = String(offset);
|
|
19356
|
+
}
|
|
19357
|
+
}, []);
|
|
19113
19358
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-processing", children: [
|
|
19114
19359
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-processing-image-wrap", children: [
|
|
19115
19360
|
previewUrl && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
@@ -19120,6 +19365,32 @@ function ProcessingView({
|
|
|
19120
19365
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-scan-overlay" })
|
|
19121
19366
|
] }),
|
|
19122
19367
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-progress-section", children: [
|
|
19368
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-progress-ring", children: [
|
|
19369
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { viewBox: "0 0 48 48", width: "48", height: "48", "aria-hidden": "true", children: [
|
|
19370
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
19371
|
+
"circle",
|
|
19372
|
+
{
|
|
19373
|
+
cx: "24",
|
|
19374
|
+
cy: "24",
|
|
19375
|
+
r: RING_RADIUS,
|
|
19376
|
+
className: "ps-tryon-progress-ring-track"
|
|
19377
|
+
}
|
|
19378
|
+
),
|
|
19379
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
19380
|
+
"circle",
|
|
19381
|
+
{
|
|
19382
|
+
ref: ringCb,
|
|
19383
|
+
cx: "24",
|
|
19384
|
+
cy: "24",
|
|
19385
|
+
r: RING_RADIUS,
|
|
19386
|
+
className: "ps-tryon-progress-ring-fill",
|
|
19387
|
+
strokeDasharray: RING_CIRCUMFERENCE,
|
|
19388
|
+
strokeDashoffset: RING_CIRCUMFERENCE
|
|
19389
|
+
}
|
|
19390
|
+
)
|
|
19391
|
+
] }),
|
|
19392
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { ref: etaCb, className: "ps-tryon-progress-eta", children: `~22s` })
|
|
19393
|
+
] }),
|
|
19123
19394
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-progress-bar-wrap", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: barCb, className: "ps-tryon-progress-bar-fill" }) }),
|
|
19124
19395
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { ref: pctCb, className: "ps-tryon-progress-pct", children: "0%" })
|
|
19125
19396
|
] }),
|
|
@@ -20785,12 +21056,13 @@ function PhotoStepMobile({
|
|
|
20785
21056
|
photoVariant = "full-body",
|
|
20786
21057
|
photoStepHeight,
|
|
20787
21058
|
onPhotoStepHeightChange,
|
|
21059
|
+
ageConfirmed,
|
|
21060
|
+
onAgeConfirmedChange,
|
|
20788
21061
|
t: t2
|
|
20789
21062
|
}) {
|
|
20790
21063
|
const isCloseUp = photoVariant === "close-up";
|
|
20791
21064
|
const fileRef = reactExports.useRef(null);
|
|
20792
21065
|
const hasPhoto = !!photoPreview;
|
|
20793
|
-
const [ageConfirmed, setAgeConfirmed] = reactExports.useState(null);
|
|
20794
21066
|
const gated = !hasPhoto && ageConfirmed !== true;
|
|
20795
21067
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-pm-root", children: [
|
|
20796
21068
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-pm-header", children: [
|
|
@@ -20842,14 +21114,14 @@ function PhotoStepMobile({
|
|
|
20842
21114
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-pm-age-gate-eyebrow", children: t2("AGE VERIFICATION") }),
|
|
20843
21115
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-pm-age-gate-question", children: t2("Is the person in this photo 18 years or older?") }),
|
|
20844
21116
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-pm-age-gate-actions", children: [
|
|
20845
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "ps-pm-age-gate-btn ps-pm-age-gate-btn-primary", onClick: () =>
|
|
20846
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "ps-pm-age-gate-btn ps-pm-age-gate-btn-secondary", onClick: () =>
|
|
21117
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "ps-pm-age-gate-btn ps-pm-age-gate-btn-primary", onClick: () => onAgeConfirmedChange(true), children: t2("Yes") }),
|
|
21118
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "ps-pm-age-gate-btn ps-pm-age-gate-btn-secondary", onClick: () => onAgeConfirmedChange(false), children: t2("No") })
|
|
20847
21119
|
] })
|
|
20848
21120
|
] }) }),
|
|
20849
21121
|
ageConfirmed === false && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-pm-age-gate", role: "alert", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-pm-age-gate-card", children: [
|
|
20850
21122
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-pm-age-gate-eyebrow ps-pm-age-gate-eyebrow-blocked", children: t2("UPLOAD NOT ALLOWED") }),
|
|
20851
21123
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-pm-age-gate-question", children: t2("For your safety, we cannot process photos of people under 18.") }),
|
|
20852
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "ps-pm-age-gate-btn ps-pm-age-gate-btn-secondary", onClick: () =>
|
|
21124
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "ps-pm-age-gate-btn ps-pm-age-gate-btn-secondary", onClick: () => onAgeConfirmedChange(null), children: t2("Go back") })
|
|
20853
21125
|
] }) })
|
|
20854
21126
|
] }) }),
|
|
20855
21127
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-pm-legal-notice", children: [
|
|
@@ -21317,6 +21589,11 @@ function BodyProfileView({
|
|
|
21317
21589
|
error,
|
|
21318
21590
|
photoStepHeight,
|
|
21319
21591
|
onPhotoStepHeightChange: setPhotoStepHeight,
|
|
21592
|
+
ageConfirmed,
|
|
21593
|
+
onAgeConfirmedChange: (v2) => {
|
|
21594
|
+
setAgeConfirmed(v2);
|
|
21595
|
+
if (v2 === true) setError("");
|
|
21596
|
+
},
|
|
21320
21597
|
t: t2
|
|
21321
21598
|
}
|
|
21322
21599
|
) });
|
|
@@ -22063,6 +22340,11 @@ function AccessorySizeView({
|
|
|
22063
22340
|
onSwitchToManual: () => setStep("manual"),
|
|
22064
22341
|
error,
|
|
22065
22342
|
photoVariant,
|
|
22343
|
+
ageConfirmed,
|
|
22344
|
+
onAgeConfirmedChange: (v2) => {
|
|
22345
|
+
setAgeConfirmed(v2);
|
|
22346
|
+
if (v2 === true) setError("");
|
|
22347
|
+
},
|
|
22066
22348
|
t: t2
|
|
22067
22349
|
}
|
|
22068
22350
|
) });
|
|
@@ -22620,6 +22902,12 @@ function detectMeasurementType(title) {
|
|
|
22620
22902
|
if (/\b(sunglass|sunglasses|eyewear|eyeglasses|glasses|spectacles|optical|goggles|frames|aviator|wayfarer|lens)\b/.test(t2)) return "face";
|
|
22621
22903
|
return "body";
|
|
22622
22904
|
}
|
|
22905
|
+
function measurementTypeToVtoCategory(type) {
|
|
22906
|
+
if (type === "face") return "sunglasses";
|
|
22907
|
+
if (type === "head") return "hat";
|
|
22908
|
+
if (type === "body") return "apparel";
|
|
22909
|
+
return null;
|
|
22910
|
+
}
|
|
22623
22911
|
function PrimeStyleTryonInner({
|
|
22624
22912
|
productImage,
|
|
22625
22913
|
productTitle = "Product",
|
|
@@ -22725,15 +23013,22 @@ function PrimeStyleTryonInner({
|
|
|
22725
23013
|
if (pollingRef.current) clearInterval(pollingRef.current);
|
|
22726
23014
|
};
|
|
22727
23015
|
}, [apiUrl]);
|
|
23016
|
+
const TARGET_SECONDS = 22;
|
|
22728
23017
|
const progressRef = reactExports.useRef(0);
|
|
22729
23018
|
const progressBarRef = reactExports.useRef(null);
|
|
22730
23019
|
const progressTextRef = reactExports.useRef(null);
|
|
22731
23020
|
const progressStatusRef = reactExports.useRef(null);
|
|
23021
|
+
const progressEtaRef = reactExports.useRef(null);
|
|
23022
|
+
const progressRingRef = reactExports.useRef(null);
|
|
23023
|
+
const progressStartTsRef = reactExports.useRef(null);
|
|
23024
|
+
const progressLastStageRef = reactExports.useRef("");
|
|
22732
23025
|
const progressIntervalRef = reactExports.useRef(null);
|
|
22733
23026
|
reactExports.useEffect(() => {
|
|
22734
23027
|
if (view === "processing") {
|
|
22735
23028
|
if (progressIntervalRef.current) return;
|
|
22736
23029
|
progressRef.current = 0;
|
|
23030
|
+
progressStartTsRef.current = Date.now();
|
|
23031
|
+
progressLastStageRef.current = "";
|
|
22737
23032
|
const statuses = [
|
|
22738
23033
|
{ at: 0, text: t2("Preparing your image...") },
|
|
22739
23034
|
{ at: 15, text: t2("Analyzing body proportions...") },
|
|
@@ -22742,17 +23037,35 @@ function PrimeStyleTryonInner({
|
|
|
22742
23037
|
{ at: 75, text: t2("Refining details...") },
|
|
22743
23038
|
{ at: 90, text: t2("Almost there...") }
|
|
22744
23039
|
];
|
|
23040
|
+
const RING_CIRCUMFERENCE2 = 2 * Math.PI * 20;
|
|
22745
23041
|
progressIntervalRef.current = setInterval(() => {
|
|
22746
|
-
|
|
22747
|
-
|
|
22748
|
-
const
|
|
22749
|
-
|
|
22750
|
-
|
|
23042
|
+
if (completedRef.current) return;
|
|
23043
|
+
const startTs = progressStartTsRef.current || Date.now();
|
|
23044
|
+
const elapsed = (Date.now() - startTs) / 1e3;
|
|
23045
|
+
const target = Math.min(95, elapsed / TARGET_SECONDS * 100);
|
|
23046
|
+
progressRef.current = target;
|
|
23047
|
+
const val = Math.round(target);
|
|
22751
23048
|
if (progressBarRef.current) progressBarRef.current.style.width = `${val}%`;
|
|
22752
23049
|
if (progressTextRef.current) progressTextRef.current.textContent = `${val}%`;
|
|
23050
|
+
if (progressRingRef.current) {
|
|
23051
|
+
const offset = RING_CIRCUMFERENCE2 * (1 - target / 100);
|
|
23052
|
+
progressRingRef.current.style.strokeDashoffset = String(offset);
|
|
23053
|
+
}
|
|
23054
|
+
if (progressEtaRef.current) {
|
|
23055
|
+
const remaining = Math.max(0, TARGET_SECONDS - Math.floor(elapsed));
|
|
23056
|
+
progressEtaRef.current.textContent = elapsed >= TARGET_SECONDS ? t2("Finalizing...") : `~${remaining}s`;
|
|
23057
|
+
}
|
|
22753
23058
|
if (progressStatusRef.current) {
|
|
22754
23059
|
const status = [...statuses].reverse().find((s) => val >= s.at);
|
|
22755
|
-
if (status
|
|
23060
|
+
if (status && status.text !== progressLastStageRef.current) {
|
|
23061
|
+
const el2 = progressStatusRef.current;
|
|
23062
|
+
el2.style.opacity = "0";
|
|
23063
|
+
setTimeout(() => {
|
|
23064
|
+
el2.textContent = status.text;
|
|
23065
|
+
el2.style.opacity = "1";
|
|
23066
|
+
}, 180);
|
|
23067
|
+
progressLastStageRef.current = status.text;
|
|
23068
|
+
}
|
|
22756
23069
|
}
|
|
22757
23070
|
}, 200);
|
|
22758
23071
|
return () => {
|
|
@@ -22764,8 +23077,9 @@ function PrimeStyleTryonInner({
|
|
|
22764
23077
|
clearInterval(progressIntervalRef.current);
|
|
22765
23078
|
progressIntervalRef.current = null;
|
|
22766
23079
|
}
|
|
23080
|
+
progressStartTsRef.current = null;
|
|
22767
23081
|
}
|
|
22768
|
-
}, [view]);
|
|
23082
|
+
}, [view, t2]);
|
|
22769
23083
|
reactExports.useEffect(() => {
|
|
22770
23084
|
return () => {
|
|
22771
23085
|
if (previewUrl) URL.revokeObjectURL(previewUrl);
|
|
@@ -23092,7 +23406,16 @@ function PrimeStyleTryonInner({
|
|
|
23092
23406
|
progressRef.current = 100;
|
|
23093
23407
|
if (progressBarRef.current) progressBarRef.current.style.width = "100%";
|
|
23094
23408
|
if (progressTextRef.current) progressTextRef.current.textContent = "100%";
|
|
23095
|
-
if (
|
|
23409
|
+
if (progressRingRef.current) progressRingRef.current.style.strokeDashoffset = "0";
|
|
23410
|
+
if (progressEtaRef.current) progressEtaRef.current.textContent = t2("Done");
|
|
23411
|
+
if (progressStatusRef.current) {
|
|
23412
|
+
const el2 = progressStatusRef.current;
|
|
23413
|
+
el2.style.opacity = "0";
|
|
23414
|
+
setTimeout(() => {
|
|
23415
|
+
el2.textContent = t2("Complete!");
|
|
23416
|
+
el2.style.opacity = "1";
|
|
23417
|
+
}, 180);
|
|
23418
|
+
}
|
|
23096
23419
|
cleanupJob();
|
|
23097
23420
|
setTryOnProcessing(false);
|
|
23098
23421
|
onComplete?.({ jobId: update.galleryId, imageUrl: update.imageUrl });
|
|
@@ -23501,25 +23824,29 @@ function PrimeStyleTryonInner({
|
|
|
23501
23824
|
}
|
|
23502
23825
|
completedRef.current = false;
|
|
23503
23826
|
setTryOnProcessing(true);
|
|
23827
|
+
const vtoCategory = measurementTypeToVtoCategory(detectMeasurementType(productTitle));
|
|
23828
|
+
const isApparel = vtoCategory === "apparel";
|
|
23504
23829
|
const previewObjUrl = (overrideFile ? null : previewUrl) || URL.createObjectURL(file);
|
|
23505
23830
|
if (overrideFile || !previewUrl) setPreviewUrl(previewObjUrl);
|
|
23506
23831
|
modelPoseRef.current = null;
|
|
23507
23832
|
setBodyLandmarks(null);
|
|
23508
|
-
|
|
23509
|
-
|
|
23510
|
-
|
|
23511
|
-
|
|
23512
|
-
|
|
23513
|
-
|
|
23514
|
-
|
|
23515
|
-
|
|
23833
|
+
if (isApparel) {
|
|
23834
|
+
detectMeasurementLines(previewObjUrl).then((lines) => {
|
|
23835
|
+
modelPoseRef.current = lines;
|
|
23836
|
+
}).catch(() => {
|
|
23837
|
+
});
|
|
23838
|
+
detectBodyLandmarks(previewObjUrl).then((lm) => {
|
|
23839
|
+
setBodyLandmarks(lm);
|
|
23840
|
+
}).catch(() => {
|
|
23841
|
+
});
|
|
23842
|
+
}
|
|
23516
23843
|
try {
|
|
23517
23844
|
const modelImage = await compressImage(file);
|
|
23518
23845
|
let fitInfo;
|
|
23519
|
-
if (sizingResult?.matchDetails?.length) {
|
|
23846
|
+
if (isApparel && sizingResult?.matchDetails?.length) {
|
|
23520
23847
|
fitInfo = buildFitInfo(sizingResult.matchDetails, modelPoseRef.current);
|
|
23521
23848
|
}
|
|
23522
|
-
const response = await apiRef.current.submitTryOn(modelImage, productImage, fitInfo);
|
|
23849
|
+
const response = await apiRef.current.submitTryOn(modelImage, productImage, fitInfo, vtoCategory ?? "apparel");
|
|
23523
23850
|
onProcessing?.(response.jobId);
|
|
23524
23851
|
unsubRef.current = sseRef.current.onJob(response.jobId, handleVtoUpdate);
|
|
23525
23852
|
let attempts = 0;
|
|
@@ -23550,11 +23877,13 @@ function PrimeStyleTryonInner({
|
|
|
23550
23877
|
setView("error");
|
|
23551
23878
|
onError?.({ message, code });
|
|
23552
23879
|
}
|
|
23553
|
-
}, [selectedFile, productImage, sizingResult, onProcessing, onError, handleVtoUpdate]);
|
|
23880
|
+
}, [selectedFile, productImage, productTitle, sizingResult, onProcessing, onError, handleVtoUpdate]);
|
|
23554
23881
|
const handleRetryWithFit = reactExports.useCallback(async (fitInfo) => {
|
|
23555
23882
|
if (!selectedFile || !apiRef.current || !sseRef.current) return;
|
|
23556
23883
|
setRetryLoading(true);
|
|
23557
|
-
|
|
23884
|
+
const vtoCategory = measurementTypeToVtoCategory(detectMeasurementType(productTitle));
|
|
23885
|
+
const isApparel = vtoCategory === "apparel";
|
|
23886
|
+
if (isApparel && modelPoseRef.current) {
|
|
23558
23887
|
const AREA_MAP = {
|
|
23559
23888
|
chest: "chest",
|
|
23560
23889
|
bust: "chest",
|
|
@@ -23580,7 +23909,8 @@ function PrimeStyleTryonInner({
|
|
|
23580
23909
|
pollingRef.current = null;
|
|
23581
23910
|
}
|
|
23582
23911
|
const modelImage = await compressImage(selectedFile);
|
|
23583
|
-
const
|
|
23912
|
+
const outboundFitInfo = isApparel ? fitInfo : void 0;
|
|
23913
|
+
const response = await apiRef.current.submitTryOn(modelImage, productImage, outboundFitInfo, vtoCategory ?? "apparel");
|
|
23584
23914
|
unsubRef.current = sseRef.current.onJob(response.jobId, (update) => {
|
|
23585
23915
|
if (update.status === "completed" && update.imageUrl) {
|
|
23586
23916
|
setResultImageUrl(update.imageUrl);
|
|
@@ -23645,7 +23975,7 @@ function PrimeStyleTryonInner({
|
|
|
23645
23975
|
} catch {
|
|
23646
23976
|
setRetryLoading(false);
|
|
23647
23977
|
}
|
|
23648
|
-
}, [selectedFile, productImage]);
|
|
23978
|
+
}, [selectedFile, productImage, productTitle]);
|
|
23649
23979
|
const handleDownload = reactExports.useCallback(() => {
|
|
23650
23980
|
if (!resultImageUrl) return;
|
|
23651
23981
|
if (resultImageUrl.startsWith("data:")) {
|
|
@@ -24087,6 +24417,8 @@ function PrimeStyleTryonInner({
|
|
|
24087
24417
|
progressBarRef,
|
|
24088
24418
|
progressTextRef,
|
|
24089
24419
|
progressStatusRef,
|
|
24420
|
+
progressEtaRef,
|
|
24421
|
+
progressRingRef,
|
|
24090
24422
|
cn,
|
|
24091
24423
|
t: t2
|
|
24092
24424
|
}
|