@primestyleai/tryon 5.10.122 → 5.10.124
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/{index-YDYXhM8c.js → index-8CWoLxU3.js} +68 -14
- package/dist/index-8CWoLxU3.js.map +1 -0
- package/dist/primestyle-tryon.js +2 -2
- package/dist/react/index.js +3489 -3426
- package/dist/react/index.js.map +1 -1
- package/dist/react/types.d.ts +5 -0
- package/dist/react/utils/photo-store.d.ts +7 -1
- package/dist/storefront/primestyle-tryon.js +165 -91
- package/package.json +1 -1
- package/dist/index-YDYXhM8c.js.map +0 -1
package/dist/react/types.d.ts
CHANGED
|
@@ -116,6 +116,11 @@ export interface HistoryEntry {
|
|
|
116
116
|
* IndexedDB rather than in this localStorage object to avoid the ~5–10 MB
|
|
117
117
|
* quota. Old entries without a photo set this false/undefined. */
|
|
118
118
|
hasPhoto?: boolean;
|
|
119
|
+
/** True when the try-on RESULT image is stored as a Blob in IndexedDB
|
|
120
|
+
* (key = `result-<entry.id>`). Restored as an object URL on history
|
|
121
|
+
* click so the result survives even if the original URL (Cloudinary
|
|
122
|
+
* / data:) expired or was lost. */
|
|
123
|
+
hasResult?: boolean;
|
|
119
124
|
/** What the user actually selected when they ran the try-on (per section). */
|
|
120
125
|
selectedSizes?: Array<{
|
|
121
126
|
sectionName: string;
|
|
@@ -15,5 +15,11 @@ export declare function savePhoto(id: string, blob: Blob): Promise<boolean>;
|
|
|
15
15
|
export declare function getPhoto(id: string): Promise<Blob | null>;
|
|
16
16
|
/** Delete a photo by historyEntryId. */
|
|
17
17
|
export declare function deletePhoto(id: string): Promise<boolean>;
|
|
18
|
-
/**
|
|
18
|
+
/** Save a try-on result Blob keyed by historyEntryId. Replaces if exists. */
|
|
19
|
+
export declare function saveResult(id: string, blob: Blob): Promise<boolean>;
|
|
20
|
+
/** Load a try-on result Blob by historyEntryId, or null if not stored. */
|
|
21
|
+
export declare function getResult(id: string): Promise<Blob | null>;
|
|
22
|
+
/** Garbage-collect: keep only photos (and results) whose id is in `keepIds`.
|
|
23
|
+
* Uses a value cursor (openCursor) so records can be deleted during
|
|
24
|
+
* iteration — openKeyCursor's cursor.delete() throws InvalidStateError. */
|
|
19
25
|
export declare function pruneToIds(keepIds: Set<string>): Promise<void>;
|
|
@@ -9624,6 +9624,7 @@ function openDb() {
|
|
|
9624
9624
|
});
|
|
9625
9625
|
return _dbPromise;
|
|
9626
9626
|
}
|
|
9627
|
+
const RESULT_PREFIX = "result-";
|
|
9627
9628
|
async function savePhoto(id2, blob) {
|
|
9628
9629
|
const db2 = await openDb();
|
|
9629
9630
|
if (!db2) return false;
|
|
@@ -9653,19 +9654,30 @@ async function getPhoto(id2) {
|
|
|
9653
9654
|
}
|
|
9654
9655
|
});
|
|
9655
9656
|
}
|
|
9657
|
+
async function saveResult(id2, blob) {
|
|
9658
|
+
return savePhoto(RESULT_PREFIX + id2, blob);
|
|
9659
|
+
}
|
|
9660
|
+
async function getResult(id2) {
|
|
9661
|
+
return getPhoto(RESULT_PREFIX + id2);
|
|
9662
|
+
}
|
|
9656
9663
|
async function pruneToIds(keepIds) {
|
|
9657
9664
|
const db2 = await openDb();
|
|
9658
9665
|
if (!db2) return;
|
|
9666
|
+
const expected = /* @__PURE__ */ new Set();
|
|
9667
|
+
for (const id2 of keepIds) {
|
|
9668
|
+
expected.add(id2);
|
|
9669
|
+
expected.add(RESULT_PREFIX + id2);
|
|
9670
|
+
}
|
|
9659
9671
|
return new Promise((resolve) => {
|
|
9660
9672
|
try {
|
|
9661
9673
|
const tx = db2.transaction(STORE, "readwrite");
|
|
9662
9674
|
const store = tx.objectStore(STORE);
|
|
9663
|
-
const cursorReq = store.
|
|
9675
|
+
const cursorReq = store.openCursor();
|
|
9664
9676
|
cursorReq.onsuccess = () => {
|
|
9665
9677
|
const cursor = cursorReq.result;
|
|
9666
9678
|
if (!cursor) return;
|
|
9667
9679
|
const key = String(cursor.key);
|
|
9668
|
-
if (!
|
|
9680
|
+
if (!expected.has(key)) cursor.delete();
|
|
9669
9681
|
cursor.continue();
|
|
9670
9682
|
};
|
|
9671
9683
|
tx.oncomplete = () => resolve();
|
|
@@ -20101,10 +20113,15 @@ function SectionDetailView({
|
|
|
20101
20113
|
if (!details.length) return [];
|
|
20102
20114
|
const isFromLength = new Set(lengthDetails.map((m2) => m2.measurement));
|
|
20103
20115
|
if (hasLengthSource) isFromLength.add("Height");
|
|
20116
|
+
const activeLengthLabel = selectedLength || effectiveRecLength;
|
|
20104
20117
|
return details.map((m2) => {
|
|
20105
20118
|
if (isFromLength.has(m2.measurement)) {
|
|
20106
20119
|
const userNum2 = userMeasurements[m2.measurement.toLowerCase()] || pNumFn(m2.userValue);
|
|
20107
|
-
const
|
|
20120
|
+
const lengthAllSizes = lengthEntry?.secResult?.allSizes;
|
|
20121
|
+
const lookupByLengthEntry = activeLengthLabel ? lengthAllSizes?.[activeLengthLabel]?.[m2.measurement] : void 0;
|
|
20122
|
+
const lookupByLength = activeLengthLabel ? allSizes?.[activeLengthLabel]?.[m2.measurement] : void 0;
|
|
20123
|
+
const lookupBySize = allSizes?.[displaySize]?.[m2.measurement];
|
|
20124
|
+
const lookup2 = lookupByLengthEntry ?? lookupByLength ?? lookupBySize;
|
|
20108
20125
|
const chartRange2 = lookup2?.chartRange ?? m2.chartRange;
|
|
20109
20126
|
const fit2 = lookup2?.fit ?? m2.fit ?? "good";
|
|
20110
20127
|
return {
|
|
@@ -20129,7 +20146,7 @@ function SectionDetailView({
|
|
|
20129
20146
|
isLength: isDirectional
|
|
20130
20147
|
};
|
|
20131
20148
|
});
|
|
20132
|
-
}, [sectionResult, lengthEntry, userMeasurements, renderRaw, allSizes, displaySize]);
|
|
20149
|
+
}, [sectionResult, lengthEntry, userMeasurements, renderRaw, allSizes, displaySize, selectedLength]);
|
|
20133
20150
|
const goodCount = fitRows.filter(
|
|
20134
20151
|
(r2) => r2.fit === "good" || r2.fit === "a-bit-tight" || r2.fit === "a-bit-loose"
|
|
20135
20152
|
).length;
|
|
@@ -21145,14 +21162,19 @@ function SizeResultView({
|
|
|
21145
21162
|
})(),
|
|
21146
21163
|
onBack: () => setActiveSection(null),
|
|
21147
21164
|
internationalSizes: entry.secResult?.internationalSizes,
|
|
21148
|
-
productImage: resultImageUrl || productImage,
|
|
21165
|
+
productImage: tryOnProcessing && previewUrl ? previewUrl : resultImageUrl || productImage,
|
|
21149
21166
|
productTitle,
|
|
21150
21167
|
isMobile: true,
|
|
21151
|
-
isTryOnImage: !!resultImageUrl,
|
|
21168
|
+
isTryOnImage: !!resultImageUrl && !tryOnProcessing,
|
|
21169
|
+
tryOnProcessing,
|
|
21170
|
+
tryOnStartedAt,
|
|
21152
21171
|
showLines,
|
|
21153
21172
|
onToggleLines: isAccessory ? void 0 : () => setShowLines(!showLines),
|
|
21154
21173
|
onImageLoad: handleImgLoad,
|
|
21155
|
-
overlayNode:
|
|
21174
|
+
overlayNode: tryOnProcessing ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
21175
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TryOnGenerationBadge, { tryOnStartedAt: tryOnStartedAt ?? null, t: t2 }),
|
|
21176
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(RegenScanOverlay, { active: true })
|
|
21177
|
+
] }) : resultImageUrl && poseReady && poseLines ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21156
21178
|
MeasurementOverlay,
|
|
21157
21179
|
{
|
|
21158
21180
|
lines: poseLines,
|
|
@@ -21183,7 +21205,19 @@ function SizeResultView({
|
|
|
21183
21205
|
] });
|
|
21184
21206
|
}
|
|
21185
21207
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2", children: [
|
|
21186
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
21208
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-bg", style: { position: "relative" }, children: [
|
|
21209
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21210
|
+
"img",
|
|
21211
|
+
{
|
|
21212
|
+
src: tryOnProcessing && previewUrl ? previewUrl : resultImageUrl || productImage,
|
|
21213
|
+
alt: productTitle,
|
|
21214
|
+
className: "ps-tryon-v2-bg-img",
|
|
21215
|
+
onLoad: handleImgLoad
|
|
21216
|
+
}
|
|
21217
|
+
),
|
|
21218
|
+
tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnGenerationBadge, { tryOnStartedAt: tryOnStartedAt ?? null, t: t2 }),
|
|
21219
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(RegenScanOverlay, { active: !!tryOnProcessing })
|
|
21220
|
+
] }),
|
|
21187
21221
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-panel", children: [
|
|
21188
21222
|
mismatchNotice,
|
|
21189
21223
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -21205,6 +21239,8 @@ function SizeResultView({
|
|
|
21205
21239
|
})(),
|
|
21206
21240
|
onBack: () => setActiveSection(null),
|
|
21207
21241
|
internationalSizes: entry.secResult?.internationalSizes,
|
|
21242
|
+
tryOnProcessing,
|
|
21243
|
+
tryOnStartedAt,
|
|
21208
21244
|
t: t2,
|
|
21209
21245
|
allSizes: entry.secResult?.allSizes ?? sizingResult?.allSizes
|
|
21210
21246
|
}
|
|
@@ -26775,7 +26811,7 @@ function CameraUploadIcon() {
|
|
|
26775
26811
|
function AccessorySizeView({
|
|
26776
26812
|
title,
|
|
26777
26813
|
fields,
|
|
26778
|
-
unitOptions
|
|
26814
|
+
unitOptions,
|
|
26779
26815
|
photoVariant = "full-body",
|
|
26780
26816
|
disablePhotoUpload = false,
|
|
26781
26817
|
productImage,
|
|
@@ -26803,6 +26839,10 @@ function AccessorySizeView({
|
|
|
26803
26839
|
});
|
|
26804
26840
|
return init;
|
|
26805
26841
|
});
|
|
26842
|
+
const resolvedUnitOptions = unitOptions ?? [
|
|
26843
|
+
{ label: t2("Centimeters"), value: "cm" },
|
|
26844
|
+
{ label: t2("Inches"), value: "in" }
|
|
26845
|
+
];
|
|
26806
26846
|
const [error, setError] = reactExports.useState("");
|
|
26807
26847
|
const fileInputRef = reactExports.useRef(null);
|
|
26808
26848
|
const [photoPreview, setPhotoPreview] = reactExports.useState(null);
|
|
@@ -26889,7 +26929,7 @@ function AccessorySizeView({
|
|
|
26889
26929
|
gender: formRef.current.gender || "male"
|
|
26890
26930
|
});
|
|
26891
26931
|
};
|
|
26892
|
-
const activeUnitLabel =
|
|
26932
|
+
const activeUnitLabel = resolvedUnitOptions.find((o) => o.value === sizingUnit)?.label || resolvedUnitOptions[0].label;
|
|
26893
26933
|
if (isMobile && step === "photo") {
|
|
26894
26934
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bp-wrapper", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
26895
26935
|
PhotoStepMobile,
|
|
@@ -26913,7 +26953,7 @@ function AccessorySizeView({
|
|
|
26913
26953
|
if (isMobile) {
|
|
26914
26954
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bp-wrapper", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bpm-root", children: [
|
|
26915
26955
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bpm-header", children: /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "ps-bpm-title", children: t2(title) }) }),
|
|
26916
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bpm-toggle", style: { padding: "0 4%" }, children:
|
|
26956
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bpm-toggle", style: { padding: "0 4%" }, children: resolvedUnitOptions.map((opt) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
26917
26957
|
"button",
|
|
26918
26958
|
{
|
|
26919
26959
|
type: "button",
|
|
@@ -26985,7 +27025,7 @@ function AccessorySizeView({
|
|
|
26985
27025
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bp-image", style: { position: "relative" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: productImage, alt: productTitle, className: "ps-bp-image-img" }) }),
|
|
26986
27026
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bp-root", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-step ps-bp-step-enter", children: [
|
|
26987
27027
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: "0.6vw", marginBottom: "0.3vw" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "ps-bp-title", style: { margin: 0 }, children: t2(title) }) }),
|
|
26988
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bp-system-toggle", children:
|
|
27028
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bp-system-toggle", children: resolvedUnitOptions.map((opt) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
26989
27029
|
"button",
|
|
26990
27030
|
{
|
|
26991
27031
|
type: "button",
|
|
@@ -27352,7 +27392,7 @@ function AccessorySizeView({
|
|
|
27352
27392
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { style: { margin: "0.2vw 0 0", fontSize: "0.65vw", color: "var(--ps-text-muted)" }, children: t2("Enter your measurements OR upload a photo — we'll use whichever you provide.") })
|
|
27353
27393
|
] }),
|
|
27354
27394
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.7vw" }, children: [
|
|
27355
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bp-system-toggle", style: { alignSelf: "center" }, children:
|
|
27395
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bp-system-toggle", style: { alignSelf: "center" }, children: resolvedUnitOptions.map((opt) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
27356
27396
|
"button",
|
|
27357
27397
|
{
|
|
27358
27398
|
type: "button",
|
|
@@ -27525,130 +27565,141 @@ function AccessorySizeView({
|
|
|
27525
27565
|
] })
|
|
27526
27566
|
] }) }) });
|
|
27527
27567
|
}
|
|
27528
|
-
|
|
27529
|
-
|
|
27530
|
-
|
|
27531
|
-
|
|
27532
|
-
|
|
27533
|
-
|
|
27534
|
-
|
|
27535
|
-
|
|
27536
|
-
|
|
27537
|
-
|
|
27538
|
-
|
|
27539
|
-
|
|
27568
|
+
function buildFallbackFootFields(t2) {
|
|
27569
|
+
return [
|
|
27570
|
+
{
|
|
27571
|
+
key: "footLengthCm",
|
|
27572
|
+
label: t2("Foot Length"),
|
|
27573
|
+
placeholder: { cm: "e.g. 26.5", in: "e.g. 10.5" },
|
|
27574
|
+
hint: t2("Measure from heel to longest toe"),
|
|
27575
|
+
min: 10,
|
|
27576
|
+
max: 35,
|
|
27577
|
+
step: 0.5
|
|
27578
|
+
}
|
|
27579
|
+
];
|
|
27580
|
+
}
|
|
27581
|
+
function buildFieldsFromSizeGuide$2(sizeGuide, t2) {
|
|
27582
|
+
const fallback = buildFallbackFootFields(t2);
|
|
27540
27583
|
const req = sizeGuide?.requiredFields;
|
|
27541
|
-
if (!req || req.length === 0) return
|
|
27584
|
+
if (!req || req.length === 0) return fallback;
|
|
27542
27585
|
const SIZE_CODE_KEYS = /* @__PURE__ */ new Set(["size", "country", "eu", "__skip__", "shoeEU", "shoeUS", "shoeUK", "shoeJP"]);
|
|
27543
27586
|
const defaultPlaceholderFor = (key, label) => {
|
|
27544
|
-
const exact =
|
|
27587
|
+
const exact = fallback.find((f2) => f2.key === key);
|
|
27545
27588
|
if (exact) return exact.placeholder;
|
|
27546
27589
|
const looksLikeFoot = /foot|length/i.test(key) || /foot|length/i.test(label);
|
|
27547
|
-
if (looksLikeFoot) return
|
|
27590
|
+
if (looksLikeFoot) return fallback[0].placeholder;
|
|
27548
27591
|
return { cm: "", in: "" };
|
|
27549
27592
|
};
|
|
27550
27593
|
const out = req.filter((f2) => !SIZE_CODE_KEYS.has(f2.key) && f2.unit !== "size").map((f2) => {
|
|
27551
|
-
const
|
|
27594
|
+
const ph2 = defaultPlaceholderFor(f2.key, f2.label || "");
|
|
27552
27595
|
return {
|
|
27553
27596
|
key: f2.key,
|
|
27554
|
-
label: f2.label || f2.key,
|
|
27597
|
+
label: t2(f2.label || f2.key),
|
|
27555
27598
|
placeholder: {
|
|
27556
|
-
cm: f2.placeholder ||
|
|
27557
|
-
in: f2.placeholder ||
|
|
27599
|
+
cm: f2.placeholder || ph2.cm,
|
|
27600
|
+
in: f2.placeholder || ph2.in
|
|
27558
27601
|
},
|
|
27559
27602
|
min: 0,
|
|
27560
27603
|
step: 0.5
|
|
27561
27604
|
};
|
|
27562
27605
|
});
|
|
27563
|
-
return out.length > 0 ? out :
|
|
27606
|
+
return out.length > 0 ? out : fallback;
|
|
27564
27607
|
}
|
|
27565
27608
|
function FootSizeView(props) {
|
|
27566
|
-
const { sizeGuide, ...rest } = props;
|
|
27567
|
-
const fields = buildFieldsFromSizeGuide$2(sizeGuide);
|
|
27609
|
+
const { sizeGuide, t: t2, ...rest } = props;
|
|
27610
|
+
const fields = buildFieldsFromSizeGuide$2(sizeGuide, t2);
|
|
27568
27611
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
27569
27612
|
AccessorySizeView,
|
|
27570
27613
|
{
|
|
27571
|
-
title: "Shoe Size",
|
|
27614
|
+
title: t2("Shoe Size"),
|
|
27572
27615
|
fields,
|
|
27573
27616
|
disablePhotoUpload: true,
|
|
27617
|
+
t: t2,
|
|
27574
27618
|
...rest
|
|
27575
27619
|
}
|
|
27576
27620
|
);
|
|
27577
27621
|
}
|
|
27578
|
-
|
|
27579
|
-
|
|
27580
|
-
|
|
27581
|
-
|
|
27582
|
-
|
|
27583
|
-
|
|
27584
|
-
|
|
27585
|
-
|
|
27586
|
-
|
|
27587
|
-
|
|
27588
|
-
|
|
27589
|
-
|
|
27622
|
+
function buildFallbackHeadFields(t2) {
|
|
27623
|
+
return [
|
|
27624
|
+
{
|
|
27625
|
+
key: "headCircumference",
|
|
27626
|
+
label: t2("Head Circumference"),
|
|
27627
|
+
placeholder: { cm: "e.g. 57", in: "e.g. 22.5" },
|
|
27628
|
+
hint: t2("Wrap a tape around the widest part of your head"),
|
|
27629
|
+
min: 48,
|
|
27630
|
+
max: 65,
|
|
27631
|
+
step: 0.5
|
|
27632
|
+
}
|
|
27633
|
+
];
|
|
27634
|
+
}
|
|
27635
|
+
function buildFieldsFromSizeGuide$1(sizeGuide, t2) {
|
|
27590
27636
|
const req = sizeGuide?.requiredFields;
|
|
27591
|
-
if (!req || req.length === 0) return
|
|
27637
|
+
if (!req || req.length === 0) return buildFallbackHeadFields(t2);
|
|
27592
27638
|
const SIZE_CODE_KEYS = /* @__PURE__ */ new Set(["size", "country", "eu", "__skip__"]);
|
|
27593
27639
|
return req.filter((f2) => !SIZE_CODE_KEYS.has(f2.key) && f2.unit !== "size").map((f2) => ({
|
|
27594
27640
|
key: f2.key,
|
|
27595
|
-
label: f2.label || f2.key,
|
|
27641
|
+
label: t2(f2.label || f2.key),
|
|
27596
27642
|
placeholder: { cm: f2.placeholder || "", in: f2.placeholder || "" },
|
|
27597
27643
|
min: 0,
|
|
27598
27644
|
step: 0.5
|
|
27599
27645
|
}));
|
|
27600
27646
|
}
|
|
27601
27647
|
function HeadSizeView(props) {
|
|
27602
|
-
const { sizeGuide, ...rest } = props;
|
|
27603
|
-
const fields = buildFieldsFromSizeGuide$1(sizeGuide);
|
|
27648
|
+
const { sizeGuide, t: t2, ...rest } = props;
|
|
27649
|
+
const fields = buildFieldsFromSizeGuide$1(sizeGuide, t2);
|
|
27604
27650
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
27605
27651
|
AccessorySizeView,
|
|
27606
27652
|
{
|
|
27607
|
-
title: "Headwear Measurements",
|
|
27653
|
+
title: t2("Headwear Measurements"),
|
|
27608
27654
|
fields,
|
|
27609
27655
|
photoVariant: "close-up",
|
|
27656
|
+
t: t2,
|
|
27610
27657
|
...rest
|
|
27611
27658
|
}
|
|
27612
27659
|
);
|
|
27613
27660
|
}
|
|
27614
|
-
|
|
27615
|
-
|
|
27616
|
-
|
|
27617
|
-
|
|
27618
|
-
|
|
27619
|
-
|
|
27620
|
-
|
|
27621
|
-
|
|
27622
|
-
|
|
27623
|
-
|
|
27624
|
-
|
|
27625
|
-
|
|
27626
|
-
|
|
27627
|
-
|
|
27628
|
-
|
|
27629
|
-
|
|
27630
|
-
|
|
27631
|
-
|
|
27632
|
-
|
|
27633
|
-
|
|
27634
|
-
|
|
27635
|
-
|
|
27636
|
-
|
|
27637
|
-
|
|
27638
|
-
|
|
27639
|
-
|
|
27640
|
-
|
|
27641
|
-
|
|
27642
|
-
|
|
27643
|
-
|
|
27644
|
-
|
|
27645
|
-
|
|
27661
|
+
function buildFallbackFaceFields(t2) {
|
|
27662
|
+
return [
|
|
27663
|
+
{
|
|
27664
|
+
key: "lensWidth",
|
|
27665
|
+
label: t2("Lens Width"),
|
|
27666
|
+
// `cm` key = mm placeholder (default eyewear unit); `in` key = cm placeholder.
|
|
27667
|
+
placeholder: { mm: "e.g. 52", cm: "e.g. 5.2" },
|
|
27668
|
+
hint: t2("Width of one lens"),
|
|
27669
|
+
min: 0,
|
|
27670
|
+
step: 1
|
|
27671
|
+
},
|
|
27672
|
+
{
|
|
27673
|
+
key: "bridgeWidth",
|
|
27674
|
+
label: t2("Bridge"),
|
|
27675
|
+
placeholder: { mm: "e.g. 18", cm: "e.g. 1.8" },
|
|
27676
|
+
hint: t2("Distance over the nose between lenses"),
|
|
27677
|
+
min: 0,
|
|
27678
|
+
step: 1
|
|
27679
|
+
},
|
|
27680
|
+
{
|
|
27681
|
+
key: "templeLength",
|
|
27682
|
+
label: t2("Arm Length"),
|
|
27683
|
+
placeholder: { mm: "e.g. 140", cm: "e.g. 14" },
|
|
27684
|
+
hint: t2("Length of the arm from hinge to tip"),
|
|
27685
|
+
min: 0,
|
|
27686
|
+
step: 1
|
|
27687
|
+
}
|
|
27688
|
+
];
|
|
27689
|
+
}
|
|
27690
|
+
function buildEyewearUnitOptions(t2) {
|
|
27691
|
+
return [
|
|
27692
|
+
{ label: t2("Millimetre"), value: "mm" },
|
|
27693
|
+
{ label: t2("Centimetre"), value: "cm" }
|
|
27694
|
+
];
|
|
27695
|
+
}
|
|
27696
|
+
function buildFieldsFromSizeGuide(sizeGuide, t2) {
|
|
27646
27697
|
const req = sizeGuide?.requiredFields;
|
|
27647
|
-
if (!req || req.length === 0) return
|
|
27698
|
+
if (!req || req.length === 0) return buildFallbackFaceFields(t2);
|
|
27648
27699
|
const SIZE_CODE_KEYS = /* @__PURE__ */ new Set(["size", "country", "eu", "__skip__"]);
|
|
27649
27700
|
return req.filter((f2) => !SIZE_CODE_KEYS.has(f2.key) && f2.unit !== "size").map((f2) => ({
|
|
27650
27701
|
key: f2.key,
|
|
27651
|
-
label: f2.label || f2.key,
|
|
27702
|
+
label: t2(f2.label || f2.key),
|
|
27652
27703
|
placeholder: {
|
|
27653
27704
|
cm: f2.placeholder || "",
|
|
27654
27705
|
in: f2.placeholder || ""
|
|
@@ -27658,15 +27709,16 @@ function buildFieldsFromSizeGuide(sizeGuide) {
|
|
|
27658
27709
|
}));
|
|
27659
27710
|
}
|
|
27660
27711
|
function FaceSizeView(props) {
|
|
27661
|
-
const { sizeGuide, ...rest } = props;
|
|
27662
|
-
const fields = buildFieldsFromSizeGuide(sizeGuide);
|
|
27712
|
+
const { sizeGuide, t: t2, ...rest } = props;
|
|
27713
|
+
const fields = buildFieldsFromSizeGuide(sizeGuide, t2);
|
|
27663
27714
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
27664
27715
|
AccessorySizeView,
|
|
27665
27716
|
{
|
|
27666
|
-
title: "Frame Measurements",
|
|
27717
|
+
title: t2("Frame Measurements"),
|
|
27667
27718
|
fields,
|
|
27668
|
-
unitOptions:
|
|
27719
|
+
unitOptions: buildEyewearUnitOptions(t2),
|
|
27669
27720
|
photoVariant: "close-up",
|
|
27721
|
+
t: t2,
|
|
27670
27722
|
...rest
|
|
27671
27723
|
}
|
|
27672
27724
|
);
|
|
@@ -29201,15 +29253,30 @@ function PrimeStyleTryonInner({
|
|
|
29201
29253
|
displayLabel: o.displayLabel,
|
|
29202
29254
|
isOverride: !!recommended && o.selectedSize !== recommended
|
|
29203
29255
|
}));
|
|
29256
|
+
let entryId = null;
|
|
29204
29257
|
setHistory((prev) => {
|
|
29205
29258
|
if (prev.length === 0) return prev;
|
|
29259
|
+
entryId = prev[0].id;
|
|
29206
29260
|
const updated = {
|
|
29207
29261
|
...prev[0],
|
|
29208
29262
|
resultImageUrl,
|
|
29263
|
+
hasResult: true,
|
|
29209
29264
|
...selectedSizes.length ? { selectedSizes } : {}
|
|
29210
29265
|
};
|
|
29211
29266
|
return [updated, ...prev.slice(1)];
|
|
29212
29267
|
});
|
|
29268
|
+
if (entryId) {
|
|
29269
|
+
const id2 = entryId;
|
|
29270
|
+
void (async () => {
|
|
29271
|
+
try {
|
|
29272
|
+
const res = await fetch(resultImageUrl);
|
|
29273
|
+
if (!res.ok) return;
|
|
29274
|
+
const blob = await res.blob();
|
|
29275
|
+
await saveResult(id2, blob);
|
|
29276
|
+
} catch {
|
|
29277
|
+
}
|
|
29278
|
+
})();
|
|
29279
|
+
}
|
|
29213
29280
|
} else if (view === "result" && resultImageUrl && !historySavedRef.current) {
|
|
29214
29281
|
historySavedRef.current = true;
|
|
29215
29282
|
saveHistoryEntry().catch(() => {
|
|
@@ -29239,6 +29306,13 @@ function PrimeStyleTryonInner({
|
|
|
29239
29306
|
setSizeGuideFetching(false);
|
|
29240
29307
|
}
|
|
29241
29308
|
setResultImageUrl(entry.resultImageUrl || null);
|
|
29309
|
+
if (entry.hasResult || entry.resultImageUrl) {
|
|
29310
|
+
void getResult(entry.id).then((blob) => {
|
|
29311
|
+
if (!blob) return;
|
|
29312
|
+
const url = URL.createObjectURL(blob);
|
|
29313
|
+
setResultImageUrl(url);
|
|
29314
|
+
});
|
|
29315
|
+
}
|
|
29242
29316
|
if (entry.hasPhoto) {
|
|
29243
29317
|
void getPhoto(entry.id).then((blob) => {
|
|
29244
29318
|
if (!blob) return;
|