@primestyleai/tryon 5.10.134 → 5.10.136
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 +3612 -3477
- package/dist/react/index.js.map +1 -1
- package/dist/react/styles.d.ts +1 -1
- package/dist/react/views/MultiSectionMobile.d.ts +4 -1
- package/dist/storefront/primestyle-tryon.js +263 -112
- package/package.json +1 -1
|
@@ -24,6 +24,9 @@ export interface MultiSectionMobileProps {
|
|
|
24
24
|
onSelectSection: (name: string) => void;
|
|
25
25
|
onTryOn: () => void;
|
|
26
26
|
tryOnProcessing?: boolean;
|
|
27
|
+
/** Epoch ms timestamp the try-on request started — drives the
|
|
28
|
+
* TryOnGenerationBadge's progress + ETA copy. */
|
|
29
|
+
tryOnStartedAt?: number | null;
|
|
27
30
|
/** When set, the image area shows the try-on result instead of productImage. */
|
|
28
31
|
resultImageUrl?: string | null;
|
|
29
32
|
/** Try-on has finished and result is ready. Switches the bottom CTA into
|
|
@@ -44,4 +47,4 @@ export interface MultiSectionMobileProps {
|
|
|
44
47
|
onImageLoad?: (e: React.SyntheticEvent<HTMLImageElement>) => void;
|
|
45
48
|
t: TranslateFn;
|
|
46
49
|
}
|
|
47
|
-
export declare function MultiSectionMobile({ productImage, productTitle, sizingResult, sizeGuide, sectionEntries, pendingCustomSizes, onSelectSection, onTryOn, tryOnProcessing, resultImageUrl, tryOnDone, onTryAgain, onClose, overlayNode, showLines, onToggleLines, onImageLoad, t, }: MultiSectionMobileProps): import("react/jsx-runtime").JSX.Element;
|
|
50
|
+
export declare function MultiSectionMobile({ productImage, productTitle, sizingResult, sizeGuide, sectionEntries, pendingCustomSizes, onSelectSection, onTryOn, tryOnProcessing, tryOnStartedAt, resultImageUrl, tryOnDone, onTryAgain, onClose, overlayNode, showLines, onToggleLines, onImageLoad, t, }: MultiSectionMobileProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -11563,6 +11563,22 @@ const STYLES$1 = `
|
|
|
11563
11563
|
@keyframes ps-tryon-badge-spin {
|
|
11564
11564
|
to { transform: rotate(360deg); }
|
|
11565
11565
|
}
|
|
11566
|
+
/* Mobile sizing for the try-on badge — desktop's max-width: 420px lives
|
|
11567
|
+
inside a roughly 360 px image hero, leaving the pill awkwardly clipped.
|
|
11568
|
+
Stretch it edge-to-edge with smaller text so it always fits. */
|
|
11569
|
+
@media (max-width: 768px) {
|
|
11570
|
+
.ps-tryon-badge {
|
|
11571
|
+
left: 12px; right: 12px; bottom: 12px;
|
|
11572
|
+
max-width: none;
|
|
11573
|
+
padding: 12px 14px;
|
|
11574
|
+
gap: 8px;
|
|
11575
|
+
border-radius: 12px;
|
|
11576
|
+
}
|
|
11577
|
+
.ps-tryon-badge-row { gap: 10px; }
|
|
11578
|
+
.ps-tryon-badge-title { font-size: 13px; }
|
|
11579
|
+
.ps-tryon-badge-pct { font-size: 11px; padding: 3px 9px; }
|
|
11580
|
+
.ps-tryon-badge-foot { font-size: 11px; gap: 8px; }
|
|
11581
|
+
}
|
|
11566
11582
|
|
|
11567
11583
|
/* ── Product photo strip (single-garment, below the size card) ──
|
|
11568
11584
|
Three thumbnails per slide, evenly spaced, auto-advances. Lives at
|
|
@@ -15316,9 +15332,12 @@ const STYLES$1 = `
|
|
|
15316
15332
|
text-align: center; padding: 4px 12px;
|
|
15317
15333
|
min-height: 64px;
|
|
15318
15334
|
/* Lock width so the cycling stage text (shorter/longer strings every
|
|
15319
|
-
~2s) doesn't reflow the sibling TryOnProgress bar.
|
|
15335
|
+
~2s) doesn't reflow the sibling TryOnProgress bar. align-self:
|
|
15336
|
+
center centers the 320px container inside the flex column — without
|
|
15337
|
+
it the container sat at the left edge of the screen on mobile. */
|
|
15320
15338
|
width: 320px;
|
|
15321
15339
|
max-width: 100%;
|
|
15340
|
+
align-self: center;
|
|
15322
15341
|
overflow: hidden;
|
|
15323
15342
|
}
|
|
15324
15343
|
.ps-msc-stage-slot {
|
|
@@ -15403,11 +15422,23 @@ const STYLES$1 = `
|
|
|
15403
15422
|
.ps-msr-fit-toggle[aria-pressed="true"] {
|
|
15404
15423
|
background: var(--ps-accent); color: #FFFFFF;
|
|
15405
15424
|
}
|
|
15406
|
-
/* Bottom action row when try-on finished — Try Again + Continue Shopping
|
|
15425
|
+
/* Bottom action row when try-on finished — Try Again + Continue Shopping.
|
|
15426
|
+
min-width: 0 lets each button actually shrink to share the row equally
|
|
15427
|
+
on narrow viewports; white-space: nowrap stops "Continue Shopping"
|
|
15428
|
+
from wrapping to a second line. */
|
|
15407
15429
|
.ps-msr-bottom-row {
|
|
15408
|
-
display: flex; gap:
|
|
15430
|
+
display: flex; gap: 8px; align-items: stretch;
|
|
15431
|
+
}
|
|
15432
|
+
.ps-msr-bottom-row .ps-msr-tryon-cta {
|
|
15433
|
+
flex: 1 1 0; min-width: 0;
|
|
15434
|
+
padding: 14px 12px; font-size: 13px;
|
|
15435
|
+
white-space: nowrap;
|
|
15436
|
+
}
|
|
15437
|
+
@media (max-width: 360px) {
|
|
15438
|
+
.ps-msr-bottom-row .ps-msr-tryon-cta {
|
|
15439
|
+
padding: 12px 10px; font-size: 12px;
|
|
15440
|
+
}
|
|
15409
15441
|
}
|
|
15410
|
-
.ps-msr-bottom-row .ps-msr-tryon-cta { flex: 1; }
|
|
15411
15442
|
.ps-msr-tryon-cta.ps-secondary {
|
|
15412
15443
|
background: transparent;
|
|
15413
15444
|
color: var(--ps-text-primary);
|
|
@@ -17477,6 +17508,11 @@ const STYLES$1 = `
|
|
|
17477
17508
|
|
|
17478
17509
|
/* Big product / try-on image */
|
|
17479
17510
|
.ps-msd-image {
|
|
17511
|
+
/* position: relative is required so the absolute children
|
|
17512
|
+
(.ps-msr-fit-toggle, .ps-tryon-badge) anchor to the image instead of
|
|
17513
|
+
the viewport. Without it the Show Fit pill rendered bottom-left of
|
|
17514
|
+
the screen on mobile. */
|
|
17515
|
+
position: relative;
|
|
17480
17516
|
width: 100%; height: 420px;
|
|
17481
17517
|
border-radius: 12px; overflow: hidden;
|
|
17482
17518
|
background: var(--ps-bg-secondary);
|
|
@@ -17517,6 +17553,12 @@ const STYLES$1 = `
|
|
|
17517
17553
|
letter-spacing: 0.05em;
|
|
17518
17554
|
color: var(--ps-text-muted);
|
|
17519
17555
|
}
|
|
17556
|
+
/* Mobile: 56 px overflows for compound labels like
|
|
17557
|
+
"MISSY 12 / Standard / Length 61". Cap at 36 px. */
|
|
17558
|
+
@media (max-width: 768px) {
|
|
17559
|
+
.ps-msd-card-size { font-size: 36px; letter-spacing: -0.015em; }
|
|
17560
|
+
.ps-msd-card-size-meta { font-size: 11px; }
|
|
17561
|
+
}
|
|
17520
17562
|
.ps-msd-card-divider {
|
|
17521
17563
|
height: 1px; background: var(--ps-border-subtle);
|
|
17522
17564
|
margin: 6px 0;
|
|
@@ -17885,6 +17927,34 @@ const STYLES$1 = `
|
|
|
17885
17927
|
color: var(--ps-accent);
|
|
17886
17928
|
}
|
|
17887
17929
|
|
|
17930
|
+
/* Mobile px-based override — desktop rules use vw units which collapse
|
|
17931
|
+
to 1–4 px on a 375 px viewport. */
|
|
17932
|
+
@media (max-width: 768px) {
|
|
17933
|
+
.ps-bp-mini-select-trigger {
|
|
17934
|
+
padding: 10px 14px;
|
|
17935
|
+
font-size: 14px;
|
|
17936
|
+
border-radius: 8px;
|
|
17937
|
+
gap: 8px;
|
|
17938
|
+
min-width: 0;
|
|
17939
|
+
}
|
|
17940
|
+
.ps-bp-mini-select-arrow { font-size: 10px; }
|
|
17941
|
+
.ps-bp-mini-select-panel {
|
|
17942
|
+
max-height: 240px;
|
|
17943
|
+
border-radius: 10px;
|
|
17944
|
+
padding: 4px;
|
|
17945
|
+
box-shadow:
|
|
17946
|
+
0 4px 12px rgba(15, 23, 42, 0.10),
|
|
17947
|
+
0 12px 32px rgba(15, 23, 42, 0.16);
|
|
17948
|
+
}
|
|
17949
|
+
.ps-bp-mini-select[data-dir="down"] .ps-bp-mini-select-panel { top: calc(100% + 6px); }
|
|
17950
|
+
.ps-bp-mini-select[data-dir="up"] .ps-bp-mini-select-panel { bottom: calc(100% + 6px); }
|
|
17951
|
+
.ps-bp-mini-select-item {
|
|
17952
|
+
padding: 10px 12px;
|
|
17953
|
+
font-size: 14px;
|
|
17954
|
+
border-radius: 6px;
|
|
17955
|
+
}
|
|
17956
|
+
}
|
|
17957
|
+
|
|
17888
17958
|
.ps-bp-bra-region-wrap { position: relative; z-index: 100; }
|
|
17889
17959
|
.ps-bp-bra-region-trigger {
|
|
17890
17960
|
display: flex; align-items: center; gap: 0.35vw;
|
|
@@ -19039,6 +19109,10 @@ function MobileBottomTabs({ mode, onSwitchToManual, onSwitchToScan, t: t2 }) {
|
|
|
19039
19109
|
] });
|
|
19040
19110
|
}
|
|
19041
19111
|
const SKELETON_CONNECTIONS$1 = [
|
|
19112
|
+
// Head → torso. Bridges the gap between the nose dot and the shoulder
|
|
19113
|
+
// line — without these the head reads as floating above the body.
|
|
19114
|
+
["nose", "leftShoulder"],
|
|
19115
|
+
["nose", "rightShoulder"],
|
|
19042
19116
|
["leftShoulder", "rightShoulder"],
|
|
19043
19117
|
["leftShoulder", "leftElbow"],
|
|
19044
19118
|
["leftElbow", "leftWrist"],
|
|
@@ -19052,6 +19126,14 @@ const SKELETON_CONNECTIONS$1 = [
|
|
|
19052
19126
|
["rightHip", "rightKnee"],
|
|
19053
19127
|
["rightKnee", "rightAnkle"]
|
|
19054
19128
|
];
|
|
19129
|
+
function isVisible(p2) {
|
|
19130
|
+
if (!p2 || typeof p2 !== "object") return false;
|
|
19131
|
+
const pt2 = p2;
|
|
19132
|
+
if (typeof pt2.x !== "number" || typeof pt2.y !== "number") return false;
|
|
19133
|
+
if (typeof pt2.visibility === "number" && pt2.visibility < 0.3) return false;
|
|
19134
|
+
if (pt2.x < 1e-3 && pt2.y < 1e-3) return false;
|
|
19135
|
+
return true;
|
|
19136
|
+
}
|
|
19055
19137
|
function MobileSkeleton({ landmarks, w: w2, h }) {
|
|
19056
19138
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
19057
19139
|
"svg",
|
|
@@ -19063,7 +19145,7 @@ function MobileSkeleton({ landmarks, w: w2, h }) {
|
|
|
19063
19145
|
SKELETON_CONNECTIONS$1.map(([a, b], i) => {
|
|
19064
19146
|
const pa2 = landmarks[a];
|
|
19065
19147
|
const pb2 = landmarks[b];
|
|
19066
|
-
if (!pa2 || !pb2) return null;
|
|
19148
|
+
if (!isVisible(pa2) || !isVisible(pb2)) return null;
|
|
19067
19149
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
19068
19150
|
"line",
|
|
19069
19151
|
{
|
|
@@ -19073,14 +19155,12 @@ function MobileSkeleton({ landmarks, w: w2, h }) {
|
|
|
19073
19155
|
y2: pb2.y * h,
|
|
19074
19156
|
stroke: "rgba(100,210,255,0.9)",
|
|
19075
19157
|
strokeWidth: "4",
|
|
19076
|
-
strokeLinecap: "round"
|
|
19077
|
-
opacity: 0,
|
|
19078
|
-
style: { animation: `ps-msc-fade 0.4s ease ${i * 0.05}s forwards` }
|
|
19158
|
+
strokeLinecap: "round"
|
|
19079
19159
|
},
|
|
19080
19160
|
`l-${i}`
|
|
19081
19161
|
);
|
|
19082
19162
|
}),
|
|
19083
|
-
Object.entries(landmarks).filter(([, v2]) => v2
|
|
19163
|
+
Object.entries(landmarks).filter(([, v2]) => isVisible(v2)).map(([key, v2]) => {
|
|
19084
19164
|
const p2 = v2;
|
|
19085
19165
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("g", { children: [
|
|
19086
19166
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -19088,10 +19168,8 @@ function MobileSkeleton({ landmarks, w: w2, h }) {
|
|
|
19088
19168
|
{
|
|
19089
19169
|
cx: p2.x * w2,
|
|
19090
19170
|
cy: p2.y * h,
|
|
19091
|
-
r:
|
|
19092
|
-
fill: "rgba(100,210,255,0.
|
|
19093
|
-
opacity: 0,
|
|
19094
|
-
style: { animation: `ps-msc-fade 0.3s ease ${i * 0.04}s forwards` }
|
|
19171
|
+
r: 14,
|
|
19172
|
+
fill: "rgba(100,210,255,0.30)"
|
|
19095
19173
|
}
|
|
19096
19174
|
),
|
|
19097
19175
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -19099,10 +19177,8 @@ function MobileSkeleton({ landmarks, w: w2, h }) {
|
|
|
19099
19177
|
{
|
|
19100
19178
|
cx: p2.x * w2,
|
|
19101
19179
|
cy: p2.y * h,
|
|
19102
|
-
r:
|
|
19103
|
-
fill: "rgba(100,210,255,0.95)"
|
|
19104
|
-
opacity: 0,
|
|
19105
|
-
style: { animation: `ps-msc-fade 0.3s ease ${i * 0.04}s forwards` }
|
|
19180
|
+
r: 9,
|
|
19181
|
+
fill: "rgba(100,210,255,0.95)"
|
|
19106
19182
|
}
|
|
19107
19183
|
)
|
|
19108
19184
|
] }, key);
|
|
@@ -19192,6 +19268,99 @@ function MobileScanningView({
|
|
|
19192
19268
|
) })
|
|
19193
19269
|
] });
|
|
19194
19270
|
}
|
|
19271
|
+
const TARGET_SECONDS = 22;
|
|
19272
|
+
function TryOnGenerationBadge({
|
|
19273
|
+
tryOnStartedAt,
|
|
19274
|
+
t: t2
|
|
19275
|
+
}) {
|
|
19276
|
+
const [, force] = reactExports.useState(0);
|
|
19277
|
+
reactExports.useEffect(() => {
|
|
19278
|
+
if (tryOnStartedAt == null) return;
|
|
19279
|
+
const id2 = setInterval(() => force((v2) => v2 + 1), 200);
|
|
19280
|
+
return () => clearInterval(id2);
|
|
19281
|
+
}, [tryOnStartedAt]);
|
|
19282
|
+
if (tryOnStartedAt == null) return null;
|
|
19283
|
+
const elapsed = (Date.now() - tryOnStartedAt) / 1e3;
|
|
19284
|
+
const pct = Math.min(95, elapsed / TARGET_SECONDS * 100);
|
|
19285
|
+
const pctRounded = Math.round(pct);
|
|
19286
|
+
const remaining = Math.max(0, TARGET_SECONDS - Math.floor(elapsed));
|
|
19287
|
+
const etaText = elapsed >= TARGET_SECONDS ? t2("almost done") : `~${remaining}s ${t2("left")}`;
|
|
19288
|
+
const statuses = [
|
|
19289
|
+
t2("Preparing your image"),
|
|
19290
|
+
t2("Analyzing body proportions"),
|
|
19291
|
+
t2("Mapping garment to body"),
|
|
19292
|
+
t2("Refining drape and shadows"),
|
|
19293
|
+
t2("Almost done")
|
|
19294
|
+
];
|
|
19295
|
+
const stepIdx = Math.min(
|
|
19296
|
+
statuses.length - 1,
|
|
19297
|
+
Math.floor(elapsed / TARGET_SECONDS * statuses.length)
|
|
19298
|
+
);
|
|
19299
|
+
const status = statuses[stepIdx];
|
|
19300
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-badge", role: "status", "aria-live": "polite", children: [
|
|
19301
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-badge-row", children: [
|
|
19302
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-badge-spinner", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { viewBox: "0 0 24 24", width: "22", height: "22", children: [
|
|
19303
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("defs", { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("linearGradient", { id: "ps-tryon-badge-grad", x1: "0", y1: "0", x2: "1", y2: "1", children: [
|
|
19304
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("stop", { offset: "0%", stopColor: "#3B82F6" }),
|
|
19305
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("stop", { offset: "100%", stopColor: "#2563EB" })
|
|
19306
|
+
] }) }),
|
|
19307
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "9", fill: "none", stroke: "rgba(59,130,246,0.18)", strokeWidth: "2.4" }),
|
|
19308
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
19309
|
+
"circle",
|
|
19310
|
+
{
|
|
19311
|
+
cx: "12",
|
|
19312
|
+
cy: "12",
|
|
19313
|
+
r: "9",
|
|
19314
|
+
fill: "none",
|
|
19315
|
+
stroke: "url(#ps-tryon-badge-grad)",
|
|
19316
|
+
strokeWidth: "2.4",
|
|
19317
|
+
strokeLinecap: "round",
|
|
19318
|
+
strokeDasharray: "56.5",
|
|
19319
|
+
strokeDashoffset: "38"
|
|
19320
|
+
}
|
|
19321
|
+
)
|
|
19322
|
+
] }) }),
|
|
19323
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-badge-title", children: t2("Generating your look...") }),
|
|
19324
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-badge-pct", children: [
|
|
19325
|
+
pctRounded,
|
|
19326
|
+
"%"
|
|
19327
|
+
] })
|
|
19328
|
+
] }),
|
|
19329
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-badge-bar", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-badge-bar-fill", style: { width: `${pctRounded}%` } }) }),
|
|
19330
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-badge-foot", children: [
|
|
19331
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-badge-status", children: [
|
|
19332
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-badge-status-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
19333
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "6", y1: "10", x2: "6", y2: "14" }),
|
|
19334
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "6", x2: "10", y2: "18" }),
|
|
19335
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "9", x2: "14", y2: "15" }),
|
|
19336
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "18", y1: "11", x2: "18", y2: "13" })
|
|
19337
|
+
] }) }),
|
|
19338
|
+
status
|
|
19339
|
+
] }),
|
|
19340
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-badge-eta", children: [
|
|
19341
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
19342
|
+
"svg",
|
|
19343
|
+
{
|
|
19344
|
+
width: "11",
|
|
19345
|
+
height: "11",
|
|
19346
|
+
viewBox: "0 0 24 24",
|
|
19347
|
+
fill: "none",
|
|
19348
|
+
stroke: "currentColor",
|
|
19349
|
+
strokeWidth: "2",
|
|
19350
|
+
strokeLinecap: "round",
|
|
19351
|
+
strokeLinejoin: "round",
|
|
19352
|
+
"aria-hidden": "true",
|
|
19353
|
+
children: [
|
|
19354
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
19355
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("polyline", { points: "12 6 12 12 16 14" })
|
|
19356
|
+
]
|
|
19357
|
+
}
|
|
19358
|
+
),
|
|
19359
|
+
etaText
|
|
19360
|
+
] })
|
|
19361
|
+
] })
|
|
19362
|
+
] });
|
|
19363
|
+
}
|
|
19195
19364
|
function garmentIconForSection$1(name) {
|
|
19196
19365
|
const n2 = name.toLowerCase();
|
|
19197
19366
|
if (n2.includes("jacket") || n2.includes("blazer") || n2.includes("coat")) return garmentJacketImg;
|
|
@@ -19223,6 +19392,7 @@ function MultiSectionMobile({
|
|
|
19223
19392
|
onSelectSection,
|
|
19224
19393
|
onTryOn,
|
|
19225
19394
|
tryOnProcessing,
|
|
19395
|
+
tryOnStartedAt,
|
|
19226
19396
|
resultImageUrl,
|
|
19227
19397
|
tryOnDone,
|
|
19228
19398
|
onTryAgain,
|
|
@@ -19268,6 +19438,7 @@ function MultiSectionMobile({
|
|
|
19268
19438
|
}
|
|
19269
19439
|
),
|
|
19270
19440
|
showLines && overlayNode,
|
|
19441
|
+
tryOnProcessing && tryOnStartedAt != null && /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnGenerationBadge, { tryOnStartedAt, t: t2 }),
|
|
19271
19442
|
showingTryOn && onToggleLines && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
19272
19443
|
"button",
|
|
19273
19444
|
{
|
|
@@ -19388,99 +19559,6 @@ function MultiSectionMobile({
|
|
|
19388
19559
|
sizeGuide ? null : null
|
|
19389
19560
|
] });
|
|
19390
19561
|
}
|
|
19391
|
-
const TARGET_SECONDS = 22;
|
|
19392
|
-
function TryOnGenerationBadge({
|
|
19393
|
-
tryOnStartedAt,
|
|
19394
|
-
t: t2
|
|
19395
|
-
}) {
|
|
19396
|
-
const [, force] = reactExports.useState(0);
|
|
19397
|
-
reactExports.useEffect(() => {
|
|
19398
|
-
if (tryOnStartedAt == null) return;
|
|
19399
|
-
const id2 = setInterval(() => force((v2) => v2 + 1), 200);
|
|
19400
|
-
return () => clearInterval(id2);
|
|
19401
|
-
}, [tryOnStartedAt]);
|
|
19402
|
-
if (tryOnStartedAt == null) return null;
|
|
19403
|
-
const elapsed = (Date.now() - tryOnStartedAt) / 1e3;
|
|
19404
|
-
const pct = Math.min(95, elapsed / TARGET_SECONDS * 100);
|
|
19405
|
-
const pctRounded = Math.round(pct);
|
|
19406
|
-
const remaining = Math.max(0, TARGET_SECONDS - Math.floor(elapsed));
|
|
19407
|
-
const etaText = elapsed >= TARGET_SECONDS ? t2("almost done") : `~${remaining}s ${t2("left")}`;
|
|
19408
|
-
const statuses = [
|
|
19409
|
-
t2("Preparing your image"),
|
|
19410
|
-
t2("Analyzing body proportions"),
|
|
19411
|
-
t2("Mapping garment to body"),
|
|
19412
|
-
t2("Refining drape and shadows"),
|
|
19413
|
-
t2("Almost done")
|
|
19414
|
-
];
|
|
19415
|
-
const stepIdx = Math.min(
|
|
19416
|
-
statuses.length - 1,
|
|
19417
|
-
Math.floor(elapsed / TARGET_SECONDS * statuses.length)
|
|
19418
|
-
);
|
|
19419
|
-
const status = statuses[stepIdx];
|
|
19420
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-badge", role: "status", "aria-live": "polite", children: [
|
|
19421
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-badge-row", children: [
|
|
19422
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-badge-spinner", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { viewBox: "0 0 24 24", width: "22", height: "22", children: [
|
|
19423
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("defs", { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("linearGradient", { id: "ps-tryon-badge-grad", x1: "0", y1: "0", x2: "1", y2: "1", children: [
|
|
19424
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("stop", { offset: "0%", stopColor: "#3B82F6" }),
|
|
19425
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("stop", { offset: "100%", stopColor: "#2563EB" })
|
|
19426
|
-
] }) }),
|
|
19427
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "9", fill: "none", stroke: "rgba(59,130,246,0.18)", strokeWidth: "2.4" }),
|
|
19428
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
19429
|
-
"circle",
|
|
19430
|
-
{
|
|
19431
|
-
cx: "12",
|
|
19432
|
-
cy: "12",
|
|
19433
|
-
r: "9",
|
|
19434
|
-
fill: "none",
|
|
19435
|
-
stroke: "url(#ps-tryon-badge-grad)",
|
|
19436
|
-
strokeWidth: "2.4",
|
|
19437
|
-
strokeLinecap: "round",
|
|
19438
|
-
strokeDasharray: "56.5",
|
|
19439
|
-
strokeDashoffset: "38"
|
|
19440
|
-
}
|
|
19441
|
-
)
|
|
19442
|
-
] }) }),
|
|
19443
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-badge-title", children: t2("Generating your look...") }),
|
|
19444
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-badge-pct", children: [
|
|
19445
|
-
pctRounded,
|
|
19446
|
-
"%"
|
|
19447
|
-
] })
|
|
19448
|
-
] }),
|
|
19449
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-badge-bar", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-badge-bar-fill", style: { width: `${pctRounded}%` } }) }),
|
|
19450
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-badge-foot", children: [
|
|
19451
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-badge-status", children: [
|
|
19452
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-badge-status-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
19453
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "6", y1: "10", x2: "6", y2: "14" }),
|
|
19454
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "6", x2: "10", y2: "18" }),
|
|
19455
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "9", x2: "14", y2: "15" }),
|
|
19456
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "18", y1: "11", x2: "18", y2: "13" })
|
|
19457
|
-
] }) }),
|
|
19458
|
-
status
|
|
19459
|
-
] }),
|
|
19460
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-badge-eta", children: [
|
|
19461
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
19462
|
-
"svg",
|
|
19463
|
-
{
|
|
19464
|
-
width: "11",
|
|
19465
|
-
height: "11",
|
|
19466
|
-
viewBox: "0 0 24 24",
|
|
19467
|
-
fill: "none",
|
|
19468
|
-
stroke: "currentColor",
|
|
19469
|
-
strokeWidth: "2",
|
|
19470
|
-
strokeLinecap: "round",
|
|
19471
|
-
strokeLinejoin: "round",
|
|
19472
|
-
"aria-hidden": "true",
|
|
19473
|
-
children: [
|
|
19474
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
19475
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("polyline", { points: "12 6 12 12 16 14" })
|
|
19476
|
-
]
|
|
19477
|
-
}
|
|
19478
|
-
),
|
|
19479
|
-
etaText
|
|
19480
|
-
] })
|
|
19481
|
-
] })
|
|
19482
|
-
] });
|
|
19483
|
-
}
|
|
19484
19562
|
const PER_SLIDE = 3;
|
|
19485
19563
|
const CYCLE_MS = 4e3;
|
|
19486
19564
|
function ProductPhotoCarouselCard({
|
|
@@ -20253,6 +20331,7 @@ function SectionDetailView({
|
|
|
20253
20331
|
}
|
|
20254
20332
|
),
|
|
20255
20333
|
showLines && overlayNode,
|
|
20334
|
+
tryOnProcessing && tryOnStartedAt != null && /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnGenerationBadge, { tryOnStartedAt, t: t2 }),
|
|
20256
20335
|
isTryOnImage && onToggleLines && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
20257
20336
|
"button",
|
|
20258
20337
|
{
|
|
@@ -21295,6 +21374,7 @@ function SizeResultView({
|
|
|
21295
21374
|
setShowPhotoGuide(true);
|
|
21296
21375
|
},
|
|
21297
21376
|
tryOnProcessing,
|
|
21377
|
+
tryOnStartedAt,
|
|
21298
21378
|
resultImageUrl,
|
|
21299
21379
|
tryOnDone: !!resultImageUrl && !tryOnProcessing,
|
|
21300
21380
|
onTryAgain: () => {
|
|
@@ -22885,7 +22965,7 @@ function CreateProfileWizard({ onSave, onCancel, apiUrl, apiKey, onPhotoPreview,
|
|
|
22885
22965
|
const CUP_OPTIONS_US2 = ["AA", "A", "B", "C", "D", "DD/E", "DDD/F", "G", "H", "I", "J"];
|
|
22886
22966
|
const isWomen = gender === "female";
|
|
22887
22967
|
const imgs = isWomen ? BODY_IMAGES.female : BODY_IMAGES.male;
|
|
22888
|
-
const manualStepOrder = isWomen ? ["identity", "stomach", "seat", "hips"
|
|
22968
|
+
const manualStepOrder = isWomen ? ["identity", "stomach", "seat", "hips"] : ["identity", "chest", "stomach", "seat"];
|
|
22889
22969
|
const manualStepIdx = manualStepOrder.indexOf(manualStep);
|
|
22890
22970
|
const manualStepCount = manualStepOrder.length;
|
|
22891
22971
|
const isLastManualStep = manualStepIdx === manualStepCount - 1;
|
|
@@ -22937,6 +23017,10 @@ function CreateProfileWizard({ onSave, onCancel, apiUrl, apiKey, onPhotoPreview,
|
|
|
22937
23017
|
setError(t2("Please enter a valid age"));
|
|
22938
23018
|
return false;
|
|
22939
23019
|
}
|
|
23020
|
+
if (isWomen && (!bandSize || !cupSize)) {
|
|
23021
|
+
setError(t2("Please select your bra band and cup size"));
|
|
23022
|
+
return false;
|
|
23023
|
+
}
|
|
22940
23024
|
setError("");
|
|
22941
23025
|
return true;
|
|
22942
23026
|
};
|
|
@@ -23327,6 +23411,63 @@ function CreateProfileWizard({ onSave, onCancel, apiUrl, apiKey, onPhotoPreview,
|
|
|
23327
23411
|
),
|
|
23328
23412
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-bp-inline-unit", children: t2("years") })
|
|
23329
23413
|
] })
|
|
23414
|
+
] }),
|
|
23415
|
+
isWomen && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { ref: inlineBraWrapRef, children: [
|
|
23416
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-inline-row", children: [
|
|
23417
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-bp-inline-label", children: t2("BRA REGION") }),
|
|
23418
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bp-inline-input-group", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
23419
|
+
MiniSelect$1,
|
|
23420
|
+
{
|
|
23421
|
+
value: braSizeRegion,
|
|
23422
|
+
options: Object.keys(BAND_SIZES$1),
|
|
23423
|
+
isOpen: inlineBraOpen === "region",
|
|
23424
|
+
onToggle: () => setInlineBraOpen(inlineBraOpen === "region" ? null : "region"),
|
|
23425
|
+
onSelect: (v2) => {
|
|
23426
|
+
setBraSizeRegion(v2);
|
|
23427
|
+
setBandSize(null);
|
|
23428
|
+
setCupSize(null);
|
|
23429
|
+
setInlineBraOpen(null);
|
|
23430
|
+
setError("");
|
|
23431
|
+
}
|
|
23432
|
+
}
|
|
23433
|
+
) })
|
|
23434
|
+
] }),
|
|
23435
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-inline-row", children: [
|
|
23436
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-bp-inline-label", children: t2("BAND") }),
|
|
23437
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bp-inline-input-group", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
23438
|
+
MiniSelect$1,
|
|
23439
|
+
{
|
|
23440
|
+
value: bandSize,
|
|
23441
|
+
options: BAND_SIZES$1[braSizeRegion] || BAND_SIZES$1.US,
|
|
23442
|
+
placeholder: "—",
|
|
23443
|
+
isOpen: inlineBraOpen === "band",
|
|
23444
|
+
onToggle: () => setInlineBraOpen(inlineBraOpen === "band" ? null : "band"),
|
|
23445
|
+
onSelect: (v2) => {
|
|
23446
|
+
setBandSize(v2);
|
|
23447
|
+
setInlineBraOpen(null);
|
|
23448
|
+
setError("");
|
|
23449
|
+
}
|
|
23450
|
+
}
|
|
23451
|
+
) })
|
|
23452
|
+
] }),
|
|
23453
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-inline-row", children: [
|
|
23454
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-bp-inline-label", children: t2("CUP") }),
|
|
23455
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bp-inline-input-group", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
23456
|
+
MiniSelect$1,
|
|
23457
|
+
{
|
|
23458
|
+
value: cupSize,
|
|
23459
|
+
options: CUP_OPTIONS_US2,
|
|
23460
|
+
placeholder: "—",
|
|
23461
|
+
isOpen: inlineBraOpen === "cup",
|
|
23462
|
+
onToggle: () => setInlineBraOpen(inlineBraOpen === "cup" ? null : "cup"),
|
|
23463
|
+
onSelect: (v2) => {
|
|
23464
|
+
setCupSize(v2);
|
|
23465
|
+
setInlineBraOpen(null);
|
|
23466
|
+
setError("");
|
|
23467
|
+
}
|
|
23468
|
+
}
|
|
23469
|
+
) })
|
|
23470
|
+
] })
|
|
23330
23471
|
] })
|
|
23331
23472
|
] }),
|
|
23332
23473
|
error && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-cpw-error", children: error })
|
|
@@ -25490,7 +25631,8 @@ function BodyProfileView({
|
|
|
25490
25631
|
setAge("");
|
|
25491
25632
|
setBandSize(null);
|
|
25492
25633
|
setCupSize(null);
|
|
25493
|
-
|
|
25634
|
+
onStartFresh?.();
|
|
25635
|
+
}, [handleRemovePhoto, onStartFresh]);
|
|
25494
25636
|
reactExports.useEffect(() => {
|
|
25495
25637
|
const profilePhoto = activeProfile?.photoBase64;
|
|
25496
25638
|
const profileId = activeProfile?.id ?? null;
|
|
@@ -26313,6 +26455,15 @@ function BodyProfileView({
|
|
|
26313
26455
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-bp-loaded-pill-text", children: t2("Loaded from profile") }),
|
|
26314
26456
|
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "ps-bp-loaded-pill-clear", onClick: handleClearFromProfile, children: t2("Clear") })
|
|
26315
26457
|
] }) }),
|
|
26458
|
+
hasActiveProfileWithMeasurements && activeProfileName && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "ps-bp-profile-hint", style: { textAlign: "center", margin: "0 0 0.5vw" }, children: [
|
|
26459
|
+
t2("Using"),
|
|
26460
|
+
" ",
|
|
26461
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: activeProfileName }),
|
|
26462
|
+
onStartFresh && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
26463
|
+
" · ",
|
|
26464
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "ps-bp-profile-hint-link", onClick: handleClearFromProfile, children: t2("start fresh") })
|
|
26465
|
+
] })
|
|
26466
|
+
] }),
|
|
26316
26467
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-inline-fields", children: [
|
|
26317
26468
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-inline-row", children: [
|
|
26318
26469
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-bp-inline-label", children: t2("HEIGHT") }),
|