@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.
- package/dist/mybodyshield/MyBodyShieldRoot.d.ts.map +1 -1
- package/dist/mybodyshield/MyBodyShieldRoot.js +54 -56
- package/dist/mybodyshield/MyBodyShieldRoot.js.map +1 -1
- package/dist/mybodyshield/MyBodyShieldRoutes.d.ts.map +1 -1
- package/dist/mybodyshield/MyBodyShieldRoutes.js +121 -62
- package/dist/mybodyshield/MyBodyShieldRoutes.js.map +1 -1
- package/dist/mybodyshield/components/EvidenceUpload.d.ts.map +1 -1
- package/dist/mybodyshield/components/EvidenceUpload.js +46 -45
- package/dist/mybodyshield/components/EvidenceUpload.js.map +1 -1
- package/dist/mybodyshield/components/FileLink.d.ts.map +1 -1
- package/dist/mybodyshield/components/FileLink.js +27 -18
- package/dist/mybodyshield/components/FileLink.js.map +1 -1
- package/dist/mybodyshield/components/MybDiscussion.d.ts +1 -1
- package/dist/mybodyshield/components/MybDiscussion.d.ts.map +1 -1
- package/dist/mybodyshield/components/MybDiscussion.js +59 -58
- package/dist/mybodyshield/components/MybDiscussion.js.map +1 -1
- package/dist/mybodyshield/components/MybTags.d.ts +1 -1
- package/dist/mybodyshield/components/MybTags.d.ts.map +1 -1
- package/dist/mybodyshield/components/MybTags.js +83 -74
- package/dist/mybodyshield/components/MybTags.js.map +1 -1
- package/dist/mybodyshield/components/PageDisabled.d.ts.map +1 -1
- package/dist/mybodyshield/components/PageDisabled.js +16 -11
- package/dist/mybodyshield/components/PageDisabled.js.map +1 -1
- package/dist/mybodyshield/components/Pagination.d.ts.map +1 -1
- package/dist/mybodyshield/components/Pagination.js +36 -27
- package/dist/mybodyshield/components/Pagination.js.map +1 -1
- package/dist/mybodyshield/components/StateViews.d.ts.map +1 -1
- package/dist/mybodyshield/components/StateViews.js +42 -34
- package/dist/mybodyshield/components/StateViews.js.map +1 -1
- package/dist/mybodyshield/components/UserSearchSelect.d.ts.map +1 -1
- package/dist/mybodyshield/components/UserSearchSelect.js +66 -68
- package/dist/mybodyshield/components/UserSearchSelect.js.map +1 -1
- package/dist/mybodyshield/hooks/index.d.ts +1 -0
- package/dist/mybodyshield/hooks/index.d.ts.map +1 -1
- package/dist/mybodyshield/hooks/index.js +1 -0
- package/dist/mybodyshield/hooks/useTr.d.ts +5 -0
- package/dist/mybodyshield/hooks/useTr.d.ts.map +1 -0
- package/dist/mybodyshield/hooks/useTr.js +12 -0
- package/dist/mybodyshield/hooks/useTr.js.map +1 -0
- package/dist/mybodyshield/pages/DashboardPage.d.ts.map +1 -1
- package/dist/mybodyshield/pages/DashboardPage.js +157 -136
- package/dist/mybodyshield/pages/DashboardPage.js.map +1 -1
- package/dist/mybodyshield/pages/SettingsPage.d.ts.map +1 -1
- package/dist/mybodyshield/pages/SettingsPage.js +50 -59
- package/dist/mybodyshield/pages/SettingsPage.js.map +1 -1
- package/dist/mybodyshield/pages/_shared/visuals.d.ts +2 -1
- package/dist/mybodyshield/pages/_shared/visuals.d.ts.map +1 -1
- package/dist/mybodyshield/pages/_shared/visuals.js +91 -81
- package/dist/mybodyshield/pages/_shared/visuals.js.map +1 -1
- package/dist/mybodyshield/pages/ai/AiControlsPage.d.ts.map +1 -1
- package/dist/mybodyshield/pages/ai/AiControlsPage.js +255 -266
- package/dist/mybodyshield/pages/ai/AiControlsPage.js.map +1 -1
- package/dist/mybodyshield/pages/coaching/CoachingPage.d.ts.map +1 -1
- package/dist/mybodyshield/pages/coaching/CoachingPage.js +321 -301
- package/dist/mybodyshield/pages/coaching/CoachingPage.js.map +1 -1
- package/dist/mybodyshield/pages/goals/GoalsPage.d.ts.map +1 -1
- package/dist/mybodyshield/pages/goals/GoalsPage.js +247 -251
- package/dist/mybodyshield/pages/goals/GoalsPage.js.map +1 -1
- package/dist/mybodyshield/pages/insights/InsightsCharts.d.ts.map +1 -1
- package/dist/mybodyshield/pages/insights/InsightsCharts.js +216 -213
- package/dist/mybodyshield/pages/insights/InsightsCharts.js.map +1 -1
- package/dist/mybodyshield/pages/insights/InsightsPage.d.ts.map +1 -1
- package/dist/mybodyshield/pages/insights/InsightsPage.js +290 -284
- package/dist/mybodyshield/pages/insights/InsightsPage.js.map +1 -1
- package/dist/mybodyshield/pages/nutrition/NutritionPage.d.ts.map +1 -1
- package/dist/mybodyshield/pages/nutrition/NutritionPage.js +575 -529
- package/dist/mybodyshield/pages/nutrition/NutritionPage.js.map +1 -1
- package/dist/mybodyshield/pages/programs/ProgramDetailPage.d.ts.map +1 -1
- package/dist/mybodyshield/pages/programs/ProgramDetailPage.js +333 -275
- package/dist/mybodyshield/pages/programs/ProgramDetailPage.js.map +1 -1
- package/dist/mybodyshield/pages/programs/ProgramsPage.d.ts.map +1 -1
- package/dist/mybodyshield/pages/programs/ProgramsPage.js +258 -253
- package/dist/mybodyshield/pages/programs/ProgramsPage.js.map +1 -1
- package/dist/mybodyshield/pages/progress/ProgressPage.d.ts.map +1 -1
- package/dist/mybodyshield/pages/progress/ProgressPage.js +271 -254
- package/dist/mybodyshield/pages/progress/ProgressPage.js.map +1 -1
- package/dist/mybodyshield/pages/recovery/RecoveryPage.d.ts.map +1 -1
- package/dist/mybodyshield/pages/recovery/RecoveryPage.js +206 -200
- package/dist/mybodyshield/pages/recovery/RecoveryPage.js.map +1 -1
- package/dist/mybodyshield/pages/train/SessionDetailPage.d.ts.map +1 -1
- package/dist/mybodyshield/pages/train/SessionDetailPage.js +327 -294
- package/dist/mybodyshield/pages/train/SessionDetailPage.js.map +1 -1
- package/dist/mybodyshield/pages/train/SessionsPage.d.ts.map +1 -1
- package/dist/mybodyshield/pages/train/SessionsPage.js +180 -163
- package/dist/mybodyshield/pages/train/SessionsPage.js.map +1 -1
- package/dist/mybodyshield/utils/i18n.d.ts +1 -2
- package/dist/mybodyshield/utils/i18n.d.ts.map +1 -1
- package/dist/mybodyshield/utils/i18n.js +15 -0
- package/dist/mybodyshield/utils/i18n.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import { cn as e } from "../../utils/cn.js";
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
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
|
|
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__ */
|
|
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__ */
|
|
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
|
-
},
|
|
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__ */
|
|
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__ */
|
|
32
|
+
children: [/* @__PURE__ */ S("svg", {
|
|
31
33
|
width: n,
|
|
32
34
|
height: n,
|
|
33
35
|
className: "-rotate-90",
|
|
34
|
-
children: [/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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__ */
|
|
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__ */
|
|
70
|
+
/* @__PURE__ */ x("div", { style: {
|
|
69
71
|
width: s(t),
|
|
70
|
-
backgroundColor:
|
|
72
|
+
backgroundColor: T.protein
|
|
71
73
|
} }),
|
|
72
|
-
/* @__PURE__ */
|
|
74
|
+
/* @__PURE__ */ x("div", { style: {
|
|
73
75
|
width: s(n),
|
|
74
|
-
backgroundColor:
|
|
76
|
+
backgroundColor: T.carbs
|
|
75
77
|
} }),
|
|
76
|
-
/* @__PURE__ */
|
|
78
|
+
/* @__PURE__ */ x("div", { style: {
|
|
77
79
|
width: s(r),
|
|
78
|
-
backgroundColor:
|
|
80
|
+
backgroundColor: T.fat
|
|
79
81
|
} })
|
|
80
82
|
]
|
|
81
83
|
});
|
|
82
|
-
},
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
"
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
className: "
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
})
|
|
99
|
-
|
|
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
|
|
109
|
+
var k = O({
|
|
105
110
|
STRENGTH: {
|
|
106
|
-
icon:
|
|
111
|
+
icon: a,
|
|
107
112
|
tint: "var(--color-accent-primary)"
|
|
108
113
|
},
|
|
109
114
|
CARDIO: {
|
|
110
|
-
icon:
|
|
115
|
+
icon: l,
|
|
111
116
|
tint: "var(--color-status-warning-text)"
|
|
112
117
|
},
|
|
113
118
|
HIIT: {
|
|
114
|
-
icon:
|
|
119
|
+
icon: b,
|
|
115
120
|
tint: "var(--color-status-error-text)"
|
|
116
121
|
},
|
|
117
122
|
MOBILITY: {
|
|
118
|
-
icon:
|
|
123
|
+
icon: h,
|
|
119
124
|
tint: "var(--color-action-primary-bg)"
|
|
120
125
|
},
|
|
121
126
|
YOGA: {
|
|
122
|
-
icon:
|
|
127
|
+
icon: o,
|
|
123
128
|
tint: "var(--color-action-primary-bg)"
|
|
124
129
|
},
|
|
125
130
|
RECOVERY: {
|
|
126
|
-
icon:
|
|
131
|
+
icon: u,
|
|
127
132
|
tint: "var(--color-status-success-text)"
|
|
128
133
|
}
|
|
129
|
-
}, "STRENGTH"),
|
|
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"),
|
|
142
|
+
}, "FULL_BODY"), j = O({
|
|
138
143
|
WEIGHT_LOSS: {
|
|
139
|
-
icon:
|
|
144
|
+
icon: g,
|
|
140
145
|
tint: "var(--color-action-primary-bg)"
|
|
141
146
|
},
|
|
142
147
|
MUSCLE_GAIN: {
|
|
143
|
-
icon:
|
|
148
|
+
icon: a,
|
|
144
149
|
tint: "var(--color-accent-primary)"
|
|
145
150
|
},
|
|
146
151
|
STRENGTH: {
|
|
147
|
-
icon:
|
|
152
|
+
icon: y,
|
|
148
153
|
tint: "var(--color-status-error-text)"
|
|
149
154
|
},
|
|
150
155
|
ENDURANCE: {
|
|
151
|
-
icon:
|
|
156
|
+
icon: n,
|
|
152
157
|
tint: "var(--color-status-warning-text)"
|
|
153
158
|
},
|
|
154
159
|
MOBILITY: {
|
|
155
|
-
icon:
|
|
160
|
+
icon: h,
|
|
156
161
|
tint: "var(--color-action-primary-bg)"
|
|
157
162
|
},
|
|
158
163
|
GENERAL_FITNESS: {
|
|
159
|
-
icon:
|
|
164
|
+
icon: m,
|
|
160
165
|
tint: "var(--color-text-secondary)"
|
|
161
166
|
}
|
|
162
|
-
}, "GENERAL_FITNESS"),
|
|
167
|
+
}, "GENERAL_FITNESS"), M = O({
|
|
163
168
|
WEIGHT: {
|
|
164
|
-
icon:
|
|
169
|
+
icon: y,
|
|
165
170
|
tint: "var(--color-accent-primary)",
|
|
166
171
|
unit: "kg"
|
|
167
172
|
},
|
|
168
173
|
BODY_FAT: {
|
|
169
|
-
icon:
|
|
174
|
+
icon: d,
|
|
170
175
|
tint: "var(--color-status-warning-text)",
|
|
171
176
|
unit: "%"
|
|
172
177
|
},
|
|
173
178
|
RESTING_HEART_RATE: {
|
|
174
|
-
icon:
|
|
179
|
+
icon: c,
|
|
175
180
|
tint: "var(--color-status-error-text)",
|
|
176
181
|
unit: "bpm"
|
|
177
182
|
},
|
|
178
183
|
WAIST: {
|
|
179
|
-
icon:
|
|
184
|
+
icon: f,
|
|
180
185
|
tint: "var(--color-action-primary-bg)",
|
|
181
186
|
unit: "cm"
|
|
182
187
|
},
|
|
183
188
|
CHEST: {
|
|
184
|
-
icon:
|
|
189
|
+
icon: f,
|
|
185
190
|
tint: "var(--color-action-primary-bg)",
|
|
186
191
|
unit: "cm"
|
|
187
192
|
},
|
|
188
193
|
HIPS: {
|
|
189
|
-
icon:
|
|
194
|
+
icon: f,
|
|
190
195
|
tint: "var(--color-action-primary-bg)",
|
|
191
196
|
unit: "cm"
|
|
192
197
|
},
|
|
193
198
|
ARM: {
|
|
194
|
-
icon:
|
|
199
|
+
icon: f,
|
|
195
200
|
tint: "var(--color-action-primary-bg)",
|
|
196
201
|
unit: "cm"
|
|
197
202
|
},
|
|
198
203
|
THIGH: {
|
|
199
|
-
icon:
|
|
204
|
+
icon: f,
|
|
200
205
|
tint: "var(--color-action-primary-bg)",
|
|
201
206
|
unit: "cm"
|
|
202
207
|
}
|
|
203
|
-
}, "WEIGHT"),
|
|
208
|
+
}, "WEIGHT"), N = O({
|
|
204
209
|
SLEEP: {
|
|
205
|
-
icon:
|
|
210
|
+
icon: r,
|
|
206
211
|
tint: "var(--color-accent-primary)",
|
|
207
|
-
|
|
212
|
+
labelKey: "mybodyshield.pages.recovery.metricNames.sleep",
|
|
213
|
+
labelFallback: "Sleep"
|
|
208
214
|
},
|
|
209
215
|
READINESS: {
|
|
210
|
-
icon:
|
|
216
|
+
icon: s,
|
|
211
217
|
tint: "var(--color-status-success-text)",
|
|
212
|
-
|
|
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
|
-
|
|
224
|
+
labelKey: "mybodyshield.pages.recovery.metricNames.soreness",
|
|
225
|
+
labelFallback: "Soreness"
|
|
218
226
|
},
|
|
219
227
|
STRESS: {
|
|
220
|
-
icon:
|
|
228
|
+
icon: i,
|
|
221
229
|
tint: "var(--color-status-error-text)",
|
|
222
|
-
|
|
230
|
+
labelKey: "mybodyshield.pages.recovery.metricNames.stress",
|
|
231
|
+
labelFallback: "Stress"
|
|
223
232
|
},
|
|
224
233
|
MOOD: {
|
|
225
|
-
icon:
|
|
234
|
+
icon: p,
|
|
226
235
|
tint: "var(--color-action-primary-bg)",
|
|
227
|
-
|
|
236
|
+
labelKey: "mybodyshield.pages.recovery.metricNames.mood",
|
|
237
|
+
labelFallback: "Mood"
|
|
228
238
|
}
|
|
229
|
-
}, "READINESS"),
|
|
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
|
-
}),
|
|
237
|
-
if (!Number.isFinite(t) || t === 0) return /* @__PURE__ */
|
|
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 ?
|
|
242
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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
|
|
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 {
|
|
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;
|
|
1
|
+
{"version":3,"file":"AiControlsPage.d.ts","sourceRoot":"","sources":["../../../../src/mybodyshield/pages/ai/AiControlsPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AA0hBH,wBAAgB,cAAc,gCAoD7B"}
|