@titan-design/react-ui 0.3.0 → 0.5.0
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/MesoStatusCard-CQk71hSi.d.mts +77 -0
- package/dist/MesoStatusCard-CQk71hSi.d.ts +77 -0
- package/dist/bodymap.d.mts +246 -3
- package/dist/bodymap.d.ts +246 -3
- package/dist/bodymap.js +441 -97
- package/dist/bodymap.js.map +1 -1
- package/dist/bodymap.mjs +1958 -66
- package/dist/bodymap.mjs.map +1 -1
- package/dist/index.d.mts +71 -738
- package/dist/index.d.ts +71 -738
- package/dist/index.js +888 -1583
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4515 -2348
- package/dist/index.mjs.map +1 -1
- package/dist/pages-D7Jlssvp.d.ts +791 -0
- package/dist/pages-MO0JCySL.d.mts +791 -0
- package/dist/pages.d.mts +4 -0
- package/dist/pages.d.ts +4 -0
- package/dist/pages.js +6646 -0
- package/dist/pages.js.map +1 -0
- package/dist/pages.mjs +6626 -0
- package/dist/pages.mjs.map +1 -0
- package/dist/theme/index.d.mts +28 -2
- package/dist/theme/index.d.ts +28 -2
- package/dist/theme/index.js +37 -0
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/index.mjs +1880 -2
- package/dist/theme/index.mjs.map +1 -1
- package/dist/theme/tokens-css.mjs +573 -1
- package/dist/theme/tokens-css.mjs.map +1 -1
- package/package.json +9 -7
- package/src/components/custom/Workout/ActiveWorkoutPage.tsx +10 -15
- package/src/components/custom/Workout/BaseBadge.stories.tsx +3 -3
- package/src/components/custom/Workout/BaseBadge.test.tsx +1 -1
- package/src/components/custom/Workout/BaseBadge.tsx +1 -1
- package/src/components/custom/Workout/BodyMap.tsx +7 -8
- package/src/components/custom/Workout/BodyMapDetailPanel.tsx +25 -28
- package/src/components/custom/Workout/CapacityBandChart.tsx +2 -3
- package/src/components/custom/Workout/ExerciseCard.tsx +17 -28
- package/src/components/custom/Workout/ExerciseDetailPage.tsx +38 -31
- package/src/components/custom/Workout/InputBar.tsx +10 -11
- package/src/components/custom/Workout/IntensityBar.test.tsx +112 -60
- package/src/components/custom/Workout/IntensityBar.tsx +109 -58
- package/src/components/custom/Workout/MesoCard.tsx +2 -6
- package/src/components/custom/Workout/MesoStatusCard.tsx +17 -15
- package/src/components/custom/Workout/MuscleGroupChip.tsx +2 -4
- package/src/components/custom/Workout/PlaceholderStrip.tsx +5 -10
- package/src/components/custom/Workout/PrBadge.tsx +3 -3
- package/src/components/custom/Workout/PrHistoryModal.tsx +14 -16
- package/src/components/custom/Workout/ProgramPlanningPage.tsx +8 -12
- package/src/components/custom/Workout/README.md +50 -0
- package/src/components/custom/Workout/ReadinessCheck.tsx +13 -11
- package/src/components/custom/Workout/RestTimer.test.tsx +41 -10
- package/src/components/custom/Workout/RestTimer.tsx +55 -49
- package/src/components/custom/Workout/SetRow.tsx +20 -8
- package/src/components/custom/Workout/StrengthTrendChart.tsx +15 -17
- package/src/components/custom/Workout/TempoBar.stories.tsx +95 -0
- package/src/components/custom/Workout/TempoBar.test.tsx +103 -0
- package/src/components/custom/Workout/TempoBar.tsx +215 -0
- package/src/components/custom/Workout/TempoDisplay.stories.tsx +69 -2
- package/src/components/custom/Workout/TempoDisplay.test.tsx +35 -0
- package/src/components/custom/Workout/TempoDisplay.tsx +104 -1
- package/src/components/custom/Workout/TrainingStatusPage.tsx +8 -17
- package/src/components/custom/Workout/VelocityStrip.test.tsx +89 -2
- package/src/components/custom/Workout/VelocityStrip.tsx +210 -43
- package/src/components/custom/Workout/WeekRow.test.tsx +2 -2
- package/src/components/custom/Workout/WeekRow.tsx +2 -1
- package/src/components/custom/Workout/WeightBadge.test.tsx +2 -2
- package/src/components/custom/Workout/WeightBadge.tsx +2 -2
- package/src/components/custom/Workout/WorkoutCard.tsx +3 -8
- package/src/components/custom/Workout/icons.tsx +68 -0
- package/src/components/custom/Workout/index.ts +47 -47
- package/src/index.ts +3 -2
- package/src/pages.ts +61 -0
- package/src/test/nativewind-stub.ts +13 -0
- package/src/test/stories-smoke.test.tsx +50 -0
- package/src/theme/ThemeProvider.test.tsx +24 -0
- package/src/theme/ThemeProvider.tsx +50 -0
- package/src/theme/barrel.ts +53 -0
- package/src/theme/index.ts +8 -41
- package/src/theme/native-theming-guard.test.ts +117 -0
- package/src/theme/resolve-color.ts +19 -0
- package/dist/bodymap-BhG55xHM.d.mts +0 -318
- package/dist/bodymap-BhG55xHM.d.ts +0 -318
- package/dist/chunk-7XPB4NAO.mjs +0 -1013
- package/dist/chunk-7XPB4NAO.mjs.map +0 -1
- package/dist/chunk-P7TSQUN6.mjs +0 -846
- package/dist/chunk-P7TSQUN6.mjs.map +0 -1
- package/dist/chunk-TOD2WQBG.mjs +0 -1048
- package/dist/chunk-TOD2WQBG.mjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -5,7 +5,6 @@ var clsx = require('clsx');
|
|
|
5
5
|
var tailwindMerge = require('tailwind-merge');
|
|
6
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
7
7
|
var React24 = require('react');
|
|
8
|
-
var lucideReact = require('lucide-react');
|
|
9
8
|
|
|
10
9
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
10
|
|
|
@@ -2160,6 +2159,9 @@ function validateCssPropertyManifest(candidate) {
|
|
|
2160
2159
|
function isCssPropertyManifest(candidate) {
|
|
2161
2160
|
return validateCssPropertyManifest(candidate).valid;
|
|
2162
2161
|
}
|
|
2162
|
+
function resolveColor(token, mode = "dark") {
|
|
2163
|
+
return reactNative.Platform.OS === "web" ? `var(--color-${token})` : getSemanticColors(mode)[token];
|
|
2164
|
+
}
|
|
2163
2165
|
|
|
2164
2166
|
// src/theme/presets/apply.ts
|
|
2165
2167
|
function colorKeyToVar(key) {
|
|
@@ -4985,7 +4987,7 @@ function ToastProvider({
|
|
|
4985
4987
|
return id;
|
|
4986
4988
|
}, [defaultDuration, maxToasts]);
|
|
4987
4989
|
const removeToast = React24.useCallback((id) => {
|
|
4988
|
-
setToasts((prev) => prev.filter((
|
|
4990
|
+
setToasts((prev) => prev.filter((t2) => t2.id !== id));
|
|
4989
4991
|
}, []);
|
|
4990
4992
|
const removeAllToasts = React24.useCallback(() => {
|
|
4991
4993
|
setToasts([]);
|
|
@@ -6752,7 +6754,7 @@ var variantColors = {
|
|
|
6752
6754
|
plain: { backgroundColor: "#1C1C1C", borderColor: "#1F1F1F" },
|
|
6753
6755
|
pr: {
|
|
6754
6756
|
backgroundColor: "rgba(255, 121, 0, 0.12)",
|
|
6755
|
-
borderColor: "rgba(255, 121, 0, 0.
|
|
6757
|
+
borderColor: "rgba(255, 121, 0, 0.3)"
|
|
6756
6758
|
}
|
|
6757
6759
|
};
|
|
6758
6760
|
function BaseBadge({
|
|
@@ -6820,6 +6822,58 @@ function BaseBadge({
|
|
|
6820
6822
|
}
|
|
6821
6823
|
return badge;
|
|
6822
6824
|
}
|
|
6825
|
+
|
|
6826
|
+
// src/components/custom/Workout/icons.tsx
|
|
6827
|
+
function DumbbellIcon({
|
|
6828
|
+
size = 24,
|
|
6829
|
+
color = "currentColor",
|
|
6830
|
+
fill = "none",
|
|
6831
|
+
strokeWidth = 2
|
|
6832
|
+
}) {
|
|
6833
|
+
return /* @__PURE__ */ jsxs(
|
|
6834
|
+
"svg",
|
|
6835
|
+
{
|
|
6836
|
+
width: size,
|
|
6837
|
+
height: size,
|
|
6838
|
+
viewBox: "0 0 24 24",
|
|
6839
|
+
fill,
|
|
6840
|
+
stroke: color,
|
|
6841
|
+
strokeWidth,
|
|
6842
|
+
strokeLinecap: "round",
|
|
6843
|
+
strokeLinejoin: "round",
|
|
6844
|
+
children: [
|
|
6845
|
+
/* @__PURE__ */ jsx("path", { d: "M14.4 14.4 9.6 9.6" }),
|
|
6846
|
+
/* @__PURE__ */ jsx("path", { d: "M18.657 21.485a2 2 0 1 1-2.829-2.828l-1.767 1.768a2 2 0 1 1-2.829-2.829l6.364-6.364a2 2 0 1 1 2.829 2.829l-1.768 1.767a2 2 0 1 1 2.828 2.829z" }),
|
|
6847
|
+
/* @__PURE__ */ jsx("path", { d: "m21.5 21.5-1.4-1.4" }),
|
|
6848
|
+
/* @__PURE__ */ jsx("path", { d: "M3.9 3.9 2.5 2.5" }),
|
|
6849
|
+
/* @__PURE__ */ jsx("path", { d: "M6.404 12.768a2 2 0 1 1-2.829-2.829l1.768-1.767a2 2 0 1 1-2.828-2.829l2.828-2.828a2 2 0 1 1 2.829 2.828l1.767-1.768a2 2 0 1 1 2.829 2.829z" })
|
|
6850
|
+
]
|
|
6851
|
+
}
|
|
6852
|
+
);
|
|
6853
|
+
}
|
|
6854
|
+
function StarIcon({
|
|
6855
|
+
size = 24,
|
|
6856
|
+
color = "currentColor",
|
|
6857
|
+
fill = "none",
|
|
6858
|
+
strokeWidth = 2
|
|
6859
|
+
}) {
|
|
6860
|
+
return /* @__PURE__ */ jsx(
|
|
6861
|
+
"svg",
|
|
6862
|
+
{
|
|
6863
|
+
width: size,
|
|
6864
|
+
height: size,
|
|
6865
|
+
viewBox: "0 0 24 24",
|
|
6866
|
+
fill,
|
|
6867
|
+
stroke: color,
|
|
6868
|
+
strokeWidth,
|
|
6869
|
+
strokeLinecap: "round",
|
|
6870
|
+
strokeLinejoin: "round",
|
|
6871
|
+
children: /* @__PURE__ */ jsx("path", { d: "M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z" })
|
|
6872
|
+
}
|
|
6873
|
+
);
|
|
6874
|
+
}
|
|
6875
|
+
|
|
6876
|
+
// src/components/custom/Workout/WeightBadge.tsx
|
|
6823
6877
|
function WeightBadge({
|
|
6824
6878
|
value,
|
|
6825
6879
|
unit = "lbs",
|
|
@@ -6845,7 +6899,7 @@ function WeightBadge({
|
|
|
6845
6899
|
size,
|
|
6846
6900
|
onPress,
|
|
6847
6901
|
className,
|
|
6848
|
-
icon: showIcon ? /* @__PURE__ */ jsx(
|
|
6902
|
+
icon: showIcon ? /* @__PURE__ */ jsx(DumbbellIcon, { size: config.iconSize, color: iconColor, strokeWidth: 2 }) : void 0,
|
|
6849
6903
|
accessibilityLabel: fullLabel,
|
|
6850
6904
|
testID: "weight-badge",
|
|
6851
6905
|
...props,
|
|
@@ -6949,7 +7003,7 @@ function PrBadge({
|
|
|
6949
7003
|
accessibilityLabel: `Personal record: ${resolvedLabel}`,
|
|
6950
7004
|
testID: "pr-badge-star",
|
|
6951
7005
|
...props,
|
|
6952
|
-
children: /* @__PURE__ */ jsx(
|
|
7006
|
+
children: /* @__PURE__ */ jsx(StarIcon, { size: 14, color: "#FF7900", fill: "#FF7900", strokeWidth: 2 })
|
|
6953
7007
|
}
|
|
6954
7008
|
) : /* @__PURE__ */ jsx(
|
|
6955
7009
|
BaseBadge,
|
|
@@ -6962,7 +7016,7 @@ function PrBadge({
|
|
|
6962
7016
|
reactNative.Text,
|
|
6963
7017
|
{
|
|
6964
7018
|
style: {
|
|
6965
|
-
fontSize:
|
|
7019
|
+
fontSize: 12,
|
|
6966
7020
|
color: "#FF7900",
|
|
6967
7021
|
fontWeight: "700",
|
|
6968
7022
|
fontFamily: "Inter, sans-serif"
|
|
@@ -7113,6 +7167,29 @@ function StatusDot({
|
|
|
7113
7167
|
}
|
|
7114
7168
|
return /* @__PURE__ */ jsx(reactNative.View, { className, ...props, children: dot });
|
|
7115
7169
|
}
|
|
7170
|
+
|
|
7171
|
+
// src/theme/workout-tokens.ts
|
|
7172
|
+
var WORKOUT_TOKENS = {
|
|
7173
|
+
// Canonical 4-band performance scale — the single source for BOTH the
|
|
7174
|
+
// VelocityStrip zone bars and the SetRow RPE color (TD-03.43). The direction
|
|
7175
|
+
// is intentionally inverted between the two consumers: for velocity, green =
|
|
7176
|
+
// fastest/best; for RPE, green = easiest. Each component maps its own
|
|
7177
|
+
// thresholds onto these four colors. Kept as vivid data-viz values (distinct
|
|
7178
|
+
// from the muted status tokens) and theme-independent, so — like the heatmap
|
|
7179
|
+
// scale below — they are consumed inline as a JS import rather than CSS vars.
|
|
7180
|
+
// A JS import also resolves on native RN, unlike var(--…) strings.
|
|
7181
|
+
scale: {
|
|
7182
|
+
green: "#2ed573",
|
|
7183
|
+
yellow: "#ffd43b",
|
|
7184
|
+
orange: "#ffa502",
|
|
7185
|
+
red: "#ff4757"
|
|
7186
|
+
},
|
|
7187
|
+
// Placeholder strip
|
|
7188
|
+
placeholder: {
|
|
7189
|
+
fill: "#3A3A3A"
|
|
7190
|
+
}};
|
|
7191
|
+
|
|
7192
|
+
// src/components/custom/Workout/PlaceholderStrip.tsx
|
|
7116
7193
|
function SingleStrip({
|
|
7117
7194
|
width,
|
|
7118
7195
|
className,
|
|
@@ -7121,15 +7198,12 @@ function SingleStrip({
|
|
|
7121
7198
|
return /* @__PURE__ */ jsx(
|
|
7122
7199
|
reactNative.View,
|
|
7123
7200
|
{
|
|
7124
|
-
className
|
|
7201
|
+
className,
|
|
7125
7202
|
style: [
|
|
7126
7203
|
{
|
|
7127
7204
|
height: 3,
|
|
7128
|
-
backgroundColor:
|
|
7129
|
-
|
|
7130
|
-
borderStyle: "dashed",
|
|
7131
|
-
borderColor: "var(--color-border-strong)",
|
|
7132
|
-
borderRadius: 1,
|
|
7205
|
+
backgroundColor: WORKOUT_TOKENS.placeholder.fill,
|
|
7206
|
+
borderRadius: 2,
|
|
7133
7207
|
opacity: 0.5
|
|
7134
7208
|
},
|
|
7135
7209
|
width != null ? { width } : { flex: 1 }
|
|
@@ -7165,10 +7239,7 @@ function SegmentedStrip({
|
|
|
7165
7239
|
style: {
|
|
7166
7240
|
flex: 1,
|
|
7167
7241
|
height: 3,
|
|
7168
|
-
backgroundColor:
|
|
7169
|
-
borderWidth: 1,
|
|
7170
|
-
borderStyle: "dashed",
|
|
7171
|
-
borderColor: "var(--color-border-strong)",
|
|
7242
|
+
backgroundColor: WORKOUT_TOKENS.placeholder.fill,
|
|
7172
7243
|
borderRadius: 1,
|
|
7173
7244
|
minWidth: 4
|
|
7174
7245
|
},
|
|
@@ -7191,23 +7262,6 @@ function PlaceholderStrip({
|
|
|
7191
7262
|
return /* @__PURE__ */ jsx(SingleStrip, { ...props });
|
|
7192
7263
|
}
|
|
7193
7264
|
|
|
7194
|
-
// src/theme/workout-tokens.ts
|
|
7195
|
-
var WORKOUT_TOKENS = {
|
|
7196
|
-
// Canonical 4-band performance scale — the single source for BOTH the
|
|
7197
|
-
// VelocityStrip zone bars and the SetRow RPE color (TD-03.43). The direction
|
|
7198
|
-
// is intentionally inverted between the two consumers: for velocity, green =
|
|
7199
|
-
// fastest/best; for RPE, green = easiest. Each component maps its own
|
|
7200
|
-
// thresholds onto these four colors. Kept as vivid data-viz values (distinct
|
|
7201
|
-
// from the muted status tokens) and theme-independent, so — like the heatmap
|
|
7202
|
-
// scale below — they are consumed inline as a JS import rather than CSS vars.
|
|
7203
|
-
// A JS import also resolves on native RN, unlike var(--…) strings.
|
|
7204
|
-
scale: {
|
|
7205
|
-
green: "#2ed573",
|
|
7206
|
-
yellow: "#ffd43b",
|
|
7207
|
-
orange: "#ffa502",
|
|
7208
|
-
red: "#ff4757"
|
|
7209
|
-
}};
|
|
7210
|
-
|
|
7211
7265
|
// src/utils/workout-format.ts
|
|
7212
7266
|
function roundRpe(rpe) {
|
|
7213
7267
|
return Math.round(rpe * 2) / 2;
|
|
@@ -7246,9 +7300,200 @@ function formatPrescription(p) {
|
|
|
7246
7300
|
return full.length > 0 ? full : null;
|
|
7247
7301
|
}
|
|
7248
7302
|
|
|
7303
|
+
// src/utils/colors.ts
|
|
7304
|
+
function getStatusColor(status) {
|
|
7305
|
+
return `var(--color-status-${status})`;
|
|
7306
|
+
}
|
|
7307
|
+
function getResultColor(result) {
|
|
7308
|
+
return `var(--color-result-${result})`;
|
|
7309
|
+
}
|
|
7310
|
+
function alpha(color, opacity) {
|
|
7311
|
+
const clampedOpacity = Math.max(0, Math.min(1, opacity));
|
|
7312
|
+
if (color.startsWith("#")) {
|
|
7313
|
+
const hex = color.slice(1);
|
|
7314
|
+
let r, g, b;
|
|
7315
|
+
if (hex.length === 3) {
|
|
7316
|
+
r = parseInt(hex[0] + hex[0], 16);
|
|
7317
|
+
g = parseInt(hex[1] + hex[1], 16);
|
|
7318
|
+
b = parseInt(hex[2] + hex[2], 16);
|
|
7319
|
+
} else if (hex.length === 6) {
|
|
7320
|
+
r = parseInt(hex.slice(0, 2), 16);
|
|
7321
|
+
g = parseInt(hex.slice(2, 4), 16);
|
|
7322
|
+
b = parseInt(hex.slice(4, 6), 16);
|
|
7323
|
+
} else {
|
|
7324
|
+
return color;
|
|
7325
|
+
}
|
|
7326
|
+
return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
|
|
7327
|
+
}
|
|
7328
|
+
const rgbMatch = color.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
|
|
7329
|
+
if (rgbMatch) {
|
|
7330
|
+
const [, r, g, b] = rgbMatch;
|
|
7331
|
+
return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
|
|
7332
|
+
}
|
|
7333
|
+
const rgbaMatch = color.match(/rgba\((\d+),\s*(\d+),\s*(\d+),\s*[\d.]+\)/);
|
|
7334
|
+
if (rgbaMatch) {
|
|
7335
|
+
const [, r, g, b] = rgbaMatch;
|
|
7336
|
+
return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
|
|
7337
|
+
}
|
|
7338
|
+
return color;
|
|
7339
|
+
}
|
|
7340
|
+
function getLuminance(color) {
|
|
7341
|
+
if (!color.startsWith("#")) return "dark";
|
|
7342
|
+
const hex = color.slice(1);
|
|
7343
|
+
let r, g, b;
|
|
7344
|
+
if (hex.length === 3) {
|
|
7345
|
+
r = parseInt(hex[0] + hex[0], 16);
|
|
7346
|
+
g = parseInt(hex[1] + hex[1], 16);
|
|
7347
|
+
b = parseInt(hex[2] + hex[2], 16);
|
|
7348
|
+
} else if (hex.length === 6) {
|
|
7349
|
+
r = parseInt(hex.slice(0, 2), 16);
|
|
7350
|
+
g = parseInt(hex.slice(2, 4), 16);
|
|
7351
|
+
b = parseInt(hex.slice(4, 6), 16);
|
|
7352
|
+
} else {
|
|
7353
|
+
return "dark";
|
|
7354
|
+
}
|
|
7355
|
+
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
7356
|
+
return luminance > 0.5 ? "light" : "dark";
|
|
7357
|
+
}
|
|
7358
|
+
function getContrastText(backgroundColor) {
|
|
7359
|
+
return getLuminance(backgroundColor) === "light" ? "#000000" : "#FFFFFF";
|
|
7360
|
+
}
|
|
7361
|
+
var t = getSemanticColors("dark");
|
|
7362
|
+
var TEMPO_PACING = {
|
|
7363
|
+
behindThresholdPct: 0.15,
|
|
7364
|
+
minPhaseDurationMs: 500
|
|
7365
|
+
};
|
|
7366
|
+
function getTempoPacingState(elapsedMs, targetMs) {
|
|
7367
|
+
if (!targetMs || targetMs < TEMPO_PACING.minPhaseDurationMs) return "none";
|
|
7368
|
+
const ratio = elapsedMs / targetMs;
|
|
7369
|
+
if (ratio > 1 + TEMPO_PACING.behindThresholdPct) return "behind";
|
|
7370
|
+
return "on-pace";
|
|
7371
|
+
}
|
|
7372
|
+
function getTempoFillPct(elapsedMs, targetMs) {
|
|
7373
|
+
if (!targetMs) return 100;
|
|
7374
|
+
return Math.min(100, elapsedMs / targetMs * 100);
|
|
7375
|
+
}
|
|
7376
|
+
var PHASE_ORDER = ["concentric", "hold", "eccentric"];
|
|
7377
|
+
var PHASE_CONFIG = {
|
|
7378
|
+
concentric: { label: "Con", color: t["status-success"], flex: 2 },
|
|
7379
|
+
hold: { label: "Hold", color: t["brand-primary"], flex: 1 },
|
|
7380
|
+
eccentric: { label: "Ecc", color: t["status-warning"], flex: 3 }
|
|
7381
|
+
};
|
|
7382
|
+
function TempoBar({
|
|
7383
|
+
activePhase,
|
|
7384
|
+
phaseElapsedMs,
|
|
7385
|
+
completed,
|
|
7386
|
+
target,
|
|
7387
|
+
className,
|
|
7388
|
+
...props
|
|
7389
|
+
}) {
|
|
7390
|
+
return /* @__PURE__ */ jsxs(reactNative.View, { className, testID: "tempo-bar", ...props, children: [
|
|
7391
|
+
/* @__PURE__ */ jsx(reactNative.View, { style: { flexDirection: "row", marginBottom: 4 }, children: PHASE_ORDER.map((phase) => {
|
|
7392
|
+
const config = PHASE_CONFIG[phase];
|
|
7393
|
+
return /* @__PURE__ */ jsx(reactNative.View, { style: { flex: config.flex, alignItems: "center" }, children: /* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 10, color: t["text-disabled"] }, children: config.label }) }, phase);
|
|
7394
|
+
}) }),
|
|
7395
|
+
/* @__PURE__ */ jsx(reactNative.View, { style: { flexDirection: "row", gap: 2, height: 20 }, children: PHASE_ORDER.map((phase) => {
|
|
7396
|
+
const config = PHASE_CONFIG[phase];
|
|
7397
|
+
const isActive = activePhase === phase;
|
|
7398
|
+
const completedMs = completed?.[phase];
|
|
7399
|
+
const targetSec = target?.[phase];
|
|
7400
|
+
const targetMs = targetSec != null ? targetSec * 1e3 : null;
|
|
7401
|
+
return /* @__PURE__ */ jsx(
|
|
7402
|
+
reactNative.View,
|
|
7403
|
+
{
|
|
7404
|
+
style: {
|
|
7405
|
+
flex: config.flex,
|
|
7406
|
+
backgroundColor: alpha("#ffffff", 0.06),
|
|
7407
|
+
borderRadius: 4,
|
|
7408
|
+
overflow: "hidden"
|
|
7409
|
+
},
|
|
7410
|
+
children: isActive ? /* @__PURE__ */ jsx(
|
|
7411
|
+
ActiveSegment,
|
|
7412
|
+
{
|
|
7413
|
+
config,
|
|
7414
|
+
phaseElapsedMs,
|
|
7415
|
+
targetMs
|
|
7416
|
+
}
|
|
7417
|
+
) : completedMs != null ? /* @__PURE__ */ jsx(CompletedSegment, { config, completedMs, targetMs }) : null
|
|
7418
|
+
},
|
|
7419
|
+
phase
|
|
7420
|
+
);
|
|
7421
|
+
}) })
|
|
7422
|
+
] });
|
|
7423
|
+
}
|
|
7424
|
+
function ActiveSegment({
|
|
7425
|
+
config,
|
|
7426
|
+
phaseElapsedMs,
|
|
7427
|
+
targetMs
|
|
7428
|
+
}) {
|
|
7429
|
+
const pacing = getTempoPacingState(phaseElapsedMs, targetMs);
|
|
7430
|
+
const barColor = pacing === "behind" ? t["status-error"] : config.color;
|
|
7431
|
+
const fillPct = getTempoFillPct(phaseElapsedMs, targetMs);
|
|
7432
|
+
const label = targetMs ? `${formatDuration(phaseElapsedMs)} / ${formatDuration(targetMs)}` : formatDuration(phaseElapsedMs);
|
|
7433
|
+
return /* @__PURE__ */ jsxs(reactNative.View, { style: { height: "100%", position: "relative" }, testID: `tempo-segment-active-${config.label}`, children: [
|
|
7434
|
+
/* @__PURE__ */ jsx(
|
|
7435
|
+
reactNative.View,
|
|
7436
|
+
{
|
|
7437
|
+
style: {
|
|
7438
|
+
position: "absolute",
|
|
7439
|
+
left: 0,
|
|
7440
|
+
top: 0,
|
|
7441
|
+
bottom: 0,
|
|
7442
|
+
width: `${fillPct}%`,
|
|
7443
|
+
backgroundColor: alpha(barColor, 0.3),
|
|
7444
|
+
borderRadius: 4
|
|
7445
|
+
}
|
|
7446
|
+
}
|
|
7447
|
+
),
|
|
7448
|
+
/* @__PURE__ */ jsx(
|
|
7449
|
+
reactNative.View,
|
|
7450
|
+
{
|
|
7451
|
+
style: {
|
|
7452
|
+
height: "100%",
|
|
7453
|
+
flexDirection: "row",
|
|
7454
|
+
alignItems: "center",
|
|
7455
|
+
justifyContent: "center"
|
|
7456
|
+
},
|
|
7457
|
+
children: /* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 12, fontWeight: "700", color: barColor }, children: label })
|
|
7458
|
+
}
|
|
7459
|
+
)
|
|
7460
|
+
] });
|
|
7461
|
+
}
|
|
7462
|
+
function CompletedSegment({
|
|
7463
|
+
config,
|
|
7464
|
+
completedMs,
|
|
7465
|
+
targetMs
|
|
7466
|
+
}) {
|
|
7467
|
+
const pacing = getTempoPacingState(completedMs, targetMs);
|
|
7468
|
+
const hitTarget = pacing !== "behind";
|
|
7469
|
+
const indicator = targetMs && targetMs >= TEMPO_PACING.minPhaseDurationMs ? hitTarget ? " \u2713" : " \u2717" : "";
|
|
7470
|
+
return /* @__PURE__ */ jsx(
|
|
7471
|
+
reactNative.View,
|
|
7472
|
+
{
|
|
7473
|
+
style: {
|
|
7474
|
+
height: "100%",
|
|
7475
|
+
flexDirection: "row",
|
|
7476
|
+
alignItems: "center",
|
|
7477
|
+
justifyContent: "center",
|
|
7478
|
+
backgroundColor: alpha(config.color, 0.15)
|
|
7479
|
+
},
|
|
7480
|
+
testID: `tempo-segment-completed-${config.label}`,
|
|
7481
|
+
children: /* @__PURE__ */ jsxs(reactNative.Text, { style: { fontSize: 12, fontWeight: "500", color: alpha(config.color, 0.7) }, children: [
|
|
7482
|
+
formatDuration(completedMs),
|
|
7483
|
+
indicator
|
|
7484
|
+
] })
|
|
7485
|
+
}
|
|
7486
|
+
);
|
|
7487
|
+
}
|
|
7488
|
+
function formatDuration(ms) {
|
|
7489
|
+
const s = ms / 1e3;
|
|
7490
|
+
return s < 10 ? s.toFixed(1) : Math.round(s).toString();
|
|
7491
|
+
}
|
|
7492
|
+
|
|
7249
7493
|
// src/components/custom/Workout/TempoDisplay.tsx
|
|
7250
7494
|
var INTER = "Inter, sans-serif";
|
|
7251
7495
|
var TEXT_TERTIARY = "#6B7280";
|
|
7496
|
+
var STATUS_ERROR = "#D14343";
|
|
7252
7497
|
var phaseColors = {
|
|
7253
7498
|
eccentric: "#FFB020",
|
|
7254
7499
|
// status-warning (amber)
|
|
@@ -7292,11 +7537,68 @@ function TempoSeparator({ color, fontSize }) {
|
|
|
7292
7537
|
}
|
|
7293
7538
|
);
|
|
7294
7539
|
}
|
|
7540
|
+
var LIVE_PHASES = [
|
|
7541
|
+
{ key: "eccentric", color: phaseColors.eccentric },
|
|
7542
|
+
{ key: "pauseBottom", color: phaseColors.pauseBottom },
|
|
7543
|
+
{ key: "concentric", color: phaseColors.concentric },
|
|
7544
|
+
{ key: "pauseTop", color: phaseColors.pauseTop }
|
|
7545
|
+
];
|
|
7546
|
+
function LiveTempoCell({
|
|
7547
|
+
value,
|
|
7548
|
+
color,
|
|
7549
|
+
isActive,
|
|
7550
|
+
phaseElapsedMs,
|
|
7551
|
+
fontSize
|
|
7552
|
+
}) {
|
|
7553
|
+
if (!isActive) {
|
|
7554
|
+
return /* @__PURE__ */ jsx(TempoValue, { value, color: alpha(color, 0.35), fontSize });
|
|
7555
|
+
}
|
|
7556
|
+
const targetMs = value > 0 ? value * 1e3 : null;
|
|
7557
|
+
const barColor = getTempoPacingState(phaseElapsedMs, targetMs) === "behind" ? STATUS_ERROR : color;
|
|
7558
|
+
const fillPct = getTempoFillPct(phaseElapsedMs, targetMs);
|
|
7559
|
+
return /* @__PURE__ */ jsxs(reactNative.View, { style: { position: "relative" }, testID: "tempo-live-active", children: [
|
|
7560
|
+
/* @__PURE__ */ jsx(
|
|
7561
|
+
reactNative.View,
|
|
7562
|
+
{
|
|
7563
|
+
style: {
|
|
7564
|
+
position: "absolute",
|
|
7565
|
+
left: 0,
|
|
7566
|
+
top: 0,
|
|
7567
|
+
bottom: 0,
|
|
7568
|
+
width: `${fillPct}%`,
|
|
7569
|
+
backgroundColor: alpha(barColor, 0.3),
|
|
7570
|
+
borderRadius: 2
|
|
7571
|
+
}
|
|
7572
|
+
}
|
|
7573
|
+
),
|
|
7574
|
+
/* @__PURE__ */ jsx(TempoValue, { value, color: barColor, fontSize })
|
|
7575
|
+
] });
|
|
7576
|
+
}
|
|
7577
|
+
function LiveTempoRow({
|
|
7578
|
+
values,
|
|
7579
|
+
live,
|
|
7580
|
+
fontSize
|
|
7581
|
+
}) {
|
|
7582
|
+
return /* @__PURE__ */ jsx(jsxRuntime.Fragment, { children: LIVE_PHASES.map((phase, i) => /* @__PURE__ */ jsxs(reactNative.View, { style: { flexDirection: "row" }, children: [
|
|
7583
|
+
i > 0 && /* @__PURE__ */ jsx(TempoSeparator, { color: phaseColors.dash, fontSize }),
|
|
7584
|
+
/* @__PURE__ */ jsx(
|
|
7585
|
+
LiveTempoCell,
|
|
7586
|
+
{
|
|
7587
|
+
value: values[i],
|
|
7588
|
+
color: phase.color,
|
|
7589
|
+
isActive: live.activePhase === phase.key,
|
|
7590
|
+
phaseElapsedMs: live.phaseElapsedMs,
|
|
7591
|
+
fontSize
|
|
7592
|
+
}
|
|
7593
|
+
)
|
|
7594
|
+
] }, phase.key)) });
|
|
7595
|
+
}
|
|
7295
7596
|
function TempoDisplay({
|
|
7296
7597
|
tempo,
|
|
7297
7598
|
size = "md",
|
|
7298
7599
|
colored = true,
|
|
7299
7600
|
showInfo = true,
|
|
7601
|
+
live,
|
|
7300
7602
|
onPress,
|
|
7301
7603
|
className,
|
|
7302
7604
|
...props
|
|
@@ -7343,7 +7645,14 @@ function TempoDisplay({
|
|
|
7343
7645
|
children: "TEMPO"
|
|
7344
7646
|
}
|
|
7345
7647
|
),
|
|
7346
|
-
/* @__PURE__ */ jsx(reactNative.View, { style: { flexDirection: "row" }, testID: "tempo-value", children:
|
|
7648
|
+
/* @__PURE__ */ jsx(reactNative.View, { style: { flexDirection: "row" }, testID: "tempo-value", children: live ? /* @__PURE__ */ jsx(
|
|
7649
|
+
LiveTempoRow,
|
|
7650
|
+
{
|
|
7651
|
+
values: [eccentric, pauseBottom, concentric, pauseTop],
|
|
7652
|
+
live,
|
|
7653
|
+
fontSize
|
|
7654
|
+
}
|
|
7655
|
+
) : colored ? /* @__PURE__ */ jsxs(jsxRuntime.Fragment, { children: [
|
|
7347
7656
|
/* @__PURE__ */ jsx(TempoValue, { value: eccentric, color: phaseColors.eccentric, fontSize }),
|
|
7348
7657
|
/* @__PURE__ */ jsx(TempoSeparator, { color: phaseColors.dash, fontSize }),
|
|
7349
7658
|
/* @__PURE__ */ jsx(TempoValue, { value: pauseBottom, color: phaseColors.pauseBottom, fontSize }),
|
|
@@ -7528,19 +7837,42 @@ function DeviationBar({
|
|
|
7528
7837
|
}
|
|
7529
7838
|
);
|
|
7530
7839
|
}
|
|
7531
|
-
var TRACK_BG = "
|
|
7532
|
-
var THRESHOLD_COLOR = "#FFFFFF";
|
|
7840
|
+
var TRACK_BG = "#333333";
|
|
7533
7841
|
var LABEL_COLOR = "#6B7280";
|
|
7534
|
-
|
|
7535
|
-
|
|
7536
|
-
|
|
7537
|
-
|
|
7538
|
-
|
|
7539
|
-
|
|
7842
|
+
var TARGET_LINE_COLOR = "rgba(33, 150, 243, 0.5)";
|
|
7843
|
+
var AT_TARGET_GLOW = "0 0 5px 1px rgba(33, 150, 243, 0.35), 0 0 10px 3px rgba(33, 150, 243, 0.15)";
|
|
7844
|
+
var ZONE = {
|
|
7845
|
+
building: "#14B8A6",
|
|
7846
|
+
// teal — below target ramp-up
|
|
7847
|
+
approaching: "#FFB020",
|
|
7848
|
+
// amber — nearing target
|
|
7849
|
+
target: "#FF7900",
|
|
7850
|
+
// brand — exactly at target
|
|
7851
|
+
over1: "#D14343",
|
|
7852
|
+
// red — mild over-target
|
|
7853
|
+
over2: "#A62626",
|
|
7854
|
+
// deep red — moderate over-target
|
|
7855
|
+
over3: "#7A1C1C"
|
|
7856
|
+
// darkest red — severe over-target
|
|
7857
|
+
};
|
|
7858
|
+
var BULGE_SIZE = { 1: 8, 2: 10, 3: 11 };
|
|
7859
|
+
function zoneForPct(pct) {
|
|
7860
|
+
if (pct >= 125) return { color: ZONE.over3, over: 3 };
|
|
7861
|
+
if (pct >= 115) return { color: ZONE.over2, over: 2 };
|
|
7862
|
+
if (pct > 100) return { color: ZONE.over1, over: 1 };
|
|
7863
|
+
if (pct === 100) return { color: ZONE.target, over: 0 };
|
|
7864
|
+
if (pct >= 75) return { color: ZONE.approaching, over: 0 };
|
|
7865
|
+
return { color: ZONE.building, over: 0 };
|
|
7866
|
+
}
|
|
7867
|
+
function clampFill(value) {
|
|
7540
7868
|
if (value < 0) return 0;
|
|
7541
7869
|
if (value > 1) return 1;
|
|
7542
7870
|
return value;
|
|
7543
7871
|
}
|
|
7872
|
+
function isAtTarget(pct, threshold) {
|
|
7873
|
+
if (threshold == null) return false;
|
|
7874
|
+
return Math.abs(pct - Math.round(threshold * 100)) <= 5;
|
|
7875
|
+
}
|
|
7544
7876
|
function IntensityBar({
|
|
7545
7877
|
level,
|
|
7546
7878
|
threshold,
|
|
@@ -7552,62 +7884,62 @@ function IntensityBar({
|
|
|
7552
7884
|
...props
|
|
7553
7885
|
}) {
|
|
7554
7886
|
const isVertical = orientation === "vertical";
|
|
7555
|
-
const
|
|
7556
|
-
const
|
|
7557
|
-
const
|
|
7558
|
-
const
|
|
7887
|
+
const fillLevel = clampFill(level);
|
|
7888
|
+
const pct = Math.round(Math.max(0, level) * 100);
|
|
7889
|
+
const zone = zoneForPct(pct);
|
|
7890
|
+
const atTarget = isAtTarget(pct, threshold);
|
|
7891
|
+
const [fillAnim] = React24.useState(() => new reactNative.Animated.Value(fillLevel));
|
|
7559
7892
|
React24.useEffect(() => {
|
|
7560
7893
|
const animation = reactNative.Animated.timing(fillAnim, {
|
|
7561
|
-
toValue:
|
|
7894
|
+
toValue: fillLevel,
|
|
7562
7895
|
duration: 250,
|
|
7563
7896
|
useNativeDriver: false
|
|
7564
7897
|
});
|
|
7565
7898
|
animation.start();
|
|
7566
7899
|
return () => animation.stop();
|
|
7567
|
-
}, [
|
|
7900
|
+
}, [fillLevel, fillAnim]);
|
|
7568
7901
|
const fillSizePercent = fillAnim.interpolate({
|
|
7569
7902
|
inputRange: [0, 1],
|
|
7570
7903
|
outputRange: ["0%", "100%"]
|
|
7571
7904
|
});
|
|
7572
7905
|
const trackStyle = isVertical ? { width: thickness, height: size } : { width: size, height: thickness };
|
|
7573
|
-
const fillStyle = isVertical ? {
|
|
7574
|
-
|
|
7575
|
-
|
|
7576
|
-
left: 0,
|
|
7577
|
-
right: 0,
|
|
7578
|
-
height: fillSizePercent
|
|
7579
|
-
} : {
|
|
7906
|
+
const fillStyle = isVertical ? { position: "absolute", bottom: 0, left: 0, right: 0, height: fillSizePercent } : { position: "absolute", top: 0, bottom: 0, left: 0, width: fillSizePercent };
|
|
7907
|
+
const bulgeSize = zone.over === 0 ? 0 : BULGE_SIZE[zone.over];
|
|
7908
|
+
const bulgeStyle = {
|
|
7580
7909
|
position: "absolute",
|
|
7581
|
-
|
|
7582
|
-
|
|
7583
|
-
|
|
7584
|
-
|
|
7910
|
+
width: bulgeSize,
|
|
7911
|
+
height: bulgeSize,
|
|
7912
|
+
borderRadius: bulgeSize / 2,
|
|
7913
|
+
backgroundColor: zone.color,
|
|
7914
|
+
zIndex: 1,
|
|
7915
|
+
...isVertical ? { top: 0, left: "50%", transform: [{ translateX: -bulgeSize / 2 }] } : { right: 0, top: "50%", transform: [{ translateY: -bulgeSize / 2 }] }
|
|
7585
7916
|
};
|
|
7586
|
-
const
|
|
7917
|
+
const targetPct = `${clampFill(threshold ?? 0) * 100}%`;
|
|
7918
|
+
const targetLineStyle = isVertical ? {
|
|
7587
7919
|
position: "absolute",
|
|
7588
|
-
bottom:
|
|
7589
|
-
left: -
|
|
7590
|
-
right: -
|
|
7591
|
-
height: 1,
|
|
7592
|
-
backgroundColor:
|
|
7920
|
+
bottom: targetPct,
|
|
7921
|
+
left: -3,
|
|
7922
|
+
right: -3,
|
|
7923
|
+
height: 1.5,
|
|
7924
|
+
backgroundColor: TARGET_LINE_COLOR,
|
|
7593
7925
|
zIndex: 4
|
|
7594
7926
|
} : {
|
|
7595
7927
|
position: "absolute",
|
|
7596
|
-
left:
|
|
7597
|
-
top: -
|
|
7598
|
-
bottom: -
|
|
7599
|
-
width: 1,
|
|
7600
|
-
backgroundColor:
|
|
7928
|
+
left: targetPct,
|
|
7929
|
+
top: -3,
|
|
7930
|
+
bottom: -3,
|
|
7931
|
+
width: 1.5,
|
|
7932
|
+
backgroundColor: TARGET_LINE_COLOR,
|
|
7601
7933
|
zIndex: 4
|
|
7602
|
-
}
|
|
7934
|
+
};
|
|
7603
7935
|
return /* @__PURE__ */ jsxs(
|
|
7604
7936
|
reactNative.View,
|
|
7605
7937
|
{
|
|
7606
7938
|
className,
|
|
7607
7939
|
style: { alignItems: "center" },
|
|
7608
7940
|
accessibilityRole: "progressbar",
|
|
7609
|
-
accessibilityValue: { min: 0, max: 100, now:
|
|
7610
|
-
accessibilityLabel: `Intensity level: ${
|
|
7941
|
+
accessibilityValue: { min: 0, max: 100, now: pct },
|
|
7942
|
+
accessibilityLabel: `Intensity level: ${pct}%`,
|
|
7611
7943
|
testID: "intensity-bar",
|
|
7612
7944
|
...props,
|
|
7613
7945
|
children: [
|
|
@@ -7629,13 +7961,32 @@ function IntensityBar({
|
|
|
7629
7961
|
style: {
|
|
7630
7962
|
...fillStyle,
|
|
7631
7963
|
borderRadius: 3,
|
|
7632
|
-
backgroundColor:
|
|
7633
|
-
zIndex: 2
|
|
7964
|
+
backgroundColor: zone.color,
|
|
7965
|
+
zIndex: 2,
|
|
7966
|
+
...atTarget ? { boxShadow: AT_TARGET_GLOW } : null
|
|
7634
7967
|
},
|
|
7635
7968
|
testID: "intensity-fill"
|
|
7636
7969
|
}
|
|
7637
7970
|
),
|
|
7638
|
-
|
|
7971
|
+
zone.over !== 0 && /* @__PURE__ */ jsx(reactNative.View, { style: bulgeStyle, testID: "intensity-bulge" }),
|
|
7972
|
+
threshold != null && /* @__PURE__ */ jsx(reactNative.View, { style: targetLineStyle, testID: "intensity-target" })
|
|
7973
|
+
]
|
|
7974
|
+
}
|
|
7975
|
+
),
|
|
7976
|
+
/* @__PURE__ */ jsxs(
|
|
7977
|
+
reactNative.Text,
|
|
7978
|
+
{
|
|
7979
|
+
style: {
|
|
7980
|
+
fontSize: 8,
|
|
7981
|
+
color: LABEL_COLOR,
|
|
7982
|
+
fontFamily: '"Nunito Sans", sans-serif',
|
|
7983
|
+
marginTop: 6
|
|
7984
|
+
},
|
|
7985
|
+
accessibilityElementsHidden: true,
|
|
7986
|
+
testID: "intensity-label",
|
|
7987
|
+
children: [
|
|
7988
|
+
pct,
|
|
7989
|
+
"%"
|
|
7639
7990
|
]
|
|
7640
7991
|
}
|
|
7641
7992
|
),
|
|
@@ -7647,7 +7998,7 @@ function IntensityBar({
|
|
|
7647
7998
|
fontWeight: "500",
|
|
7648
7999
|
color: LABEL_COLOR,
|
|
7649
8000
|
fontFamily: "Inter, sans-serif",
|
|
7650
|
-
marginTop:
|
|
8001
|
+
marginTop: 2
|
|
7651
8002
|
},
|
|
7652
8003
|
accessibilityElementsHidden: true,
|
|
7653
8004
|
testID: "intensity-threshold-label",
|
|
@@ -7811,6 +8162,13 @@ function WorkoutPill({
|
|
|
7811
8162
|
return pill;
|
|
7812
8163
|
}
|
|
7813
8164
|
var VEL_COLORS = WORKOUT_TOKENS.scale;
|
|
8165
|
+
var zoneIdToScaleToken = {
|
|
8166
|
+
speed: "green",
|
|
8167
|
+
power: "yellow",
|
|
8168
|
+
strengthSpeed: "orange",
|
|
8169
|
+
maximalStrength: "red",
|
|
8170
|
+
grinding: "red"
|
|
8171
|
+
};
|
|
7814
8172
|
function getVelocityZoneColor(velocity) {
|
|
7815
8173
|
if (velocity >= 1) return "vel-green";
|
|
7816
8174
|
if (velocity >= 0.75) return "vel-yellow";
|
|
@@ -7823,47 +8181,62 @@ function getVelocityZoneName(velocity) {
|
|
|
7823
8181
|
if (velocity >= 0.5) return "Strength-Speed";
|
|
7824
8182
|
return "Strength";
|
|
7825
8183
|
}
|
|
8184
|
+
var zoneHexMap = {
|
|
8185
|
+
"vel-green": VEL_COLORS.green,
|
|
8186
|
+
"vel-yellow": VEL_COLORS.yellow,
|
|
8187
|
+
"vel-orange": VEL_COLORS.orange,
|
|
8188
|
+
"vel-red": VEL_COLORS.red
|
|
8189
|
+
};
|
|
7826
8190
|
function calculateVelocityLoss(velocities) {
|
|
7827
8191
|
if (velocities.length < 2) return 0;
|
|
7828
|
-
const
|
|
8192
|
+
const best = Math.max(...velocities);
|
|
8193
|
+
if (best <= 0) return 0;
|
|
7829
8194
|
const last = velocities[velocities.length - 1];
|
|
7830
|
-
|
|
7831
|
-
return Math.round((first - last) / first * 100);
|
|
8195
|
+
return Math.max(0, Math.round((best - last) / best * 100));
|
|
7832
8196
|
}
|
|
7833
8197
|
function calculateMeanVelocity(velocities) {
|
|
7834
8198
|
if (velocities.length === 0) return 0;
|
|
7835
8199
|
const sum = velocities.reduce((acc, v) => acc + v, 0);
|
|
7836
8200
|
return sum / velocities.length;
|
|
7837
8201
|
}
|
|
7838
|
-
function
|
|
7839
|
-
|
|
7840
|
-
|
|
7841
|
-
return VEL_COLORS.green;
|
|
7842
|
-
case "vel-yellow":
|
|
7843
|
-
return VEL_COLORS.yellow;
|
|
7844
|
-
case "vel-orange":
|
|
7845
|
-
return VEL_COLORS.orange;
|
|
7846
|
-
case "vel-red":
|
|
7847
|
-
return VEL_COLORS.red;
|
|
7848
|
-
default:
|
|
7849
|
-
return VEL_COLORS.green;
|
|
8202
|
+
function classifyBand(velocity, bands) {
|
|
8203
|
+
for (const band of bands) {
|
|
8204
|
+
if (band.max === null || velocity < band.max) return band;
|
|
7850
8205
|
}
|
|
8206
|
+
return bands[bands.length - 1];
|
|
8207
|
+
}
|
|
8208
|
+
function bandColor(band) {
|
|
8209
|
+
const token = zoneIdToScaleToken[band.id];
|
|
8210
|
+
return token ? VEL_COLORS[token] : VEL_COLORS.green;
|
|
7851
8211
|
}
|
|
7852
|
-
var zoneHexMap = {
|
|
7853
|
-
"vel-green": VEL_COLORS.green,
|
|
7854
|
-
"vel-yellow": VEL_COLORS.yellow,
|
|
7855
|
-
"vel-orange": VEL_COLORS.orange,
|
|
7856
|
-
"vel-red": VEL_COLORS.red
|
|
7857
|
-
};
|
|
7858
8212
|
function getLossStyle(loss) {
|
|
7859
8213
|
if (loss > 25) return { color: VEL_COLORS.red };
|
|
7860
8214
|
if (loss > 20) return { color: VEL_COLORS.orange };
|
|
7861
8215
|
return null;
|
|
7862
8216
|
}
|
|
8217
|
+
function getReducedMotionPreference() {
|
|
8218
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
|
|
8219
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
8220
|
+
}
|
|
8221
|
+
function usePrefersReducedMotion() {
|
|
8222
|
+
const [reduced, setReduced] = React24.useState(getReducedMotionPreference);
|
|
8223
|
+
React24.useEffect(() => {
|
|
8224
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
8225
|
+
const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
8226
|
+
const handler = () => setReduced(mq.matches);
|
|
8227
|
+
handler();
|
|
8228
|
+
mq.addEventListener?.("change", handler);
|
|
8229
|
+
return () => mq.removeEventListener?.("change", handler);
|
|
8230
|
+
}, []);
|
|
8231
|
+
return reduced;
|
|
8232
|
+
}
|
|
7863
8233
|
var ANIMATION_DURATION = 400;
|
|
7864
8234
|
var ANIMATION_EASING = reactNative.Easing.bezier(0.22, 1, 0.36, 1);
|
|
8235
|
+
var POP_EASING = reactNative.Easing.bezier(0.34, 1.56, 0.64, 1);
|
|
7865
8236
|
function VelocityStrip({
|
|
7866
8237
|
velocities,
|
|
8238
|
+
zones,
|
|
8239
|
+
liveRepIndex,
|
|
7867
8240
|
expanded = false,
|
|
7868
8241
|
onToggle,
|
|
7869
8242
|
onRepPress,
|
|
@@ -7875,10 +8248,48 @@ function VelocityStrip({
|
|
|
7875
8248
|
const maxVelocity = Math.max(...velocities, 0);
|
|
7876
8249
|
const meanVelocity = calculateMeanVelocity(velocities);
|
|
7877
8250
|
const loss = calculateVelocityLoss(velocities);
|
|
7878
|
-
const
|
|
8251
|
+
const hasZones = zones != null && zones.length > 0;
|
|
8252
|
+
const barColorFor = (v) => hasZones ? bandColor(classifyBand(v, zones)) : zoneHexMap[getVelocityZoneColor(v)];
|
|
8253
|
+
const meanZone = hasZones ? classifyBand(meanVelocity, zones)?.label ?? "" : getVelocityZoneName(meanVelocity);
|
|
8254
|
+
const prefersReducedMotion = usePrefersReducedMotion();
|
|
7879
8255
|
const [heightAnim] = React24.useState(() => new reactNative.Animated.Value(expanded ? 60 : 3));
|
|
7880
8256
|
const [labelOpacity] = React24.useState(() => new reactNative.Animated.Value(expanded ? 1 : 0));
|
|
7881
8257
|
const [infoOpacity] = React24.useState(() => new reactNative.Animated.Value(expanded ? 1 : 0));
|
|
8258
|
+
const [liveScale] = React24.useState(() => new reactNative.Animated.Value(1));
|
|
8259
|
+
const liveVelocity = liveRepIndex != null ? velocities[liveRepIndex] : void 0;
|
|
8260
|
+
const isNewPeak = liveVelocity != null && maxVelocity > 0 && liveVelocity === maxVelocity;
|
|
8261
|
+
React24.useEffect(() => {
|
|
8262
|
+
if (variant === "mini" || liveRepIndex == null || liveVelocity == null) return;
|
|
8263
|
+
if (prefersReducedMotion) {
|
|
8264
|
+
liveScale.setValue(1);
|
|
8265
|
+
return;
|
|
8266
|
+
}
|
|
8267
|
+
if (isNewPeak) {
|
|
8268
|
+
liveScale.setValue(1);
|
|
8269
|
+
reactNative.Animated.sequence([
|
|
8270
|
+
reactNative.Animated.timing(liveScale, {
|
|
8271
|
+
toValue: 1.25,
|
|
8272
|
+
duration: 150,
|
|
8273
|
+
easing: reactNative.Easing.out(reactNative.Easing.quad),
|
|
8274
|
+
useNativeDriver: true
|
|
8275
|
+
}),
|
|
8276
|
+
reactNative.Animated.spring(liveScale, {
|
|
8277
|
+
toValue: 1,
|
|
8278
|
+
friction: 3,
|
|
8279
|
+
tension: 140,
|
|
8280
|
+
useNativeDriver: true
|
|
8281
|
+
})
|
|
8282
|
+
]).start();
|
|
8283
|
+
} else {
|
|
8284
|
+
liveScale.setValue(0.8);
|
|
8285
|
+
reactNative.Animated.timing(liveScale, {
|
|
8286
|
+
toValue: 1,
|
|
8287
|
+
duration: 300,
|
|
8288
|
+
easing: POP_EASING,
|
|
8289
|
+
useNativeDriver: true
|
|
8290
|
+
}).start();
|
|
8291
|
+
}
|
|
8292
|
+
}, [variant, liveRepIndex, liveVelocity, isNewPeak, prefersReducedMotion, liveScale]);
|
|
7882
8293
|
React24.useEffect(() => {
|
|
7883
8294
|
if (variant === "mini") return;
|
|
7884
8295
|
reactNative.Animated.parallel([
|
|
@@ -7918,7 +8329,7 @@ function VelocityStrip({
|
|
|
7918
8329
|
{
|
|
7919
8330
|
style: {
|
|
7920
8331
|
flex: 1,
|
|
7921
|
-
backgroundColor:
|
|
8332
|
+
backgroundColor: barColorFor(v),
|
|
7922
8333
|
borderRadius: 1,
|
|
7923
8334
|
minWidth: 4,
|
|
7924
8335
|
height: "100%"
|
|
@@ -7937,7 +8348,7 @@ function VelocityStrip({
|
|
|
7937
8348
|
const stripContent = /* @__PURE__ */ jsxs(
|
|
7938
8349
|
reactNative.Animated.View,
|
|
7939
8350
|
{
|
|
7940
|
-
className,
|
|
8351
|
+
className: [className, expanded ? "bg-surface-raised" : "bg-transparent"].filter(Boolean).join(" "),
|
|
7941
8352
|
style: [
|
|
7942
8353
|
{
|
|
7943
8354
|
height: heightAnim,
|
|
@@ -7948,7 +8359,6 @@ function VelocityStrip({
|
|
|
7948
8359
|
paddingBottom: expanded ? 24 : 0,
|
|
7949
8360
|
paddingHorizontal: expanded ? 6 : 0,
|
|
7950
8361
|
paddingVertical: expanded ? void 0 : 8,
|
|
7951
|
-
backgroundColor: expanded ? "var(--color-surface-raised)" : "transparent",
|
|
7952
8362
|
overflow: expanded ? "visible" : "hidden"
|
|
7953
8363
|
}
|
|
7954
8364
|
],
|
|
@@ -7962,9 +8372,36 @@ function VelocityStrip({
|
|
|
7962
8372
|
{
|
|
7963
8373
|
style: { flexDirection: "row", flex: 1, gap: 2, alignItems: "flex-end" },
|
|
7964
8374
|
children: velocities.map((v, i) => {
|
|
7965
|
-
const
|
|
8375
|
+
const barBackground = barColorFor(v);
|
|
7966
8376
|
const barHeightPct = maxVelocity > 0 ? Math.round(v / (maxVelocity * 1.15) * 100) : 0;
|
|
7967
|
-
const
|
|
8377
|
+
const isLive = liveRepIndex === i;
|
|
8378
|
+
const liveLabelSuffix = isLive ? isNewPeak ? ", latest rep, new set peak" : ", latest rep" : "";
|
|
8379
|
+
const barStyle = expanded ? { height: `${barHeightPct}%`, minHeight: 2, borderTopLeftRadius: 2, borderTopRightRadius: 2, backgroundColor: barBackground } : {
|
|
8380
|
+
minHeight: "100%",
|
|
8381
|
+
borderTopLeftRadius: 2,
|
|
8382
|
+
borderTopRightRadius: 2,
|
|
8383
|
+
borderBottomLeftRadius: 0,
|
|
8384
|
+
borderBottomRightRadius: 0,
|
|
8385
|
+
backgroundColor: barBackground
|
|
8386
|
+
};
|
|
8387
|
+
const barInner = isLive ? /* @__PURE__ */ jsx(
|
|
8388
|
+
reactNative.Animated.View,
|
|
8389
|
+
{
|
|
8390
|
+
style: [barStyle, { transform: [{ scale: liveScale }] }],
|
|
8391
|
+
testID: `velocity-bar-${i}`,
|
|
8392
|
+
accessibilityRole: "image",
|
|
8393
|
+
accessibilityLabel: `Rep ${i + 1}: ${formatVelocity(v)} meters per second${liveLabelSuffix}`
|
|
8394
|
+
}
|
|
8395
|
+
) : /* @__PURE__ */ jsx(
|
|
8396
|
+
reactNative.View,
|
|
8397
|
+
{
|
|
8398
|
+
style: barStyle,
|
|
8399
|
+
testID: `velocity-bar-${i}`,
|
|
8400
|
+
accessibilityRole: "image",
|
|
8401
|
+
accessibilityLabel: `Rep ${i + 1}: ${formatVelocity(v)} meters per second`
|
|
8402
|
+
}
|
|
8403
|
+
);
|
|
8404
|
+
const bar = /* @__PURE__ */ jsxs(
|
|
7968
8405
|
reactNative.View,
|
|
7969
8406
|
{
|
|
7970
8407
|
style: { flex: 1, height: "100%", justifyContent: "flex-end", position: "relative" },
|
|
@@ -7972,27 +8409,13 @@ function VelocityStrip({
|
|
|
7972
8409
|
expanded && /* @__PURE__ */ jsx(reactNative.Animated.View, { style: { opacity: labelOpacity, alignItems: "center", position: "absolute", top: -13, left: 0, right: 0 }, accessibilityElementsHidden: true, children: /* @__PURE__ */ jsx(
|
|
7973
8410
|
reactNative.Text,
|
|
7974
8411
|
{
|
|
7975
|
-
|
|
8412
|
+
className: "text-text-secondary",
|
|
8413
|
+
style: { fontSize: 8, fontWeight: "600" },
|
|
7976
8414
|
testID: `velocity-label-${i}`,
|
|
7977
8415
|
children: formatVelocity(v)
|
|
7978
8416
|
}
|
|
7979
8417
|
) }),
|
|
7980
|
-
|
|
7981
|
-
reactNative.View,
|
|
7982
|
-
{
|
|
7983
|
-
style: expanded ? { height: `${barHeightPct}%`, minHeight: 2, borderTopLeftRadius: 2, borderTopRightRadius: 2, backgroundColor: zoneHexMap[zone] } : {
|
|
7984
|
-
minHeight: "100%",
|
|
7985
|
-
borderTopLeftRadius: 2,
|
|
7986
|
-
borderTopRightRadius: 2,
|
|
7987
|
-
borderBottomLeftRadius: 0,
|
|
7988
|
-
borderBottomRightRadius: 0,
|
|
7989
|
-
backgroundColor: zoneHexMap[zone]
|
|
7990
|
-
},
|
|
7991
|
-
testID: `velocity-bar-${i}`,
|
|
7992
|
-
accessibilityRole: "image",
|
|
7993
|
-
accessibilityLabel: `Rep ${i + 1}: ${formatVelocity(v)} meters per second`
|
|
7994
|
-
}
|
|
7995
|
-
)
|
|
8418
|
+
barInner
|
|
7996
8419
|
]
|
|
7997
8420
|
},
|
|
7998
8421
|
i
|
|
@@ -8032,9 +8455,9 @@ function VelocityStrip({
|
|
|
8032
8455
|
/* @__PURE__ */ jsxs(
|
|
8033
8456
|
reactNative.Text,
|
|
8034
8457
|
{
|
|
8458
|
+
className: "text-text-secondary",
|
|
8035
8459
|
style: {
|
|
8036
8460
|
fontSize: 10,
|
|
8037
|
-
color: "var(--color-text-secondary)",
|
|
8038
8461
|
fontFamily: "Inter, sans-serif"
|
|
8039
8462
|
},
|
|
8040
8463
|
children: [
|
|
@@ -8050,9 +8473,9 @@ function VelocityStrip({
|
|
|
8050
8473
|
/* @__PURE__ */ jsxs(
|
|
8051
8474
|
reactNative.Text,
|
|
8052
8475
|
{
|
|
8476
|
+
className: "text-text-secondary",
|
|
8053
8477
|
style: {
|
|
8054
8478
|
fontSize: 10,
|
|
8055
|
-
color: "var(--color-text-secondary)",
|
|
8056
8479
|
fontFamily: "Inter, sans-serif",
|
|
8057
8480
|
...getLossStyle(loss)
|
|
8058
8481
|
},
|
|
@@ -8102,16 +8525,14 @@ function MuscleGroupChip({
|
|
|
8102
8525
|
const content = /* @__PURE__ */ jsxs(
|
|
8103
8526
|
reactNative.View,
|
|
8104
8527
|
{
|
|
8105
|
-
className,
|
|
8528
|
+
className: ["bg-surface-raised border-border", className].filter(Boolean).join(" "),
|
|
8106
8529
|
style: {
|
|
8107
8530
|
flexDirection: "row",
|
|
8108
8531
|
alignItems: "center",
|
|
8109
8532
|
borderRadius: 9999,
|
|
8110
8533
|
paddingHorizontal: 9,
|
|
8111
8534
|
paddingVertical: 3,
|
|
8112
|
-
|
|
8113
|
-
borderWidth: 1,
|
|
8114
|
-
borderColor: "var(--color-border-default)"
|
|
8535
|
+
borderWidth: 1
|
|
8115
8536
|
},
|
|
8116
8537
|
accessibilityLabel: onPress ? void 0 : `${name}, volume status: ${statusLabel}`,
|
|
8117
8538
|
testID: "muscle-group-chip",
|
|
@@ -8135,11 +8556,11 @@ function MuscleGroupChip({
|
|
|
8135
8556
|
/* @__PURE__ */ jsx(
|
|
8136
8557
|
reactNative.Text,
|
|
8137
8558
|
{
|
|
8559
|
+
className: "text-text-secondary",
|
|
8138
8560
|
style: {
|
|
8139
8561
|
fontFamily: "Inter, sans-serif",
|
|
8140
8562
|
fontWeight: "500",
|
|
8141
|
-
fontSize: 11
|
|
8142
|
-
color: "var(--color-text-secondary)"
|
|
8563
|
+
fontSize: 11
|
|
8143
8564
|
},
|
|
8144
8565
|
accessibilityElementsHidden: true,
|
|
8145
8566
|
children: name
|
|
@@ -8327,6 +8748,8 @@ function SetRow({
|
|
|
8327
8748
|
rpe,
|
|
8328
8749
|
unit,
|
|
8329
8750
|
velocities,
|
|
8751
|
+
velocityZones,
|
|
8752
|
+
velocityLiveRepIndex,
|
|
8330
8753
|
velocityExpanded,
|
|
8331
8754
|
onVelocityToggle,
|
|
8332
8755
|
setType,
|
|
@@ -8389,11 +8812,11 @@ function SetRow({
|
|
|
8389
8812
|
) : /* @__PURE__ */ jsx(
|
|
8390
8813
|
reactNative.Text,
|
|
8391
8814
|
{
|
|
8815
|
+
className: "text-text-secondary",
|
|
8392
8816
|
style: {
|
|
8393
8817
|
fontSize: 13,
|
|
8394
8818
|
fontWeight: "600",
|
|
8395
|
-
fontFamily: "Inter, sans-serif"
|
|
8396
|
-
color: "var(--color-text-secondary)"
|
|
8819
|
+
fontFamily: "Inter, sans-serif"
|
|
8397
8820
|
},
|
|
8398
8821
|
children: setNumber
|
|
8399
8822
|
}
|
|
@@ -8408,10 +8831,10 @@ function SetRow({
|
|
|
8408
8831
|
children: /* @__PURE__ */ jsx(
|
|
8409
8832
|
reactNative.Text,
|
|
8410
8833
|
{
|
|
8834
|
+
className: "text-text-secondary",
|
|
8411
8835
|
style: {
|
|
8412
8836
|
fontSize: 12,
|
|
8413
|
-
fontFamily: "Inter, sans-serif"
|
|
8414
|
-
color: "var(--color-text-secondary)"
|
|
8837
|
+
fontFamily: "Inter, sans-serif"
|
|
8415
8838
|
},
|
|
8416
8839
|
children: previous ? `${previous.reps} x ${roundWeight(previous.weight)}` : "\u2014"
|
|
8417
8840
|
}
|
|
@@ -8426,11 +8849,11 @@ function SetRow({
|
|
|
8426
8849
|
children: isActive && reps == null && targets ? /* @__PURE__ */ jsx(
|
|
8427
8850
|
reactNative.Text,
|
|
8428
8851
|
{
|
|
8852
|
+
className: "text-text-tertiary",
|
|
8429
8853
|
style: {
|
|
8430
8854
|
fontSize: 13,
|
|
8431
8855
|
fontStyle: "italic",
|
|
8432
|
-
fontFamily: "Inter, sans-serif"
|
|
8433
|
-
color: "var(--color-text-tertiary)"
|
|
8856
|
+
fontFamily: "Inter, sans-serif"
|
|
8434
8857
|
},
|
|
8435
8858
|
testID: "set-row-target-reps",
|
|
8436
8859
|
children: targets.reps
|
|
@@ -8438,11 +8861,11 @@ function SetRow({
|
|
|
8438
8861
|
) : /* @__PURE__ */ jsx(
|
|
8439
8862
|
reactNative.Text,
|
|
8440
8863
|
{
|
|
8864
|
+
className: reps != null ? "text-text-primary" : "text-text-tertiary",
|
|
8441
8865
|
style: {
|
|
8442
8866
|
fontSize: 14,
|
|
8443
8867
|
fontWeight: "600",
|
|
8444
|
-
fontFamily: "Inter, sans-serif"
|
|
8445
|
-
color: reps != null ? "var(--color-text-primary)" : "var(--color-text-tertiary)"
|
|
8868
|
+
fontFamily: "Inter, sans-serif"
|
|
8446
8869
|
},
|
|
8447
8870
|
children: reps != null ? reps : "\u2014"
|
|
8448
8871
|
}
|
|
@@ -8457,11 +8880,11 @@ function SetRow({
|
|
|
8457
8880
|
children: isActive && weight == null && targets ? /* @__PURE__ */ jsx(
|
|
8458
8881
|
reactNative.Text,
|
|
8459
8882
|
{
|
|
8883
|
+
className: "text-text-tertiary",
|
|
8460
8884
|
style: {
|
|
8461
8885
|
fontSize: 13,
|
|
8462
8886
|
fontStyle: "italic",
|
|
8463
|
-
fontFamily: "Inter, sans-serif"
|
|
8464
|
-
color: "var(--color-text-tertiary)"
|
|
8887
|
+
fontFamily: "Inter, sans-serif"
|
|
8465
8888
|
},
|
|
8466
8889
|
testID: "set-row-target-weight",
|
|
8467
8890
|
children: roundWeight(targets.weight)
|
|
@@ -8469,11 +8892,11 @@ function SetRow({
|
|
|
8469
8892
|
) : /* @__PURE__ */ jsx(
|
|
8470
8893
|
reactNative.Text,
|
|
8471
8894
|
{
|
|
8895
|
+
className: weight != null ? "text-text-primary" : "text-text-tertiary",
|
|
8472
8896
|
style: {
|
|
8473
8897
|
fontSize: 14,
|
|
8474
8898
|
fontWeight: "600",
|
|
8475
|
-
fontFamily: "Inter, sans-serif"
|
|
8476
|
-
color: weight != null ? "var(--color-text-primary)" : "var(--color-text-tertiary)"
|
|
8899
|
+
fontFamily: "Inter, sans-serif"
|
|
8477
8900
|
},
|
|
8478
8901
|
children: weight != null ? roundWeight(weight) : "\u2014"
|
|
8479
8902
|
}
|
|
@@ -8488,11 +8911,14 @@ function SetRow({
|
|
|
8488
8911
|
children: /* @__PURE__ */ jsx(
|
|
8489
8912
|
reactNative.Text,
|
|
8490
8913
|
{
|
|
8914
|
+
className: rpe != null ? void 0 : "text-text-tertiary",
|
|
8491
8915
|
style: {
|
|
8492
8916
|
fontSize: 13,
|
|
8493
8917
|
fontWeight: "600",
|
|
8494
8918
|
fontFamily: "Inter, sans-serif",
|
|
8495
|
-
|
|
8919
|
+
// rpeColor returns a concrete hex (native-safe); only the tertiary
|
|
8920
|
+
// fallback needs the className token.
|
|
8921
|
+
color: rpe != null ? rpeColor(rpe) : void 0
|
|
8496
8922
|
},
|
|
8497
8923
|
children: rpe != null ? roundRpe(rpe) : "\u2014"
|
|
8498
8924
|
}
|
|
@@ -8526,6 +8952,8 @@ function SetRow({
|
|
|
8526
8952
|
VelocityStrip,
|
|
8527
8953
|
{
|
|
8528
8954
|
velocities,
|
|
8955
|
+
zones: velocityZones,
|
|
8956
|
+
liveRepIndex: velocityLiveRepIndex,
|
|
8529
8957
|
expanded: velocityExpanded,
|
|
8530
8958
|
onToggle: onVelocityToggle,
|
|
8531
8959
|
variant: onVelocityToggle ? "full" : "mini"
|
|
@@ -8538,18 +8966,14 @@ function SetRow({
|
|
|
8538
8966
|
);
|
|
8539
8967
|
}
|
|
8540
8968
|
var BRAND_PRIMARY2 = "#FF7900";
|
|
8541
|
-
var
|
|
8542
|
-
var TEXT_TERTIARY2 = "var(--color-text-tertiary)";
|
|
8969
|
+
var INPUT_CLASSNAME = "bg-surface-raised border-border-strong text-text-primary";
|
|
8543
8970
|
var inputStyle = {
|
|
8544
8971
|
fontSize: 14,
|
|
8545
8972
|
fontWeight: "600",
|
|
8546
8973
|
fontFamily: "Inter, sans-serif",
|
|
8547
|
-
backgroundColor: "var(--color-surface-raised)",
|
|
8548
8974
|
borderWidth: 1,
|
|
8549
|
-
borderColor: "var(--color-border-strong)",
|
|
8550
8975
|
borderRadius: 6,
|
|
8551
8976
|
textAlign: "center",
|
|
8552
|
-
color: TEXT_PRIMARY,
|
|
8553
8977
|
paddingVertical: 5,
|
|
8554
8978
|
paddingHorizontal: 2
|
|
8555
8979
|
};
|
|
@@ -8571,11 +8995,11 @@ function InputBar({
|
|
|
8571
8995
|
return /* @__PURE__ */ jsxs(
|
|
8572
8996
|
reactNative.View,
|
|
8573
8997
|
{
|
|
8998
|
+
className: "bg-surface-elevated",
|
|
8574
8999
|
style: {
|
|
8575
9000
|
width: "100%",
|
|
8576
|
-
backgroundColor: "var(--color-surface-elevated)",
|
|
8577
9001
|
borderTopWidth: 1,
|
|
8578
|
-
borderTopColor: "
|
|
9002
|
+
borderTopColor: resolveColor("border-default"),
|
|
8579
9003
|
paddingTop: 10,
|
|
8580
9004
|
paddingHorizontal: 16,
|
|
8581
9005
|
paddingBottom: 12,
|
|
@@ -8590,11 +9014,11 @@ function InputBar({
|
|
|
8590
9014
|
/* @__PURE__ */ jsx(
|
|
8591
9015
|
reactNative.Text,
|
|
8592
9016
|
{
|
|
9017
|
+
className: "text-text-primary",
|
|
8593
9018
|
style: {
|
|
8594
9019
|
fontSize: 12,
|
|
8595
9020
|
fontWeight: "700",
|
|
8596
|
-
fontFamily: '"Space Grotesk", sans-serif'
|
|
8597
|
-
color: TEXT_PRIMARY
|
|
9021
|
+
fontFamily: '"Space Grotesk", sans-serif'
|
|
8598
9022
|
},
|
|
8599
9023
|
testID: "input-bar-exercise-name",
|
|
8600
9024
|
numberOfLines: 1,
|
|
@@ -8604,10 +9028,10 @@ function InputBar({
|
|
|
8604
9028
|
/* @__PURE__ */ jsx(
|
|
8605
9029
|
reactNative.Text,
|
|
8606
9030
|
{
|
|
9031
|
+
className: "text-text-tertiary",
|
|
8607
9032
|
style: {
|
|
8608
9033
|
fontSize: 10,
|
|
8609
|
-
fontFamily: "Inter, sans-serif"
|
|
8610
|
-
color: TEXT_TERTIARY2
|
|
9034
|
+
fontFamily: "Inter, sans-serif"
|
|
8611
9035
|
},
|
|
8612
9036
|
testID: "input-bar-set-info",
|
|
8613
9037
|
children: setLabel
|
|
@@ -8620,6 +9044,7 @@ function InputBar({
|
|
|
8620
9044
|
{
|
|
8621
9045
|
value: reps,
|
|
8622
9046
|
onChangeText: onRepsChange,
|
|
9047
|
+
className: INPUT_CLASSNAME,
|
|
8623
9048
|
style: { ...inputStyle, width: 36 },
|
|
8624
9049
|
accessibilityLabel: "Reps",
|
|
8625
9050
|
testID: "input-bar-reps",
|
|
@@ -8629,10 +9054,10 @@ function InputBar({
|
|
|
8629
9054
|
/* @__PURE__ */ jsx(
|
|
8630
9055
|
reactNative.Text,
|
|
8631
9056
|
{
|
|
9057
|
+
className: "text-text-tertiary",
|
|
8632
9058
|
style: {
|
|
8633
9059
|
fontSize: 12,
|
|
8634
|
-
fontFamily: "Inter, sans-serif"
|
|
8635
|
-
color: TEXT_TERTIARY2
|
|
9060
|
+
fontFamily: "Inter, sans-serif"
|
|
8636
9061
|
},
|
|
8637
9062
|
children: "\xD7"
|
|
8638
9063
|
}
|
|
@@ -8642,6 +9067,7 @@ function InputBar({
|
|
|
8642
9067
|
{
|
|
8643
9068
|
value: weight,
|
|
8644
9069
|
onChangeText: onWeightChange,
|
|
9070
|
+
className: INPUT_CLASSNAME,
|
|
8645
9071
|
style: { ...inputStyle, width: 52 },
|
|
8646
9072
|
accessibilityLabel: `Weight in ${unit}`,
|
|
8647
9073
|
testID: "input-bar-weight",
|
|
@@ -8651,11 +9077,11 @@ function InputBar({
|
|
|
8651
9077
|
/* @__PURE__ */ jsx(
|
|
8652
9078
|
reactNative.Text,
|
|
8653
9079
|
{
|
|
9080
|
+
className: "text-text-tertiary",
|
|
8654
9081
|
style: {
|
|
8655
9082
|
fontSize: 12,
|
|
8656
9083
|
fontWeight: "500",
|
|
8657
|
-
fontFamily: "Inter, sans-serif"
|
|
8658
|
-
color: TEXT_TERTIARY2
|
|
9084
|
+
fontFamily: "Inter, sans-serif"
|
|
8659
9085
|
},
|
|
8660
9086
|
testID: "input-bar-unit",
|
|
8661
9087
|
children: unit
|
|
@@ -8702,7 +9128,8 @@ function RestTimer({
|
|
|
8702
9128
|
onSkip,
|
|
8703
9129
|
onAddTime,
|
|
8704
9130
|
nextSetInfo,
|
|
8705
|
-
visible
|
|
9131
|
+
visible,
|
|
9132
|
+
displayOnly = false
|
|
8706
9133
|
}) {
|
|
8707
9134
|
if (!visible) return null;
|
|
8708
9135
|
const remainingMs = Math.max(0, totalSeconds * 1e3 - elapsedMs);
|
|
@@ -8715,11 +9142,11 @@ function RestTimer({
|
|
|
8715
9142
|
return /* @__PURE__ */ jsxs(
|
|
8716
9143
|
reactNative.View,
|
|
8717
9144
|
{
|
|
9145
|
+
className: "bg-surface-raised",
|
|
8718
9146
|
style: {
|
|
8719
9147
|
width: "100%",
|
|
8720
|
-
backgroundColor: "var(--color-surface-raised)",
|
|
8721
9148
|
borderTopWidth: 1,
|
|
8722
|
-
borderTopColor: "
|
|
9149
|
+
borderTopColor: resolveColor("border-default"),
|
|
8723
9150
|
paddingVertical: 12,
|
|
8724
9151
|
paddingHorizontal: 16
|
|
8725
9152
|
},
|
|
@@ -8741,13 +9168,13 @@ function RestTimer({
|
|
|
8741
9168
|
/* @__PURE__ */ jsx(
|
|
8742
9169
|
reactNative.Text,
|
|
8743
9170
|
{
|
|
9171
|
+
className: "text-text-secondary",
|
|
8744
9172
|
style: {
|
|
8745
9173
|
fontSize: 11,
|
|
8746
9174
|
fontFamily: "Inter, sans-serif",
|
|
8747
9175
|
fontWeight: "600",
|
|
8748
9176
|
textTransform: "uppercase",
|
|
8749
|
-
letterSpacing: 1
|
|
8750
|
-
color: "var(--color-text-secondary)"
|
|
9177
|
+
letterSpacing: 1
|
|
8751
9178
|
},
|
|
8752
9179
|
testID: "rest-timer-label",
|
|
8753
9180
|
children: "REST"
|
|
@@ -8756,10 +9183,10 @@ function RestTimer({
|
|
|
8756
9183
|
nextSetInfo != null && /* @__PURE__ */ jsx(
|
|
8757
9184
|
reactNative.Text,
|
|
8758
9185
|
{
|
|
9186
|
+
className: "text-text-tertiary",
|
|
8759
9187
|
style: {
|
|
8760
9188
|
fontSize: 11,
|
|
8761
9189
|
fontFamily: "Inter, sans-serif",
|
|
8762
|
-
color: "var(--color-text-tertiary)",
|
|
8763
9190
|
marginTop: 2
|
|
8764
9191
|
},
|
|
8765
9192
|
testID: "rest-timer-next-set",
|
|
@@ -8770,11 +9197,11 @@ function RestTimer({
|
|
|
8770
9197
|
/* @__PURE__ */ jsx(
|
|
8771
9198
|
reactNative.Text,
|
|
8772
9199
|
{
|
|
9200
|
+
className: "text-text-primary",
|
|
8773
9201
|
style: {
|
|
8774
9202
|
fontSize: 28,
|
|
8775
9203
|
fontFamily: '"Space Grotesk", sans-serif',
|
|
8776
9204
|
fontWeight: "700",
|
|
8777
|
-
color: "var(--color-text-primary)",
|
|
8778
9205
|
fontVariant: ["tabular-nums"],
|
|
8779
9206
|
letterSpacing: -0.5
|
|
8780
9207
|
},
|
|
@@ -8788,9 +9215,9 @@ function RestTimer({
|
|
|
8788
9215
|
/* @__PURE__ */ jsx(
|
|
8789
9216
|
reactNative.View,
|
|
8790
9217
|
{
|
|
9218
|
+
className: "bg-border",
|
|
8791
9219
|
style: {
|
|
8792
9220
|
height: 3,
|
|
8793
|
-
backgroundColor: "var(--color-border-default)",
|
|
8794
9221
|
borderRadius: 2,
|
|
8795
9222
|
marginBottom: 12
|
|
8796
9223
|
},
|
|
@@ -8809,7 +9236,7 @@ function RestTimer({
|
|
|
8809
9236
|
)
|
|
8810
9237
|
}
|
|
8811
9238
|
),
|
|
8812
|
-
/* @__PURE__ */ jsxs(reactNative.View, { style: { flexDirection: "row", gap: 8 }, children: [
|
|
9239
|
+
!displayOnly && /* @__PURE__ */ jsxs(reactNative.View, { style: { flexDirection: "row", gap: 8 }, children: [
|
|
8813
9240
|
/* @__PURE__ */ jsx(
|
|
8814
9241
|
reactNative.Pressable,
|
|
8815
9242
|
{
|
|
@@ -8826,11 +9253,11 @@ function RestTimer({
|
|
|
8826
9253
|
children: /* @__PURE__ */ jsx(
|
|
8827
9254
|
reactNative.Text,
|
|
8828
9255
|
{
|
|
9256
|
+
className: "text-text-secondary",
|
|
8829
9257
|
style: {
|
|
8830
9258
|
fontSize: 11,
|
|
8831
9259
|
fontFamily: "Inter, sans-serif",
|
|
8832
|
-
fontWeight: "600"
|
|
8833
|
-
color: "var(--color-text-secondary)"
|
|
9260
|
+
fontWeight: "600"
|
|
8834
9261
|
},
|
|
8835
9262
|
children: "+30s"
|
|
8836
9263
|
}
|
|
@@ -8869,19 +9296,6 @@ function RestTimer({
|
|
|
8869
9296
|
}
|
|
8870
9297
|
);
|
|
8871
9298
|
}
|
|
8872
|
-
var COLORS = {
|
|
8873
|
-
// Theme-aware tokens: text foregrounds and this card's own surfaces/borders
|
|
8874
|
-
// must flip together so text stays readable in both light and dark. The
|
|
8875
|
-
// expanded/pressed surfaces are self-owned here (not from a themed Card), so
|
|
8876
|
-
// hardcoding dark values would leave dark-on-dark once the text flips.
|
|
8877
|
-
// react-native-web passes the CSS var through to the inline style.
|
|
8878
|
-
textPrimary: "var(--color-text-primary)",
|
|
8879
|
-
textSecondary: "var(--color-text-secondary)",
|
|
8880
|
-
textTertiary: "var(--color-text-tertiary)",
|
|
8881
|
-
surfaceRaised: "var(--color-surface-raised)",
|
|
8882
|
-
surfaceElevated: "var(--color-surface-elevated)",
|
|
8883
|
-
borderDefault: "var(--color-border-default)"
|
|
8884
|
-
};
|
|
8885
9299
|
function buildColumnHeaders(unit) {
|
|
8886
9300
|
return ["SET", "PREV", "REPS", unit.toUpperCase(), "RPE"];
|
|
8887
9301
|
}
|
|
@@ -8939,6 +9353,7 @@ function CollapsedCard({
|
|
|
8939
9353
|
e1rm,
|
|
8940
9354
|
isPR,
|
|
8941
9355
|
setVelocities,
|
|
9356
|
+
velocityZones,
|
|
8942
9357
|
totalPlannedSets,
|
|
8943
9358
|
supersetPosition
|
|
8944
9359
|
}) {
|
|
@@ -8959,11 +9374,11 @@ function CollapsedCard({
|
|
|
8959
9374
|
children: /* @__PURE__ */ jsxs(
|
|
8960
9375
|
reactNative.View,
|
|
8961
9376
|
{
|
|
9377
|
+
className: pressed ? "bg-surface-raised" : void 0,
|
|
8962
9378
|
style: {
|
|
8963
9379
|
padding: 12,
|
|
8964
9380
|
paddingHorizontal: 14,
|
|
8965
9381
|
cursor: "pointer",
|
|
8966
|
-
backgroundColor: pressed ? COLORS.surfaceRaised : "transparent",
|
|
8967
9382
|
...borderRadius,
|
|
8968
9383
|
...supersetMargin
|
|
8969
9384
|
},
|
|
@@ -8977,11 +9392,11 @@ function CollapsedCard({
|
|
|
8977
9392
|
/* @__PURE__ */ jsx(
|
|
8978
9393
|
reactNative.Text,
|
|
8979
9394
|
{
|
|
9395
|
+
className: "text-text-primary",
|
|
8980
9396
|
style: {
|
|
8981
9397
|
fontSize: 14,
|
|
8982
9398
|
fontFamily: '"Space Grotesk", sans-serif',
|
|
8983
|
-
fontWeight: "700"
|
|
8984
|
-
color: COLORS.textPrimary
|
|
9399
|
+
fontWeight: "700"
|
|
8985
9400
|
},
|
|
8986
9401
|
testID: "exercise-card-name",
|
|
8987
9402
|
children: name
|
|
@@ -8991,10 +9406,10 @@ function CollapsedCard({
|
|
|
8991
9406
|
summary && /* @__PURE__ */ jsx(
|
|
8992
9407
|
reactNative.Text,
|
|
8993
9408
|
{
|
|
9409
|
+
className: "text-text-secondary",
|
|
8994
9410
|
style: {
|
|
8995
9411
|
fontSize: 12,
|
|
8996
9412
|
fontFamily: "Inter, sans-serif",
|
|
8997
|
-
color: COLORS.textSecondary,
|
|
8998
9413
|
marginRight: 8
|
|
8999
9414
|
},
|
|
9000
9415
|
testID: "exercise-card-summary",
|
|
@@ -9026,6 +9441,7 @@ function CollapsedCard({
|
|
|
9026
9441
|
VelocityStrip,
|
|
9027
9442
|
{
|
|
9028
9443
|
velocities,
|
|
9444
|
+
zones: velocityZones,
|
|
9029
9445
|
variant: "mini",
|
|
9030
9446
|
testID: `exercise-card-velocity-strip-${i}`
|
|
9031
9447
|
},
|
|
@@ -9064,10 +9480,9 @@ function ExpandedCard({
|
|
|
9064
9480
|
return /* @__PURE__ */ jsxs(
|
|
9065
9481
|
reactNative.View,
|
|
9066
9482
|
{
|
|
9483
|
+
className: "bg-surface-elevated border-border",
|
|
9067
9484
|
style: {
|
|
9068
|
-
backgroundColor: COLORS.surfaceElevated,
|
|
9069
9485
|
borderWidth: 1,
|
|
9070
|
-
borderColor: COLORS.borderDefault,
|
|
9071
9486
|
...borderRadius,
|
|
9072
9487
|
...supersetMargin
|
|
9073
9488
|
},
|
|
@@ -9090,17 +9505,17 @@ function ExpandedCard({
|
|
|
9090
9505
|
paddingHorizontal: 14,
|
|
9091
9506
|
paddingBottom: 10,
|
|
9092
9507
|
borderBottomWidth: 1,
|
|
9093
|
-
borderBottomColor:
|
|
9508
|
+
borderBottomColor: resolveColor("border-default")
|
|
9094
9509
|
},
|
|
9095
9510
|
children: [
|
|
9096
9511
|
/* @__PURE__ */ jsx(
|
|
9097
9512
|
reactNative.Text,
|
|
9098
9513
|
{
|
|
9514
|
+
className: "text-text-primary",
|
|
9099
9515
|
style: {
|
|
9100
9516
|
fontSize: 14,
|
|
9101
9517
|
fontFamily: '"Space Grotesk", sans-serif',
|
|
9102
|
-
fontWeight: "700"
|
|
9103
|
-
color: COLORS.textPrimary
|
|
9518
|
+
fontWeight: "700"
|
|
9104
9519
|
},
|
|
9105
9520
|
testID: "exercise-card-name",
|
|
9106
9521
|
children: name
|
|
@@ -9110,10 +9525,10 @@ function ExpandedCard({
|
|
|
9110
9525
|
summary && /* @__PURE__ */ jsx(
|
|
9111
9526
|
reactNative.Text,
|
|
9112
9527
|
{
|
|
9528
|
+
className: "text-text-secondary",
|
|
9113
9529
|
style: {
|
|
9114
9530
|
fontSize: 12,
|
|
9115
9531
|
fontFamily: "Inter, sans-serif",
|
|
9116
|
-
color: COLORS.textSecondary,
|
|
9117
9532
|
marginRight: 8
|
|
9118
9533
|
},
|
|
9119
9534
|
testID: "exercise-card-summary",
|
|
@@ -9164,13 +9579,13 @@ function ExpandedCard({
|
|
|
9164
9579
|
children: /* @__PURE__ */ jsx(
|
|
9165
9580
|
reactNative.Text,
|
|
9166
9581
|
{
|
|
9582
|
+
className: "text-text-tertiary",
|
|
9167
9583
|
style: {
|
|
9168
9584
|
fontSize: 10,
|
|
9169
9585
|
fontWeight: "600",
|
|
9170
9586
|
fontFamily: "Inter, sans-serif",
|
|
9171
9587
|
textTransform: "uppercase",
|
|
9172
|
-
letterSpacing: 0.8
|
|
9173
|
-
color: COLORS.textTertiary
|
|
9588
|
+
letterSpacing: 0.8
|
|
9174
9589
|
},
|
|
9175
9590
|
children: header
|
|
9176
9591
|
}
|
|
@@ -9210,11 +9625,11 @@ function UpcomingCard({
|
|
|
9210
9625
|
/* @__PURE__ */ jsx(
|
|
9211
9626
|
reactNative.Text,
|
|
9212
9627
|
{
|
|
9628
|
+
className: "text-text-primary",
|
|
9213
9629
|
style: {
|
|
9214
9630
|
fontSize: 14,
|
|
9215
9631
|
fontFamily: '"Space Grotesk", sans-serif',
|
|
9216
|
-
fontWeight: "700"
|
|
9217
|
-
color: COLORS.textPrimary
|
|
9632
|
+
fontWeight: "700"
|
|
9218
9633
|
},
|
|
9219
9634
|
testID: "exercise-card-name",
|
|
9220
9635
|
children: name
|
|
@@ -9223,10 +9638,10 @@ function UpcomingCard({
|
|
|
9223
9638
|
prescription && /* @__PURE__ */ jsx(
|
|
9224
9639
|
reactNative.Text,
|
|
9225
9640
|
{
|
|
9641
|
+
className: "text-text-secondary",
|
|
9226
9642
|
style: {
|
|
9227
9643
|
fontSize: 12,
|
|
9228
9644
|
fontFamily: "Inter, sans-serif",
|
|
9229
|
-
color: COLORS.textSecondary,
|
|
9230
9645
|
marginLeft: 8
|
|
9231
9646
|
},
|
|
9232
9647
|
testID: "exercise-card-prescription",
|
|
@@ -9237,10 +9652,10 @@ function UpcomingCard({
|
|
|
9237
9652
|
previousBest && /* @__PURE__ */ jsx(
|
|
9238
9653
|
reactNative.Text,
|
|
9239
9654
|
{
|
|
9655
|
+
className: "text-text-tertiary",
|
|
9240
9656
|
style: {
|
|
9241
9657
|
fontSize: 11,
|
|
9242
|
-
fontFamily: "Inter, sans-serif"
|
|
9243
|
-
color: COLORS.textTertiary
|
|
9658
|
+
fontFamily: "Inter, sans-serif"
|
|
9244
9659
|
},
|
|
9245
9660
|
testID: "exercise-card-previous-best",
|
|
9246
9661
|
children: previousBest
|
|
@@ -9478,11 +9893,12 @@ function WeekRow({
|
|
|
9478
9893
|
/* @__PURE__ */ jsx(
|
|
9479
9894
|
reactNative.Text,
|
|
9480
9895
|
{
|
|
9896
|
+
className: isCurrent ? void 0 : "text-text-primary",
|
|
9481
9897
|
style: {
|
|
9482
9898
|
fontSize: 13,
|
|
9483
9899
|
fontWeight: "700",
|
|
9484
9900
|
fontFamily: "Inter, sans-serif",
|
|
9485
|
-
color: isCurrent ? BRAND_PRIMARY5 :
|
|
9901
|
+
color: isCurrent ? BRAND_PRIMARY5 : void 0
|
|
9486
9902
|
},
|
|
9487
9903
|
accessibilityElementsHidden: true,
|
|
9488
9904
|
children: `W${weekNumber}`
|
|
@@ -9521,21 +9937,16 @@ function WeekRow({
|
|
|
9521
9937
|
}
|
|
9522
9938
|
);
|
|
9523
9939
|
}
|
|
9524
|
-
var
|
|
9525
|
-
// Theme-aware foregrounds: resolve to a readable color in both light and dark
|
|
9526
|
-
// (react-native-web passes the CSS var through to the inline style).
|
|
9527
|
-
textPrimary: "var(--color-text-primary)",
|
|
9528
|
-
textSecondary: "var(--color-text-secondary)",
|
|
9529
|
-
textTertiary: "var(--color-text-tertiary)",
|
|
9940
|
+
var COLORS = {
|
|
9530
9941
|
statusSuccess: "#14B8A6",
|
|
9531
9942
|
brandPrimary: "#FF7900",
|
|
9532
9943
|
borderDefault: "#1F1F1F",
|
|
9533
9944
|
brandPrimarySubtle: "rgba(255,121,0,0.06)"
|
|
9534
9945
|
};
|
|
9535
9946
|
var statusBorderColors = {
|
|
9536
|
-
completed:
|
|
9537
|
-
today:
|
|
9538
|
-
upcoming:
|
|
9947
|
+
completed: COLORS.statusSuccess,
|
|
9948
|
+
today: COLORS.brandPrimary,
|
|
9949
|
+
upcoming: COLORS.borderDefault
|
|
9539
9950
|
};
|
|
9540
9951
|
var volumeStatusMap = {
|
|
9541
9952
|
under: "behind",
|
|
@@ -9572,11 +9983,11 @@ function WorkoutCard({
|
|
|
9572
9983
|
/* @__PURE__ */ jsx(
|
|
9573
9984
|
reactNative.Text,
|
|
9574
9985
|
{
|
|
9986
|
+
className: "text-text-primary",
|
|
9575
9987
|
style: {
|
|
9576
9988
|
fontSize: 15,
|
|
9577
9989
|
fontFamily: '"Space Grotesk", sans-serif',
|
|
9578
|
-
fontWeight: "700"
|
|
9579
|
-
color: COLORS2.textPrimary
|
|
9990
|
+
fontWeight: "700"
|
|
9580
9991
|
},
|
|
9581
9992
|
testID: "workout-card-name",
|
|
9582
9993
|
children: name
|
|
@@ -9586,10 +9997,10 @@ function WorkoutCard({
|
|
|
9586
9997
|
/* @__PURE__ */ jsx(
|
|
9587
9998
|
reactNative.Text,
|
|
9588
9999
|
{
|
|
10000
|
+
className: "text-text-tertiary",
|
|
9589
10001
|
style: {
|
|
9590
10002
|
fontSize: 11,
|
|
9591
|
-
fontFamily: "Inter, sans-serif"
|
|
9592
|
-
color: COLORS2.textTertiary
|
|
10003
|
+
fontFamily: "Inter, sans-serif"
|
|
9593
10004
|
},
|
|
9594
10005
|
testID: "workout-card-date",
|
|
9595
10006
|
children: date
|
|
@@ -9599,11 +10010,11 @@ function WorkoutCard({
|
|
|
9599
10010
|
/* @__PURE__ */ jsx(
|
|
9600
10011
|
reactNative.Text,
|
|
9601
10012
|
{
|
|
10013
|
+
className: "text-text-secondary",
|
|
9602
10014
|
style: {
|
|
9603
10015
|
marginTop: 4,
|
|
9604
10016
|
fontSize: 12,
|
|
9605
|
-
fontFamily: "Inter, sans-serif"
|
|
9606
|
-
color: COLORS2.textSecondary
|
|
10017
|
+
fontFamily: "Inter, sans-serif"
|
|
9607
10018
|
},
|
|
9608
10019
|
testID: "workout-card-stats",
|
|
9609
10020
|
children: formatStats(totalSets, totalVolume, unit, duration)
|
|
@@ -9634,7 +10045,7 @@ function WorkoutCard({
|
|
|
9634
10045
|
variant: "accent",
|
|
9635
10046
|
elevation: 1,
|
|
9636
10047
|
accentColor: statusBorderColors[status],
|
|
9637
|
-
bgColor: isToday ?
|
|
10048
|
+
bgColor: isToday ? COLORS.brandPrimarySubtle : void 0,
|
|
9638
10049
|
className,
|
|
9639
10050
|
style: isUpcoming ? { opacity: 0.6 } : void 0,
|
|
9640
10051
|
testID: "workout-card",
|
|
@@ -9674,8 +10085,6 @@ var BRAND_PRIMARY6 = "#FF7900";
|
|
|
9674
10085
|
var BRAND_PRIMARY_DARK = "#C45E00";
|
|
9675
10086
|
var BRAND_PRIMARY_LIGHT = "#FFB066";
|
|
9676
10087
|
var BORDER_DEFAULT = "#1F1F1F";
|
|
9677
|
-
var TEXT_PRIMARY2 = "var(--color-text-primary)";
|
|
9678
|
-
var TEXT_SECONDARY = "var(--color-text-secondary)";
|
|
9679
10088
|
var ACCENT_STOPS = [BRAND_PRIMARY_DARK, BRAND_PRIMARY6, BRAND_PRIMARY_LIGHT];
|
|
9680
10089
|
function heatmapColor(percentage) {
|
|
9681
10090
|
const clamped = Math.max(0, Math.min(100, percentage));
|
|
@@ -9718,11 +10127,11 @@ function MesoCard({
|
|
|
9718
10127
|
/* @__PURE__ */ jsx(
|
|
9719
10128
|
reactNative.Text,
|
|
9720
10129
|
{
|
|
10130
|
+
className: "text-text-primary",
|
|
9721
10131
|
style: {
|
|
9722
10132
|
fontSize: 15,
|
|
9723
10133
|
fontFamily: '"Space Grotesk", sans-serif',
|
|
9724
|
-
fontWeight: "700"
|
|
9725
|
-
color: TEXT_PRIMARY2
|
|
10134
|
+
fontWeight: "700"
|
|
9726
10135
|
},
|
|
9727
10136
|
testID: "meso-card-name",
|
|
9728
10137
|
children: name
|
|
@@ -9733,11 +10142,11 @@ function MesoCard({
|
|
|
9733
10142
|
/* @__PURE__ */ jsx(
|
|
9734
10143
|
reactNative.Text,
|
|
9735
10144
|
{
|
|
10145
|
+
className: "text-text-secondary",
|
|
9736
10146
|
style: {
|
|
9737
10147
|
marginTop: 4,
|
|
9738
10148
|
fontSize: 12,
|
|
9739
|
-
fontFamily: "Inter, sans-serif"
|
|
9740
|
-
color: TEXT_SECONDARY
|
|
10149
|
+
fontFamily: "Inter, sans-serif"
|
|
9741
10150
|
},
|
|
9742
10151
|
testID: "meso-card-subheader",
|
|
9743
10152
|
children: `${split} \xB7 ${weekRange}`
|
|
@@ -9831,11 +10240,7 @@ function MesoCard({
|
|
|
9831
10240
|
var BRAND_PRIMARY7 = "#FF7900";
|
|
9832
10241
|
var RECENT_BORDER = "rgba(255,176,32,0.3)";
|
|
9833
10242
|
var RECENT_GLOW = "0 0 12px rgba(255,176,32,0.06)";
|
|
9834
|
-
var
|
|
9835
|
-
var BORDER_DEFAULT2 = "var(--color-border-default)";
|
|
9836
|
-
var TEXT_PRIMARY3 = "var(--color-text-primary)";
|
|
9837
|
-
var TEXT_SECONDARY2 = "var(--color-text-secondary)";
|
|
9838
|
-
var TEXT_TERTIARY3 = "var(--color-text-tertiary)";
|
|
10243
|
+
var BORDER_DEFAULT2 = resolveColor("border-default");
|
|
9839
10244
|
var TYPE_LABELS = {
|
|
9840
10245
|
e1rm: "e1RM",
|
|
9841
10246
|
weight: "Weight",
|
|
@@ -9861,30 +10266,29 @@ function PrRecordRow({ record, index }) {
|
|
|
9861
10266
|
{
|
|
9862
10267
|
accessibilityRole: "text",
|
|
9863
10268
|
accessibilityLabel: a11yLabel,
|
|
9864
|
-
className: "flex-row items-center",
|
|
10269
|
+
className: "flex-row items-center bg-surface-raised",
|
|
9865
10270
|
style: {
|
|
9866
10271
|
gap: 10,
|
|
9867
10272
|
paddingVertical: 10,
|
|
9868
10273
|
paddingHorizontal: 12,
|
|
9869
10274
|
marginBottom: 8,
|
|
9870
10275
|
borderRadius: 8,
|
|
9871
|
-
backgroundColor: SURFACE_RAISED,
|
|
9872
10276
|
borderWidth: 1,
|
|
9873
10277
|
borderColor: record.isRecent ? RECENT_BORDER : BORDER_DEFAULT2,
|
|
9874
10278
|
...record.isRecent ? { boxShadow: RECENT_GLOW } : {}
|
|
9875
10279
|
},
|
|
9876
10280
|
testID: `pr-history-modal-record-${index}`,
|
|
9877
10281
|
children: [
|
|
9878
|
-
/* @__PURE__ */ jsx(
|
|
10282
|
+
/* @__PURE__ */ jsx(StarIcon, { size: 16, color: BRAND_PRIMARY7, fill: BRAND_PRIMARY7, strokeWidth: 2 }),
|
|
9879
10283
|
/* @__PURE__ */ jsx(
|
|
9880
10284
|
reactNative.Text,
|
|
9881
10285
|
{
|
|
10286
|
+
className: "text-text-secondary",
|
|
9882
10287
|
style: {
|
|
9883
10288
|
flex: 1,
|
|
9884
10289
|
fontSize: 13,
|
|
9885
10290
|
fontFamily: "Inter, sans-serif",
|
|
9886
|
-
fontWeight: "600"
|
|
9887
|
-
color: TEXT_SECONDARY2
|
|
10291
|
+
fontWeight: "600"
|
|
9888
10292
|
},
|
|
9889
10293
|
testID: `pr-history-modal-record-${index}-type`,
|
|
9890
10294
|
children: label
|
|
@@ -9893,11 +10297,11 @@ function PrRecordRow({ record, index }) {
|
|
|
9893
10297
|
/* @__PURE__ */ jsx(
|
|
9894
10298
|
reactNative.Text,
|
|
9895
10299
|
{
|
|
10300
|
+
className: "text-text-primary",
|
|
9896
10301
|
style: {
|
|
9897
10302
|
fontSize: 14,
|
|
9898
10303
|
fontFamily: '"Space Grotesk", sans-serif',
|
|
9899
|
-
fontWeight: "700"
|
|
9900
|
-
color: TEXT_PRIMARY3
|
|
10304
|
+
fontWeight: "700"
|
|
9901
10305
|
},
|
|
9902
10306
|
testID: `pr-history-modal-record-${index}-value`,
|
|
9903
10307
|
children: valueText
|
|
@@ -9906,12 +10310,12 @@ function PrRecordRow({ record, index }) {
|
|
|
9906
10310
|
/* @__PURE__ */ jsx(
|
|
9907
10311
|
reactNative.Text,
|
|
9908
10312
|
{
|
|
10313
|
+
className: "text-text-tertiary",
|
|
9909
10314
|
style: {
|
|
9910
10315
|
minWidth: 64,
|
|
9911
10316
|
textAlign: "right",
|
|
9912
10317
|
fontSize: 11,
|
|
9913
|
-
fontFamily: "Inter, sans-serif"
|
|
9914
|
-
color: TEXT_TERTIARY3
|
|
10318
|
+
fontFamily: "Inter, sans-serif"
|
|
9915
10319
|
},
|
|
9916
10320
|
testID: `pr-history-modal-record-${index}-date`,
|
|
9917
10321
|
children: record.date
|
|
@@ -9949,13 +10353,13 @@ function PrHistoryModal({
|
|
|
9949
10353
|
reactNative.View,
|
|
9950
10354
|
{
|
|
9951
10355
|
accessibilityElementsHidden: true,
|
|
10356
|
+
className: "bg-border",
|
|
9952
10357
|
style: {
|
|
9953
10358
|
alignSelf: "center",
|
|
9954
10359
|
width: 40,
|
|
9955
10360
|
height: 4,
|
|
9956
10361
|
borderRadius: 2,
|
|
9957
|
-
marginTop: 8
|
|
9958
|
-
backgroundColor: BORDER_DEFAULT2
|
|
10362
|
+
marginTop: 8
|
|
9959
10363
|
},
|
|
9960
10364
|
testID: "pr-history-modal-handle"
|
|
9961
10365
|
}
|
|
@@ -9971,11 +10375,11 @@ function PrHistoryModal({
|
|
|
9971
10375
|
reactNative.Text,
|
|
9972
10376
|
{
|
|
9973
10377
|
accessibilityRole: "header",
|
|
10378
|
+
className: "text-text-primary",
|
|
9974
10379
|
style: {
|
|
9975
10380
|
fontSize: 16,
|
|
9976
10381
|
fontFamily: '"Space Grotesk", sans-serif',
|
|
9977
|
-
fontWeight: "700"
|
|
9978
|
-
color: TEXT_PRIMARY3
|
|
10382
|
+
fontWeight: "700"
|
|
9979
10383
|
},
|
|
9980
10384
|
testID: "pr-history-modal-title",
|
|
9981
10385
|
children: dialogLabel
|
|
@@ -9990,7 +10394,7 @@ function PrHistoryModal({
|
|
|
9990
10394
|
hitSlop: 8,
|
|
9991
10395
|
style: { padding: 4, margin: -4 },
|
|
9992
10396
|
testID: "pr-history-modal-close",
|
|
9993
|
-
children: /* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 22, lineHeight: 22
|
|
10397
|
+
children: /* @__PURE__ */ jsx(reactNative.Text, { className: "text-text-secondary", style: { fontSize: 22, lineHeight: 22 }, children: "\xD7" })
|
|
9994
10398
|
}
|
|
9995
10399
|
)
|
|
9996
10400
|
]
|
|
@@ -9999,11 +10403,11 @@ function PrHistoryModal({
|
|
|
9999
10403
|
/* @__PURE__ */ jsx(DrawerBody, { className: "px-4 pt-0 pb-4", children: records.length === 0 ? /* @__PURE__ */ jsx(reactNative.View, { style: { paddingVertical: 24 }, testID: "pr-history-modal-empty", children: /* @__PURE__ */ jsx(
|
|
10000
10404
|
reactNative.Text,
|
|
10001
10405
|
{
|
|
10406
|
+
className: "text-text-tertiary",
|
|
10002
10407
|
style: {
|
|
10003
10408
|
textAlign: "center",
|
|
10004
10409
|
fontSize: 13,
|
|
10005
|
-
fontFamily: "Inter, sans-serif"
|
|
10006
|
-
color: TEXT_TERTIARY3
|
|
10410
|
+
fontFamily: "Inter, sans-serif"
|
|
10007
10411
|
},
|
|
10008
10412
|
children: "No personal records yet"
|
|
10009
10413
|
}
|
|
@@ -10023,9 +10427,7 @@ var BRAND_PRIMARY8 = "#FF7900";
|
|
|
10023
10427
|
var BRAND_PRIMARY_SUBTLE = "rgba(255,121,0,0.12)";
|
|
10024
10428
|
var STATUS_SUCCESS = "#14B8A6";
|
|
10025
10429
|
var STATUS_WARNING = "#FFB020";
|
|
10026
|
-
var
|
|
10027
|
-
var TEXT_PRIMARY4 = "var(--color-text-primary)";
|
|
10028
|
-
var TEXT_SECONDARY3 = "var(--color-text-secondary)";
|
|
10430
|
+
var STATUS_ERROR2 = "#D14343";
|
|
10029
10431
|
var EMOJI_SETS = {
|
|
10030
10432
|
sleep: ["\u{1F634}", "\u{1F610}", "\u{1F642}", "\u{1F60A}", "\u{1F929}"],
|
|
10031
10433
|
soreness: ["\u{1F635}", "\u{1F623}", "\u{1F610}", "\u{1F642}", "\u{1F4AA}"],
|
|
@@ -10034,7 +10436,7 @@ var EMOJI_SETS = {
|
|
|
10034
10436
|
};
|
|
10035
10437
|
var DEFAULT_EMOJI_SET = ["\u{1F61E}", "\u{1F615}", "\u{1F610}", "\u{1F642}", "\u{1F604}"];
|
|
10036
10438
|
function scoreColor(score) {
|
|
10037
|
-
if (score < 40) return
|
|
10439
|
+
if (score < 40) return STATUS_ERROR2;
|
|
10038
10440
|
if (score < 70) return STATUS_WARNING;
|
|
10039
10441
|
return STATUS_SUCCESS;
|
|
10040
10442
|
}
|
|
@@ -10057,7 +10459,8 @@ function EmojiSlider({ factor }) {
|
|
|
10057
10459
|
/* @__PURE__ */ jsx(
|
|
10058
10460
|
reactNative.Text,
|
|
10059
10461
|
{
|
|
10060
|
-
|
|
10462
|
+
className: "text-text-secondary",
|
|
10463
|
+
style: { fontSize: 12, fontWeight: "500", fontFamily: "Inter, sans-serif" },
|
|
10061
10464
|
testID: "readiness-check-factor-label",
|
|
10062
10465
|
children: factor.label
|
|
10063
10466
|
}
|
|
@@ -10081,14 +10484,15 @@ function EmojiSlider({ factor }) {
|
|
|
10081
10484
|
accessibilityLabel: `${factor.label} level ${level} of 5`,
|
|
10082
10485
|
"aria-checked": selected,
|
|
10083
10486
|
testID: "readiness-check-emoji",
|
|
10487
|
+
className: selected ? void 0 : "border-border bg-surface-raised",
|
|
10084
10488
|
style: ({ pressed }) => ({
|
|
10085
10489
|
flex: 1,
|
|
10086
10490
|
alignItems: "center",
|
|
10087
10491
|
paddingVertical: 8,
|
|
10088
10492
|
borderRadius: 8,
|
|
10089
10493
|
borderWidth: 1,
|
|
10090
|
-
borderColor: selected ? BRAND_PRIMARY8 :
|
|
10091
|
-
backgroundColor: selected ? BRAND_PRIMARY_SUBTLE :
|
|
10494
|
+
borderColor: selected ? BRAND_PRIMARY8 : void 0,
|
|
10495
|
+
backgroundColor: selected ? BRAND_PRIMARY_SUBTLE : void 0,
|
|
10092
10496
|
opacity: selected ? 1 : pressed ? 0.8 : 0.55,
|
|
10093
10497
|
transform: [{ scale: selected ? 1.06 : 1 }]
|
|
10094
10498
|
}),
|
|
@@ -10109,13 +10513,13 @@ function ScoreGauge({ score }) {
|
|
|
10109
10513
|
accessibilityRole: "image",
|
|
10110
10514
|
accessibilityLabel: `Readiness score: ${score} out of 100`,
|
|
10111
10515
|
testID: "readiness-check-score",
|
|
10516
|
+
className: "bg-surface-raised",
|
|
10112
10517
|
style: {
|
|
10113
10518
|
width: 60,
|
|
10114
10519
|
height: 60,
|
|
10115
10520
|
borderRadius: 30,
|
|
10116
10521
|
borderWidth: 4,
|
|
10117
10522
|
borderColor: color,
|
|
10118
|
-
backgroundColor: "var(--color-surface-raised)",
|
|
10119
10523
|
alignItems: "center",
|
|
10120
10524
|
justifyContent: "center"
|
|
10121
10525
|
},
|
|
@@ -10135,13 +10539,12 @@ function WarmUpCard({ validation }) {
|
|
|
10135
10539
|
return /* @__PURE__ */ jsxs(
|
|
10136
10540
|
reactNative.View,
|
|
10137
10541
|
{
|
|
10542
|
+
className: "border-border bg-surface-raised",
|
|
10138
10543
|
style: {
|
|
10139
10544
|
marginTop: 16,
|
|
10140
10545
|
padding: 12,
|
|
10141
10546
|
borderRadius: 8,
|
|
10142
|
-
borderWidth: 1
|
|
10143
|
-
borderColor: "var(--color-border-default)",
|
|
10144
|
-
backgroundColor: "var(--color-surface-raised)"
|
|
10547
|
+
borderWidth: 1
|
|
10145
10548
|
},
|
|
10146
10549
|
testID: "readiness-check-warmup",
|
|
10147
10550
|
children: [
|
|
@@ -10149,7 +10552,8 @@ function WarmUpCard({ validation }) {
|
|
|
10149
10552
|
/* @__PURE__ */ jsx(
|
|
10150
10553
|
reactNative.Text,
|
|
10151
10554
|
{
|
|
10152
|
-
|
|
10555
|
+
className: "text-text-secondary",
|
|
10556
|
+
style: { fontSize: 12, fontWeight: "600", fontFamily: "Inter, sans-serif" },
|
|
10153
10557
|
testID: "readiness-check-warmup-deficit",
|
|
10154
10558
|
children: velocityDeficitText(validation.velocityDeficit)
|
|
10155
10559
|
}
|
|
@@ -10159,7 +10563,8 @@ function WarmUpCard({ validation }) {
|
|
|
10159
10563
|
/* @__PURE__ */ jsx(
|
|
10160
10564
|
reactNative.Text,
|
|
10161
10565
|
{
|
|
10162
|
-
|
|
10566
|
+
className: "text-text-primary",
|
|
10567
|
+
style: { marginTop: 6, fontSize: 13, fontFamily: "Inter, sans-serif" },
|
|
10163
10568
|
testID: "readiness-check-warmup-recommendation",
|
|
10164
10569
|
children: validation.recommendation
|
|
10165
10570
|
}
|
|
@@ -10181,7 +10586,8 @@ function ReadinessCheck({
|
|
|
10181
10586
|
/* @__PURE__ */ jsx(
|
|
10182
10587
|
reactNative.Text,
|
|
10183
10588
|
{
|
|
10184
|
-
|
|
10589
|
+
className: "text-text-primary",
|
|
10590
|
+
style: { fontSize: 18, fontWeight: "700", fontFamily: '"Space Grotesk", sans-serif' },
|
|
10185
10591
|
testID: "readiness-check-title",
|
|
10186
10592
|
children: "How are you feeling?"
|
|
10187
10593
|
}
|
|
@@ -10214,21 +10620,18 @@ function ReadinessCheck({
|
|
|
10214
10620
|
var BRAND_PRIMARY9 = "#FF7900";
|
|
10215
10621
|
var BRAND_PRIMARY_DARK2 = "#C45E00";
|
|
10216
10622
|
var BRAND_PRIMARY_LIGHT2 = "#FFB066";
|
|
10217
|
-
var TEXT_PRIMARY5 = "var(--color-text-primary)";
|
|
10218
|
-
var TEXT_SECONDARY4 = "var(--color-text-secondary)";
|
|
10219
|
-
var TEXT_TERTIARY4 = "var(--color-text-tertiary)";
|
|
10220
10623
|
var SUCCESS = "#14B8A6";
|
|
10221
10624
|
var WARNING = "#FFB020";
|
|
10222
10625
|
var ERROR = "#D14343";
|
|
10223
10626
|
var ACCENT_STOPS2 = [BRAND_PRIMARY_DARK2, BRAND_PRIMARY9, BRAND_PRIMARY_LIGHT2];
|
|
10224
|
-
var CARD_GRADIENT =
|
|
10627
|
+
var CARD_GRADIENT = `linear-gradient(135deg, ${resolveColor("surface-elevated")} 0%, ${resolveColor("surface-raised")} 100%)`;
|
|
10225
10628
|
var GAUGE_GRADIENT = "linear-gradient(90deg, rgba(20,184,166,0.25) 0%, rgba(255,176,32,0.25) 50%, rgba(209,67,67,0.25) 100%)";
|
|
10226
10629
|
var STATUS_VARIANTS = {
|
|
10227
10630
|
success: { bg: "rgba(20,184,166,0.15)", border: "rgba(20,184,166,0.3)", text: SUCCESS },
|
|
10228
10631
|
warning: { bg: "rgba(255,176,32,0.15)", border: "rgba(255,176,32,0.3)", text: WARNING },
|
|
10229
10632
|
error: { bg: "rgba(209,67,67,0.15)", border: "rgba(209,67,67,0.25)", text: ERROR }
|
|
10230
10633
|
};
|
|
10231
|
-
function
|
|
10634
|
+
function clamp01(value) {
|
|
10232
10635
|
if (!Number.isFinite(value)) return 0;
|
|
10233
10636
|
if (value < 0) return 0;
|
|
10234
10637
|
if (value > 1) return 1;
|
|
@@ -10248,7 +10651,8 @@ function renderCoachingText(text, highlights) {
|
|
|
10248
10651
|
(part, index) => highlights.includes(part) ? /* @__PURE__ */ jsx(
|
|
10249
10652
|
reactNative.Text,
|
|
10250
10653
|
{
|
|
10251
|
-
|
|
10654
|
+
className: "text-text-primary",
|
|
10655
|
+
style: { fontWeight: "700" },
|
|
10252
10656
|
children: part
|
|
10253
10657
|
},
|
|
10254
10658
|
`${part}-${index}`
|
|
@@ -10295,13 +10699,13 @@ function MetricCell({ metric }) {
|
|
|
10295
10699
|
/* @__PURE__ */ jsx(
|
|
10296
10700
|
reactNative.Text,
|
|
10297
10701
|
{
|
|
10702
|
+
className: "text-text-tertiary",
|
|
10298
10703
|
style: {
|
|
10299
10704
|
fontSize: 10,
|
|
10300
10705
|
fontFamily: "Inter, sans-serif",
|
|
10301
10706
|
fontWeight: "600",
|
|
10302
10707
|
letterSpacing: 0.5,
|
|
10303
|
-
textTransform: "uppercase"
|
|
10304
|
-
color: TEXT_TERTIARY4
|
|
10708
|
+
textTransform: "uppercase"
|
|
10305
10709
|
},
|
|
10306
10710
|
children: metric.label
|
|
10307
10711
|
}
|
|
@@ -10309,12 +10713,12 @@ function MetricCell({ metric }) {
|
|
|
10309
10713
|
/* @__PURE__ */ jsx(
|
|
10310
10714
|
reactNative.Text,
|
|
10311
10715
|
{
|
|
10716
|
+
className: "text-text-primary",
|
|
10312
10717
|
style: {
|
|
10313
10718
|
marginTop: 2,
|
|
10314
10719
|
fontSize: 13,
|
|
10315
10720
|
fontFamily: "Inter, sans-serif",
|
|
10316
|
-
fontWeight: "600"
|
|
10317
|
-
color: TEXT_PRIMARY5
|
|
10721
|
+
fontWeight: "600"
|
|
10318
10722
|
},
|
|
10319
10723
|
children: metric.value
|
|
10320
10724
|
}
|
|
@@ -10322,7 +10726,7 @@ function MetricCell({ metric }) {
|
|
|
10322
10726
|
] });
|
|
10323
10727
|
}
|
|
10324
10728
|
function Gauge({ gauge }) {
|
|
10325
|
-
const level =
|
|
10729
|
+
const level = clamp01(gauge.level);
|
|
10326
10730
|
const percentage = Math.round(level * 100);
|
|
10327
10731
|
const markerColor = getGaugeZoneColor(level);
|
|
10328
10732
|
return /* @__PURE__ */ jsxs(
|
|
@@ -10346,13 +10750,13 @@ function Gauge({ gauge }) {
|
|
|
10346
10750
|
/* @__PURE__ */ jsx(
|
|
10347
10751
|
reactNative.Text,
|
|
10348
10752
|
{
|
|
10753
|
+
className: "text-text-secondary",
|
|
10349
10754
|
style: {
|
|
10350
10755
|
fontSize: 10,
|
|
10351
10756
|
fontFamily: "Inter, sans-serif",
|
|
10352
10757
|
fontWeight: "500",
|
|
10353
10758
|
letterSpacing: 0.5,
|
|
10354
|
-
textTransform: "uppercase"
|
|
10355
|
-
color: TEXT_SECONDARY4
|
|
10759
|
+
textTransform: "uppercase"
|
|
10356
10760
|
},
|
|
10357
10761
|
children: gauge.label
|
|
10358
10762
|
}
|
|
@@ -10360,11 +10764,11 @@ function Gauge({ gauge }) {
|
|
|
10360
10764
|
gauge.sublabel != null && /* @__PURE__ */ jsx(
|
|
10361
10765
|
reactNative.Text,
|
|
10362
10766
|
{
|
|
10767
|
+
className: "text-text-tertiary",
|
|
10363
10768
|
style: {
|
|
10364
10769
|
fontSize: 10,
|
|
10365
10770
|
fontFamily: "Inter, sans-serif",
|
|
10366
|
-
fontWeight: "500"
|
|
10367
|
-
color: TEXT_TERTIARY4
|
|
10771
|
+
fontWeight: "500"
|
|
10368
10772
|
},
|
|
10369
10773
|
children: gauge.sublabel
|
|
10370
10774
|
}
|
|
@@ -10401,6 +10805,7 @@ function Gauge({ gauge }) {
|
|
|
10401
10805
|
/* @__PURE__ */ jsx(
|
|
10402
10806
|
reactNative.View,
|
|
10403
10807
|
{
|
|
10808
|
+
className: "border-text-primary",
|
|
10404
10809
|
style: {
|
|
10405
10810
|
position: "absolute",
|
|
10406
10811
|
left: `${percentage}%`,
|
|
@@ -10410,7 +10815,6 @@ function Gauge({ gauge }) {
|
|
|
10410
10815
|
height: 14,
|
|
10411
10816
|
borderRadius: 9999,
|
|
10412
10817
|
borderWidth: 2,
|
|
10413
|
-
borderColor: TEXT_PRIMARY5,
|
|
10414
10818
|
backgroundColor: markerColor,
|
|
10415
10819
|
boxShadow: "0 0 4px rgba(0,0,0,0.5)"
|
|
10416
10820
|
},
|
|
@@ -10473,12 +10877,12 @@ function MesoStatusCard({
|
|
|
10473
10877
|
/* @__PURE__ */ jsx(
|
|
10474
10878
|
reactNative.Text,
|
|
10475
10879
|
{
|
|
10880
|
+
className: "text-text-primary",
|
|
10476
10881
|
style: {
|
|
10477
10882
|
flexShrink: 1,
|
|
10478
10883
|
fontSize: 15,
|
|
10479
10884
|
fontFamily: '"Space Grotesk", sans-serif',
|
|
10480
|
-
fontWeight: "700"
|
|
10481
|
-
color: TEXT_PRIMARY5
|
|
10885
|
+
fontWeight: "700"
|
|
10482
10886
|
},
|
|
10483
10887
|
testID: "meso-status-card-name",
|
|
10484
10888
|
children: mesoName
|
|
@@ -10491,11 +10895,11 @@ function MesoStatusCard({
|
|
|
10491
10895
|
/* @__PURE__ */ jsx(
|
|
10492
10896
|
reactNative.Text,
|
|
10493
10897
|
{
|
|
10898
|
+
className: "text-text-secondary",
|
|
10494
10899
|
style: {
|
|
10495
10900
|
marginTop: 4,
|
|
10496
10901
|
fontSize: 12,
|
|
10497
|
-
fontFamily: "Inter, sans-serif"
|
|
10498
|
-
color: TEXT_SECONDARY4
|
|
10902
|
+
fontFamily: "Inter, sans-serif"
|
|
10499
10903
|
},
|
|
10500
10904
|
testID: "meso-status-card-subtitle",
|
|
10501
10905
|
children: mesoSubtitle
|
|
@@ -10527,11 +10931,11 @@ function MesoStatusCard({
|
|
|
10527
10931
|
children: /* @__PURE__ */ jsx(
|
|
10528
10932
|
reactNative.Text,
|
|
10529
10933
|
{
|
|
10934
|
+
className: "text-text-secondary",
|
|
10530
10935
|
style: {
|
|
10531
10936
|
fontSize: 12,
|
|
10532
10937
|
lineHeight: 17,
|
|
10533
|
-
fontFamily: "Inter, sans-serif"
|
|
10534
|
-
color: TEXT_SECONDARY4
|
|
10938
|
+
fontFamily: "Inter, sans-serif"
|
|
10535
10939
|
},
|
|
10536
10940
|
children: renderCoachingText(coaching.text, coaching.highlights)
|
|
10537
10941
|
}
|
|
@@ -10576,15 +10980,11 @@ function MesoStatusCard({
|
|
|
10576
10980
|
);
|
|
10577
10981
|
}
|
|
10578
10982
|
var BRAND_PRIMARY10 = "#FF7900";
|
|
10579
|
-
var
|
|
10580
|
-
var TEXT_SECONDARY5 = "var(--color-text-secondary)";
|
|
10581
|
-
var TEXT_TERTIARY5 = "var(--color-text-tertiary)";
|
|
10582
|
-
var BORDER_STRONG = "var(--color-border-strong)";
|
|
10983
|
+
var PROJECTION_LINE_COLOR = resolveColor("text-tertiary");
|
|
10583
10984
|
var STATUS_SUCCESS2 = "#14B8A6";
|
|
10584
|
-
var
|
|
10985
|
+
var STATUS_ERROR3 = "#D14343";
|
|
10585
10986
|
var STATUS_WARNING2 = "#FFB020";
|
|
10586
10987
|
var GRID_LINE = "rgba(255,255,255,0.06)";
|
|
10587
|
-
var TOOLTIP_BG = "var(--color-surface-elevated)";
|
|
10588
10988
|
var SUCCESS_PILL_BG = "rgba(20,184,166,0.10)";
|
|
10589
10989
|
var SUCCESS_PILL_BORDER = "rgba(20,184,166,0.20)";
|
|
10590
10990
|
var ERROR_PILL_BG = "rgba(209,67,67,0.10)";
|
|
@@ -10592,8 +10992,8 @@ var ERROR_PILL_BORDER = "rgba(209,67,67,0.20)";
|
|
|
10592
10992
|
var PLOT_LEFT = 26;
|
|
10593
10993
|
var TOOLTIP_WIDTH = 124;
|
|
10594
10994
|
function timeOf(dateStr) {
|
|
10595
|
-
const
|
|
10596
|
-
return Number.isNaN(
|
|
10995
|
+
const t2 = Date.parse(dateStr);
|
|
10996
|
+
return Number.isNaN(t2) ? 0 : t2;
|
|
10597
10997
|
}
|
|
10598
10998
|
function formatValue(value) {
|
|
10599
10999
|
return `${Math.round(value)}`;
|
|
@@ -10765,7 +11165,7 @@ function StrengthTrendChart({
|
|
|
10765
11165
|
alignItems: "center",
|
|
10766
11166
|
justifyContent: "center"
|
|
10767
11167
|
},
|
|
10768
|
-
children: /* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 12, fontFamily: "Inter, sans-serif"
|
|
11168
|
+
children: /* @__PURE__ */ jsx(reactNative.Text, { className: "text-text-tertiary", style: { fontSize: 12, fontFamily: "Inter, sans-serif" }, children: "No strength data yet" })
|
|
10769
11169
|
}
|
|
10770
11170
|
)
|
|
10771
11171
|
}
|
|
@@ -10809,6 +11209,7 @@ function StrengthTrendChart({
|
|
|
10809
11209
|
children: /* @__PURE__ */ jsx(
|
|
10810
11210
|
reactNative.Text,
|
|
10811
11211
|
{
|
|
11212
|
+
className: "text-text-tertiary",
|
|
10812
11213
|
style: {
|
|
10813
11214
|
position: "absolute",
|
|
10814
11215
|
left: -PLOT_LEFT,
|
|
@@ -10816,8 +11217,7 @@ function StrengthTrendChart({
|
|
|
10816
11217
|
width: PLOT_LEFT - 4,
|
|
10817
11218
|
textAlign: "right",
|
|
10818
11219
|
fontSize: 9,
|
|
10819
|
-
fontFamily: "Inter, sans-serif"
|
|
10820
|
-
color: TEXT_TERTIARY5
|
|
11220
|
+
fontFamily: "Inter, sans-serif"
|
|
10821
11221
|
},
|
|
10822
11222
|
children: line.label
|
|
10823
11223
|
}
|
|
@@ -10860,7 +11260,7 @@ function StrengthTrendChart({
|
|
|
10860
11260
|
ChartLine,
|
|
10861
11261
|
{
|
|
10862
11262
|
coords: geometry.projection,
|
|
10863
|
-
color:
|
|
11263
|
+
color: PROJECTION_LINE_COLOR,
|
|
10864
11264
|
strokeWidth: 2,
|
|
10865
11265
|
dashed: true,
|
|
10866
11266
|
testID: "strength-trend-chart-projection-segment"
|
|
@@ -10936,6 +11336,7 @@ function StrengthTrendChart({
|
|
|
10936
11336
|
{
|
|
10937
11337
|
testID: "strength-trend-chart-tooltip",
|
|
10938
11338
|
accessibilityElementsHidden: true,
|
|
11339
|
+
className: "bg-surface-elevated border-border-strong",
|
|
10939
11340
|
style: {
|
|
10940
11341
|
position: "absolute",
|
|
10941
11342
|
left: Math.max(
|
|
@@ -10944,9 +11345,7 @@ function StrengthTrendChart({
|
|
|
10944
11345
|
),
|
|
10945
11346
|
top: Math.max(0, selectedCoord.y - 52),
|
|
10946
11347
|
maxWidth: TOOLTIP_WIDTH,
|
|
10947
|
-
backgroundColor: TOOLTIP_BG,
|
|
10948
11348
|
borderWidth: 1,
|
|
10949
|
-
borderColor: BORDER_STRONG,
|
|
10950
11349
|
borderRadius: 8,
|
|
10951
11350
|
paddingVertical: 8,
|
|
10952
11351
|
paddingHorizontal: 10
|
|
@@ -10955,10 +11354,10 @@ function StrengthTrendChart({
|
|
|
10955
11354
|
/* @__PURE__ */ jsx(
|
|
10956
11355
|
reactNative.Text,
|
|
10957
11356
|
{
|
|
11357
|
+
className: "text-text-tertiary",
|
|
10958
11358
|
style: {
|
|
10959
11359
|
fontSize: 10,
|
|
10960
|
-
fontFamily: "Inter, sans-serif"
|
|
10961
|
-
color: TEXT_TERTIARY5
|
|
11360
|
+
fontFamily: "Inter, sans-serif"
|
|
10962
11361
|
},
|
|
10963
11362
|
children: selectedCoord.point.sessionLabel ?? selectedCoord.point.date
|
|
10964
11363
|
}
|
|
@@ -10966,12 +11365,12 @@ function StrengthTrendChart({
|
|
|
10966
11365
|
/* @__PURE__ */ jsx(
|
|
10967
11366
|
reactNative.Text,
|
|
10968
11367
|
{
|
|
11368
|
+
className: "text-text-primary",
|
|
10969
11369
|
style: {
|
|
10970
11370
|
marginTop: 2,
|
|
10971
11371
|
fontSize: 13,
|
|
10972
11372
|
fontFamily: "Inter, sans-serif",
|
|
10973
|
-
fontWeight: "700"
|
|
10974
|
-
color: TEXT_PRIMARY6
|
|
11373
|
+
fontWeight: "700"
|
|
10975
11374
|
},
|
|
10976
11375
|
children: `${formatValue(selectedCoord.point.e1rm)} ${unit}`
|
|
10977
11376
|
}
|
|
@@ -10983,7 +11382,7 @@ function StrengthTrendChart({
|
|
|
10983
11382
|
marginTop: 1,
|
|
10984
11383
|
fontSize: 10,
|
|
10985
11384
|
fontFamily: "Inter, sans-serif",
|
|
10986
|
-
color: selectedCoord.point.e1rm - geometry.actual[selected - 1].point.e1rm >= 0 ? STATUS_SUCCESS2 :
|
|
11385
|
+
color: selectedCoord.point.e1rm - geometry.actual[selected - 1].point.e1rm >= 0 ? STATUS_SUCCESS2 : STATUS_ERROR3
|
|
10987
11386
|
},
|
|
10988
11387
|
children: `${selectedCoord.point.e1rm - geometry.actual[selected - 1].point.e1rm >= 0 ? "+" : "-"}${Math.abs(
|
|
10989
11388
|
selectedCoord.point.e1rm - geometry.actual[selected - 1].point.e1rm
|
|
@@ -11004,14 +11403,14 @@ function StrengthTrendChart({
|
|
|
11004
11403
|
reactNative.Text,
|
|
11005
11404
|
{
|
|
11006
11405
|
testID: "strength-trend-chart-axis-label",
|
|
11406
|
+
className: "text-text-tertiary",
|
|
11007
11407
|
style: {
|
|
11008
11408
|
position: "absolute",
|
|
11009
11409
|
left: boundary.x - 24,
|
|
11010
11410
|
width: 48,
|
|
11011
11411
|
textAlign: "center",
|
|
11012
11412
|
fontSize: 10,
|
|
11013
|
-
fontFamily: "Inter, sans-serif"
|
|
11014
|
-
color: TEXT_TERTIARY5
|
|
11413
|
+
fontFamily: "Inter, sans-serif"
|
|
11015
11414
|
},
|
|
11016
11415
|
children: boundary.label
|
|
11017
11416
|
},
|
|
@@ -11039,7 +11438,7 @@ function StrengthTrendChart({
|
|
|
11039
11438
|
fontSize: 11,
|
|
11040
11439
|
fontFamily: "Inter, sans-serif",
|
|
11041
11440
|
fontWeight: "600",
|
|
11042
|
-
color: trend.positive ? STATUS_SUCCESS2 :
|
|
11441
|
+
color: trend.positive ? STATUS_SUCCESS2 : STATUS_ERROR3
|
|
11043
11442
|
},
|
|
11044
11443
|
children: trendText
|
|
11045
11444
|
}
|
|
@@ -11055,7 +11454,7 @@ function StrengthTrendChart({
|
|
|
11055
11454
|
children: [
|
|
11056
11455
|
/* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", style: { gap: 5 }, children: [
|
|
11057
11456
|
/* @__PURE__ */ jsx(reactNative.View, { style: { width: 14, height: 2.5, borderRadius: 1.5, backgroundColor: BRAND_PRIMARY10 } }),
|
|
11058
|
-
/* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 10, fontFamily: "Inter, sans-serif"
|
|
11457
|
+
/* @__PURE__ */ jsx(reactNative.Text, { className: "text-text-secondary", style: { fontSize: 10, fontFamily: "Inter, sans-serif" }, children: "Actual" })
|
|
11059
11458
|
] }),
|
|
11060
11459
|
/* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", style: { gap: 5 }, children: [
|
|
11061
11460
|
/* @__PURE__ */ jsx(
|
|
@@ -11066,15 +11465,15 @@ function StrengthTrendChart({
|
|
|
11066
11465
|
height: 0,
|
|
11067
11466
|
borderTopWidth: 2,
|
|
11068
11467
|
borderStyle: "dashed",
|
|
11069
|
-
borderTopColor:
|
|
11468
|
+
borderTopColor: PROJECTION_LINE_COLOR
|
|
11070
11469
|
}
|
|
11071
11470
|
}
|
|
11072
11471
|
),
|
|
11073
|
-
/* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 10, fontFamily: "Inter, sans-serif"
|
|
11472
|
+
/* @__PURE__ */ jsx(reactNative.Text, { className: "text-text-secondary", style: { fontSize: 10, fontFamily: "Inter, sans-serif" }, children: "Projected" })
|
|
11074
11473
|
] }),
|
|
11075
11474
|
/* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", style: { gap: 5 }, children: [
|
|
11076
11475
|
/* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 12, color: STATUS_WARNING2 }, children: "\u2605" }),
|
|
11077
|
-
/* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 10, fontFamily: "Inter, sans-serif"
|
|
11476
|
+
/* @__PURE__ */ jsx(reactNative.Text, { className: "text-text-secondary", style: { fontSize: 10, fontFamily: "Inter, sans-serif" }, children: "PR" })
|
|
11078
11477
|
] })
|
|
11079
11478
|
]
|
|
11080
11479
|
}
|
|
@@ -11087,7 +11486,6 @@ var STATUS_SUCCESS3 = "#14B8A6";
|
|
|
11087
11486
|
var STATUS_WARNING3 = "#FFB020";
|
|
11088
11487
|
var STATUS_INFO = "#2196F3";
|
|
11089
11488
|
var DOT_BORDER = "#F3F4F6";
|
|
11090
|
-
var TEXT_TERTIARY6 = "var(--color-text-tertiary)";
|
|
11091
11489
|
var BAND_FILL = "rgba(20,184,166,0.1)";
|
|
11092
11490
|
var BAND_EDGE = "rgba(20,184,166,0.45)";
|
|
11093
11491
|
var PROJECTION_FILL = "rgba(20,184,166,0.05)";
|
|
@@ -11129,8 +11527,8 @@ function interpEdge(pixels, x, key) {
|
|
|
11129
11527
|
const a = pixels[i];
|
|
11130
11528
|
const b = pixels[i + 1];
|
|
11131
11529
|
if (x >= a.x && x <= b.x) {
|
|
11132
|
-
const
|
|
11133
|
-
return a[key] +
|
|
11530
|
+
const t2 = b.x === a.x ? 0 : (x - a.x) / (b.x - a.x);
|
|
11531
|
+
return a[key] + t2 * (b[key] - a[key]);
|
|
11134
11532
|
}
|
|
11135
11533
|
}
|
|
11136
11534
|
return pixels[pixels.length - 1][key];
|
|
@@ -11368,6 +11766,7 @@ function CapacityBandChart({
|
|
|
11368
11766
|
/* @__PURE__ */ jsx(
|
|
11369
11767
|
reactNative.Text,
|
|
11370
11768
|
{
|
|
11769
|
+
className: "text-text-tertiary",
|
|
11371
11770
|
style: {
|
|
11372
11771
|
position: "absolute",
|
|
11373
11772
|
left: PADDING_LEFT / 2 - 14,
|
|
@@ -11376,7 +11775,6 @@ function CapacityBandChart({
|
|
|
11376
11775
|
textAlign: "center",
|
|
11377
11776
|
fontSize: 9,
|
|
11378
11777
|
fontFamily: "Inter, sans-serif",
|
|
11379
|
-
color: TEXT_TERTIARY6,
|
|
11380
11778
|
transform: [{ rotate: "-90deg" }]
|
|
11381
11779
|
},
|
|
11382
11780
|
accessibilityElementsHidden: true,
|
|
@@ -11390,6 +11788,7 @@ function CapacityBandChart({
|
|
|
11390
11788
|
return /* @__PURE__ */ jsx(
|
|
11391
11789
|
reactNative.Text,
|
|
11392
11790
|
{
|
|
11791
|
+
className: "text-text-tertiary",
|
|
11393
11792
|
style: {
|
|
11394
11793
|
position: "absolute",
|
|
11395
11794
|
left: toX(point.date) - 14,
|
|
@@ -11397,8 +11796,7 @@ function CapacityBandChart({
|
|
|
11397
11796
|
width: 28,
|
|
11398
11797
|
textAlign: "center",
|
|
11399
11798
|
fontSize: 10,
|
|
11400
|
-
fontFamily: "Inter, sans-serif"
|
|
11401
|
-
color: TEXT_TERTIARY6
|
|
11799
|
+
fontFamily: "Inter, sans-serif"
|
|
11402
11800
|
},
|
|
11403
11801
|
accessibilityElementsHidden: true,
|
|
11404
11802
|
importantForAccessibility: "no-hide-descendants",
|
|
@@ -11460,1196 +11858,176 @@ function CapacityBandChart({
|
|
|
11460
11858
|
}
|
|
11461
11859
|
);
|
|
11462
11860
|
}
|
|
11463
|
-
var
|
|
11464
|
-
|
|
11465
|
-
|
|
11466
|
-
|
|
11467
|
-
|
|
11468
|
-
|
|
11469
|
-
|
|
11470
|
-
|
|
11471
|
-
|
|
11472
|
-
|
|
11473
|
-
|
|
11474
|
-
|
|
11475
|
-
if (
|
|
11476
|
-
if (
|
|
11477
|
-
return
|
|
11478
|
-
}
|
|
11479
|
-
function toProgressBarMesos(mesos) {
|
|
11480
|
-
return mesos.map(({ id, name, weekCount, status, currentWeek }) => ({
|
|
11481
|
-
id,
|
|
11482
|
-
name,
|
|
11483
|
-
weekCount,
|
|
11484
|
-
status,
|
|
11485
|
-
currentWeek
|
|
11486
|
-
}));
|
|
11487
|
-
}
|
|
11488
|
-
function findMeso(mesos, id) {
|
|
11489
|
-
if (id == null) return null;
|
|
11490
|
-
return mesos.find((meso) => meso.id === id) ?? null;
|
|
11491
|
-
}
|
|
11492
|
-
function findWeek(meso, weekNumber) {
|
|
11493
|
-
if (meso == null || weekNumber == null) return null;
|
|
11494
|
-
return meso.weeks.find((week) => week.weekNumber === weekNumber) ?? null;
|
|
11495
|
-
}
|
|
11496
|
-
function findWorkout(week, workoutId) {
|
|
11497
|
-
if (week == null || workoutId == null) return null;
|
|
11498
|
-
return week.workouts.find((workout) => workout.id === workoutId) ?? null;
|
|
11861
|
+
var PALETTE = [
|
|
11862
|
+
"#5B9BD5",
|
|
11863
|
+
"#14B8A6",
|
|
11864
|
+
"#F4A736",
|
|
11865
|
+
"#F83030",
|
|
11866
|
+
"#823CA0",
|
|
11867
|
+
"#D4A520",
|
|
11868
|
+
"#406D87",
|
|
11869
|
+
"#43C6B7"
|
|
11870
|
+
];
|
|
11871
|
+
function scaleValue(v, scale) {
|
|
11872
|
+
if (v <= 0) return 0;
|
|
11873
|
+
if (scale === "sqrt") return Math.sqrt(v);
|
|
11874
|
+
if (scale === "log") return Math.log10(v + 1);
|
|
11875
|
+
return v;
|
|
11499
11876
|
}
|
|
11500
|
-
function
|
|
11501
|
-
const
|
|
11502
|
-
|
|
11503
|
-
|
|
11504
|
-
|
|
11505
|
-
|
|
11506
|
-
|
|
11877
|
+
function worstRatio(row, side) {
|
|
11878
|
+
const sum = row.reduce((s, r) => s + r.area, 0);
|
|
11879
|
+
const thickness = sum / side;
|
|
11880
|
+
let worst = 0;
|
|
11881
|
+
for (const r of row) {
|
|
11882
|
+
const len = r.area / thickness;
|
|
11883
|
+
const ratio = Math.max(thickness / len, len / thickness);
|
|
11884
|
+
if (ratio > worst) worst = ratio;
|
|
11507
11885
|
}
|
|
11508
|
-
return
|
|
11886
|
+
return worst;
|
|
11509
11887
|
}
|
|
11510
|
-
function
|
|
11511
|
-
|
|
11512
|
-
|
|
11513
|
-
|
|
11514
|
-
|
|
11515
|
-
|
|
11516
|
-
|
|
11517
|
-
|
|
11518
|
-
|
|
11519
|
-
|
|
11520
|
-
|
|
11521
|
-
|
|
11522
|
-
|
|
11523
|
-
|
|
11524
|
-
|
|
11525
|
-
|
|
11526
|
-
|
|
11527
|
-
|
|
11528
|
-
|
|
11529
|
-
|
|
11530
|
-
|
|
11531
|
-
|
|
11532
|
-
|
|
11533
|
-
fontFamily: "Inter, sans-serif",
|
|
11534
|
-
fontWeight: isLast ? "700" : "500",
|
|
11535
|
-
color: isLast ? TEXT_PRIMARY7 : BRAND_PRIMARY11
|
|
11536
|
-
},
|
|
11537
|
-
children: crumb.label
|
|
11538
|
-
}
|
|
11539
|
-
)
|
|
11540
|
-
}
|
|
11541
|
-
)
|
|
11542
|
-
] }, crumb.key);
|
|
11543
|
-
})
|
|
11888
|
+
function squarify(data, w, h) {
|
|
11889
|
+
const total = data.reduce((s, d) => s + d.value, 0);
|
|
11890
|
+
if (total <= 0 || w <= 0 || h <= 0) return [];
|
|
11891
|
+
const scaled = data.map((d) => ({ datum: d, area: d.value / total * w * h }));
|
|
11892
|
+
const out = [];
|
|
11893
|
+
let rx = 0;
|
|
11894
|
+
let ry = 0;
|
|
11895
|
+
let rw = w;
|
|
11896
|
+
let rh = h;
|
|
11897
|
+
let i = 0;
|
|
11898
|
+
while (i < scaled.length) {
|
|
11899
|
+
const vertical = rw >= rh;
|
|
11900
|
+
const side = vertical ? rh : rw;
|
|
11901
|
+
let row = [];
|
|
11902
|
+
let bestWorst = Infinity;
|
|
11903
|
+
let j = i;
|
|
11904
|
+
while (j < scaled.length) {
|
|
11905
|
+
const trial = [...row, scaled[j]];
|
|
11906
|
+
const worst = worstRatio(trial, side);
|
|
11907
|
+
if (row.length > 0 && worst > bestWorst) break;
|
|
11908
|
+
row = trial;
|
|
11909
|
+
bestWorst = worst;
|
|
11910
|
+
j++;
|
|
11544
11911
|
}
|
|
11545
|
-
|
|
11546
|
-
|
|
11547
|
-
|
|
11548
|
-
|
|
11549
|
-
|
|
11550
|
-
|
|
11551
|
-
|
|
11552
|
-
|
|
11553
|
-
|
|
11554
|
-
|
|
11555
|
-
|
|
11556
|
-
|
|
11557
|
-
|
|
11558
|
-
|
|
11559
|
-
|
|
11560
|
-
|
|
11561
|
-
|
|
11912
|
+
const rowArea = row.reduce((s, r) => s + r.area, 0);
|
|
11913
|
+
const thickness = rowArea / side;
|
|
11914
|
+
let along = vertical ? ry : rx;
|
|
11915
|
+
for (const r of row) {
|
|
11916
|
+
const len = r.area / thickness;
|
|
11917
|
+
out.push(
|
|
11918
|
+
vertical ? { x: rx, y: along, w: thickness, h: len, datum: r.datum } : { x: along, y: ry, w: len, h: thickness, datum: r.datum }
|
|
11919
|
+
);
|
|
11920
|
+
along += len;
|
|
11921
|
+
}
|
|
11922
|
+
if (vertical) {
|
|
11923
|
+
rx += thickness;
|
|
11924
|
+
rw -= thickness;
|
|
11925
|
+
} else {
|
|
11926
|
+
ry += thickness;
|
|
11927
|
+
rh -= thickness;
|
|
11928
|
+
}
|
|
11929
|
+
i = j;
|
|
11930
|
+
}
|
|
11931
|
+
return out;
|
|
11562
11932
|
}
|
|
11563
|
-
function
|
|
11564
|
-
|
|
11565
|
-
|
|
11933
|
+
function Treemap({
|
|
11934
|
+
data,
|
|
11935
|
+
width,
|
|
11936
|
+
height,
|
|
11937
|
+
scale = "sqrt",
|
|
11938
|
+
maxTiles = 60,
|
|
11939
|
+
onPress,
|
|
11940
|
+
selectedId,
|
|
11941
|
+
className,
|
|
11942
|
+
...props
|
|
11943
|
+
}) {
|
|
11944
|
+
const clean = data.filter((d) => d.value > 0).sort((a, b) => b.value - a.value).map((d, i) => ({ ...d, color: d.color ?? PALETTE[i % PALETTE.length] }));
|
|
11945
|
+
let tiles = clean;
|
|
11946
|
+
if (clean.length > maxTiles) {
|
|
11947
|
+
const head = clean.slice(0, maxTiles - 1);
|
|
11948
|
+
const restValue = clean.slice(maxTiles - 1).reduce((s, d) => s + d.value, 0);
|
|
11949
|
+
tiles = [
|
|
11950
|
+
...head,
|
|
11951
|
+
{ id: "__more__", value: restValue, color: "#3a3a3a", label: `+${clean.length - (maxTiles - 1)} more` }
|
|
11952
|
+
];
|
|
11953
|
+
}
|
|
11954
|
+
const weighted = tiles.map((d) => ({ ...d, value: scaleValue(d.value, scale) }));
|
|
11955
|
+
const rects = squarify(weighted, width, height);
|
|
11956
|
+
return /* @__PURE__ */ jsx(reactNative.View, { className: cn("relative", className), style: { width, height }, ...props, children: rects.map((r) => {
|
|
11957
|
+
const selected = r.datum.id === selectedId;
|
|
11958
|
+
const labelFits = r.w > 54 && r.h > 22;
|
|
11959
|
+
const pressable = r.datum.id !== "__more__";
|
|
11566
11960
|
return /* @__PURE__ */ jsx(
|
|
11567
|
-
|
|
11961
|
+
reactNative.Pressable,
|
|
11568
11962
|
{
|
|
11569
|
-
|
|
11570
|
-
|
|
11571
|
-
|
|
11572
|
-
|
|
11573
|
-
|
|
11574
|
-
|
|
11575
|
-
|
|
11576
|
-
|
|
11577
|
-
|
|
11578
|
-
|
|
11579
|
-
|
|
11963
|
+
testID: `treemap-tile-${r.datum.id}`,
|
|
11964
|
+
accessibilityLabel: r.datum.label ?? r.datum.id,
|
|
11965
|
+
onPress: pressable ? () => onPress?.(r.datum.id) : void 0,
|
|
11966
|
+
style: {
|
|
11967
|
+
position: "absolute",
|
|
11968
|
+
left: r.x,
|
|
11969
|
+
top: r.y,
|
|
11970
|
+
width: Math.max(0, r.w - 2),
|
|
11971
|
+
height: Math.max(0, r.h - 2),
|
|
11972
|
+
backgroundColor: r.datum.color,
|
|
11973
|
+
borderRadius: 3,
|
|
11974
|
+
opacity: selected ? 1 : 0.9,
|
|
11975
|
+
borderWidth: selected ? 2 : 0,
|
|
11976
|
+
borderColor: "#ffffff",
|
|
11977
|
+
padding: 4,
|
|
11978
|
+
overflow: "hidden"
|
|
11979
|
+
},
|
|
11980
|
+
children: labelFits && /* @__PURE__ */ jsx(reactNative.Text, { numberOfLines: 2, className: "text-[10px] font-semibold text-[#0b0b0b]", children: r.datum.label ?? r.datum.id })
|
|
11580
11981
|
},
|
|
11581
|
-
|
|
11982
|
+
r.datum.id
|
|
11582
11983
|
);
|
|
11583
11984
|
}) });
|
|
11584
11985
|
}
|
|
11585
|
-
|
|
11586
|
-
|
|
11587
|
-
|
|
11588
|
-
|
|
11589
|
-
|
|
11590
|
-
|
|
11591
|
-
|
|
11592
|
-
|
|
11593
|
-
|
|
11594
|
-
|
|
11595
|
-
|
|
11596
|
-
|
|
11597
|
-
|
|
11598
|
-
|
|
11599
|
-
|
|
11600
|
-
|
|
11601
|
-
|
|
11602
|
-
|
|
11986
|
+
var PALETTE2 = [
|
|
11987
|
+
"#5B9BD5",
|
|
11988
|
+
"#14B8A6",
|
|
11989
|
+
"#F4A736",
|
|
11990
|
+
"#F83030",
|
|
11991
|
+
"#823CA0",
|
|
11992
|
+
"#D4A520",
|
|
11993
|
+
"#406D87",
|
|
11994
|
+
"#43C6B7"
|
|
11995
|
+
];
|
|
11996
|
+
var GRID_LINE2 = "rgba(255,255,255,0.07)";
|
|
11997
|
+
var AXIS_LINE = "rgba(255,255,255,0.18)";
|
|
11998
|
+
var DIAGONAL_LINE = "rgba(255,255,255,0.28)";
|
|
11999
|
+
var DEFAULT_R = 6;
|
|
12000
|
+
var PLOT_LEFT2 = 40;
|
|
12001
|
+
var PLOT_RIGHT = 12;
|
|
12002
|
+
var PLOT_TOP = 12;
|
|
12003
|
+
var PLOT_BOTTOM = 34;
|
|
12004
|
+
var TICK_COUNT = 5;
|
|
12005
|
+
function domainOf(values, min, max) {
|
|
12006
|
+
const lo = min ?? (values.length ? Math.min(...values) : 0);
|
|
12007
|
+
const hi = max ?? (values.length ? Math.max(...values) : 1);
|
|
12008
|
+
if (hi > lo) return { min: lo, max: hi };
|
|
12009
|
+
const pad = Math.abs(hi) * 0.1 || 0.5;
|
|
12010
|
+
return { min: lo - pad, max: hi + pad };
|
|
11603
12011
|
}
|
|
11604
|
-
function
|
|
11605
|
-
|
|
11606
|
-
...exercise,
|
|
11607
|
-
state: exercise.state === "upcoming" ? exercise.state : index === expandedExercise ? "expanded" : "collapsed",
|
|
11608
|
-
onToggle: () => onToggleExercise(index)
|
|
11609
|
-
}));
|
|
11610
|
-
return /* @__PURE__ */ jsx(reactNative.View, { testID: "program-planning-page-workout-level", children: /* @__PURE__ */ jsx(
|
|
11611
|
-
WorkoutCard,
|
|
11612
|
-
{
|
|
11613
|
-
name: workout.name,
|
|
11614
|
-
date: workout.date,
|
|
11615
|
-
duration: workout.duration,
|
|
11616
|
-
status: workout.status,
|
|
11617
|
-
muscleGroups: workout.muscleGroups,
|
|
11618
|
-
totalSets: workout.totalSets,
|
|
11619
|
-
totalVolume: workout.totalVolume,
|
|
11620
|
-
unit: workout.unit,
|
|
11621
|
-
exercises,
|
|
11622
|
-
expanded: true,
|
|
11623
|
-
onToggle: () => void 0
|
|
11624
|
-
}
|
|
11625
|
-
) });
|
|
12012
|
+
function ticksOf(d, count) {
|
|
12013
|
+
return Array.from({ length: count }, (_, i) => d.min + (d.max - d.min) * i / (count - 1));
|
|
11626
12014
|
}
|
|
11627
|
-
function
|
|
11628
|
-
|
|
11629
|
-
|
|
11630
|
-
|
|
11631
|
-
|
|
12015
|
+
function formatTick(v) {
|
|
12016
|
+
if (Number.isInteger(v)) return `${v}`;
|
|
12017
|
+
return v.toFixed(Math.abs(v) < 1 ? 2 : 1);
|
|
12018
|
+
}
|
|
12019
|
+
function LineSegment({
|
|
12020
|
+
x1,
|
|
12021
|
+
y1,
|
|
12022
|
+
x2,
|
|
12023
|
+
y2,
|
|
12024
|
+
color,
|
|
12025
|
+
testID
|
|
11632
12026
|
}) {
|
|
11633
|
-
const
|
|
11634
|
-
const
|
|
11635
|
-
const
|
|
11636
|
-
const
|
|
11637
|
-
const progressMesos = React24.useMemo(() => toProgressBarMesos(mesos), [mesos]);
|
|
11638
|
-
const activeMeso = findMeso(mesos, activeMesoId);
|
|
11639
|
-
const level = deriveNavLevel({ weekNumber: selectedWeek, workoutId: selectedWorkoutId });
|
|
11640
|
-
const activeWeek = findWeek(activeMeso, selectedWeek);
|
|
11641
|
-
const activeWorkout = findWorkout(activeWeek, selectedWorkoutId);
|
|
11642
|
-
const selectMeso = (id) => {
|
|
11643
|
-
setActiveMesoId(id);
|
|
11644
|
-
setSelectedWeek(null);
|
|
11645
|
-
setSelectedWorkoutId(null);
|
|
11646
|
-
};
|
|
11647
|
-
const selectWeek = (weekNumber) => {
|
|
11648
|
-
setSelectedWeek(weekNumber);
|
|
11649
|
-
setSelectedWorkoutId(null);
|
|
11650
|
-
setExpandedExercise(null);
|
|
11651
|
-
};
|
|
11652
|
-
const selectWorkout = (id) => {
|
|
11653
|
-
setSelectedWorkoutId(id);
|
|
11654
|
-
setExpandedExercise(null);
|
|
11655
|
-
};
|
|
11656
|
-
const toggleExercise = (index) => setExpandedExercise((current) => current === index ? null : index);
|
|
11657
|
-
const navigateTo = (target) => {
|
|
11658
|
-
if (target === "meso") selectMeso(activeMesoId ?? mesos[0]?.id);
|
|
11659
|
-
else if (target === "week" && selectedWeek != null) selectWeek(selectedWeek);
|
|
11660
|
-
};
|
|
11661
|
-
return /* @__PURE__ */ jsx(
|
|
11662
|
-
reactNative.View,
|
|
11663
|
-
{
|
|
11664
|
-
className,
|
|
11665
|
-
style: { width: 390, backgroundColor: PAGE_BG },
|
|
11666
|
-
accessibilityRole: "main",
|
|
11667
|
-
"aria-label": title,
|
|
11668
|
-
testID: "program-planning-page",
|
|
11669
|
-
...props,
|
|
11670
|
-
children: /* @__PURE__ */ jsxs(reactNative.View, { style: { padding: 16, gap: 14 }, testID: "program-planning-page-content", children: [
|
|
11671
|
-
/* @__PURE__ */ jsx(
|
|
11672
|
-
reactNative.Text,
|
|
11673
|
-
{
|
|
11674
|
-
accessibilityRole: "header",
|
|
11675
|
-
style: {
|
|
11676
|
-
fontSize: 20,
|
|
11677
|
-
fontFamily: '"Space Grotesk", sans-serif',
|
|
11678
|
-
fontWeight: "700",
|
|
11679
|
-
color: TEXT_PRIMARY7
|
|
11680
|
-
},
|
|
11681
|
-
testID: "program-planning-page-title",
|
|
11682
|
-
children: title
|
|
11683
|
-
}
|
|
11684
|
-
),
|
|
11685
|
-
/* @__PURE__ */ jsx(reactNative.View, { style: { marginHorizontal: -16 }, children: /* @__PURE__ */ jsx(
|
|
11686
|
-
MesoProgressBar,
|
|
11687
|
-
{
|
|
11688
|
-
mesos: progressMesos,
|
|
11689
|
-
activeMesoId,
|
|
11690
|
-
onMesoPress: selectMeso
|
|
11691
|
-
}
|
|
11692
|
-
) }),
|
|
11693
|
-
activeMeso != null && /* @__PURE__ */ jsx(
|
|
11694
|
-
Breadcrumbs2,
|
|
11695
|
-
{
|
|
11696
|
-
crumbs: buildBreadcrumbs(activeMeso, selectedWeek, activeWorkout),
|
|
11697
|
-
onNavigate: navigateTo
|
|
11698
|
-
}
|
|
11699
|
-
),
|
|
11700
|
-
/* @__PURE__ */ jsxs(
|
|
11701
|
-
reactNative.View,
|
|
11702
|
-
{
|
|
11703
|
-
style: {
|
|
11704
|
-
backgroundColor: SURFACE_ELEVATED,
|
|
11705
|
-
borderWidth: 1,
|
|
11706
|
-
borderColor: BORDER_DEFAULT3,
|
|
11707
|
-
borderRadius: 12,
|
|
11708
|
-
padding: 12
|
|
11709
|
-
},
|
|
11710
|
-
testID: "program-planning-page-body",
|
|
11711
|
-
children: [
|
|
11712
|
-
level === "meso" && /* @__PURE__ */ jsx(
|
|
11713
|
-
MesoLevel,
|
|
11714
|
-
{
|
|
11715
|
-
mesos,
|
|
11716
|
-
activeMesoId,
|
|
11717
|
-
onSelectMeso: selectMeso,
|
|
11718
|
-
onSelectWeek: selectWeek
|
|
11719
|
-
}
|
|
11720
|
-
),
|
|
11721
|
-
level === "week" && activeWeek != null && /* @__PURE__ */ jsx(WeekLevel, { week: activeWeek, onSelectWorkout: selectWorkout }),
|
|
11722
|
-
level === "workout" && activeWorkout != null && /* @__PURE__ */ jsx(
|
|
11723
|
-
WorkoutLevel,
|
|
11724
|
-
{
|
|
11725
|
-
workout: activeWorkout,
|
|
11726
|
-
expandedExercise,
|
|
11727
|
-
onToggleExercise: toggleExercise
|
|
11728
|
-
}
|
|
11729
|
-
)
|
|
11730
|
-
]
|
|
11731
|
-
}
|
|
11732
|
-
)
|
|
11733
|
-
] })
|
|
11734
|
-
}
|
|
11735
|
-
);
|
|
11736
|
-
}
|
|
11737
|
-
var SURFACE_ELEVATED2 = "var(--color-surface-elevated)";
|
|
11738
|
-
var BORDER_DEFAULT4 = "var(--color-border-default)";
|
|
11739
|
-
var BRAND_PRIMARY12 = "#FF7900";
|
|
11740
|
-
var TEXT_PRIMARY8 = "var(--color-text-primary)";
|
|
11741
|
-
var TEXT_SECONDARY6 = "var(--color-text-secondary)";
|
|
11742
|
-
var TEXT_TERTIARY8 = "var(--color-text-tertiary)";
|
|
11743
|
-
var PAGE_BG2 = "var(--color-background-base)";
|
|
11744
|
-
var CHART_WIDTH = 326;
|
|
11745
|
-
var CHART_HEIGHT = 150;
|
|
11746
|
-
var EXERCISE_DETAIL_TABS = [
|
|
11747
|
-
{ key: "progress", label: "Progress" },
|
|
11748
|
-
{ key: "history", label: "History" },
|
|
11749
|
-
{ key: "advanced", label: "Advanced" }
|
|
11750
|
-
];
|
|
11751
|
-
function deriveExerciseStats(entries) {
|
|
11752
|
-
let bestE1rm = null;
|
|
11753
|
-
let prCount = 0;
|
|
11754
|
-
for (const entry of entries) {
|
|
11755
|
-
if (entry.e1rm != null && (bestE1rm == null || entry.e1rm.value > bestE1rm)) {
|
|
11756
|
-
bestE1rm = entry.e1rm.value;
|
|
11757
|
-
}
|
|
11758
|
-
if (entry.isPR) prCount += 1;
|
|
11759
|
-
}
|
|
11760
|
-
return { sessions: entries.length, bestE1rm, prCount };
|
|
11761
|
-
}
|
|
11762
|
-
function toExerciseCardProps(entry, expanded, onToggle) {
|
|
11763
|
-
return {
|
|
11764
|
-
name: entry.title,
|
|
11765
|
-
state: expanded ? "expanded" : "collapsed",
|
|
11766
|
-
onToggle,
|
|
11767
|
-
summary: entry.summary,
|
|
11768
|
-
e1rm: entry.e1rm,
|
|
11769
|
-
isPR: entry.isPR,
|
|
11770
|
-
tempo: entry.tempo,
|
|
11771
|
-
sets: expanded ? entry.sets : void 0
|
|
11772
|
-
};
|
|
11773
|
-
}
|
|
11774
|
-
function summarizeVbt(sets) {
|
|
11775
|
-
const allReps = sets.flatMap((set) => set.velocities);
|
|
11776
|
-
const meanVelocity = calculateMeanVelocity(allReps);
|
|
11777
|
-
let velocityLoss = 0;
|
|
11778
|
-
for (const set of sets) {
|
|
11779
|
-
velocityLoss = Math.max(velocityLoss, calculateVelocityLoss(set.velocities));
|
|
11780
|
-
}
|
|
11781
|
-
return { meanVelocity, velocityLoss };
|
|
11782
|
-
}
|
|
11783
|
-
function TabBar({ active, onSelect }) {
|
|
11784
|
-
return /* @__PURE__ */ jsx(
|
|
11785
|
-
reactNative.View,
|
|
11786
|
-
{
|
|
11787
|
-
className: "flex-row",
|
|
11788
|
-
style: {
|
|
11789
|
-
borderBottomWidth: 1,
|
|
11790
|
-
borderBottomColor: BORDER_DEFAULT4
|
|
11791
|
-
},
|
|
11792
|
-
accessibilityRole: "tablist",
|
|
11793
|
-
testID: "exercise-detail-page-tabs",
|
|
11794
|
-
children: EXERCISE_DETAIL_TABS.map(({ key, label }) => {
|
|
11795
|
-
const isActive = key === active;
|
|
11796
|
-
return /* @__PURE__ */ jsx(
|
|
11797
|
-
reactNative.Pressable,
|
|
11798
|
-
{
|
|
11799
|
-
onPress: () => onSelect(key),
|
|
11800
|
-
accessibilityRole: "tab",
|
|
11801
|
-
accessibilityState: { selected: isActive },
|
|
11802
|
-
style: {
|
|
11803
|
-
flex: 1,
|
|
11804
|
-
alignItems: "center",
|
|
11805
|
-
paddingVertical: 10,
|
|
11806
|
-
borderBottomWidth: 2,
|
|
11807
|
-
borderBottomColor: isActive ? BRAND_PRIMARY12 : "transparent"
|
|
11808
|
-
},
|
|
11809
|
-
testID: `exercise-detail-page-tab-${key}`,
|
|
11810
|
-
children: /* @__PURE__ */ jsx(
|
|
11811
|
-
reactNative.Text,
|
|
11812
|
-
{
|
|
11813
|
-
style: {
|
|
11814
|
-
fontSize: 13,
|
|
11815
|
-
fontFamily: "Inter, sans-serif",
|
|
11816
|
-
fontWeight: isActive ? "700" : "500",
|
|
11817
|
-
color: isActive ? TEXT_PRIMARY8 : TEXT_TERTIARY8
|
|
11818
|
-
},
|
|
11819
|
-
children: label
|
|
11820
|
-
}
|
|
11821
|
-
)
|
|
11822
|
-
},
|
|
11823
|
-
key
|
|
11824
|
-
);
|
|
11825
|
-
})
|
|
11826
|
-
}
|
|
11827
|
-
);
|
|
11828
|
-
}
|
|
11829
|
-
var STAT_CARDS = [
|
|
11830
|
-
{ key: "sessions", label: "Sessions" },
|
|
11831
|
-
{ key: "bestE1rm", label: "Best e1RM" },
|
|
11832
|
-
{ key: "prCount", label: "PRs" }
|
|
11833
|
-
];
|
|
11834
|
-
function StatStrip({ stats, unit }) {
|
|
11835
|
-
return /* @__PURE__ */ jsx(reactNative.View, { className: "flex-row", style: { gap: 8 }, testID: "exercise-detail-page-stats", children: STAT_CARDS.map(({ key, label }) => {
|
|
11836
|
-
const raw = stats[key];
|
|
11837
|
-
const value = key === "bestE1rm" ? raw == null ? "\u2014" : `${raw} ${unit}` : `${raw}`;
|
|
11838
|
-
return /* @__PURE__ */ jsxs(
|
|
11839
|
-
reactNative.View,
|
|
11840
|
-
{
|
|
11841
|
-
style: {
|
|
11842
|
-
flex: 1,
|
|
11843
|
-
padding: 12,
|
|
11844
|
-
borderRadius: 10,
|
|
11845
|
-
backgroundColor: SURFACE_ELEVATED2,
|
|
11846
|
-
borderWidth: 1,
|
|
11847
|
-
borderColor: BORDER_DEFAULT4
|
|
11848
|
-
},
|
|
11849
|
-
testID: `exercise-detail-page-stat-${key}`,
|
|
11850
|
-
children: [
|
|
11851
|
-
/* @__PURE__ */ jsx(
|
|
11852
|
-
reactNative.Text,
|
|
11853
|
-
{
|
|
11854
|
-
style: {
|
|
11855
|
-
fontSize: 18,
|
|
11856
|
-
fontFamily: '"Space Grotesk", sans-serif',
|
|
11857
|
-
fontWeight: "700",
|
|
11858
|
-
color: TEXT_PRIMARY8
|
|
11859
|
-
},
|
|
11860
|
-
children: value
|
|
11861
|
-
}
|
|
11862
|
-
),
|
|
11863
|
-
/* @__PURE__ */ jsx(
|
|
11864
|
-
reactNative.Text,
|
|
11865
|
-
{
|
|
11866
|
-
style: {
|
|
11867
|
-
marginTop: 2,
|
|
11868
|
-
fontSize: 10,
|
|
11869
|
-
fontFamily: "Inter, sans-serif",
|
|
11870
|
-
fontWeight: "600",
|
|
11871
|
-
letterSpacing: 0.4,
|
|
11872
|
-
textTransform: "uppercase",
|
|
11873
|
-
color: TEXT_TERTIARY8
|
|
11874
|
-
},
|
|
11875
|
-
children: label
|
|
11876
|
-
}
|
|
11877
|
-
)
|
|
11878
|
-
]
|
|
11879
|
-
},
|
|
11880
|
-
key
|
|
11881
|
-
);
|
|
11882
|
-
}) });
|
|
11883
|
-
}
|
|
11884
|
-
function SectionCard({
|
|
11885
|
-
title,
|
|
11886
|
-
children,
|
|
11887
|
-
testID
|
|
11888
|
-
}) {
|
|
11889
|
-
return /* @__PURE__ */ jsxs(
|
|
11890
|
-
reactNative.View,
|
|
11891
|
-
{
|
|
11892
|
-
style: {
|
|
11893
|
-
backgroundColor: SURFACE_ELEVATED2,
|
|
11894
|
-
borderWidth: 1,
|
|
11895
|
-
borderColor: BORDER_DEFAULT4,
|
|
11896
|
-
borderRadius: 12,
|
|
11897
|
-
padding: 12,
|
|
11898
|
-
gap: 10
|
|
11899
|
-
},
|
|
11900
|
-
testID,
|
|
11901
|
-
children: [
|
|
11902
|
-
/* @__PURE__ */ jsx(
|
|
11903
|
-
reactNative.Text,
|
|
11904
|
-
{
|
|
11905
|
-
style: {
|
|
11906
|
-
fontSize: 11,
|
|
11907
|
-
fontFamily: "Inter, sans-serif",
|
|
11908
|
-
fontWeight: "600",
|
|
11909
|
-
letterSpacing: 0.6,
|
|
11910
|
-
textTransform: "uppercase",
|
|
11911
|
-
color: TEXT_TERTIARY8
|
|
11912
|
-
},
|
|
11913
|
-
children: title
|
|
11914
|
-
}
|
|
11915
|
-
),
|
|
11916
|
-
children
|
|
11917
|
-
]
|
|
11918
|
-
}
|
|
11919
|
-
);
|
|
11920
|
-
}
|
|
11921
|
-
function EntryList({ entries, expandedId, onToggle, emptyLabel, testID }) {
|
|
11922
|
-
if (entries.length === 0) {
|
|
11923
|
-
return /* @__PURE__ */ jsx(
|
|
11924
|
-
reactNative.Text,
|
|
11925
|
-
{
|
|
11926
|
-
style: { fontSize: 12, fontFamily: "Inter, sans-serif", color: TEXT_TERTIARY8 },
|
|
11927
|
-
testID: `${testID}-empty`,
|
|
11928
|
-
children: emptyLabel
|
|
11929
|
-
}
|
|
11930
|
-
);
|
|
11931
|
-
}
|
|
11932
|
-
return /* @__PURE__ */ jsx(reactNative.View, { style: { gap: 8 }, testID, children: entries.map((entry) => /* @__PURE__ */ jsx(
|
|
11933
|
-
ExerciseCard,
|
|
11934
|
-
{
|
|
11935
|
-
...toExerciseCardProps(entry, entry.id === expandedId, () => onToggle(entry.id))
|
|
11936
|
-
},
|
|
11937
|
-
entry.id
|
|
11938
|
-
)) });
|
|
11939
|
-
}
|
|
11940
|
-
function VbtBreakdown({ sets }) {
|
|
11941
|
-
return /* @__PURE__ */ jsx(reactNative.View, { style: { gap: 10 }, testID: "exercise-detail-page-vbt-breakdown", children: sets.map((set) => {
|
|
11942
|
-
const mean = calculateMeanVelocity(set.velocities);
|
|
11943
|
-
const loss = calculateVelocityLoss(set.velocities);
|
|
11944
|
-
return /* @__PURE__ */ jsxs(
|
|
11945
|
-
reactNative.View,
|
|
11946
|
-
{
|
|
11947
|
-
className: "flex-row items-center",
|
|
11948
|
-
style: { gap: 10 },
|
|
11949
|
-
testID: "exercise-detail-page-vbt-set",
|
|
11950
|
-
children: [
|
|
11951
|
-
/* @__PURE__ */ jsx(
|
|
11952
|
-
reactNative.Text,
|
|
11953
|
-
{
|
|
11954
|
-
style: {
|
|
11955
|
-
width: 44,
|
|
11956
|
-
fontSize: 11,
|
|
11957
|
-
fontFamily: "Inter, sans-serif",
|
|
11958
|
-
fontWeight: "600",
|
|
11959
|
-
color: TEXT_SECONDARY6
|
|
11960
|
-
},
|
|
11961
|
-
children: set.label
|
|
11962
|
-
}
|
|
11963
|
-
),
|
|
11964
|
-
/* @__PURE__ */ jsx(reactNative.View, { className: "flex-1", style: { height: 8, justifyContent: "center" }, children: /* @__PURE__ */ jsx(VelocityStrip, { velocities: set.velocities, variant: "mini" }) }),
|
|
11965
|
-
/* @__PURE__ */ jsx(
|
|
11966
|
-
reactNative.Text,
|
|
11967
|
-
{
|
|
11968
|
-
style: {
|
|
11969
|
-
fontSize: 11,
|
|
11970
|
-
fontFamily: "Inter, sans-serif",
|
|
11971
|
-
fontVariant: ["tabular-nums"],
|
|
11972
|
-
color: TEXT_TERTIARY8
|
|
11973
|
-
},
|
|
11974
|
-
children: `${mean.toFixed(2)} \xB7 -${loss}%`
|
|
11975
|
-
}
|
|
11976
|
-
)
|
|
11977
|
-
]
|
|
11978
|
-
},
|
|
11979
|
-
set.label
|
|
11980
|
-
);
|
|
11981
|
-
}) });
|
|
11982
|
-
}
|
|
11983
|
-
function VbtSummaryRow({ summary }) {
|
|
11984
|
-
const cells = [
|
|
11985
|
-
{ label: "Mean Velocity", value: `${summary.meanVelocity.toFixed(2)} m/s` },
|
|
11986
|
-
{ label: "Peak Vel. Loss", value: `-${summary.velocityLoss}%` }
|
|
11987
|
-
];
|
|
11988
|
-
return /* @__PURE__ */ jsx(reactNative.View, { className: "flex-row", style: { gap: 8 }, testID: "exercise-detail-page-vbt-summary", children: cells.map((cell) => /* @__PURE__ */ jsxs(
|
|
11989
|
-
reactNative.View,
|
|
11990
|
-
{
|
|
11991
|
-
style: {
|
|
11992
|
-
flex: 1,
|
|
11993
|
-
padding: 12,
|
|
11994
|
-
borderRadius: 10,
|
|
11995
|
-
backgroundColor: SURFACE_ELEVATED2,
|
|
11996
|
-
borderWidth: 1,
|
|
11997
|
-
borderColor: BORDER_DEFAULT4
|
|
11998
|
-
},
|
|
11999
|
-
children: [
|
|
12000
|
-
/* @__PURE__ */ jsx(
|
|
12001
|
-
reactNative.Text,
|
|
12002
|
-
{
|
|
12003
|
-
style: {
|
|
12004
|
-
fontSize: 16,
|
|
12005
|
-
fontFamily: '"Space Grotesk", sans-serif',
|
|
12006
|
-
fontWeight: "700",
|
|
12007
|
-
color: TEXT_PRIMARY8
|
|
12008
|
-
},
|
|
12009
|
-
children: cell.value
|
|
12010
|
-
}
|
|
12011
|
-
),
|
|
12012
|
-
/* @__PURE__ */ jsx(
|
|
12013
|
-
reactNative.Text,
|
|
12014
|
-
{
|
|
12015
|
-
style: {
|
|
12016
|
-
marginTop: 2,
|
|
12017
|
-
fontSize: 10,
|
|
12018
|
-
fontFamily: "Inter, sans-serif",
|
|
12019
|
-
fontWeight: "600",
|
|
12020
|
-
letterSpacing: 0.4,
|
|
12021
|
-
textTransform: "uppercase",
|
|
12022
|
-
color: TEXT_TERTIARY8
|
|
12023
|
-
},
|
|
12024
|
-
children: cell.label
|
|
12025
|
-
}
|
|
12026
|
-
)
|
|
12027
|
-
]
|
|
12028
|
-
},
|
|
12029
|
-
cell.label
|
|
12030
|
-
)) });
|
|
12031
|
-
}
|
|
12032
|
-
function ExerciseDetailPage({
|
|
12033
|
-
exercise,
|
|
12034
|
-
meso,
|
|
12035
|
-
trend,
|
|
12036
|
-
progression,
|
|
12037
|
-
history,
|
|
12038
|
-
vbt,
|
|
12039
|
-
className,
|
|
12040
|
-
...props
|
|
12041
|
-
}) {
|
|
12042
|
-
const [tab, setTab] = React24.useState("progress");
|
|
12043
|
-
const [expandedProgressId, setExpandedProgressId] = React24.useState(null);
|
|
12044
|
-
const [expandedHistoryId, setExpandedHistoryId] = React24.useState(null);
|
|
12045
|
-
const stats = React24.useMemo(() => deriveExerciseStats(history), [history]);
|
|
12046
|
-
const vbtSummary = React24.useMemo(() => summarizeVbt(vbt.sets), [vbt.sets]);
|
|
12047
|
-
const toggle = (setId) => (id) => setId((current) => current === id ? null : id);
|
|
12048
|
-
return /* @__PURE__ */ jsx(
|
|
12049
|
-
reactNative.View,
|
|
12050
|
-
{
|
|
12051
|
-
className,
|
|
12052
|
-
style: { width: 390, backgroundColor: PAGE_BG2 },
|
|
12053
|
-
accessibilityRole: "main",
|
|
12054
|
-
"aria-label": exercise.name,
|
|
12055
|
-
testID: "exercise-detail-page",
|
|
12056
|
-
...props,
|
|
12057
|
-
children: /* @__PURE__ */ jsxs(reactNative.View, { style: { padding: 16, gap: 14 }, testID: "exercise-detail-page-content", children: [
|
|
12058
|
-
/* @__PURE__ */ jsxs(
|
|
12059
|
-
reactNative.View,
|
|
12060
|
-
{
|
|
12061
|
-
className: "flex-row items-start justify-between",
|
|
12062
|
-
style: { gap: 8 },
|
|
12063
|
-
testID: "exercise-detail-page-header",
|
|
12064
|
-
children: [
|
|
12065
|
-
/* @__PURE__ */ jsxs(reactNative.View, { style: { flexShrink: 1 }, children: [
|
|
12066
|
-
/* @__PURE__ */ jsx(
|
|
12067
|
-
reactNative.Text,
|
|
12068
|
-
{
|
|
12069
|
-
accessibilityRole: "header",
|
|
12070
|
-
style: {
|
|
12071
|
-
fontSize: 20,
|
|
12072
|
-
fontFamily: '"Space Grotesk", sans-serif',
|
|
12073
|
-
fontWeight: "700",
|
|
12074
|
-
color: TEXT_PRIMARY8
|
|
12075
|
-
},
|
|
12076
|
-
testID: "exercise-detail-page-title",
|
|
12077
|
-
children: exercise.name
|
|
12078
|
-
}
|
|
12079
|
-
),
|
|
12080
|
-
/* @__PURE__ */ jsx(
|
|
12081
|
-
reactNative.Text,
|
|
12082
|
-
{
|
|
12083
|
-
style: {
|
|
12084
|
-
marginTop: 2,
|
|
12085
|
-
fontSize: 12,
|
|
12086
|
-
fontFamily: "Inter, sans-serif",
|
|
12087
|
-
color: TEXT_SECONDARY6
|
|
12088
|
-
},
|
|
12089
|
-
testID: "exercise-detail-page-subtitle",
|
|
12090
|
-
children: exercise.subtitle
|
|
12091
|
-
}
|
|
12092
|
-
)
|
|
12093
|
-
] }),
|
|
12094
|
-
exercise.currentE1rm != null && /* @__PURE__ */ jsxs(
|
|
12095
|
-
reactNative.View,
|
|
12096
|
-
{
|
|
12097
|
-
style: {
|
|
12098
|
-
paddingVertical: 4,
|
|
12099
|
-
paddingHorizontal: 10,
|
|
12100
|
-
borderRadius: 6,
|
|
12101
|
-
backgroundColor: "rgba(255,121,0,0.10)",
|
|
12102
|
-
borderWidth: 1,
|
|
12103
|
-
borderColor: "rgba(255,121,0,0.25)"
|
|
12104
|
-
},
|
|
12105
|
-
testID: "exercise-detail-page-e1rm",
|
|
12106
|
-
children: [
|
|
12107
|
-
/* @__PURE__ */ jsx(
|
|
12108
|
-
reactNative.Text,
|
|
12109
|
-
{
|
|
12110
|
-
style: {
|
|
12111
|
-
fontSize: 9,
|
|
12112
|
-
fontFamily: "Inter, sans-serif",
|
|
12113
|
-
fontWeight: "600",
|
|
12114
|
-
letterSpacing: 0.4,
|
|
12115
|
-
textTransform: "uppercase",
|
|
12116
|
-
color: TEXT_TERTIARY8
|
|
12117
|
-
},
|
|
12118
|
-
children: "e1RM"
|
|
12119
|
-
}
|
|
12120
|
-
),
|
|
12121
|
-
/* @__PURE__ */ jsx(
|
|
12122
|
-
reactNative.Text,
|
|
12123
|
-
{
|
|
12124
|
-
style: {
|
|
12125
|
-
fontSize: 15,
|
|
12126
|
-
fontFamily: '"Space Grotesk", sans-serif',
|
|
12127
|
-
fontWeight: "700",
|
|
12128
|
-
color: BRAND_PRIMARY12
|
|
12129
|
-
},
|
|
12130
|
-
children: `${exercise.currentE1rm} ${exercise.unit}`
|
|
12131
|
-
}
|
|
12132
|
-
)
|
|
12133
|
-
]
|
|
12134
|
-
}
|
|
12135
|
-
)
|
|
12136
|
-
]
|
|
12137
|
-
}
|
|
12138
|
-
),
|
|
12139
|
-
/* @__PURE__ */ jsx(TabBar, { active: tab, onSelect: setTab }),
|
|
12140
|
-
tab === "progress" && /* @__PURE__ */ jsxs(reactNative.View, { style: { gap: 14 }, testID: "exercise-detail-page-panel-progress", children: [
|
|
12141
|
-
/* @__PURE__ */ jsx(MesoStatusCard, { ...meso }),
|
|
12142
|
-
/* @__PURE__ */ jsx(StatStrip, { stats, unit: exercise.unit }),
|
|
12143
|
-
/* @__PURE__ */ jsx(SectionCard, { title: "Strength Trend", testID: "exercise-detail-page-trend", children: /* @__PURE__ */ jsx(
|
|
12144
|
-
StrengthTrendChart,
|
|
12145
|
-
{
|
|
12146
|
-
data: trend.data,
|
|
12147
|
-
projection: trend.projection,
|
|
12148
|
-
mesoBoundaries: trend.mesoBoundaries,
|
|
12149
|
-
width: CHART_WIDTH,
|
|
12150
|
-
height: CHART_HEIGHT,
|
|
12151
|
-
unit: exercise.unit,
|
|
12152
|
-
animateOnMount: false
|
|
12153
|
-
}
|
|
12154
|
-
) }),
|
|
12155
|
-
/* @__PURE__ */ jsx(SectionCard, { title: "Week-by-Week", testID: "exercise-detail-page-progression", children: /* @__PURE__ */ jsx(
|
|
12156
|
-
EntryList,
|
|
12157
|
-
{
|
|
12158
|
-
entries: progression,
|
|
12159
|
-
expandedId: expandedProgressId,
|
|
12160
|
-
onToggle: toggle(setExpandedProgressId),
|
|
12161
|
-
emptyLabel: "No progression logged yet",
|
|
12162
|
-
testID: "exercise-detail-page-progression-list"
|
|
12163
|
-
}
|
|
12164
|
-
) })
|
|
12165
|
-
] }),
|
|
12166
|
-
tab === "history" && /* @__PURE__ */ jsx(reactNative.View, { style: { gap: 14 }, testID: "exercise-detail-page-panel-history", children: /* @__PURE__ */ jsx(SectionCard, { title: "All Sessions", testID: "exercise-detail-page-history", children: /* @__PURE__ */ jsx(
|
|
12167
|
-
EntryList,
|
|
12168
|
-
{
|
|
12169
|
-
entries: history,
|
|
12170
|
-
expandedId: expandedHistoryId,
|
|
12171
|
-
onToggle: toggle(setExpandedHistoryId),
|
|
12172
|
-
emptyLabel: "No sessions logged yet",
|
|
12173
|
-
testID: "exercise-detail-page-history-list"
|
|
12174
|
-
}
|
|
12175
|
-
) }) }),
|
|
12176
|
-
tab === "advanced" && /* @__PURE__ */ jsxs(reactNative.View, { style: { gap: 14 }, testID: "exercise-detail-page-panel-advanced", children: [
|
|
12177
|
-
/* @__PURE__ */ jsx(SectionCard, { title: "Capacity Band", testID: "exercise-detail-page-capacity", children: /* @__PURE__ */ jsx(
|
|
12178
|
-
CapacityBandChart,
|
|
12179
|
-
{
|
|
12180
|
-
band: vbt.band,
|
|
12181
|
-
workouts: vbt.workouts,
|
|
12182
|
-
projection: vbt.projection,
|
|
12183
|
-
width: CHART_WIDTH,
|
|
12184
|
-
height: CHART_HEIGHT
|
|
12185
|
-
}
|
|
12186
|
-
) }),
|
|
12187
|
-
/* @__PURE__ */ jsx(VbtSummaryRow, { summary: vbtSummary }),
|
|
12188
|
-
/* @__PURE__ */ jsx(SectionCard, { title: "Velocity Breakdown", testID: "exercise-detail-page-velocity", children: /* @__PURE__ */ jsx(VbtBreakdown, { sets: vbt.sets }) })
|
|
12189
|
-
] })
|
|
12190
|
-
] })
|
|
12191
|
-
}
|
|
12192
|
-
);
|
|
12193
|
-
}
|
|
12194
|
-
var SURFACE_ELEVATED3 = "var(--color-surface-elevated)";
|
|
12195
|
-
var BORDER_DEFAULT5 = "var(--color-border-default)";
|
|
12196
|
-
var BRAND_PRIMARY13 = "#FF7900";
|
|
12197
|
-
var TEXT_PRIMARY9 = "var(--color-text-primary)";
|
|
12198
|
-
var TEXT_SECONDARY7 = "var(--color-text-secondary)";
|
|
12199
|
-
var TEXT_TERTIARY9 = "var(--color-text-tertiary)";
|
|
12200
|
-
var PAGE_BG3 = "var(--color-background-base)";
|
|
12201
|
-
function countCompletedSets(exercise) {
|
|
12202
|
-
if (exercise.setVelocities != null) return exercise.setVelocities.length;
|
|
12203
|
-
if (exercise.status === "completed") return exercise.totalPlannedSets;
|
|
12204
|
-
return 0;
|
|
12205
|
-
}
|
|
12206
|
-
function deriveWorkoutProgress(exercises) {
|
|
12207
|
-
let completedExercises = 0;
|
|
12208
|
-
let completedSets = 0;
|
|
12209
|
-
let totalSets = 0;
|
|
12210
|
-
for (const exercise of exercises) {
|
|
12211
|
-
if (exercise.status === "completed") completedExercises += 1;
|
|
12212
|
-
completedSets += countCompletedSets(exercise);
|
|
12213
|
-
totalSets += exercise.totalPlannedSets;
|
|
12214
|
-
}
|
|
12215
|
-
return {
|
|
12216
|
-
completedExercises,
|
|
12217
|
-
totalExercises: exercises.length,
|
|
12218
|
-
completedSets,
|
|
12219
|
-
totalSets,
|
|
12220
|
-
fraction: totalSets === 0 ? 0 : completedSets / totalSets
|
|
12221
|
-
};
|
|
12222
|
-
}
|
|
12223
|
-
function findActiveExercise(exercises) {
|
|
12224
|
-
return exercises.find((exercise) => exercise.status === "active") ?? null;
|
|
12225
|
-
}
|
|
12226
|
-
function statusToCardState(status, focused) {
|
|
12227
|
-
if (status === "upcoming") return "upcoming";
|
|
12228
|
-
return focused ? "expanded" : "collapsed";
|
|
12229
|
-
}
|
|
12230
|
-
function toActiveCardProps(exercise, focused, onToggle, supersetPosition = null, supersetColor) {
|
|
12231
|
-
const state = statusToCardState(exercise.status, focused);
|
|
12232
|
-
return {
|
|
12233
|
-
name: exercise.name,
|
|
12234
|
-
state,
|
|
12235
|
-
onToggle,
|
|
12236
|
-
summary: exercise.summary,
|
|
12237
|
-
e1rm: exercise.e1rm,
|
|
12238
|
-
isPR: exercise.isPR,
|
|
12239
|
-
tempo: exercise.tempo,
|
|
12240
|
-
setVelocities: exercise.setVelocities,
|
|
12241
|
-
totalPlannedSets: exercise.totalPlannedSets,
|
|
12242
|
-
sets: state === "expanded" ? exercise.sets : void 0,
|
|
12243
|
-
prescription: exercise.prescription,
|
|
12244
|
-
previousBest: exercise.previousBest,
|
|
12245
|
-
supersetPosition,
|
|
12246
|
-
supersetColor
|
|
12247
|
-
};
|
|
12248
|
-
}
|
|
12249
|
-
function groupExercises(exercises, supersets) {
|
|
12250
|
-
const byId = new Map(supersets.map((superset) => [superset.id, superset]));
|
|
12251
|
-
const groups = [];
|
|
12252
|
-
for (const exercise of exercises) {
|
|
12253
|
-
const superset = exercise.supersetId != null ? byId.get(exercise.supersetId) : void 0;
|
|
12254
|
-
const last = groups[groups.length - 1];
|
|
12255
|
-
if (superset != null && last?.type === "superset" && last.superset.id === superset.id) {
|
|
12256
|
-
last.exercises.push(exercise);
|
|
12257
|
-
} else if (superset != null) {
|
|
12258
|
-
groups.push({ type: "superset", superset, exercises: [exercise] });
|
|
12259
|
-
} else {
|
|
12260
|
-
groups.push({ type: "single", exercise });
|
|
12261
|
-
}
|
|
12262
|
-
}
|
|
12263
|
-
return groups;
|
|
12264
|
-
}
|
|
12265
|
-
function supersetPositionAt(index, length) {
|
|
12266
|
-
if (length === 1) return null;
|
|
12267
|
-
if (index === 0) return "first";
|
|
12268
|
-
if (index === length - 1) return "last";
|
|
12269
|
-
return "middle";
|
|
12270
|
-
}
|
|
12271
|
-
function WorkoutHeader({
|
|
12272
|
-
title,
|
|
12273
|
-
subtitle,
|
|
12274
|
-
progress
|
|
12275
|
-
}) {
|
|
12276
|
-
return /* @__PURE__ */ jsxs(reactNative.View, { style: { gap: 10 }, testID: "active-workout-page-header", children: [
|
|
12277
|
-
/* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-start justify-between", style: { gap: 8 }, children: [
|
|
12278
|
-
/* @__PURE__ */ jsxs(reactNative.View, { style: { flexShrink: 1 }, children: [
|
|
12279
|
-
/* @__PURE__ */ jsx(
|
|
12280
|
-
reactNative.Text,
|
|
12281
|
-
{
|
|
12282
|
-
accessibilityRole: "header",
|
|
12283
|
-
style: {
|
|
12284
|
-
fontSize: 20,
|
|
12285
|
-
fontFamily: '"Space Grotesk", sans-serif',
|
|
12286
|
-
fontWeight: "700",
|
|
12287
|
-
color: TEXT_PRIMARY9
|
|
12288
|
-
},
|
|
12289
|
-
testID: "active-workout-page-title",
|
|
12290
|
-
children: title
|
|
12291
|
-
}
|
|
12292
|
-
),
|
|
12293
|
-
subtitle != null && /* @__PURE__ */ jsx(
|
|
12294
|
-
reactNative.Text,
|
|
12295
|
-
{
|
|
12296
|
-
style: {
|
|
12297
|
-
marginTop: 2,
|
|
12298
|
-
fontSize: 12,
|
|
12299
|
-
fontFamily: "Inter, sans-serif",
|
|
12300
|
-
color: TEXT_SECONDARY7
|
|
12301
|
-
},
|
|
12302
|
-
testID: "active-workout-page-subtitle",
|
|
12303
|
-
children: subtitle
|
|
12304
|
-
}
|
|
12305
|
-
)
|
|
12306
|
-
] }),
|
|
12307
|
-
/* @__PURE__ */ jsxs(reactNative.View, { style: { alignItems: "flex-end" }, testID: "active-workout-page-progress-count", children: [
|
|
12308
|
-
/* @__PURE__ */ jsx(
|
|
12309
|
-
reactNative.Text,
|
|
12310
|
-
{
|
|
12311
|
-
style: {
|
|
12312
|
-
fontSize: 15,
|
|
12313
|
-
fontFamily: '"Space Grotesk", sans-serif',
|
|
12314
|
-
fontWeight: "700",
|
|
12315
|
-
color: BRAND_PRIMARY13,
|
|
12316
|
-
fontVariant: ["tabular-nums"]
|
|
12317
|
-
},
|
|
12318
|
-
children: `${progress.completedExercises}/${progress.totalExercises}`
|
|
12319
|
-
}
|
|
12320
|
-
),
|
|
12321
|
-
/* @__PURE__ */ jsx(
|
|
12322
|
-
reactNative.Text,
|
|
12323
|
-
{
|
|
12324
|
-
style: {
|
|
12325
|
-
fontSize: 10,
|
|
12326
|
-
fontFamily: "Inter, sans-serif",
|
|
12327
|
-
fontWeight: "600",
|
|
12328
|
-
letterSpacing: 0.4,
|
|
12329
|
-
textTransform: "uppercase",
|
|
12330
|
-
color: TEXT_TERTIARY9
|
|
12331
|
-
},
|
|
12332
|
-
children: `${progress.completedSets}/${progress.totalSets} sets`
|
|
12333
|
-
}
|
|
12334
|
-
)
|
|
12335
|
-
] })
|
|
12336
|
-
] }),
|
|
12337
|
-
/* @__PURE__ */ jsx(
|
|
12338
|
-
reactNative.View,
|
|
12339
|
-
{
|
|
12340
|
-
style: { height: 4, backgroundColor: BORDER_DEFAULT5, borderRadius: 2 },
|
|
12341
|
-
testID: "active-workout-page-progress-track",
|
|
12342
|
-
children: /* @__PURE__ */ jsx(
|
|
12343
|
-
reactNative.View,
|
|
12344
|
-
{
|
|
12345
|
-
style: {
|
|
12346
|
-
height: "100%",
|
|
12347
|
-
width: `${Math.round(progress.fraction * 100)}%`,
|
|
12348
|
-
backgroundColor: BRAND_PRIMARY13,
|
|
12349
|
-
borderRadius: 2
|
|
12350
|
-
},
|
|
12351
|
-
testID: "active-workout-page-progress-fill"
|
|
12352
|
-
}
|
|
12353
|
-
)
|
|
12354
|
-
}
|
|
12355
|
-
)
|
|
12356
|
-
] });
|
|
12357
|
-
}
|
|
12358
|
-
function ExerciseList({ groups, focusedId, onToggle }) {
|
|
12359
|
-
return /* @__PURE__ */ jsx(reactNative.View, { style: { gap: 10 }, testID: "active-workout-page-exercises", children: groups.map((group) => {
|
|
12360
|
-
if (group.type === "single") {
|
|
12361
|
-
return /* @__PURE__ */ jsx(
|
|
12362
|
-
reactNative.View,
|
|
12363
|
-
{
|
|
12364
|
-
style: {
|
|
12365
|
-
backgroundColor: SURFACE_ELEVATED3,
|
|
12366
|
-
borderWidth: 1,
|
|
12367
|
-
borderColor: BORDER_DEFAULT5,
|
|
12368
|
-
borderRadius: 12
|
|
12369
|
-
},
|
|
12370
|
-
children: /* @__PURE__ */ jsx(
|
|
12371
|
-
ExerciseCard,
|
|
12372
|
-
{
|
|
12373
|
-
...toActiveCardProps(
|
|
12374
|
-
group.exercise,
|
|
12375
|
-
group.exercise.id === focusedId,
|
|
12376
|
-
() => onToggle(group.exercise.id)
|
|
12377
|
-
)
|
|
12378
|
-
}
|
|
12379
|
-
)
|
|
12380
|
-
},
|
|
12381
|
-
group.exercise.id
|
|
12382
|
-
);
|
|
12383
|
-
}
|
|
12384
|
-
return /* @__PURE__ */ jsx(
|
|
12385
|
-
SupersetWrapper,
|
|
12386
|
-
{
|
|
12387
|
-
label: group.superset.label,
|
|
12388
|
-
color: group.superset.color,
|
|
12389
|
-
children: group.exercises.map((exercise, index) => /* @__PURE__ */ jsx(
|
|
12390
|
-
ExerciseCard,
|
|
12391
|
-
{
|
|
12392
|
-
...toActiveCardProps(
|
|
12393
|
-
exercise,
|
|
12394
|
-
exercise.id === focusedId,
|
|
12395
|
-
() => onToggle(exercise.id),
|
|
12396
|
-
supersetPositionAt(index, group.exercises.length),
|
|
12397
|
-
group.superset.color
|
|
12398
|
-
)
|
|
12399
|
-
},
|
|
12400
|
-
exercise.id
|
|
12401
|
-
))
|
|
12402
|
-
},
|
|
12403
|
-
group.superset.id
|
|
12404
|
-
);
|
|
12405
|
-
}) });
|
|
12406
|
-
}
|
|
12407
|
-
function ActiveWorkoutPage({
|
|
12408
|
-
title = "Active Workout",
|
|
12409
|
-
subtitle,
|
|
12410
|
-
exercises,
|
|
12411
|
-
supersets = [],
|
|
12412
|
-
input,
|
|
12413
|
-
rest,
|
|
12414
|
-
initialResting = false,
|
|
12415
|
-
className,
|
|
12416
|
-
...props
|
|
12417
|
-
}) {
|
|
12418
|
-
const active = findActiveExercise(exercises);
|
|
12419
|
-
const [focusedId, setFocusedId] = React24.useState(active?.id ?? null);
|
|
12420
|
-
const [resting, setResting] = React24.useState(initialResting);
|
|
12421
|
-
const [reps, setReps] = React24.useState(input?.reps ?? "");
|
|
12422
|
-
const [weight, setWeight] = React24.useState(input?.weight ?? "");
|
|
12423
|
-
const progress = React24.useMemo(() => deriveWorkoutProgress(exercises), [exercises]);
|
|
12424
|
-
const groups = React24.useMemo(() => groupExercises(exercises, supersets), [exercises, supersets]);
|
|
12425
|
-
const toggleFocus = (id) => setFocusedId((current) => current === id ? null : id);
|
|
12426
|
-
const nextSetNumber = active != null ? countCompletedSets(active) + 1 : 1;
|
|
12427
|
-
const canRecord = reps.trim() !== "" && weight.trim() !== "";
|
|
12428
|
-
const showRest = resting && rest != null;
|
|
12429
|
-
const showInput = !showRest && active != null;
|
|
12430
|
-
return /* @__PURE__ */ jsxs(
|
|
12431
|
-
reactNative.View,
|
|
12432
|
-
{
|
|
12433
|
-
className,
|
|
12434
|
-
style: { position: "relative", width: 390, backgroundColor: PAGE_BG3 },
|
|
12435
|
-
accessibilityRole: "main",
|
|
12436
|
-
"aria-label": title,
|
|
12437
|
-
testID: "active-workout-page",
|
|
12438
|
-
...props,
|
|
12439
|
-
children: [
|
|
12440
|
-
/* @__PURE__ */ jsxs(reactNative.View, { style: { padding: 16, gap: 14 }, testID: "active-workout-page-content", children: [
|
|
12441
|
-
/* @__PURE__ */ jsx(WorkoutHeader, { title, subtitle, progress }),
|
|
12442
|
-
/* @__PURE__ */ jsx(ExerciseList, { groups, focusedId, onToggle: toggleFocus })
|
|
12443
|
-
] }),
|
|
12444
|
-
(showRest || showInput) && /* @__PURE__ */ jsx(
|
|
12445
|
-
reactNative.View,
|
|
12446
|
-
{
|
|
12447
|
-
style: { borderTopWidth: 1, borderTopColor: BORDER_DEFAULT5 },
|
|
12448
|
-
testID: "active-workout-page-bottom-bar",
|
|
12449
|
-
children: showRest && rest != null ? /* @__PURE__ */ jsx(
|
|
12450
|
-
RestTimer,
|
|
12451
|
-
{
|
|
12452
|
-
totalSeconds: rest.totalSeconds,
|
|
12453
|
-
elapsedMs: rest.elapsedMs,
|
|
12454
|
-
nextSetInfo: rest.nextSetInfo,
|
|
12455
|
-
onSkip: () => setResting(false),
|
|
12456
|
-
onAddTime: () => void 0,
|
|
12457
|
-
visible: true
|
|
12458
|
-
}
|
|
12459
|
-
) : active != null && /* @__PURE__ */ jsx(
|
|
12460
|
-
InputBar,
|
|
12461
|
-
{
|
|
12462
|
-
exerciseName: active.name,
|
|
12463
|
-
setNumber: nextSetNumber,
|
|
12464
|
-
totalSets: active.totalPlannedSets,
|
|
12465
|
-
reps,
|
|
12466
|
-
weight,
|
|
12467
|
-
unit: active.unit,
|
|
12468
|
-
onRepsChange: setReps,
|
|
12469
|
-
onWeightChange: setWeight,
|
|
12470
|
-
onRecord: () => {
|
|
12471
|
-
if (rest != null) setResting(true);
|
|
12472
|
-
},
|
|
12473
|
-
canRecord,
|
|
12474
|
-
visible: true
|
|
12475
|
-
}
|
|
12476
|
-
)
|
|
12477
|
-
}
|
|
12478
|
-
)
|
|
12479
|
-
]
|
|
12480
|
-
}
|
|
12481
|
-
);
|
|
12482
|
-
}
|
|
12483
|
-
var PALETTE = [
|
|
12484
|
-
"#5B9BD5",
|
|
12485
|
-
"#14B8A6",
|
|
12486
|
-
"#F4A736",
|
|
12487
|
-
"#F83030",
|
|
12488
|
-
"#823CA0",
|
|
12489
|
-
"#D4A520",
|
|
12490
|
-
"#406D87",
|
|
12491
|
-
"#43C6B7"
|
|
12492
|
-
];
|
|
12493
|
-
function scaleValue(v, scale) {
|
|
12494
|
-
if (v <= 0) return 0;
|
|
12495
|
-
if (scale === "sqrt") return Math.sqrt(v);
|
|
12496
|
-
if (scale === "log") return Math.log10(v + 1);
|
|
12497
|
-
return v;
|
|
12498
|
-
}
|
|
12499
|
-
function worstRatio(row, side) {
|
|
12500
|
-
const sum = row.reduce((s, r) => s + r.area, 0);
|
|
12501
|
-
const thickness = sum / side;
|
|
12502
|
-
let worst = 0;
|
|
12503
|
-
for (const r of row) {
|
|
12504
|
-
const len = r.area / thickness;
|
|
12505
|
-
const ratio = Math.max(thickness / len, len / thickness);
|
|
12506
|
-
if (ratio > worst) worst = ratio;
|
|
12507
|
-
}
|
|
12508
|
-
return worst;
|
|
12509
|
-
}
|
|
12510
|
-
function squarify(data, w, h) {
|
|
12511
|
-
const total = data.reduce((s, d) => s + d.value, 0);
|
|
12512
|
-
if (total <= 0 || w <= 0 || h <= 0) return [];
|
|
12513
|
-
const scaled = data.map((d) => ({ datum: d, area: d.value / total * w * h }));
|
|
12514
|
-
const out = [];
|
|
12515
|
-
let rx = 0;
|
|
12516
|
-
let ry = 0;
|
|
12517
|
-
let rw = w;
|
|
12518
|
-
let rh = h;
|
|
12519
|
-
let i = 0;
|
|
12520
|
-
while (i < scaled.length) {
|
|
12521
|
-
const vertical = rw >= rh;
|
|
12522
|
-
const side = vertical ? rh : rw;
|
|
12523
|
-
let row = [];
|
|
12524
|
-
let bestWorst = Infinity;
|
|
12525
|
-
let j = i;
|
|
12526
|
-
while (j < scaled.length) {
|
|
12527
|
-
const trial = [...row, scaled[j]];
|
|
12528
|
-
const worst = worstRatio(trial, side);
|
|
12529
|
-
if (row.length > 0 && worst > bestWorst) break;
|
|
12530
|
-
row = trial;
|
|
12531
|
-
bestWorst = worst;
|
|
12532
|
-
j++;
|
|
12533
|
-
}
|
|
12534
|
-
const rowArea = row.reduce((s, r) => s + r.area, 0);
|
|
12535
|
-
const thickness = rowArea / side;
|
|
12536
|
-
let along = vertical ? ry : rx;
|
|
12537
|
-
for (const r of row) {
|
|
12538
|
-
const len = r.area / thickness;
|
|
12539
|
-
out.push(
|
|
12540
|
-
vertical ? { x: rx, y: along, w: thickness, h: len, datum: r.datum } : { x: along, y: ry, w: len, h: thickness, datum: r.datum }
|
|
12541
|
-
);
|
|
12542
|
-
along += len;
|
|
12543
|
-
}
|
|
12544
|
-
if (vertical) {
|
|
12545
|
-
rx += thickness;
|
|
12546
|
-
rw -= thickness;
|
|
12547
|
-
} else {
|
|
12548
|
-
ry += thickness;
|
|
12549
|
-
rh -= thickness;
|
|
12550
|
-
}
|
|
12551
|
-
i = j;
|
|
12552
|
-
}
|
|
12553
|
-
return out;
|
|
12554
|
-
}
|
|
12555
|
-
function Treemap({
|
|
12556
|
-
data,
|
|
12557
|
-
width,
|
|
12558
|
-
height,
|
|
12559
|
-
scale = "sqrt",
|
|
12560
|
-
maxTiles = 60,
|
|
12561
|
-
onPress,
|
|
12562
|
-
selectedId,
|
|
12563
|
-
className,
|
|
12564
|
-
...props
|
|
12565
|
-
}) {
|
|
12566
|
-
const clean = data.filter((d) => d.value > 0).sort((a, b) => b.value - a.value).map((d, i) => ({ ...d, color: d.color ?? PALETTE[i % PALETTE.length] }));
|
|
12567
|
-
let tiles = clean;
|
|
12568
|
-
if (clean.length > maxTiles) {
|
|
12569
|
-
const head = clean.slice(0, maxTiles - 1);
|
|
12570
|
-
const restValue = clean.slice(maxTiles - 1).reduce((s, d) => s + d.value, 0);
|
|
12571
|
-
tiles = [
|
|
12572
|
-
...head,
|
|
12573
|
-
{ id: "__more__", value: restValue, color: "#3a3a3a", label: `+${clean.length - (maxTiles - 1)} more` }
|
|
12574
|
-
];
|
|
12575
|
-
}
|
|
12576
|
-
const weighted = tiles.map((d) => ({ ...d, value: scaleValue(d.value, scale) }));
|
|
12577
|
-
const rects = squarify(weighted, width, height);
|
|
12578
|
-
return /* @__PURE__ */ jsx(reactNative.View, { className: cn("relative", className), style: { width, height }, ...props, children: rects.map((r) => {
|
|
12579
|
-
const selected = r.datum.id === selectedId;
|
|
12580
|
-
const labelFits = r.w > 54 && r.h > 22;
|
|
12581
|
-
const pressable = r.datum.id !== "__more__";
|
|
12582
|
-
return /* @__PURE__ */ jsx(
|
|
12583
|
-
reactNative.Pressable,
|
|
12584
|
-
{
|
|
12585
|
-
testID: `treemap-tile-${r.datum.id}`,
|
|
12586
|
-
accessibilityLabel: r.datum.label ?? r.datum.id,
|
|
12587
|
-
onPress: pressable ? () => onPress?.(r.datum.id) : void 0,
|
|
12588
|
-
style: {
|
|
12589
|
-
position: "absolute",
|
|
12590
|
-
left: r.x,
|
|
12591
|
-
top: r.y,
|
|
12592
|
-
width: Math.max(0, r.w - 2),
|
|
12593
|
-
height: Math.max(0, r.h - 2),
|
|
12594
|
-
backgroundColor: r.datum.color,
|
|
12595
|
-
borderRadius: 3,
|
|
12596
|
-
opacity: selected ? 1 : 0.9,
|
|
12597
|
-
borderWidth: selected ? 2 : 0,
|
|
12598
|
-
borderColor: "#ffffff",
|
|
12599
|
-
padding: 4,
|
|
12600
|
-
overflow: "hidden"
|
|
12601
|
-
},
|
|
12602
|
-
children: labelFits && /* @__PURE__ */ jsx(reactNative.Text, { numberOfLines: 2, className: "text-[10px] font-semibold text-[#0b0b0b]", children: r.datum.label ?? r.datum.id })
|
|
12603
|
-
},
|
|
12604
|
-
r.datum.id
|
|
12605
|
-
);
|
|
12606
|
-
}) });
|
|
12607
|
-
}
|
|
12608
|
-
var PALETTE2 = [
|
|
12609
|
-
"#5B9BD5",
|
|
12610
|
-
"#14B8A6",
|
|
12611
|
-
"#F4A736",
|
|
12612
|
-
"#F83030",
|
|
12613
|
-
"#823CA0",
|
|
12614
|
-
"#D4A520",
|
|
12615
|
-
"#406D87",
|
|
12616
|
-
"#43C6B7"
|
|
12617
|
-
];
|
|
12618
|
-
var GRID_LINE2 = "rgba(255,255,255,0.07)";
|
|
12619
|
-
var AXIS_LINE = "rgba(255,255,255,0.18)";
|
|
12620
|
-
var DIAGONAL_LINE = "rgba(255,255,255,0.28)";
|
|
12621
|
-
var DEFAULT_R = 6;
|
|
12622
|
-
var PLOT_LEFT2 = 40;
|
|
12623
|
-
var PLOT_RIGHT = 12;
|
|
12624
|
-
var PLOT_TOP = 12;
|
|
12625
|
-
var PLOT_BOTTOM = 34;
|
|
12626
|
-
var TICK_COUNT = 5;
|
|
12627
|
-
function domainOf(values, min, max) {
|
|
12628
|
-
const lo = min ?? (values.length ? Math.min(...values) : 0);
|
|
12629
|
-
const hi = max ?? (values.length ? Math.max(...values) : 1);
|
|
12630
|
-
if (hi > lo) return { min: lo, max: hi };
|
|
12631
|
-
const pad = Math.abs(hi) * 0.1 || 0.5;
|
|
12632
|
-
return { min: lo - pad, max: hi + pad };
|
|
12633
|
-
}
|
|
12634
|
-
function ticksOf(d, count) {
|
|
12635
|
-
return Array.from({ length: count }, (_, i) => d.min + (d.max - d.min) * i / (count - 1));
|
|
12636
|
-
}
|
|
12637
|
-
function formatTick(v) {
|
|
12638
|
-
if (Number.isInteger(v)) return `${v}`;
|
|
12639
|
-
return v.toFixed(Math.abs(v) < 1 ? 2 : 1);
|
|
12640
|
-
}
|
|
12641
|
-
function LineSegment({
|
|
12642
|
-
x1,
|
|
12643
|
-
y1,
|
|
12644
|
-
x2,
|
|
12645
|
-
y2,
|
|
12646
|
-
color,
|
|
12647
|
-
testID
|
|
12648
|
-
}) {
|
|
12649
|
-
const dx = x2 - x1;
|
|
12650
|
-
const dy = y2 - y1;
|
|
12651
|
-
const length = Math.sqrt(dx * dx + dy * dy);
|
|
12652
|
-
const angle = Math.atan2(dy, dx) * (180 / Math.PI);
|
|
12027
|
+
const dx = x2 - x1;
|
|
12028
|
+
const dy = y2 - y1;
|
|
12029
|
+
const length = Math.sqrt(dx * dx + dy * dy);
|
|
12030
|
+
const angle = Math.atan2(dy, dx) * (180 / Math.PI);
|
|
12653
12031
|
return /* @__PURE__ */ jsx(
|
|
12654
12032
|
reactNative.View,
|
|
12655
12033
|
{
|
|
@@ -12704,28 +12082,28 @@ function Scatter({
|
|
|
12704
12082
|
testID: "scatter-canvas",
|
|
12705
12083
|
style: { position: "absolute", top: 0, left: 0, width, height, overflow: "hidden" },
|
|
12706
12084
|
children: [
|
|
12707
|
-
ticksOf(yd, TICK_COUNT).map((
|
|
12708
|
-
const y = toY(
|
|
12085
|
+
ticksOf(yd, TICK_COUNT).map((t2, i) => {
|
|
12086
|
+
const y = toY(t2);
|
|
12709
12087
|
return /* @__PURE__ */ jsx(
|
|
12710
12088
|
reactNative.View,
|
|
12711
12089
|
{
|
|
12712
12090
|
accessibilityElementsHidden: true,
|
|
12713
12091
|
testID: "scatter-gridline-y",
|
|
12714
12092
|
style: { position: "absolute", left: PLOT_LEFT2, width: innerW, top: y, height: 1, backgroundColor: GRID_LINE2 },
|
|
12715
|
-
children: /* @__PURE__ */ jsx(reactNative.Text, { className: "text-[9px] text-text-tertiary", style: { position: "absolute", left: -PLOT_LEFT2, top: -6, width: PLOT_LEFT2 - 6, textAlign: "right" }, children: formatTick(
|
|
12093
|
+
children: /* @__PURE__ */ jsx(reactNative.Text, { className: "text-[9px] text-text-tertiary", style: { position: "absolute", left: -PLOT_LEFT2, top: -6, width: PLOT_LEFT2 - 6, textAlign: "right" }, children: formatTick(t2) })
|
|
12716
12094
|
},
|
|
12717
12095
|
`y-${i}`
|
|
12718
12096
|
);
|
|
12719
12097
|
}),
|
|
12720
|
-
ticksOf(xd, TICK_COUNT).map((
|
|
12721
|
-
const x = toX(
|
|
12098
|
+
ticksOf(xd, TICK_COUNT).map((t2, i) => {
|
|
12099
|
+
const x = toX(t2);
|
|
12722
12100
|
return /* @__PURE__ */ jsx(
|
|
12723
12101
|
reactNative.View,
|
|
12724
12102
|
{
|
|
12725
12103
|
accessibilityElementsHidden: true,
|
|
12726
12104
|
testID: "scatter-gridline-x",
|
|
12727
12105
|
style: { position: "absolute", top: PLOT_TOP, height: innerH, left: x, width: 1, backgroundColor: GRID_LINE2 },
|
|
12728
|
-
children: /* @__PURE__ */ jsx(reactNative.Text, { className: "text-[9px] text-text-tertiary", style: { position: "absolute", top: innerH + 4, left: -16, width: 32, textAlign: "center" }, children: formatTick(
|
|
12106
|
+
children: /* @__PURE__ */ jsx(reactNative.Text, { className: "text-[9px] text-text-tertiary", style: { position: "absolute", top: innerH + 4, left: -16, width: 32, textAlign: "center" }, children: formatTick(t2) })
|
|
12729
12107
|
},
|
|
12730
12108
|
`x-${i}`
|
|
12731
12109
|
);
|
|
@@ -12787,24 +12165,24 @@ function Scatter({
|
|
|
12787
12165
|
}
|
|
12788
12166
|
var STATUS_SUCCESS4 = "#14B8A6";
|
|
12789
12167
|
var STATUS_WARNING4 = "#FFB020";
|
|
12790
|
-
var
|
|
12168
|
+
var STATUS_ERROR4 = "#D14343";
|
|
12791
12169
|
var TRACK = "rgba(255,255,255,0.08)";
|
|
12792
12170
|
var DEFAULT_THRESHOLDS = [
|
|
12793
|
-
{ value: 0, color:
|
|
12171
|
+
{ value: 0, color: STATUS_ERROR4 },
|
|
12794
12172
|
{ value: 60, color: STATUS_WARNING4 },
|
|
12795
12173
|
{ value: 80, color: STATUS_SUCCESS4 }
|
|
12796
12174
|
];
|
|
12797
12175
|
var ARC_START = 135;
|
|
12798
12176
|
var ARC_SWEEP = 270;
|
|
12799
12177
|
var SEGMENTS = 40;
|
|
12800
|
-
function
|
|
12178
|
+
function clamp012(n) {
|
|
12801
12179
|
if (Number.isNaN(n)) return 0;
|
|
12802
12180
|
return Math.max(0, Math.min(1, n));
|
|
12803
12181
|
}
|
|
12804
12182
|
function formatValue2(v) {
|
|
12805
12183
|
return Number.isInteger(v) ? `${v}` : v.toFixed(1);
|
|
12806
12184
|
}
|
|
12807
|
-
function
|
|
12185
|
+
function bandColor2(fraction, bands, min, max) {
|
|
12808
12186
|
const value = min + fraction * (max - min);
|
|
12809
12187
|
const sorted = [...bands].sort((a, b) => a.value - b.value);
|
|
12810
12188
|
let color = sorted[0]?.color ?? STATUS_SUCCESS4;
|
|
@@ -12842,10 +12220,10 @@ function Gauge2({
|
|
|
12842
12220
|
...props
|
|
12843
12221
|
}) {
|
|
12844
12222
|
const span = max - min || 1;
|
|
12845
|
-
const fill =
|
|
12846
|
-
const activeColor = (f) => color ??
|
|
12223
|
+
const fill = clamp012((value - min) / span);
|
|
12224
|
+
const activeColor = (f) => color ?? bandColor2(f, thresholds, min, max);
|
|
12847
12225
|
const ticks = buildTicks(fill, size, activeColor);
|
|
12848
|
-
const displayColor = color ??
|
|
12226
|
+
const displayColor = color ?? bandColor2(fill, thresholds, min, max);
|
|
12849
12227
|
const tickLength = size * 0.11;
|
|
12850
12228
|
const tickThickness = Math.max(2, size * 0.9 / SEGMENTS);
|
|
12851
12229
|
const ariaLabel = `${label ? `${label}: ` : ""}${formatValue2(value)}${unit ?? ""} of ${formatValue2(max)}`;
|
|
@@ -12859,23 +12237,23 @@ function Gauge2({
|
|
|
12859
12237
|
testID: "gauge",
|
|
12860
12238
|
...props,
|
|
12861
12239
|
children: [
|
|
12862
|
-
ticks.map((
|
|
12240
|
+
ticks.map((t2) => /* @__PURE__ */ jsx(
|
|
12863
12241
|
reactNative.View,
|
|
12864
12242
|
{
|
|
12865
12243
|
accessibilityElementsHidden: true,
|
|
12866
12244
|
testID: "gauge-segment",
|
|
12867
12245
|
style: {
|
|
12868
12246
|
position: "absolute",
|
|
12869
|
-
left:
|
|
12870
|
-
top:
|
|
12247
|
+
left: t2.left - tickThickness / 2,
|
|
12248
|
+
top: t2.top - tickLength / 2,
|
|
12871
12249
|
width: tickThickness,
|
|
12872
12250
|
height: tickLength,
|
|
12873
12251
|
borderRadius: tickThickness / 2,
|
|
12874
|
-
backgroundColor:
|
|
12875
|
-
transform: [{ rotate:
|
|
12252
|
+
backgroundColor: t2.color,
|
|
12253
|
+
transform: [{ rotate: t2.rotate }]
|
|
12876
12254
|
}
|
|
12877
12255
|
},
|
|
12878
|
-
|
|
12256
|
+
t2.key
|
|
12879
12257
|
)),
|
|
12880
12258
|
/* @__PURE__ */ jsxs(reactNative.View, { style: { position: "absolute", top: 0, left: 0, width: size, height: size }, className: "items-center justify-center", children: [
|
|
12881
12259
|
/* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-baseline gap-0.5", children: [
|
|
@@ -12889,65 +12267,6 @@ function Gauge2({
|
|
|
12889
12267
|
);
|
|
12890
12268
|
}
|
|
12891
12269
|
|
|
12892
|
-
// src/utils/colors.ts
|
|
12893
|
-
function getStatusColor(status) {
|
|
12894
|
-
return `var(--color-status-${status})`;
|
|
12895
|
-
}
|
|
12896
|
-
function getResultColor(result) {
|
|
12897
|
-
return `var(--color-result-${result})`;
|
|
12898
|
-
}
|
|
12899
|
-
function alpha(color, opacity) {
|
|
12900
|
-
const clampedOpacity = Math.max(0, Math.min(1, opacity));
|
|
12901
|
-
if (color.startsWith("#")) {
|
|
12902
|
-
const hex = color.slice(1);
|
|
12903
|
-
let r, g, b;
|
|
12904
|
-
if (hex.length === 3) {
|
|
12905
|
-
r = parseInt(hex[0] + hex[0], 16);
|
|
12906
|
-
g = parseInt(hex[1] + hex[1], 16);
|
|
12907
|
-
b = parseInt(hex[2] + hex[2], 16);
|
|
12908
|
-
} else if (hex.length === 6) {
|
|
12909
|
-
r = parseInt(hex.slice(0, 2), 16);
|
|
12910
|
-
g = parseInt(hex.slice(2, 4), 16);
|
|
12911
|
-
b = parseInt(hex.slice(4, 6), 16);
|
|
12912
|
-
} else {
|
|
12913
|
-
return color;
|
|
12914
|
-
}
|
|
12915
|
-
return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
|
|
12916
|
-
}
|
|
12917
|
-
const rgbMatch = color.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
|
|
12918
|
-
if (rgbMatch) {
|
|
12919
|
-
const [, r, g, b] = rgbMatch;
|
|
12920
|
-
return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
|
|
12921
|
-
}
|
|
12922
|
-
const rgbaMatch = color.match(/rgba\((\d+),\s*(\d+),\s*(\d+),\s*[\d.]+\)/);
|
|
12923
|
-
if (rgbaMatch) {
|
|
12924
|
-
const [, r, g, b] = rgbaMatch;
|
|
12925
|
-
return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
|
|
12926
|
-
}
|
|
12927
|
-
return color;
|
|
12928
|
-
}
|
|
12929
|
-
function getLuminance(color) {
|
|
12930
|
-
if (!color.startsWith("#")) return "dark";
|
|
12931
|
-
const hex = color.slice(1);
|
|
12932
|
-
let r, g, b;
|
|
12933
|
-
if (hex.length === 3) {
|
|
12934
|
-
r = parseInt(hex[0] + hex[0], 16);
|
|
12935
|
-
g = parseInt(hex[1] + hex[1], 16);
|
|
12936
|
-
b = parseInt(hex[2] + hex[2], 16);
|
|
12937
|
-
} else if (hex.length === 6) {
|
|
12938
|
-
r = parseInt(hex.slice(0, 2), 16);
|
|
12939
|
-
g = parseInt(hex.slice(2, 4), 16);
|
|
12940
|
-
b = parseInt(hex.slice(4, 6), 16);
|
|
12941
|
-
} else {
|
|
12942
|
-
return "dark";
|
|
12943
|
-
}
|
|
12944
|
-
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
12945
|
-
return luminance > 0.5 ? "light" : "dark";
|
|
12946
|
-
}
|
|
12947
|
-
function getContrastText(backgroundColor) {
|
|
12948
|
-
return getLuminance(backgroundColor) === "light" ? "#000000" : "#FFFFFF";
|
|
12949
|
-
}
|
|
12950
|
-
|
|
12951
12270
|
// src/utils/form.ts
|
|
12952
12271
|
function getFieldValidationProps(state) {
|
|
12953
12272
|
return {
|
|
@@ -13040,7 +12359,6 @@ exports.Accordion = Accordion;
|
|
|
13040
12359
|
exports.AccordionButton = AccordionButton;
|
|
13041
12360
|
exports.AccordionItem = AccordionItem;
|
|
13042
12361
|
exports.AccordionPanel = AccordionPanel;
|
|
13043
|
-
exports.ActiveWorkoutPage = ActiveWorkoutPage;
|
|
13044
12362
|
exports.Alert = Alert;
|
|
13045
12363
|
exports.AlertDescription = AlertDescription;
|
|
13046
12364
|
exports.AlertTitle = AlertTitle;
|
|
@@ -13081,10 +12399,8 @@ exports.Drawer = Drawer;
|
|
|
13081
12399
|
exports.DrawerBody = DrawerBody;
|
|
13082
12400
|
exports.DrawerFooter = DrawerFooter;
|
|
13083
12401
|
exports.DrawerHeader = DrawerHeader;
|
|
13084
|
-
exports.EXERCISE_DETAIL_TABS = EXERCISE_DETAIL_TABS;
|
|
13085
12402
|
exports.EmptyState = EmptyState;
|
|
13086
12403
|
exports.ExerciseCard = ExerciseCard;
|
|
13087
|
-
exports.ExerciseDetailPage = ExerciseDetailPage;
|
|
13088
12404
|
exports.FormActions = FormActions;
|
|
13089
12405
|
exports.FormField = FormField;
|
|
13090
12406
|
exports.FormRow = FormRow;
|
|
@@ -13137,7 +12453,6 @@ exports.PopoverContent = PopoverContent;
|
|
|
13137
12453
|
exports.PopoverTrigger = PopoverTrigger;
|
|
13138
12454
|
exports.PrBadge = PrBadge;
|
|
13139
12455
|
exports.PrHistoryModal = PrHistoryModal;
|
|
13140
|
-
exports.ProgramPlanningPage = ProgramPlanningPage;
|
|
13141
12456
|
exports.Progress = Progress;
|
|
13142
12457
|
exports.ProgressSteps = ProgressSteps;
|
|
13143
12458
|
exports.Radio = Radio;
|
|
@@ -13175,6 +12490,7 @@ exports.StrengthTrendChart = StrengthTrendChart;
|
|
|
13175
12490
|
exports.SupersetWrapper = SupersetWrapper;
|
|
13176
12491
|
exports.Surface = Surface;
|
|
13177
12492
|
exports.Switch = Switch;
|
|
12493
|
+
exports.TEMPO_PACING = TEMPO_PACING;
|
|
13178
12494
|
exports.Tab = Tab;
|
|
13179
12495
|
exports.TabList = TabList;
|
|
13180
12496
|
exports.TabPanel = TabPanel;
|
|
@@ -13187,6 +12503,7 @@ exports.TableHeaderCell = TableHeaderCell;
|
|
|
13187
12503
|
exports.TablePagination = TablePagination;
|
|
13188
12504
|
exports.TableRow = TableRow;
|
|
13189
12505
|
exports.Tabs = Tabs;
|
|
12506
|
+
exports.TempoBar = TempoBar;
|
|
13190
12507
|
exports.TempoDisplay = TempoDisplay;
|
|
13191
12508
|
exports.Toast = Toast;
|
|
13192
12509
|
exports.ToastProvider = ToastProvider;
|
|
@@ -13204,14 +12521,12 @@ exports.WorkoutPill = WorkoutPill;
|
|
|
13204
12521
|
exports.alpha = alpha;
|
|
13205
12522
|
exports.applyThemePreset = applyThemePreset;
|
|
13206
12523
|
exports.audiobookPreset = audiobookPreset;
|
|
13207
|
-
exports.buildBreadcrumbs = buildBreadcrumbs;
|
|
13208
12524
|
exports.buttonSizes = buttonSizes;
|
|
13209
12525
|
exports.calculateMeanVelocity = calculateMeanVelocity;
|
|
13210
12526
|
exports.calculateVelocityLoss = calculateVelocityLoss;
|
|
13211
12527
|
exports.cn = cn;
|
|
13212
12528
|
exports.componentElevationRanges = componentElevationRanges;
|
|
13213
12529
|
exports.composeValidators = composeValidators;
|
|
13214
|
-
exports.countCompletedSets = countCompletedSets;
|
|
13215
12530
|
exports.createFieldId = createFieldId;
|
|
13216
12531
|
exports.createFlatShadow = createFlatShadow;
|
|
13217
12532
|
exports.createPressedHoverShadow = createPressedHoverShadow;
|
|
@@ -13221,15 +12536,8 @@ exports.createRaisedShadow = createRaisedShadow;
|
|
|
13221
12536
|
exports.darkThemeCSSVars = darkThemeCSSVars;
|
|
13222
12537
|
exports.darken = darken;
|
|
13223
12538
|
exports.defaultPreset = defaultPreset;
|
|
13224
|
-
exports.deriveExerciseStats = deriveExerciseStats;
|
|
13225
|
-
exports.deriveNavLevel = deriveNavLevel;
|
|
13226
|
-
exports.deriveWorkoutProgress = deriveWorkoutProgress;
|
|
13227
12539
|
exports.discreteRainbow = discreteRainbow;
|
|
13228
12540
|
exports.elevationSystem = elevationSystem;
|
|
13229
|
-
exports.findActiveExercise = findActiveExercise;
|
|
13230
|
-
exports.findMeso = findMeso;
|
|
13231
|
-
exports.findWeek = findWeek;
|
|
13232
|
-
exports.findWorkout = findWorkout;
|
|
13233
12541
|
exports.formatDateTime = formatDateTime;
|
|
13234
12542
|
exports.formatPrescription = formatPrescription;
|
|
13235
12543
|
exports.formatSignedPct = formatSignedPct;
|
|
@@ -13248,12 +12556,13 @@ exports.getLuminance = getLuminance;
|
|
|
13248
12556
|
exports.getResultColor = getResultColor;
|
|
13249
12557
|
exports.getSemanticColors = getSemanticColors;
|
|
13250
12558
|
exports.getStatusColor = getStatusColor;
|
|
12559
|
+
exports.getTempoFillPct = getTempoFillPct;
|
|
12560
|
+
exports.getTempoPacingState = getTempoPacingState;
|
|
13251
12561
|
exports.getThemeCSSVars = getThemeCSSVars;
|
|
13252
12562
|
exports.getValidatedElevation = getValidatedElevation;
|
|
13253
12563
|
exports.getVelocityZoneColor = getVelocityZoneColor;
|
|
13254
12564
|
exports.getVelocityZoneName = getVelocityZoneName;
|
|
13255
12565
|
exports.gluestackConfig = gluestackConfig;
|
|
13256
|
-
exports.groupExercises = groupExercises;
|
|
13257
12566
|
exports.hasMaxLength = hasMaxLength;
|
|
13258
12567
|
exports.hasMinLength = hasMinLength;
|
|
13259
12568
|
exports.hexToRgb = hexToRgb;
|
|
@@ -13272,6 +12581,7 @@ exports.primitiveShadows = primitiveShadows;
|
|
|
13272
12581
|
exports.primitiveSpacing = primitiveSpacing;
|
|
13273
12582
|
exports.primitiveTypography = primitiveTypography;
|
|
13274
12583
|
exports.primitiveZIndex = primitiveZIndex;
|
|
12584
|
+
exports.resolveColor = resolveColor;
|
|
13275
12585
|
exports.rgbToHex = rgbToHex;
|
|
13276
12586
|
exports.rgbToHsv = rgbToHsv;
|
|
13277
12587
|
exports.roundRpe = roundRpe;
|
|
@@ -13282,11 +12592,6 @@ exports.semanticColorsDark = semanticColorsDark;
|
|
|
13282
12592
|
exports.semanticColorsLight = semanticColorsLight;
|
|
13283
12593
|
exports.semanticTypography = semanticTypography;
|
|
13284
12594
|
exports.shadowColors = shadowColors;
|
|
13285
|
-
exports.statusToCardState = statusToCardState;
|
|
13286
|
-
exports.summarizeVbt = summarizeVbt;
|
|
13287
|
-
exports.toActiveCardProps = toActiveCardProps;
|
|
13288
|
-
exports.toExerciseCardProps = toExerciseCardProps;
|
|
13289
|
-
exports.toProgressBarMesos = toProgressBarMesos;
|
|
13290
12595
|
exports.useTable = useTable;
|
|
13291
12596
|
exports.useToast = useToast;
|
|
13292
12597
|
exports.useToolbarButton = useToolbarButton;
|