@primestyleai/tryon 5.6.10 → 5.6.11

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.
@@ -4002,40 +4002,18 @@ const STYLES = `
4002
4002
  .ps-msp-avatar { color: var(--ps-accent); border-color: var(--ps-accent); }
4003
4003
  .ps-msp-avatar-tag { background: var(--ps-accent); }
4004
4004
 
4005
- .ps-msp-card-thumb {
4006
- position: relative;
4007
- height: 90px;
4008
- background: var(--ps-bg-secondary);
4009
- border-radius: 8px;
4010
- display: flex; align-items: center; justify-content: center;
4011
- margin-bottom: 22px;
4012
- color: var(--ps-text-secondary);
4013
- overflow: visible;
4014
- }
4015
- .ps-msp-card-thumb::after {
4016
- /* Clip the rectangle photo only, not the circle overlay */
4017
- content: ""; display: block;
4018
- }
4019
- .ps-msp-card-photo {
4020
- width: 100%; height: 100%; object-fit: cover; display: block;
4021
- border-radius: 8px;
4022
- /* Same head-bias crop as the profile detail avatar */
4023
- object-position: 50% 12%;
4024
- }
4025
- /* Circular profile avatar overlay — sits on the bottom-left of the
4026
- rectangular thumb, social-card style. Shows the head crop. */
4005
+ /* Big circular profile avatar — only chrome on the card, no
4006
+ rectangular hero. Shows the head crop via object-position 12%. */
4027
4007
  .ps-msp-card-circle {
4028
- position: absolute;
4029
- left: 12px; bottom: -18px;
4030
- width: 44px; height: 44px;
4008
+ width: 110px; height: 110px;
4031
4009
  border-radius: 50%;
4032
- background: var(--ps-bg-primary);
4033
- border: 3px solid var(--ps-bg-primary);
4034
- box-shadow: 0 4px 12px rgba(0,0,0,0.12);
4010
+ background: var(--ps-bg-secondary);
4011
+ border: 3px solid var(--ps-accent);
4012
+ box-shadow: 0 6px 18px rgba(33, 84, 239, 0.18);
4035
4013
  overflow: hidden;
4036
4014
  display: flex; align-items: center; justify-content: center;
4037
4015
  color: var(--ps-accent);
4038
- z-index: 2;
4016
+ margin: 6px auto 14px;
4039
4017
  }
4040
4018
  .ps-msp-card-circle img {
4041
4019
  width: 100%; height: 100%; object-fit: cover;
@@ -4681,7 +4659,32 @@ const STYLES = `
4681
4659
  100% { background-position: -200% 0; }
4682
4660
  }
4683
4661
 
4684
- /* Saved sizes history (per-product cache) */
4662
+ /* Inline measurement edit inputs */
4663
+ .ps-pmv-measure.ps-editing {
4664
+ border-color: var(--ps-accent);
4665
+ background: rgba(33, 84, 239, 0.04);
4666
+ }
4667
+ .ps-pmv-measure-edit {
4668
+ display: flex; align-items: baseline; gap: 4px;
4669
+ }
4670
+ .ps-pmv-measure-input {
4671
+ flex: 1; min-width: 0;
4672
+ background: transparent; border: none; outline: none;
4673
+ font-family: inherit;
4674
+ font-size: 18px; font-weight: 700;
4675
+ color: var(--ps-text-primary);
4676
+ padding: 0;
4677
+ font-feature-settings: "tnum" 1;
4678
+ }
4679
+ .ps-pmv-measure-input::-webkit-outer-spin-button,
4680
+ .ps-pmv-measure-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
4681
+ .ps-pmv-measure-input[type="number"] { -moz-appearance: textfield; }
4682
+ .ps-pmv-measure-input-unit {
4683
+ font-size: 11px; color: var(--ps-text-muted); font-weight: 500;
4684
+ }
4685
+
4686
+ /* Saved sizes history (per-product cache) — kept for backwards compat,
4687
+ no longer rendered inside ProfileMeasurementsView */
4685
4688
  .ps-pmv-history {
4686
4689
  display: flex; flex-direction: column; gap: 8px;
4687
4690
  }
@@ -8250,7 +8253,7 @@ function ProfileMeasurementsView({
8250
8253
  profile,
8251
8254
  isActive,
8252
8255
  onSelect,
8253
- onEdit,
8256
+ onSaveMeasurements,
8254
8257
  onDelete,
8255
8258
  onBack,
8256
8259
  onSave,
@@ -8260,6 +8263,33 @@ function ProfileMeasurementsView({
8260
8263
  const measurements = profile.measurements || {};
8261
8264
  const unit = profile.measurementsUnit || "cm";
8262
8265
  const hasMeasurements = Object.keys(measurements).some((k) => measurements[k] != null);
8266
+ const [editing, setEditing] = useState(false);
8267
+ const [draft, setDraft] = useState({});
8268
+ useEffect(() => {
8269
+ if (!editing) return;
8270
+ const next = {};
8271
+ for (const f of fields) {
8272
+ const v = measurements[f.key];
8273
+ if (v != null) next[f.key] = String(Math.round(v * 10) / 10);
8274
+ }
8275
+ setDraft(next);
8276
+ }, [editing]);
8277
+ const handleDraftChange = (key, value) => {
8278
+ setDraft((prev) => ({ ...prev, [key]: value }));
8279
+ };
8280
+ const handleEditSave = () => {
8281
+ const updated = { ...measurements };
8282
+ for (const [key, raw] of Object.entries(draft)) {
8283
+ const v = parseFloat(raw);
8284
+ if (!isNaN(v) && v > 0) updated[key] = v;
8285
+ }
8286
+ onSaveMeasurements(updated);
8287
+ setEditing(false);
8288
+ };
8289
+ const handleEditCancel = () => {
8290
+ setEditing(false);
8291
+ setDraft({});
8292
+ };
8263
8293
  const heightDisplay = (() => {
8264
8294
  const h = profile.height ?? profile.heightCm;
8265
8295
  if (!h) return "—";
@@ -8310,44 +8340,45 @@ function ProfileMeasurementsView({
8310
8340
  /* @__PURE__ */ jsx("span", { children: t("Calculating...") })
8311
8341
  ] })
8312
8342
  ] }),
8313
- /* @__PURE__ */ jsx("div", { className: "ps-pmv-section-sub", children: hasMeasurements ? t("Calculated from your basics. Used to recommend the perfect size for any product.") : t("Our AI is computing your full body proportions — this usually takes a few seconds.") })
8343
+ /* @__PURE__ */ jsx("div", { className: "ps-pmv-section-sub", children: hasMeasurements ? editing ? t("Tap any value to edit. Save when you're done.") : t("Calculated from your basics. Used to recommend the perfect size for any product.") : t("Our AI is computing your full body proportions — this usually takes a few seconds.") })
8314
8344
  ] }),
8315
8345
  /* @__PURE__ */ jsx("div", { className: "ps-pmv-measure-grid", children: fields.map((f) => {
8316
8346
  const v = measurements[f.key];
8317
- return /* @__PURE__ */ jsxs("div", { className: `ps-pmv-measure${v == null ? " ps-loading" : ""}`, children: [
8347
+ return /* @__PURE__ */ jsxs("div", { className: `ps-pmv-measure${v == null && !editing ? " ps-loading" : ""}${editing ? " ps-editing" : ""}`, children: [
8318
8348
  /* @__PURE__ */ jsx("div", { className: "ps-pmv-measure-label", children: t(f.label) }),
8319
- /* @__PURE__ */ jsx("div", { className: `ps-pmv-measure-value${v == null ? " ps-loading" : ""}`, children: v != null ? `${Math.round(v * 10) / 10} ${unit}` : "—" })
8349
+ editing ? /* @__PURE__ */ jsxs("div", { className: "ps-pmv-measure-edit", children: [
8350
+ /* @__PURE__ */ jsx(
8351
+ "input",
8352
+ {
8353
+ type: "number",
8354
+ inputMode: "decimal",
8355
+ className: "ps-pmv-measure-input",
8356
+ value: draft[f.key] ?? "",
8357
+ placeholder: "—",
8358
+ onChange: (e) => handleDraftChange(f.key, e.target.value)
8359
+ }
8360
+ ),
8361
+ /* @__PURE__ */ jsx("span", { className: "ps-pmv-measure-input-unit", children: unit })
8362
+ ] }) : /* @__PURE__ */ jsx("div", { className: `ps-pmv-measure-value${v == null ? " ps-loading" : ""}`, children: v != null ? `${Math.round(v * 10) / 10} ${unit}` : "—" })
8320
8363
  ] }, f.key);
8321
8364
  }) })
8322
8365
  ] }),
8323
- profile.sizeHistory && profile.sizeHistory.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ps-pmv-section", children: [
8324
- /* @__PURE__ */ jsxs("div", { className: "ps-pmv-section-head", children: [
8325
- /* @__PURE__ */ jsx("div", { className: "ps-pmv-section-title", children: t("SAVED SIZES") }),
8326
- /* @__PURE__ */ jsx("div", { className: "ps-pmv-section-sub", children: t("Recommendations from this profile across products") })
8327
- ] }),
8328
- /* @__PURE__ */ jsx("div", { className: "ps-pmv-history", children: profile.sizeHistory.slice(0, 6).map((entry) => /* @__PURE__ */ jsxs("div", { className: "ps-pmv-history-card", children: [
8329
- entry.productImage && /* @__PURE__ */ jsx("div", { className: "ps-pmv-history-thumb", children: /* @__PURE__ */ jsx("img", { src: entry.productImage, alt: entry.productTitle }) }),
8330
- /* @__PURE__ */ jsxs("div", { className: "ps-pmv-history-info", children: [
8331
- /* @__PURE__ */ jsx("div", { className: "ps-pmv-history-name", children: entry.productTitle }),
8332
- /* @__PURE__ */ jsx("div", { className: "ps-pmv-history-meta", children: new Date(entry.savedAt).toLocaleDateString(void 0, { month: "short", day: "numeric" }) })
8333
- ] }),
8334
- /* @__PURE__ */ jsx("div", { className: "ps-pmv-history-size", children: entry.recommendedSize })
8335
- ] }, `${entry.productId}-${entry.savedAt}`)) })
8336
- ] }),
8337
8366
  /* @__PURE__ */ jsxs("div", { className: "ps-pmv-actions", children: [
8338
- /* @__PURE__ */ jsx("button", { type: "button", className: "ps-pmv-btn-secondary", onClick: onBack, children: t("Back") }),
8367
+ /* @__PURE__ */ jsx("button", { type: "button", className: "ps-pmv-btn-secondary", onClick: editing ? handleEditCancel : onBack, children: editing ? t("Cancel") : t("Back") }),
8339
8368
  /* @__PURE__ */ jsxs("div", { className: "ps-pmv-actions-right", children: [
8340
- /* @__PURE__ */ jsx("button", { type: "button", className: "ps-pmv-btn-edit", onClick: onEdit, children: t("Edit") }),
8341
- /* @__PURE__ */ jsx("button", { type: "button", className: "ps-pmv-btn-delete", onClick: onDelete, children: t("Delete") }),
8342
- !isActive && /* @__PURE__ */ jsx("button", { type: "button", className: "ps-pmv-btn-secondary", onClick: onSelect, children: t("USE THIS PROFILE") }),
8369
+ !editing && /* @__PURE__ */ jsxs(Fragment, { children: [
8370
+ /* @__PURE__ */ jsx("button", { type: "button", className: "ps-pmv-btn-edit", onClick: () => setEditing(true), children: t("Edit") }),
8371
+ /* @__PURE__ */ jsx("button", { type: "button", className: "ps-pmv-btn-delete", onClick: onDelete, children: t("Delete") }),
8372
+ !isActive && /* @__PURE__ */ jsx("button", { type: "button", className: "ps-pmv-btn-secondary", onClick: onSelect, children: t("USE THIS PROFILE") })
8373
+ ] }),
8343
8374
  /* @__PURE__ */ jsx(
8344
8375
  "button",
8345
8376
  {
8346
8377
  type: "button",
8347
8378
  className: "ps-pmv-btn-primary",
8348
- onClick: onSave,
8379
+ onClick: editing ? handleEditSave : onSave,
8349
8380
  disabled: !hasMeasurements,
8350
- children: hasMeasurements ? t("SAVE") : /* @__PURE__ */ jsxs(Fragment, { children: [
8381
+ children: hasMeasurements ? editing ? t("SAVE CHANGES") : t("SAVE") : /* @__PURE__ */ jsxs(Fragment, { children: [
8351
8382
  /* @__PURE__ */ jsx("span", { className: "ps-pmv-btn-spinner" }),
8352
8383
  t("CALCULATING")
8353
8384
  ] })
@@ -8357,12 +8388,6 @@ function ProfileMeasurementsView({
8357
8388
  ] })
8358
8389
  ] });
8359
8390
  }
8360
- function ProfileAvatar({ gender }) {
8361
- return /* @__PURE__ */ jsxs("div", { className: "ps-msp-avatar", children: [
8362
- /* @__PURE__ */ jsx(UserIcon, { size: 28 }),
8363
- gender && /* @__PURE__ */ jsx("span", { className: `ps-msp-avatar-tag ps-${gender}`, children: gender === "female" ? "♀" : "♂" })
8364
- ] });
8365
- }
8366
8391
  function ProfileCard({
8367
8392
  profile,
8368
8393
  isActive,
@@ -8400,10 +8425,7 @@ function ProfileCard({
8400
8425
  tabIndex: 0,
8401
8426
  children: [
8402
8427
  /* @__PURE__ */ jsx("div", { className: "ps-msp-card-header", children: /* @__PURE__ */ jsx("span", { className: "ps-msp-card-tag", children: isActive ? t("DEFAULT PROFILE") : profile.gender === "female" ? t("WOMEN'S FIT") : t("MEN'S FIT") }) }),
8403
- /* @__PURE__ */ jsxs("div", { className: "ps-msp-card-thumb", children: [
8404
- profile.photoBase64 ? /* @__PURE__ */ jsx("img", { src: profile.photoBase64, alt: profile.name, className: "ps-msp-card-photo" }) : /* @__PURE__ */ jsx(ProfileAvatar, { gender: profile.gender }),
8405
- /* @__PURE__ */ jsx("div", { className: "ps-msp-card-circle", children: profile.photoBase64 ? /* @__PURE__ */ jsx("img", { src: profile.photoBase64, alt: "" }) : /* @__PURE__ */ jsx(UserIcon, { size: 18 }) })
8406
- ] }),
8428
+ /* @__PURE__ */ jsx("div", { className: "ps-msp-card-circle", children: profile.photoBase64 ? /* @__PURE__ */ jsx("img", { src: profile.photoBase64, alt: profile.name }) : /* @__PURE__ */ jsx(UserIcon, { size: 32 }) }),
8407
8429
  /* @__PURE__ */ jsx("div", { className: "ps-msp-card-name", children: profile.name }),
8408
8430
  /* @__PURE__ */ jsxs("div", { className: "ps-msp-card-meta", children: [
8409
8431
  heightDisplay && /* @__PURE__ */ jsxs("div", { className: "ps-msp-meta-row", children: [
@@ -8473,6 +8495,7 @@ function MySizingProfilesView({
8473
8495
  onSelectProfile,
8474
8496
  onEditProfile,
8475
8497
  onSaveNewProfile,
8498
+ onSaveProfileMeasurements,
8476
8499
  onDeleteProfile,
8477
8500
  onClose,
8478
8501
  t
@@ -8504,9 +8527,7 @@ function MySizingProfilesView({
8504
8527
  onSelectProfile(viewingProfile.id);
8505
8528
  setViewingId(null);
8506
8529
  },
8507
- onEdit: () => {
8508
- onEditProfile(viewingProfile);
8509
- },
8530
+ onSaveMeasurements: (m) => onSaveProfileMeasurements(viewingProfile.id, m),
8510
8531
  onDelete: () => {
8511
8532
  onDeleteProfile(viewingProfile.id);
8512
8533
  setViewingId(null);
@@ -10954,7 +10975,34 @@ function PrimeStyleTryonInner({
10954
10975
  activeProfileId,
10955
10976
  onSelectProfile: (id) => {
10956
10977
  setActiveProfileId$1(id);
10957
- setView("body-profile");
10978
+ const p = profiles.find((x) => x.id === id);
10979
+ if (!p || !p.measurements || Object.keys(p.measurements).length === 0) {
10980
+ setView("body-profile");
10981
+ return;
10982
+ }
10983
+ setSizingResult(null);
10984
+ setSizingLoading(true);
10985
+ setEstimationDone(true);
10986
+ setView("size-result");
10987
+ recommendForProduct({
10988
+ productId: effectiveProductId,
10989
+ productTitle,
10990
+ productImage,
10991
+ sizeGuideData,
10992
+ profile: p,
10993
+ apiUrl,
10994
+ skipCache: true
10995
+ // always re-recommend on explicit profile select
10996
+ }).then((res) => {
10997
+ if (res?.raw) {
10998
+ setSizingResult(res.raw);
10999
+ }
11000
+ }).catch(() => {
11001
+ }).finally(() => setSizingLoading(false));
11002
+ },
11003
+ onSaveProfileMeasurements: (id, measurements) => {
11004
+ updateProfileMeasurements(id, measurements, profiles.find((x) => x.id === id)?.measurementsUnit || "cm");
11005
+ setProfiles(lsGet("profiles", []));
10958
11006
  },
10959
11007
  onEditProfile: (p) => {
10960
11008
  setProfileDetail(p);