@burdenoff/microfe-mybodyshield 2026.827.1 → 2026.830.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.
Files changed (90) hide show
  1. package/dist/mybodyshield/MyBodyShieldRoot.d.ts.map +1 -1
  2. package/dist/mybodyshield/MyBodyShieldRoot.js +54 -56
  3. package/dist/mybodyshield/MyBodyShieldRoot.js.map +1 -1
  4. package/dist/mybodyshield/MyBodyShieldRoutes.d.ts.map +1 -1
  5. package/dist/mybodyshield/MyBodyShieldRoutes.js +121 -62
  6. package/dist/mybodyshield/MyBodyShieldRoutes.js.map +1 -1
  7. package/dist/mybodyshield/components/EvidenceUpload.d.ts.map +1 -1
  8. package/dist/mybodyshield/components/EvidenceUpload.js +46 -45
  9. package/dist/mybodyshield/components/EvidenceUpload.js.map +1 -1
  10. package/dist/mybodyshield/components/FileLink.d.ts.map +1 -1
  11. package/dist/mybodyshield/components/FileLink.js +27 -18
  12. package/dist/mybodyshield/components/FileLink.js.map +1 -1
  13. package/dist/mybodyshield/components/MybDiscussion.d.ts +1 -1
  14. package/dist/mybodyshield/components/MybDiscussion.d.ts.map +1 -1
  15. package/dist/mybodyshield/components/MybDiscussion.js +59 -58
  16. package/dist/mybodyshield/components/MybDiscussion.js.map +1 -1
  17. package/dist/mybodyshield/components/MybTags.d.ts +1 -1
  18. package/dist/mybodyshield/components/MybTags.d.ts.map +1 -1
  19. package/dist/mybodyshield/components/MybTags.js +83 -74
  20. package/dist/mybodyshield/components/MybTags.js.map +1 -1
  21. package/dist/mybodyshield/components/PageDisabled.d.ts.map +1 -1
  22. package/dist/mybodyshield/components/PageDisabled.js +16 -11
  23. package/dist/mybodyshield/components/PageDisabled.js.map +1 -1
  24. package/dist/mybodyshield/components/Pagination.d.ts.map +1 -1
  25. package/dist/mybodyshield/components/Pagination.js +36 -27
  26. package/dist/mybodyshield/components/Pagination.js.map +1 -1
  27. package/dist/mybodyshield/components/StateViews.d.ts.map +1 -1
  28. package/dist/mybodyshield/components/StateViews.js +42 -34
  29. package/dist/mybodyshield/components/StateViews.js.map +1 -1
  30. package/dist/mybodyshield/components/UserSearchSelect.d.ts.map +1 -1
  31. package/dist/mybodyshield/components/UserSearchSelect.js +66 -68
  32. package/dist/mybodyshield/components/UserSearchSelect.js.map +1 -1
  33. package/dist/mybodyshield/hooks/index.d.ts +1 -0
  34. package/dist/mybodyshield/hooks/index.d.ts.map +1 -1
  35. package/dist/mybodyshield/hooks/index.js +1 -0
  36. package/dist/mybodyshield/hooks/useTr.d.ts +5 -0
  37. package/dist/mybodyshield/hooks/useTr.d.ts.map +1 -0
  38. package/dist/mybodyshield/hooks/useTr.js +12 -0
  39. package/dist/mybodyshield/hooks/useTr.js.map +1 -0
  40. package/dist/mybodyshield/pages/DashboardPage.d.ts.map +1 -1
  41. package/dist/mybodyshield/pages/DashboardPage.js +157 -136
  42. package/dist/mybodyshield/pages/DashboardPage.js.map +1 -1
  43. package/dist/mybodyshield/pages/SettingsPage.d.ts.map +1 -1
  44. package/dist/mybodyshield/pages/SettingsPage.js +50 -59
  45. package/dist/mybodyshield/pages/SettingsPage.js.map +1 -1
  46. package/dist/mybodyshield/pages/_shared/visuals.d.ts +2 -1
  47. package/dist/mybodyshield/pages/_shared/visuals.d.ts.map +1 -1
  48. package/dist/mybodyshield/pages/_shared/visuals.js +91 -81
  49. package/dist/mybodyshield/pages/_shared/visuals.js.map +1 -1
  50. package/dist/mybodyshield/pages/ai/AiControlsPage.d.ts.map +1 -1
  51. package/dist/mybodyshield/pages/ai/AiControlsPage.js +255 -266
  52. package/dist/mybodyshield/pages/ai/AiControlsPage.js.map +1 -1
  53. package/dist/mybodyshield/pages/coaching/CoachingPage.d.ts.map +1 -1
  54. package/dist/mybodyshield/pages/coaching/CoachingPage.js +321 -301
  55. package/dist/mybodyshield/pages/coaching/CoachingPage.js.map +1 -1
  56. package/dist/mybodyshield/pages/goals/GoalsPage.d.ts.map +1 -1
  57. package/dist/mybodyshield/pages/goals/GoalsPage.js +247 -251
  58. package/dist/mybodyshield/pages/goals/GoalsPage.js.map +1 -1
  59. package/dist/mybodyshield/pages/insights/InsightsCharts.d.ts.map +1 -1
  60. package/dist/mybodyshield/pages/insights/InsightsCharts.js +216 -213
  61. package/dist/mybodyshield/pages/insights/InsightsCharts.js.map +1 -1
  62. package/dist/mybodyshield/pages/insights/InsightsPage.d.ts.map +1 -1
  63. package/dist/mybodyshield/pages/insights/InsightsPage.js +290 -284
  64. package/dist/mybodyshield/pages/insights/InsightsPage.js.map +1 -1
  65. package/dist/mybodyshield/pages/nutrition/NutritionPage.d.ts.map +1 -1
  66. package/dist/mybodyshield/pages/nutrition/NutritionPage.js +575 -529
  67. package/dist/mybodyshield/pages/nutrition/NutritionPage.js.map +1 -1
  68. package/dist/mybodyshield/pages/programs/ProgramDetailPage.d.ts.map +1 -1
  69. package/dist/mybodyshield/pages/programs/ProgramDetailPage.js +333 -275
  70. package/dist/mybodyshield/pages/programs/ProgramDetailPage.js.map +1 -1
  71. package/dist/mybodyshield/pages/programs/ProgramsPage.d.ts.map +1 -1
  72. package/dist/mybodyshield/pages/programs/ProgramsPage.js +258 -253
  73. package/dist/mybodyshield/pages/programs/ProgramsPage.js.map +1 -1
  74. package/dist/mybodyshield/pages/progress/ProgressPage.d.ts.map +1 -1
  75. package/dist/mybodyshield/pages/progress/ProgressPage.js +271 -254
  76. package/dist/mybodyshield/pages/progress/ProgressPage.js.map +1 -1
  77. package/dist/mybodyshield/pages/recovery/RecoveryPage.d.ts.map +1 -1
  78. package/dist/mybodyshield/pages/recovery/RecoveryPage.js +206 -200
  79. package/dist/mybodyshield/pages/recovery/RecoveryPage.js.map +1 -1
  80. package/dist/mybodyshield/pages/train/SessionDetailPage.d.ts.map +1 -1
  81. package/dist/mybodyshield/pages/train/SessionDetailPage.js +327 -294
  82. package/dist/mybodyshield/pages/train/SessionDetailPage.js.map +1 -1
  83. package/dist/mybodyshield/pages/train/SessionsPage.d.ts.map +1 -1
  84. package/dist/mybodyshield/pages/train/SessionsPage.js +180 -163
  85. package/dist/mybodyshield/pages/train/SessionsPage.js.map +1 -1
  86. package/dist/mybodyshield/utils/i18n.d.ts +1 -2
  87. package/dist/mybodyshield/utils/i18n.d.ts.map +1 -1
  88. package/dist/mybodyshield/utils/i18n.js +15 -0
  89. package/dist/mybodyshield/utils/i18n.js.map +1 -0
  90. package/package.json +1 -1
@@ -1,17 +1,19 @@
1
1
  import { cn as e } from "../../utils/cn.js";
2
- import { Activity as t, BedDouble as n, Brain as r, Dumbbell as i, Flower2 as a, Gauge as o, Heart as s, HeartPulse as c, Moon as l, Percent as u, Ruler as d, Smile as f, Sparkles as p, StretchHorizontal as m, TrendingDown as h, TrendingUp as g, Waves as _, Weight as v, Zap as y } from "lucide-react";
3
- import { jsx as b, jsxs as x } from "react/jsx-runtime";
2
+ import { useTr as t } from "../../hooks/useTr.js";
3
+ import "../../hooks/index.js";
4
+ import { Activity as n, BedDouble as r, Brain as i, Dumbbell as a, Flower2 as o, Gauge as s, Heart as c, HeartPulse as l, Moon as u, Percent as d, Ruler as f, Smile as p, Sparkles as m, StretchHorizontal as h, TrendingDown as g, TrendingUp as _, Waves as v, Weight as y, Zap as b } from "lucide-react";
5
+ import { jsx as x, jsxs as S } from "react/jsx-runtime";
4
6
  //#region src/mybodyshield/pages/_shared/visuals.tsx
5
- var S = ({ value: t, color: n = "var(--color-action-primary-bg)", height: r = 8, className: i }) => {
7
+ var C = ({ value: t, color: n = "var(--color-action-primary-bg)", height: r = 8, className: i }) => {
6
8
  let a = Math.max(0, Math.min(100, t));
7
- return /* @__PURE__ */ b("div", {
9
+ return /* @__PURE__ */ x("div", {
8
10
  className: e("w-full overflow-hidden rounded-full bg-bg-sunken", i),
9
11
  style: { height: r },
10
12
  role: "progressbar",
11
13
  "aria-valuenow": Math.round(a),
12
14
  "aria-valuemin": 0,
13
15
  "aria-valuemax": 100,
14
- children: /* @__PURE__ */ b("div", {
16
+ children: /* @__PURE__ */ x("div", {
15
17
  className: "h-full rounded-full transition-[width] duration-500 ease-out",
16
18
  style: {
17
19
  width: `${a}%`,
@@ -19,26 +21,26 @@ var S = ({ value: t, color: n = "var(--color-action-primary-bg)", height: r = 8,
19
21
  }
20
22
  })
21
23
  });
22
- }, C = ({ value: t, size: n = 96, stroke: r = 9, color: i = "var(--color-action-primary-bg)", trackColor: a = "var(--color-bg-sunken)", children: o, className: s }) => {
24
+ }, w = ({ value: t, size: n = 96, stroke: r = 9, color: i = "var(--color-action-primary-bg)", trackColor: a = "var(--color-bg-sunken)", children: o, className: s }) => {
23
25
  let c = Math.max(0, Math.min(100, t)), l = (n - r) / 2, u = 2 * Math.PI * l, d = u - c / 100 * u;
24
- return /* @__PURE__ */ x("div", {
26
+ return /* @__PURE__ */ S("div", {
25
27
  className: e("relative inline-flex items-center justify-center", s),
26
28
  style: {
27
29
  width: n,
28
30
  height: n
29
31
  },
30
- children: [/* @__PURE__ */ x("svg", {
32
+ children: [/* @__PURE__ */ S("svg", {
31
33
  width: n,
32
34
  height: n,
33
35
  className: "-rotate-90",
34
- children: [/* @__PURE__ */ b("circle", {
36
+ children: [/* @__PURE__ */ x("circle", {
35
37
  cx: n / 2,
36
38
  cy: n / 2,
37
39
  r: l,
38
40
  fill: "none",
39
41
  stroke: a,
40
42
  strokeWidth: r
41
- }), /* @__PURE__ */ b("circle", {
43
+ }), /* @__PURE__ */ x("circle", {
42
44
  cx: n / 2,
43
45
  cy: n / 2,
44
46
  r: l,
@@ -50,83 +52,86 @@ var S = ({ value: t, color: n = "var(--color-action-primary-bg)", height: r = 8,
50
52
  strokeDashoffset: d,
51
53
  className: "transition-[stroke-dashoffset] duration-700 ease-out"
52
54
  })]
53
- }), o != null && /* @__PURE__ */ b("div", {
55
+ }), o != null && /* @__PURE__ */ x("div", {
54
56
  className: "absolute inset-0 flex flex-col items-center justify-center",
55
57
  children: o
56
58
  })]
57
59
  });
58
- }, w = {
60
+ }, T = {
59
61
  protein: "var(--color-action-primary-bg)",
60
62
  carbs: "var(--color-status-warning-text)",
61
63
  fat: "var(--color-accent-primary)"
62
- }, T = ({ proteinG: t, carbsG: n, fatG: r, height: i = 8, className: a }) => {
64
+ }, E = ({ proteinG: t, carbsG: n, fatG: r, height: i = 8, className: a }) => {
63
65
  let o = Math.max(1, t + n + r), s = (e) => `${e / o * 100}%`;
64
- return /* @__PURE__ */ x("div", {
66
+ return /* @__PURE__ */ S("div", {
65
67
  className: e("flex w-full overflow-hidden rounded-full bg-bg-sunken", a),
66
68
  style: { height: i },
67
69
  children: [
68
- /* @__PURE__ */ b("div", { style: {
70
+ /* @__PURE__ */ x("div", { style: {
69
71
  width: s(t),
70
- backgroundColor: w.protein
72
+ backgroundColor: T.protein
71
73
  } }),
72
- /* @__PURE__ */ b("div", { style: {
74
+ /* @__PURE__ */ x("div", { style: {
73
75
  width: s(n),
74
- backgroundColor: w.carbs
76
+ backgroundColor: T.carbs
75
77
  } }),
76
- /* @__PURE__ */ b("div", { style: {
78
+ /* @__PURE__ */ x("div", { style: {
77
79
  width: s(r),
78
- backgroundColor: w.fat
80
+ backgroundColor: T.fat
79
81
  } })
80
82
  ]
81
83
  });
82
- }, E = ({ className: t }) => /* @__PURE__ */ b("div", {
83
- className: e("flex flex-wrap items-center gap-3 text-xs text-text-tertiary", t),
84
- children: [
85
- "protein",
86
- "carbs",
87
- "fat"
88
- ].map((e) => /* @__PURE__ */ x("span", {
89
- className: "inline-flex items-center gap-1.5",
90
- children: [/* @__PURE__ */ b("span", {
91
- className: "size-2 rounded-full",
92
- style: { backgroundColor: w[e] }
93
- }), /* @__PURE__ */ b("span", {
94
- className: "capitalize",
95
- children: e
96
- })]
97
- }, e))
98
- });
99
- function D(e, t) {
84
+ }, D = ({ className: n }) => {
85
+ let r = t();
86
+ return /* @__PURE__ */ x("div", {
87
+ className: e("flex flex-wrap items-center gap-3 text-xs text-text-tertiary", n),
88
+ children: [
89
+ "protein",
90
+ "carbs",
91
+ "fat"
92
+ ].map((e) => /* @__PURE__ */ S("span", {
93
+ className: "inline-flex items-center gap-1.5",
94
+ children: [/* @__PURE__ */ x("span", {
95
+ className: "size-2 rounded-full",
96
+ style: { backgroundColor: T[e] }
97
+ }), /* @__PURE__ */ x("span", {
98
+ className: "capitalize",
99
+ children: r(`mybodyshield.common.${e}`, e === "protein" ? "Protein" : e === "carbs" ? "Carbs" : "Fat")
100
+ })]
101
+ }, e))
102
+ });
103
+ };
104
+ function O(e, t) {
100
105
  return new Proxy(e, { get(e, n) {
101
106
  return e[n] ?? e[t];
102
107
  } });
103
108
  }
104
- var O = D({
109
+ var k = O({
105
110
  STRENGTH: {
106
- icon: i,
111
+ icon: a,
107
112
  tint: "var(--color-accent-primary)"
108
113
  },
109
114
  CARDIO: {
110
- icon: c,
115
+ icon: l,
111
116
  tint: "var(--color-status-warning-text)"
112
117
  },
113
118
  HIIT: {
114
- icon: y,
119
+ icon: b,
115
120
  tint: "var(--color-status-error-text)"
116
121
  },
117
122
  MOBILITY: {
118
- icon: m,
123
+ icon: h,
119
124
  tint: "var(--color-action-primary-bg)"
120
125
  },
121
126
  YOGA: {
122
- icon: a,
127
+ icon: o,
123
128
  tint: "var(--color-action-primary-bg)"
124
129
  },
125
130
  RECOVERY: {
126
- icon: l,
131
+ icon: u,
127
132
  tint: "var(--color-status-success-text)"
128
133
  }
129
- }, "STRENGTH"), k = D({
134
+ }, "STRENGTH"), A = O({
130
135
  CHEST: { tint: "var(--color-accent-primary)" },
131
136
  BACK: { tint: "var(--color-action-primary-bg)" },
132
137
  LEGS: { tint: "var(--color-status-warning-text)" },
@@ -134,128 +139,133 @@ var O = D({
134
139
  ARMS: { tint: "var(--color-accent-primary)" },
135
140
  CORE: { tint: "var(--color-status-success-text)" },
136
141
  FULL_BODY: { tint: "var(--color-text-secondary)" }
137
- }, "FULL_BODY"), A = D({
142
+ }, "FULL_BODY"), j = O({
138
143
  WEIGHT_LOSS: {
139
- icon: h,
144
+ icon: g,
140
145
  tint: "var(--color-action-primary-bg)"
141
146
  },
142
147
  MUSCLE_GAIN: {
143
- icon: i,
148
+ icon: a,
144
149
  tint: "var(--color-accent-primary)"
145
150
  },
146
151
  STRENGTH: {
147
- icon: v,
152
+ icon: y,
148
153
  tint: "var(--color-status-error-text)"
149
154
  },
150
155
  ENDURANCE: {
151
- icon: t,
156
+ icon: n,
152
157
  tint: "var(--color-status-warning-text)"
153
158
  },
154
159
  MOBILITY: {
155
- icon: m,
160
+ icon: h,
156
161
  tint: "var(--color-action-primary-bg)"
157
162
  },
158
163
  GENERAL_FITNESS: {
159
- icon: p,
164
+ icon: m,
160
165
  tint: "var(--color-text-secondary)"
161
166
  }
162
- }, "GENERAL_FITNESS"), j = D({
167
+ }, "GENERAL_FITNESS"), M = O({
163
168
  WEIGHT: {
164
- icon: v,
169
+ icon: y,
165
170
  tint: "var(--color-accent-primary)",
166
171
  unit: "kg"
167
172
  },
168
173
  BODY_FAT: {
169
- icon: u,
174
+ icon: d,
170
175
  tint: "var(--color-status-warning-text)",
171
176
  unit: "%"
172
177
  },
173
178
  RESTING_HEART_RATE: {
174
- icon: s,
179
+ icon: c,
175
180
  tint: "var(--color-status-error-text)",
176
181
  unit: "bpm"
177
182
  },
178
183
  WAIST: {
179
- icon: d,
184
+ icon: f,
180
185
  tint: "var(--color-action-primary-bg)",
181
186
  unit: "cm"
182
187
  },
183
188
  CHEST: {
184
- icon: d,
189
+ icon: f,
185
190
  tint: "var(--color-action-primary-bg)",
186
191
  unit: "cm"
187
192
  },
188
193
  HIPS: {
189
- icon: d,
194
+ icon: f,
190
195
  tint: "var(--color-action-primary-bg)",
191
196
  unit: "cm"
192
197
  },
193
198
  ARM: {
194
- icon: d,
199
+ icon: f,
195
200
  tint: "var(--color-action-primary-bg)",
196
201
  unit: "cm"
197
202
  },
198
203
  THIGH: {
199
- icon: d,
204
+ icon: f,
200
205
  tint: "var(--color-action-primary-bg)",
201
206
  unit: "cm"
202
207
  }
203
- }, "WEIGHT"), M = D({
208
+ }, "WEIGHT"), N = O({
204
209
  SLEEP: {
205
- icon: n,
210
+ icon: r,
206
211
  tint: "var(--color-accent-primary)",
207
- label: "Sleep"
212
+ labelKey: "mybodyshield.pages.recovery.metricNames.sleep",
213
+ labelFallback: "Sleep"
208
214
  },
209
215
  READINESS: {
210
- icon: o,
216
+ icon: s,
211
217
  tint: "var(--color-status-success-text)",
212
- label: "Readiness"
218
+ labelKey: "mybodyshield.pages.recovery.metricNames.readiness",
219
+ labelFallback: "Readiness"
213
220
  },
214
221
  SORENESS: {
215
- icon: _,
222
+ icon: v,
216
223
  tint: "var(--color-status-warning-text)",
217
- label: "Soreness"
224
+ labelKey: "mybodyshield.pages.recovery.metricNames.soreness",
225
+ labelFallback: "Soreness"
218
226
  },
219
227
  STRESS: {
220
- icon: r,
228
+ icon: i,
221
229
  tint: "var(--color-status-error-text)",
222
- label: "Stress"
230
+ labelKey: "mybodyshield.pages.recovery.metricNames.stress",
231
+ labelFallback: "Stress"
223
232
  },
224
233
  MOOD: {
225
- icon: f,
234
+ icon: p,
226
235
  tint: "var(--color-action-primary-bg)",
227
- label: "Mood"
236
+ labelKey: "mybodyshield.pages.recovery.metricNames.mood",
237
+ labelFallback: "Mood"
228
238
  }
229
- }, "READINESS"), N = ({ icon: t, tint: n = "var(--color-action-primary-bg)", className: r }) => /* @__PURE__ */ b("span", {
239
+ }, "READINESS"), P = ({ icon: t, tint: n = "var(--color-action-primary-bg)", className: r }) => /* @__PURE__ */ x("span", {
230
240
  className: e("flex size-9 shrink-0 items-center justify-center rounded-lg", r),
231
241
  style: {
232
242
  backgroundColor: `color-mix(in srgb, ${n} 16%, transparent)`,
233
243
  color: n
234
244
  },
235
245
  children: t
236
- }), P = ({ delta: t, unit: n = "", goodDirection: r = "up" }) => {
237
- if (!Number.isFinite(t) || t === 0) return /* @__PURE__ */ x("span", {
246
+ }), F = ({ delta: t, unit: n = "", goodDirection: r = "up" }) => {
247
+ if (!Number.isFinite(t) || t === 0) return /* @__PURE__ */ S("span", {
238
248
  className: "text-xs text-text-tertiary",
239
249
  children: ["±0", n]
240
250
  });
241
- let i = t > 0, a = r === "up" ? i : !i, o = i ? g : h;
242
- return /* @__PURE__ */ x("span", {
251
+ let i = t > 0, a = r === "up" ? i : !i, o = i ? _ : g;
252
+ return /* @__PURE__ */ S("span", {
243
253
  className: e("inline-flex items-center gap-1 text-xs font-medium tabular-nums", a ? "text-status-success-text" : "text-status-error-text"),
244
254
  children: [
245
- /* @__PURE__ */ b(o, { className: "h-3.5 w-3.5" }),
255
+ /* @__PURE__ */ x(o, { className: "h-3.5 w-3.5" }),
246
256
  i ? "+" : "",
247
257
  t.toFixed(1),
248
258
  n
249
259
  ]
250
260
  });
251
261
  };
252
- function F(e) {
262
+ function I(e) {
253
263
  let t = e.targetValue - e.baselineValue;
254
264
  if (t === 0) return e.currentValue >= e.targetValue ? 100 : 0;
255
265
  let n = (e.currentValue - e.baselineValue) / t * 100;
256
266
  return Math.max(0, Math.min(100, n));
257
267
  }
258
268
  //#endregion
259
- export { A as GOAL_TYPE_META, N as IconChip, w as MACRO_HUE, j as METRIC_META, k as MUSCLE_META, T as MacroBar, E as MacroLegend, S as Meter, C as ProgressRing, M as RECOVERY_META, P as TrendPill, O as WORKOUT_TYPE_META, F as computeGoalProgress };
269
+ export { j as GOAL_TYPE_META, P as IconChip, T as MACRO_HUE, M as METRIC_META, A as MUSCLE_META, E as MacroBar, D as MacroLegend, C as Meter, w as ProgressRing, N as RECOVERY_META, F as TrendPill, k as WORKOUT_TYPE_META, I as computeGoalProgress };
260
270
 
261
271
  //# sourceMappingURL=visuals.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"visuals.js","names":[],"sources":["../../../../src/mybodyshield/pages/_shared/visuals.tsx"],"sourcesContent":["/**\n * Shared fitness-domain visual helpers.\n * @module mybodyshield/pages/_shared\n *\n * Token-driven (no raw colors) SVG/CSS visual primitives + domain icon/tint\n * maps reused across the MyBodyShield pages. Everything reads fe-libs semantic\n * tokens so light/dark themes and custom themes work automatically.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport {\n Dumbbell,\n HeartPulse,\n Timer,\n Activity,\n StretchHorizontal,\n Flower2,\n Moon,\n Weight,\n Ruler,\n Percent,\n Heart,\n TrendingDown,\n TrendingUp,\n Zap,\n Waves,\n Target,\n Sparkles,\n Brain,\n BedDouble,\n Gauge,\n Smile,\n} from 'lucide-react';\nimport { cn } from '../../utils/cn';\nimport type {\n MybBodyMetricType,\n MybGoalType,\n MybMuscleGroup,\n MybRecoveryMetric,\n MybWorkoutType,\n} from '../../types';\n\n// ============================================================================\n// Meter — a horizontal progress bar with a token-driven fill\n// ============================================================================\n\nexport const Meter: FC<{\n /** 0–100 percentage. */\n value: number;\n /** CSS color for the fill (default: brand emerald). */\n color?: string;\n height?: number;\n className?: string;\n}> = ({ value, color = 'var(--color-action-primary-bg)', height = 8, className }) => {\n const pct = Math.max(0, Math.min(100, value));\n return (\n <div\n className={cn('w-full overflow-hidden rounded-full bg-bg-sunken', className)}\n style={{ height }}\n role=\"progressbar\"\n aria-valuenow={Math.round(pct)}\n aria-valuemin={0}\n aria-valuemax={100}\n >\n <div\n className=\"h-full rounded-full transition-[width] duration-500 ease-out\"\n style={{ width: `${pct}%`, backgroundColor: color }}\n />\n </div>\n );\n};\n\n// ============================================================================\n// ProgressRing — a circular progress indicator (goal progress, readiness)\n// ============================================================================\n\nexport const ProgressRing: FC<{\n value: number;\n size?: number;\n stroke?: number;\n color?: string;\n trackColor?: string;\n children?: ReactNode;\n className?: string;\n}> = ({\n value,\n size = 96,\n stroke = 9,\n color = 'var(--color-action-primary-bg)',\n trackColor = 'var(--color-bg-sunken)',\n children,\n className,\n}) => {\n const pct = Math.max(0, Math.min(100, value));\n const r = (size - stroke) / 2;\n const c = 2 * Math.PI * r;\n const offset = c - (pct / 100) * c;\n return (\n <div\n className={cn('relative inline-flex items-center justify-center', className)}\n style={{ width: size, height: size }}\n >\n <svg width={size} height={size} className=\"-rotate-90\">\n <circle\n cx={size / 2}\n cy={size / 2}\n r={r}\n fill=\"none\"\n stroke={trackColor}\n strokeWidth={stroke}\n />\n <circle\n cx={size / 2}\n cy={size / 2}\n r={r}\n fill=\"none\"\n stroke={color}\n strokeWidth={stroke}\n strokeLinecap=\"round\"\n strokeDasharray={c}\n strokeDashoffset={offset}\n className=\"transition-[stroke-dashoffset] duration-700 ease-out\"\n />\n </svg>\n {children != null && (\n <div className=\"absolute inset-0 flex flex-col items-center justify-center\">{children}</div>\n )}\n </div>\n );\n};\n\n// ============================================================================\n// MacroBar — a stacked protein/carbs/fat bar (grams → proportion)\n// ============================================================================\n\nexport const MACRO_HUE = {\n protein: 'var(--color-action-primary-bg)',\n carbs: 'var(--color-status-warning-text)',\n fat: 'var(--color-accent-primary)',\n} as const;\n\nexport const MacroBar: FC<{\n proteinG: number;\n carbsG: number;\n fatG: number;\n height?: number;\n className?: string;\n}> = ({ proteinG, carbsG, fatG, height = 8, className }) => {\n const total = Math.max(1, proteinG + carbsG + fatG);\n const seg = (g: number) => `${(g / total) * 100}%`;\n return (\n <div\n className={cn('flex w-full overflow-hidden rounded-full bg-bg-sunken', className)}\n style={{ height }}\n >\n <div style={{ width: seg(proteinG), backgroundColor: MACRO_HUE.protein }} />\n <div style={{ width: seg(carbsG), backgroundColor: MACRO_HUE.carbs }} />\n <div style={{ width: seg(fatG), backgroundColor: MACRO_HUE.fat }} />\n </div>\n );\n};\n\nexport const MacroLegend: FC<{ className?: string }> = ({ className }) => (\n <div className={cn('flex flex-wrap items-center gap-3 text-xs text-text-tertiary', className)}>\n {(['protein', 'carbs', 'fat'] as const).map((k) => (\n <span key={k} className=\"inline-flex items-center gap-1.5\">\n <span className=\"size-2 rounded-full\" style={{ backgroundColor: MACRO_HUE[k] }} />\n <span className=\"capitalize\">{k}</span>\n </span>\n ))}\n </div>\n);\n\n// ============================================================================\n// Domain icon + tint maps (semantic tokens only)\n// ============================================================================\n\n/**\n * Wrap an enum→meta map so an unknown server enum value (svc stores enums as\n * TEXT, so a value outside the client union is plausible) resolves to a safe\n * fallback entry instead of `undefined` — accessing `.icon`/`.tint`/`.label` on\n * `undefined` would otherwise crash the whole page.\n */\nfunction metaWithFallback<K extends string, V>(\n source: Record<K, V>,\n fallback: NoInfer<K>\n): Record<K, V> {\n return new Proxy(source, {\n get(target, prop: string) {\n return (target as Record<string, V>)[prop] ?? target[fallback];\n },\n }) as Record<K, V>;\n}\n\nconst WORKOUT_TYPE_META_SOURCE: Record<MybWorkoutType, { icon: typeof Dumbbell; tint: string }> = {\n STRENGTH: { icon: Dumbbell, tint: 'var(--color-accent-primary)' },\n CARDIO: { icon: HeartPulse, tint: 'var(--color-status-warning-text)' },\n HIIT: { icon: Zap, tint: 'var(--color-status-error-text)' },\n MOBILITY: { icon: StretchHorizontal, tint: 'var(--color-action-primary-bg)' },\n YOGA: { icon: Flower2, tint: 'var(--color-action-primary-bg)' },\n RECOVERY: { icon: Moon, tint: 'var(--color-status-success-text)' },\n};\nexport const WORKOUT_TYPE_META = metaWithFallback(WORKOUT_TYPE_META_SOURCE, 'STRENGTH');\n\nconst MUSCLE_META_SOURCE: Record<MybMuscleGroup, { tint: string }> = {\n CHEST: { tint: 'var(--color-accent-primary)' },\n BACK: { tint: 'var(--color-action-primary-bg)' },\n LEGS: { tint: 'var(--color-status-warning-text)' },\n SHOULDERS: { tint: 'var(--color-status-error-text)' },\n ARMS: { tint: 'var(--color-accent-primary)' },\n CORE: { tint: 'var(--color-status-success-text)' },\n FULL_BODY: { tint: 'var(--color-text-secondary)' },\n};\nexport const MUSCLE_META = metaWithFallback(MUSCLE_META_SOURCE, 'FULL_BODY');\n\nconst GOAL_TYPE_META_SOURCE: Record<MybGoalType, { icon: typeof Target; tint: string }> = {\n WEIGHT_LOSS: { icon: TrendingDown, tint: 'var(--color-action-primary-bg)' },\n MUSCLE_GAIN: { icon: Dumbbell, tint: 'var(--color-accent-primary)' },\n STRENGTH: { icon: Weight, tint: 'var(--color-status-error-text)' },\n ENDURANCE: { icon: Activity, tint: 'var(--color-status-warning-text)' },\n MOBILITY: { icon: StretchHorizontal, tint: 'var(--color-action-primary-bg)' },\n GENERAL_FITNESS: { icon: Sparkles, tint: 'var(--color-text-secondary)' },\n};\nexport const GOAL_TYPE_META = metaWithFallback(GOAL_TYPE_META_SOURCE, 'GENERAL_FITNESS');\n\nconst METRIC_META_SOURCE: Record<\n MybBodyMetricType,\n { icon: typeof Weight; tint: string; unit: string }\n> = {\n WEIGHT: { icon: Weight, tint: 'var(--color-accent-primary)', unit: 'kg' },\n BODY_FAT: { icon: Percent, tint: 'var(--color-status-warning-text)', unit: '%' },\n RESTING_HEART_RATE: { icon: Heart, tint: 'var(--color-status-error-text)', unit: 'bpm' },\n WAIST: { icon: Ruler, tint: 'var(--color-action-primary-bg)', unit: 'cm' },\n CHEST: { icon: Ruler, tint: 'var(--color-action-primary-bg)', unit: 'cm' },\n HIPS: { icon: Ruler, tint: 'var(--color-action-primary-bg)', unit: 'cm' },\n ARM: { icon: Ruler, tint: 'var(--color-action-primary-bg)', unit: 'cm' },\n THIGH: { icon: Ruler, tint: 'var(--color-action-primary-bg)', unit: 'cm' },\n};\nexport const METRIC_META = metaWithFallback(METRIC_META_SOURCE, 'WEIGHT');\n\nconst RECOVERY_META_SOURCE: Record<\n MybRecoveryMetric,\n { icon: typeof Gauge; tint: string; label: string }\n> = {\n SLEEP: { icon: BedDouble, tint: 'var(--color-accent-primary)', label: 'Sleep' },\n READINESS: { icon: Gauge, tint: 'var(--color-status-success-text)', label: 'Readiness' },\n SORENESS: { icon: Waves, tint: 'var(--color-status-warning-text)', label: 'Soreness' },\n STRESS: { icon: Brain, tint: 'var(--color-status-error-text)', label: 'Stress' },\n MOOD: { icon: Smile, tint: 'var(--color-action-primary-bg)', label: 'Mood' },\n};\nexport const RECOVERY_META = metaWithFallback(RECOVERY_META_SOURCE, 'READINESS');\n\n// ============================================================================\n// Small helpers\n// ============================================================================\n\n/** Circular icon chip with a soft tinted background. */\nexport const IconChip: FC<{ icon: ReactNode; tint?: string; className?: string }> = ({\n icon,\n tint = 'var(--color-action-primary-bg)',\n className,\n}) => (\n <span\n className={cn('flex size-9 shrink-0 items-center justify-center rounded-lg', className)}\n style={{ backgroundColor: `color-mix(in srgb, ${tint} 16%, transparent)`, color: tint }}\n >\n {icon}\n </span>\n);\n\n/** A small trend delta pill (up/down/flat) with semantic color. */\nexport const TrendPill: FC<{ delta: number; unit?: string; goodDirection?: 'up' | 'down' }> = ({\n delta,\n unit = '',\n goodDirection = 'up',\n}) => {\n if (!Number.isFinite(delta) || delta === 0) {\n return <span className=\"text-xs text-text-tertiary\">±0{unit}</span>;\n }\n const up = delta > 0;\n const good = goodDirection === 'up' ? up : !up;\n const Icon = up ? TrendingUp : TrendingDown;\n return (\n <span\n className={cn(\n 'inline-flex items-center gap-1 text-xs font-medium tabular-nums',\n good ? 'text-status-success-text' : 'text-status-error-text'\n )}\n >\n <Icon className=\"h-3.5 w-3.5\" />\n {up ? '+' : ''}\n {delta.toFixed(1)}\n {unit}\n </span>\n );\n};\n\n/** Compute a goal's completion percentage from baseline → target → current. */\nexport function computeGoalProgress(goal: {\n baselineValue: number;\n targetValue: number;\n currentValue: number;\n}): number {\n const span = goal.targetValue - goal.baselineValue;\n if (span === 0) return goal.currentValue >= goal.targetValue ? 100 : 0;\n const done = ((goal.currentValue - goal.baselineValue) / span) * 100;\n return Math.max(0, Math.min(100, done));\n}\n\nexport { Timer };\n"],"mappings":"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"}
1
+ {"version":3,"file":"visuals.js","names":[],"sources":["../../../../src/mybodyshield/pages/_shared/visuals.tsx"],"sourcesContent":["/**\n * Shared fitness-domain visual helpers.\n * @module mybodyshield/pages/_shared\n *\n * Token-driven (no raw colors) SVG/CSS visual primitives + domain icon/tint\n * maps reused across the MyBodyShield pages. Everything reads fe-libs semantic\n * tokens so light/dark themes and custom themes work automatically.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport {\n Dumbbell,\n HeartPulse,\n Timer,\n Activity,\n StretchHorizontal,\n Flower2,\n Moon,\n Weight,\n Ruler,\n Percent,\n Heart,\n TrendingDown,\n TrendingUp,\n Zap,\n Waves,\n Target,\n Sparkles,\n Brain,\n BedDouble,\n Gauge,\n Smile,\n} from 'lucide-react';\nimport { cn } from '../../utils/cn';\nimport { useTr } from '../../hooks';\nimport type {\n MybBodyMetricType,\n MybGoalType,\n MybMuscleGroup,\n MybRecoveryMetric,\n MybWorkoutType,\n} from '../../types';\n\n// ============================================================================\n// Meter — a horizontal progress bar with a token-driven fill\n// ============================================================================\n\nexport const Meter: FC<{\n /** 0–100 percentage. */\n value: number;\n /** CSS color for the fill (default: brand emerald). */\n color?: string;\n height?: number;\n className?: string;\n}> = ({ value, color = 'var(--color-action-primary-bg)', height = 8, className }) => {\n const pct = Math.max(0, Math.min(100, value));\n return (\n <div\n className={cn('w-full overflow-hidden rounded-full bg-bg-sunken', className)}\n style={{ height }}\n role=\"progressbar\"\n aria-valuenow={Math.round(pct)}\n aria-valuemin={0}\n aria-valuemax={100}\n >\n <div\n className=\"h-full rounded-full transition-[width] duration-500 ease-out\"\n style={{ width: `${pct}%`, backgroundColor: color }}\n />\n </div>\n );\n};\n\n// ============================================================================\n// ProgressRing — a circular progress indicator (goal progress, readiness)\n// ============================================================================\n\nexport const ProgressRing: FC<{\n value: number;\n size?: number;\n stroke?: number;\n color?: string;\n trackColor?: string;\n children?: ReactNode;\n className?: string;\n}> = ({\n value,\n size = 96,\n stroke = 9,\n color = 'var(--color-action-primary-bg)',\n trackColor = 'var(--color-bg-sunken)',\n children,\n className,\n}) => {\n const pct = Math.max(0, Math.min(100, value));\n const r = (size - stroke) / 2;\n const c = 2 * Math.PI * r;\n const offset = c - (pct / 100) * c;\n return (\n <div\n className={cn('relative inline-flex items-center justify-center', className)}\n style={{ width: size, height: size }}\n >\n <svg width={size} height={size} className=\"-rotate-90\">\n <circle\n cx={size / 2}\n cy={size / 2}\n r={r}\n fill=\"none\"\n stroke={trackColor}\n strokeWidth={stroke}\n />\n <circle\n cx={size / 2}\n cy={size / 2}\n r={r}\n fill=\"none\"\n stroke={color}\n strokeWidth={stroke}\n strokeLinecap=\"round\"\n strokeDasharray={c}\n strokeDashoffset={offset}\n className=\"transition-[stroke-dashoffset] duration-700 ease-out\"\n />\n </svg>\n {children != null && (\n <div className=\"absolute inset-0 flex flex-col items-center justify-center\">{children}</div>\n )}\n </div>\n );\n};\n\n// ============================================================================\n// MacroBar — a stacked protein/carbs/fat bar (grams → proportion)\n// ============================================================================\n\nexport const MACRO_HUE = {\n protein: 'var(--color-action-primary-bg)',\n carbs: 'var(--color-status-warning-text)',\n fat: 'var(--color-accent-primary)',\n} as const;\n\nexport const MacroBar: FC<{\n proteinG: number;\n carbsG: number;\n fatG: number;\n height?: number;\n className?: string;\n}> = ({ proteinG, carbsG, fatG, height = 8, className }) => {\n const total = Math.max(1, proteinG + carbsG + fatG);\n const seg = (g: number) => `${(g / total) * 100}%`;\n return (\n <div\n className={cn('flex w-full overflow-hidden rounded-full bg-bg-sunken', className)}\n style={{ height }}\n >\n <div style={{ width: seg(proteinG), backgroundColor: MACRO_HUE.protein }} />\n <div style={{ width: seg(carbsG), backgroundColor: MACRO_HUE.carbs }} />\n <div style={{ width: seg(fatG), backgroundColor: MACRO_HUE.fat }} />\n </div>\n );\n};\n\nexport const MacroLegend: FC<{ className?: string }> = ({ className }) => {\n const t = useTr();\n return (\n <div className={cn('flex flex-wrap items-center gap-3 text-xs text-text-tertiary', className)}>\n {(['protein', 'carbs', 'fat'] as const).map((k) => (\n <span key={k} className=\"inline-flex items-center gap-1.5\">\n <span className=\"size-2 rounded-full\" style={{ backgroundColor: MACRO_HUE[k] }} />\n <span className=\"capitalize\">\n {t(\n `mybodyshield.common.${k}`,\n k === 'protein' ? 'Protein' : k === 'carbs' ? 'Carbs' : 'Fat'\n )}\n </span>\n </span>\n ))}\n </div>\n );\n};\n\n// ============================================================================\n// Domain icon + tint maps (semantic tokens only)\n// ============================================================================\n\n/**\n * Wrap an enum→meta map so an unknown server enum value (svc stores enums as\n * TEXT, so a value outside the client union is plausible) resolves to a safe\n * fallback entry instead of `undefined` — accessing `.icon`/`.tint`/`.label` on\n * `undefined` would otherwise crash the whole page.\n */\nfunction metaWithFallback<K extends string, V>(\n source: Record<K, V>,\n fallback: NoInfer<K>\n): Record<K, V> {\n return new Proxy(source, {\n get(target, prop: string) {\n return (target as Record<string, V>)[prop] ?? target[fallback];\n },\n }) as Record<K, V>;\n}\n\nconst WORKOUT_TYPE_META_SOURCE: Record<MybWorkoutType, { icon: typeof Dumbbell; tint: string }> = {\n STRENGTH: { icon: Dumbbell, tint: 'var(--color-accent-primary)' },\n CARDIO: { icon: HeartPulse, tint: 'var(--color-status-warning-text)' },\n HIIT: { icon: Zap, tint: 'var(--color-status-error-text)' },\n MOBILITY: { icon: StretchHorizontal, tint: 'var(--color-action-primary-bg)' },\n YOGA: { icon: Flower2, tint: 'var(--color-action-primary-bg)' },\n RECOVERY: { icon: Moon, tint: 'var(--color-status-success-text)' },\n};\nexport const WORKOUT_TYPE_META = metaWithFallback(WORKOUT_TYPE_META_SOURCE, 'STRENGTH');\n\nconst MUSCLE_META_SOURCE: Record<MybMuscleGroup, { tint: string }> = {\n CHEST: { tint: 'var(--color-accent-primary)' },\n BACK: { tint: 'var(--color-action-primary-bg)' },\n LEGS: { tint: 'var(--color-status-warning-text)' },\n SHOULDERS: { tint: 'var(--color-status-error-text)' },\n ARMS: { tint: 'var(--color-accent-primary)' },\n CORE: { tint: 'var(--color-status-success-text)' },\n FULL_BODY: { tint: 'var(--color-text-secondary)' },\n};\nexport const MUSCLE_META = metaWithFallback(MUSCLE_META_SOURCE, 'FULL_BODY');\n\nconst GOAL_TYPE_META_SOURCE: Record<MybGoalType, { icon: typeof Target; tint: string }> = {\n WEIGHT_LOSS: { icon: TrendingDown, tint: 'var(--color-action-primary-bg)' },\n MUSCLE_GAIN: { icon: Dumbbell, tint: 'var(--color-accent-primary)' },\n STRENGTH: { icon: Weight, tint: 'var(--color-status-error-text)' },\n ENDURANCE: { icon: Activity, tint: 'var(--color-status-warning-text)' },\n MOBILITY: { icon: StretchHorizontal, tint: 'var(--color-action-primary-bg)' },\n GENERAL_FITNESS: { icon: Sparkles, tint: 'var(--color-text-secondary)' },\n};\nexport const GOAL_TYPE_META = metaWithFallback(GOAL_TYPE_META_SOURCE, 'GENERAL_FITNESS');\n\nconst METRIC_META_SOURCE: Record<\n MybBodyMetricType,\n { icon: typeof Weight; tint: string; unit: string }\n> = {\n WEIGHT: { icon: Weight, tint: 'var(--color-accent-primary)', unit: 'kg' },\n BODY_FAT: { icon: Percent, tint: 'var(--color-status-warning-text)', unit: '%' },\n RESTING_HEART_RATE: { icon: Heart, tint: 'var(--color-status-error-text)', unit: 'bpm' },\n WAIST: { icon: Ruler, tint: 'var(--color-action-primary-bg)', unit: 'cm' },\n CHEST: { icon: Ruler, tint: 'var(--color-action-primary-bg)', unit: 'cm' },\n HIPS: { icon: Ruler, tint: 'var(--color-action-primary-bg)', unit: 'cm' },\n ARM: { icon: Ruler, tint: 'var(--color-action-primary-bg)', unit: 'cm' },\n THIGH: { icon: Ruler, tint: 'var(--color-action-primary-bg)', unit: 'cm' },\n};\nexport const METRIC_META = metaWithFallback(METRIC_META_SOURCE, 'WEIGHT');\n\nconst RECOVERY_META_SOURCE: Record<\n MybRecoveryMetric,\n { icon: typeof Gauge; tint: string; labelKey: string; labelFallback: string }\n> = {\n SLEEP: {\n icon: BedDouble,\n tint: 'var(--color-accent-primary)',\n labelKey: 'mybodyshield.pages.recovery.metricNames.sleep',\n labelFallback: 'Sleep',\n },\n READINESS: {\n icon: Gauge,\n tint: 'var(--color-status-success-text)',\n labelKey: 'mybodyshield.pages.recovery.metricNames.readiness',\n labelFallback: 'Readiness',\n },\n SORENESS: {\n icon: Waves,\n tint: 'var(--color-status-warning-text)',\n labelKey: 'mybodyshield.pages.recovery.metricNames.soreness',\n labelFallback: 'Soreness',\n },\n STRESS: {\n icon: Brain,\n tint: 'var(--color-status-error-text)',\n labelKey: 'mybodyshield.pages.recovery.metricNames.stress',\n labelFallback: 'Stress',\n },\n MOOD: {\n icon: Smile,\n tint: 'var(--color-action-primary-bg)',\n labelKey: 'mybodyshield.pages.recovery.metricNames.mood',\n labelFallback: 'Mood',\n },\n};\nexport const RECOVERY_META = metaWithFallback(RECOVERY_META_SOURCE, 'READINESS');\n\n// ============================================================================\n// Small helpers\n// ============================================================================\n\n/** Circular icon chip with a soft tinted background. */\nexport const IconChip: FC<{ icon: ReactNode; tint?: string; className?: string }> = ({\n icon,\n tint = 'var(--color-action-primary-bg)',\n className,\n}) => (\n <span\n className={cn('flex size-9 shrink-0 items-center justify-center rounded-lg', className)}\n style={{ backgroundColor: `color-mix(in srgb, ${tint} 16%, transparent)`, color: tint }}\n >\n {icon}\n </span>\n);\n\n/** A small trend delta pill (up/down/flat) with semantic color. */\nexport const TrendPill: FC<{ delta: number; unit?: string; goodDirection?: 'up' | 'down' }> = ({\n delta,\n unit = '',\n goodDirection = 'up',\n}) => {\n if (!Number.isFinite(delta) || delta === 0) {\n return <span className=\"text-xs text-text-tertiary\">±0{unit}</span>;\n }\n const up = delta > 0;\n const good = goodDirection === 'up' ? up : !up;\n const Icon = up ? TrendingUp : TrendingDown;\n return (\n <span\n className={cn(\n 'inline-flex items-center gap-1 text-xs font-medium tabular-nums',\n good ? 'text-status-success-text' : 'text-status-error-text'\n )}\n >\n <Icon className=\"h-3.5 w-3.5\" />\n {up ? '+' : ''}\n {delta.toFixed(1)}\n {unit}\n </span>\n );\n};\n\n/** Compute a goal's completion percentage from baseline → target → current. */\nexport function computeGoalProgress(goal: {\n baselineValue: number;\n targetValue: number;\n currentValue: number;\n}): number {\n const span = goal.targetValue - goal.baselineValue;\n if (span === 0) return goal.currentValue >= goal.targetValue ? 100 : 0;\n const done = ((goal.currentValue - goal.baselineValue) / span) * 100;\n return Math.max(0, Math.min(100, done));\n}\n\nexport { Timer };\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"AiControlsPage.d.ts","sourceRoot":"","sources":["../../../../src/mybodyshield/pages/ai/AiControlsPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAgcH,wBAAgB,cAAc,gCA2C7B"}
1
+ {"version":3,"file":"AiControlsPage.d.ts","sourceRoot":"","sources":["../../../../src/mybodyshield/pages/ai/AiControlsPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AA0hBH,wBAAgB,cAAc,gCAoD7B"}