@titan-design/react-ui 0.4.0 → 0.6.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 +232 -185
- package/dist/bodymap.js.map +1 -1
- package/dist/bodymap.mjs +1963 -11
- package/dist/bodymap.mjs.map +1 -1
- package/dist/index.d.mts +193 -744
- package/dist/index.d.ts +193 -744
- package/dist/index.js +1551 -1856
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +10770 -8213
- 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 +6694 -0
- package/dist/pages.js.map +1 -0
- package/dist/pages.mjs +6674 -0
- package/dist/pages.mjs.map +1 -0
- package/dist/theme/index.d.mts +473 -211
- package/dist/theme/index.d.ts +473 -211
- package/dist/theme/index.js +341 -127
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/index.mjs +2085 -2
- package/dist/theme/index.mjs.map +1 -1
- package/dist/theme/tokens-css.js +148 -139
- package/dist/theme/tokens-css.js.map +1 -1
- package/dist/theme/tokens-css.mjs +582 -1
- package/dist/theme/tokens-css.mjs.map +1 -1
- package/package.json +11 -7
- package/src/components/custom/DateTime/DateTime.stories.tsx +82 -6
- package/src/components/custom/DateTime/DateTime.test.tsx +29 -3
- package/src/components/custom/DateTime/DateTime.tsx +55 -15
- package/src/components/custom/Gauge/Gauge.test.tsx +2 -2
- package/src/components/custom/Gauge/Gauge.tsx +6 -3
- package/src/components/custom/Scatter/Scatter.tsx +3 -5
- package/src/components/custom/Treemap/Treemap.tsx +3 -5
- package/src/components/custom/Typography/Typography.stories.tsx +45 -27
- package/src/components/custom/Typography/Typography.test.tsx +13 -3
- package/src/components/custom/Typography/Typography.tsx +5 -0
- package/src/components/custom/Workout/ActiveWorkoutPage.tsx +2 -1
- 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 +6 -3
- package/src/components/custom/Workout/BodyMapDetailPanel.tsx +6 -3
- package/src/components/custom/Workout/CapacityBandChart.test.tsx +2 -2
- package/src/components/custom/Workout/CapacityBandChart.tsx +9 -6
- package/src/components/custom/Workout/DeviationBar.test.tsx +1 -1
- package/src/components/custom/Workout/DeviationBar.tsx +7 -4
- package/src/components/custom/Workout/ExerciseCard.tsx +5 -1
- package/src/components/custom/Workout/ExerciseDetailPage.tsx +19 -5
- package/src/components/custom/Workout/InputBar.tsx +2 -1
- package/src/components/custom/Workout/IntensityBar.test.tsx +112 -60
- package/src/components/custom/Workout/IntensityBar.tsx +113 -58
- package/src/components/custom/Workout/MesoCard.tsx +8 -3
- package/src/components/custom/Workout/MesoProgressBar.test.tsx +1 -1
- package/src/components/custom/Workout/MesoProgressBar.tsx +3 -2
- package/src/components/custom/Workout/MesoStatusCard.tsx +20 -13
- package/src/components/custom/Workout/MuscleGroupChip.tsx +7 -4
- package/src/components/custom/Workout/PlaceholderStrip.tsx +5 -9
- package/src/components/custom/Workout/PrBadge.tsx +7 -4
- package/src/components/custom/Workout/PrHistoryModal.tsx +6 -5
- package/src/components/custom/Workout/ProgramPlanningPage.tsx +2 -1
- package/src/components/custom/Workout/README.md +50 -0
- package/src/components/custom/Workout/ReadinessCheck.tsx +7 -4
- package/src/components/custom/Workout/RestTimer.test.tsx +41 -10
- package/src/components/custom/Workout/RestTimer.tsx +50 -44
- package/src/components/custom/Workout/SetRow.tsx +12 -2
- package/src/components/custom/Workout/Sparkline.tsx +2 -1
- package/src/components/custom/Workout/StatusDot.test.tsx +2 -2
- package/src/components/custom/Workout/StatusDot.tsx +12 -9
- package/src/components/custom/Workout/StrengthTrendChart.tsx +9 -6
- package/src/components/custom/Workout/SupersetWrapper.tsx +2 -1
- 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 +109 -3
- package/src/components/custom/Workout/VelocityStrip.test.tsx +89 -2
- package/src/components/custom/Workout/VelocityStrip.tsx +203 -38
- package/src/components/custom/Workout/WeekRow.test.tsx +2 -2
- package/src/components/custom/Workout/WeekRow.tsx +3 -2
- package/src/components/custom/Workout/WeightBadge.test.tsx +2 -2
- package/src/components/custom/Workout/WeightBadge.tsx +8 -4
- package/src/components/custom/Workout/WorkoutCard.tsx +5 -2
- package/src/components/custom/Workout/WorkoutPill.tsx +12 -8
- package/src/components/custom/Workout/icons.tsx +7 -0
- package/src/components/custom/Workout/index.ts +38 -47
- package/src/components/icons/SvgIcon.tsx +50 -0
- package/src/components/icons/icons.stories.tsx +57 -0
- package/src/components/icons/icons.test.tsx +43 -0
- package/src/components/icons/icons.tsx +45 -0
- package/src/components/icons/index.ts +4 -0
- package/src/components/index.ts +6 -0
- package/src/components/shell/BrandLockup.stories.tsx +27 -0
- package/src/components/shell/BrandLockup.test.tsx +23 -0
- package/src/components/shell/BrandLockup.tsx +47 -0
- package/src/components/shell/DeviceIndicator.stories.tsx +28 -0
- package/src/components/shell/DeviceIndicator.test.tsx +26 -0
- package/src/components/shell/DeviceIndicator.tsx +52 -0
- package/src/components/shell/DeviceMenu.stories.tsx +47 -0
- package/src/components/shell/DeviceMenu.test.tsx +40 -0
- package/src/components/shell/DeviceMenu.tsx +65 -0
- package/src/components/shell/DeviceRow.stories.tsx +38 -0
- package/src/components/shell/DeviceRow.test.tsx +37 -0
- package/src/components/shell/DeviceRow.tsx +58 -0
- package/src/components/shell/README.md +86 -0
- package/src/components/shell/SessionStatePill.stories.tsx +27 -0
- package/src/components/shell/SessionStatePill.test.tsx +25 -0
- package/src/components/shell/SessionStatePill.tsx +46 -0
- package/src/components/shell/TopBar.stories.tsx +49 -0
- package/src/components/shell/TopBar.test.tsx +36 -0
- package/src/components/shell/TopBar.tsx +89 -0
- package/src/components/shell/index.ts +8 -0
- package/src/components/ui/indicator/Indicator.stories.tsx +37 -1
- package/src/components/ui/indicator/Indicator.test.tsx +19 -1
- package/src/components/ui/indicator/Indicator.tsx +45 -6
- package/src/components/ui/indicator/index.ts +1 -1
- package/src/components/ui/spinner/Spinner.tsx +3 -2
- package/src/components/ui/toolbar-button/ToolbarButton.tsx +2 -1
- package/src/index.ts +3 -2
- package/src/pages.ts +61 -0
- package/src/test/stories-smoke.test.tsx +50 -0
- package/src/theme/ColorSystem.stories.tsx +323 -0
- package/src/theme/Colors.stories.tsx +69 -1
- package/src/theme/barrel.ts +54 -0
- package/src/theme/config.ts +16 -3
- package/src/theme/extracted-colors-dataviz.ts +21 -0
- package/src/theme/extracted-colors-ui.ts +20 -0
- package/src/theme/global.css +64 -52
- package/src/theme/gradients.test.ts +25 -0
- package/src/theme/gradients.ts +36 -0
- package/src/theme/index.ts +8 -43
- package/src/theme/native-theming-guard.test.ts +117 -0
- package/src/theme/tokens/primitives.test.ts +232 -0
- package/src/theme/tokens/primitives.ts +247 -0
- package/src/theme/tokens/semantic.ts +93 -81
- package/src/theme/workout-tokens.ts +22 -21
- package/src/utils/avatar-color.ts +3 -3
- package/tailwind.config.js +10 -3
- package/dist/bodymap-BhG55xHM.d.mts +0 -318
- package/dist/bodymap-BhG55xHM.d.ts +0 -318
- package/dist/chunk-2SISKTWM.mjs +0 -1027
- package/dist/chunk-2SISKTWM.mjs.map +0 -1
- package/dist/chunk-7XPB4NAO.mjs +0 -1013
- package/dist/chunk-7XPB4NAO.mjs.map +0 -1
- package/dist/chunk-SNVKL5WZ.mjs +0 -883
- package/dist/chunk-SNVKL5WZ.mjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
3
4
|
var reactNative = require('react-native');
|
|
4
5
|
var clsx = require('clsx');
|
|
5
6
|
var tailwindMerge = require('tailwind-merge');
|
|
6
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
7
7
|
var React24 = require('react');
|
|
8
|
-
var nativewind = require('nativewind');
|
|
9
|
-
var lucideReact = require('lucide-react');
|
|
10
8
|
|
|
11
9
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
10
|
|
|
@@ -18,9 +16,6 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
18
16
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
19
17
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
20
18
|
});
|
|
21
|
-
function cn(...inputs) {
|
|
22
|
-
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
23
|
-
}
|
|
24
19
|
function wrapJsx(fn) {
|
|
25
20
|
return function(type, props, ...rest) {
|
|
26
21
|
if (props && typeof props.className === "string" && props.className) {
|
|
@@ -39,6 +34,58 @@ function wrapJsx(fn) {
|
|
|
39
34
|
var jsx = wrapJsx(jsxRuntime.jsx);
|
|
40
35
|
var jsxs = wrapJsx(jsxRuntime.jsxs);
|
|
41
36
|
|
|
37
|
+
// src/components/icons/SvgIcon.tsx
|
|
38
|
+
function SvgIcon({
|
|
39
|
+
size = 24,
|
|
40
|
+
color = "currentColor",
|
|
41
|
+
strokeWidth = 2,
|
|
42
|
+
fill = "none",
|
|
43
|
+
title,
|
|
44
|
+
children
|
|
45
|
+
}) {
|
|
46
|
+
return /* @__PURE__ */ jsxs(
|
|
47
|
+
"svg",
|
|
48
|
+
{
|
|
49
|
+
width: size,
|
|
50
|
+
height: size,
|
|
51
|
+
viewBox: "0 0 24 24",
|
|
52
|
+
fill,
|
|
53
|
+
stroke: color,
|
|
54
|
+
strokeWidth,
|
|
55
|
+
strokeLinecap: "round",
|
|
56
|
+
strokeLinejoin: "round",
|
|
57
|
+
...title ? { role: "img", "aria-label": title } : { "aria-hidden": true },
|
|
58
|
+
children: [
|
|
59
|
+
title ? /* @__PURE__ */ jsx("title", { children: title }) : null,
|
|
60
|
+
children
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// src/components/icons/icons.tsx
|
|
67
|
+
function VoltrasMark({ size = 14, ...props }) {
|
|
68
|
+
return /* @__PURE__ */ jsx(SvgIcon, { size, ...props, children: /* @__PURE__ */ jsx("path", { d: "M12 2 22 12 12 22 2 12Z" }) });
|
|
69
|
+
}
|
|
70
|
+
function BluetoothIcon({ size = 18, ...props }) {
|
|
71
|
+
return /* @__PURE__ */ jsx(SvgIcon, { size, ...props, children: /* @__PURE__ */ jsx("path", { d: "M7 7 17 17 12 22 12 2 17 7 7 17" }) });
|
|
72
|
+
}
|
|
73
|
+
function DumbbellIcon(props) {
|
|
74
|
+
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
75
|
+
/* @__PURE__ */ jsx("path", { d: "M14.4 14.4 9.6 9.6" }),
|
|
76
|
+
/* @__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" }),
|
|
77
|
+
/* @__PURE__ */ jsx("path", { d: "m21.5 21.5-1.4-1.4" }),
|
|
78
|
+
/* @__PURE__ */ jsx("path", { d: "M3.9 3.9 2.5 2.5" }),
|
|
79
|
+
/* @__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" })
|
|
80
|
+
] });
|
|
81
|
+
}
|
|
82
|
+
function StarIcon(props) {
|
|
83
|
+
return /* @__PURE__ */ jsx(SvgIcon, { ...props, 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" }) });
|
|
84
|
+
}
|
|
85
|
+
function cn(...inputs) {
|
|
86
|
+
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
87
|
+
}
|
|
88
|
+
|
|
42
89
|
// src/components/ui/alert/Alert.tsx
|
|
43
90
|
var statusColors = {
|
|
44
91
|
success: {
|
|
@@ -196,6 +243,38 @@ var primitiveColors = {
|
|
|
196
243
|
800: "#991B1B",
|
|
197
244
|
900: "#7F1D1D"
|
|
198
245
|
},
|
|
246
|
+
// Vivid green scale (live/go success)
|
|
247
|
+
greenVivid: {
|
|
248
|
+
50: "#E9FBF0",
|
|
249
|
+
100: "#C8F7DA",
|
|
250
|
+
200: "#9FF0BF",
|
|
251
|
+
300: "#6BE79D",
|
|
252
|
+
400: "#47DE84",
|
|
253
|
+
// Success vivid light
|
|
254
|
+
500: "#2ED573",
|
|
255
|
+
// Success vivid main
|
|
256
|
+
600: "#22B85F",
|
|
257
|
+
700: "#1A9950",
|
|
258
|
+
// Success vivid dark
|
|
259
|
+
800: "#157A40",
|
|
260
|
+
900: "#105C30"
|
|
261
|
+
},
|
|
262
|
+
// Vivid red scale (alert)
|
|
263
|
+
redVivid: {
|
|
264
|
+
50: "#FFECEE",
|
|
265
|
+
100: "#FFD6DB",
|
|
266
|
+
200: "#FFB3BC",
|
|
267
|
+
300: "#FF8593",
|
|
268
|
+
400: "#FF6070",
|
|
269
|
+
// Error vivid light
|
|
270
|
+
500: "#FF4757",
|
|
271
|
+
// Error vivid main
|
|
272
|
+
600: "#E63548",
|
|
273
|
+
700: "#C42539",
|
|
274
|
+
// Error vivid dark
|
|
275
|
+
800: "#9E1C2C",
|
|
276
|
+
900: "#7A1520"
|
|
277
|
+
},
|
|
199
278
|
// Amber scale (warning)
|
|
200
279
|
amber: {
|
|
201
280
|
50: "#FFFBEB",
|
|
@@ -285,6 +364,162 @@ var primitiveColors = {
|
|
|
285
364
|
black: "#000000",
|
|
286
365
|
transparent: "transparent"
|
|
287
366
|
};
|
|
367
|
+
var primitiveRamps = {
|
|
368
|
+
red: {
|
|
369
|
+
50: "#FFF4F4",
|
|
370
|
+
100: "#FFE3E5",
|
|
371
|
+
200: "#FFC2C5",
|
|
372
|
+
300: "#FF9A9D",
|
|
373
|
+
400: "#F77175",
|
|
374
|
+
500: "#E05254",
|
|
375
|
+
600: "#D14343",
|
|
376
|
+
// pin
|
|
377
|
+
700: "#A4221C",
|
|
378
|
+
800: "#7E1002",
|
|
379
|
+
900: "#5A0900",
|
|
380
|
+
950: "#3D0400"
|
|
381
|
+
},
|
|
382
|
+
orange: {
|
|
383
|
+
50: "#FFF5ED",
|
|
384
|
+
100: "#FFE6D4",
|
|
385
|
+
200: "#FFC7A2",
|
|
386
|
+
300: "#FFA063",
|
|
387
|
+
400: "#FF7900",
|
|
388
|
+
// pin
|
|
389
|
+
500: "#DA5F00",
|
|
390
|
+
600: "#B94A00",
|
|
391
|
+
700: "#983804",
|
|
392
|
+
800: "#6F290F",
|
|
393
|
+
900: "#4E1C0C",
|
|
394
|
+
950: "#331107"
|
|
395
|
+
},
|
|
396
|
+
amber: {
|
|
397
|
+
50: "#FFF7DD",
|
|
398
|
+
100: "#FFEAA9",
|
|
399
|
+
200: "#FFD352",
|
|
400
|
+
300: "#F9B415",
|
|
401
|
+
// pin
|
|
402
|
+
400: "#E08C00",
|
|
403
|
+
500: "#C27400",
|
|
404
|
+
600: "#A45E00",
|
|
405
|
+
700: "#814D14",
|
|
406
|
+
800: "#5B3A1A",
|
|
407
|
+
900: "#442503",
|
|
408
|
+
950: "#301500"
|
|
409
|
+
},
|
|
410
|
+
green: {
|
|
411
|
+
50: "#E3FFEE",
|
|
412
|
+
100: "#B5FFD2",
|
|
413
|
+
200: "#58F69E",
|
|
414
|
+
300: "#2ED573",
|
|
415
|
+
// pin
|
|
416
|
+
400: "#21C05D",
|
|
417
|
+
500: "#22A444",
|
|
418
|
+
600: "#298732",
|
|
419
|
+
700: "#2B6B25",
|
|
420
|
+
800: "#264D1C",
|
|
421
|
+
900: "#1B3515",
|
|
422
|
+
950: "#11220D"
|
|
423
|
+
},
|
|
424
|
+
cyan: {
|
|
425
|
+
50: "#E6FBFF",
|
|
426
|
+
100: "#C2F6FF",
|
|
427
|
+
200: "#62EAFF",
|
|
428
|
+
300: "#22D3EE",
|
|
429
|
+
// pin
|
|
430
|
+
400: "#01B5D1",
|
|
431
|
+
500: "#2697B7",
|
|
432
|
+
600: "#307B9B",
|
|
433
|
+
700: "#2A617F",
|
|
434
|
+
800: "#22465F",
|
|
435
|
+
900: "#0B3149",
|
|
436
|
+
950: "#001F36"
|
|
437
|
+
},
|
|
438
|
+
blue: {
|
|
439
|
+
50: "#EFF8FF",
|
|
440
|
+
100: "#D9EFFF",
|
|
441
|
+
200: "#ACDBFF",
|
|
442
|
+
300: "#78C2FF",
|
|
443
|
+
400: "#3CA8FF",
|
|
444
|
+
500: "#2196F3",
|
|
445
|
+
// pin
|
|
446
|
+
600: "#1072CB",
|
|
447
|
+
700: "#135AA8",
|
|
448
|
+
800: "#14407E",
|
|
449
|
+
900: "#112C5A",
|
|
450
|
+
950: "#091B3C"
|
|
451
|
+
},
|
|
452
|
+
magenta: {
|
|
453
|
+
50: "#FFF3F9",
|
|
454
|
+
100: "#FFE2F1",
|
|
455
|
+
200: "#FFBDE2",
|
|
456
|
+
300: "#FF8FD5",
|
|
457
|
+
400: "#ED69C3",
|
|
458
|
+
500: "#D548AF",
|
|
459
|
+
600: "#BA2996",
|
|
460
|
+
700: "#9C0D7A",
|
|
461
|
+
// pin
|
|
462
|
+
800: "#77005A",
|
|
463
|
+
900: "#56003F",
|
|
464
|
+
950: "#3B0029"
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
var categoricalPalette = {
|
|
468
|
+
default: [
|
|
469
|
+
primitiveRamps.blue[500],
|
|
470
|
+
primitiveRamps.magenta[500],
|
|
471
|
+
primitiveRamps.red[500],
|
|
472
|
+
primitiveRamps.orange[400],
|
|
473
|
+
primitiveRamps.green[300],
|
|
474
|
+
primitiveRamps.cyan[300],
|
|
475
|
+
primitiveRamps.amber[600]
|
|
476
|
+
// extended (7th) — pair with a legend
|
|
477
|
+
],
|
|
478
|
+
dark: [
|
|
479
|
+
primitiveRamps.blue[600],
|
|
480
|
+
primitiveRamps.magenta[600],
|
|
481
|
+
primitiveRamps.red[500],
|
|
482
|
+
primitiveRamps.orange[600],
|
|
483
|
+
primitiveRamps.green[800],
|
|
484
|
+
primitiveRamps.cyan[800],
|
|
485
|
+
primitiveRamps.amber[500]
|
|
486
|
+
// extended (7th) — pair with a legend
|
|
487
|
+
]
|
|
488
|
+
};
|
|
489
|
+
var CATEGORICAL_CVD_SAFE_MAX = 6;
|
|
490
|
+
function getCategoricalColor(index, variant = "default") {
|
|
491
|
+
const palette = categoricalPalette[variant];
|
|
492
|
+
index = Math.max(0, Math.floor(index));
|
|
493
|
+
return palette[index % palette.length];
|
|
494
|
+
}
|
|
495
|
+
var divergingScale = [
|
|
496
|
+
primitiveRamps.blue[500],
|
|
497
|
+
// under
|
|
498
|
+
primitiveRamps.cyan[300],
|
|
499
|
+
// maintenance
|
|
500
|
+
primitiveRamps.green[200],
|
|
501
|
+
// optimal (light center)
|
|
502
|
+
primitiveRamps.amber[300],
|
|
503
|
+
// approaching
|
|
504
|
+
primitiveRamps.red[600]
|
|
505
|
+
// over
|
|
506
|
+
];
|
|
507
|
+
var sequentialEffort = [
|
|
508
|
+
primitiveRamps.green[300],
|
|
509
|
+
primitiveRamps.amber[200],
|
|
510
|
+
primitiveRamps.amber[300],
|
|
511
|
+
primitiveRamps.orange[400],
|
|
512
|
+
primitiveRamps.red[600],
|
|
513
|
+
primitiveRamps.red[700]
|
|
514
|
+
];
|
|
515
|
+
function bestTextColor(hex) {
|
|
516
|
+
const [r, g, b] = [0, 2, 4].map((i) => {
|
|
517
|
+
const c = parseInt(hex.replace("#", "").slice(i, i + 2), 16) / 255;
|
|
518
|
+
return c >= 0.04045 ? ((c + 0.055) / 1.055) ** 2.4 : c / 12.92;
|
|
519
|
+
});
|
|
520
|
+
const l = 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
521
|
+
return (l + 0.05) / 0.05 >= 1.05 / (l + 0.05) ? "#000000" : "#FFFFFF";
|
|
522
|
+
}
|
|
288
523
|
var discreteRainbow = [
|
|
289
524
|
"#E8ECFB",
|
|
290
525
|
"#D9CCE3",
|
|
@@ -494,56 +729,43 @@ var primitiveZIndex = {
|
|
|
494
729
|
// src/theme/tokens/semantic.ts
|
|
495
730
|
var semanticColorsLight = {
|
|
496
731
|
// Brand colors (brand-*)
|
|
497
|
-
"brand-primary":
|
|
498
|
-
|
|
499
|
-
"brand-primary-
|
|
500
|
-
// #FF9630
|
|
501
|
-
"brand-primary-dark": primitiveColors.accent[700],
|
|
502
|
-
// #D0620C
|
|
732
|
+
"brand-primary": primitiveRamps.orange[400],
|
|
733
|
+
"brand-primary-light": primitiveRamps.orange[300],
|
|
734
|
+
"brand-primary-dark": primitiveRamps.orange[500],
|
|
503
735
|
"brand-primary-subtle": "rgba(255, 121, 0, 0.08)",
|
|
504
|
-
"brand-primary-hover":
|
|
505
|
-
"brand-primary-active":
|
|
506
|
-
"brand-secondary":
|
|
507
|
-
|
|
508
|
-
"brand-secondary-
|
|
509
|
-
|
|
510
|
-
"brand-secondary-
|
|
511
|
-
|
|
512
|
-
"brand-secondary-subtle": "rgba(64, 109, 135, 0.08)",
|
|
513
|
-
"brand-secondary-hover": primitiveColors.steel[600],
|
|
514
|
-
"brand-secondary-active": primitiveColors.steel[700],
|
|
736
|
+
"brand-primary-hover": primitiveRamps.orange[500],
|
|
737
|
+
"brand-primary-active": primitiveRamps.orange[600],
|
|
738
|
+
"brand-secondary": primitiveRamps.cyan[600],
|
|
739
|
+
"brand-secondary-light": primitiveRamps.cyan[500],
|
|
740
|
+
"brand-secondary-dark": primitiveRamps.cyan[700],
|
|
741
|
+
"brand-secondary-subtle": "rgba(48, 123, 155, 0.08)",
|
|
742
|
+
"brand-secondary-hover": primitiveRamps.cyan[700],
|
|
743
|
+
"brand-secondary-active": primitiveRamps.cyan[800],
|
|
515
744
|
// Text on brand backgrounds (on-*)
|
|
516
745
|
"on-brand-primary": primitiveColors.white,
|
|
517
746
|
"on-brand-secondary": primitiveColors.white,
|
|
518
747
|
// Status colors (status-*)
|
|
519
|
-
"status-success":
|
|
520
|
-
|
|
521
|
-
"status-success-
|
|
522
|
-
|
|
523
|
-
"status-
|
|
524
|
-
|
|
525
|
-
"status-
|
|
526
|
-
"status-error":
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
"status-error-dark": primitiveColors.
|
|
531
|
-
|
|
532
|
-
"status-
|
|
533
|
-
"status-warning":
|
|
534
|
-
|
|
535
|
-
"status-warning-
|
|
536
|
-
|
|
537
|
-
"status-
|
|
538
|
-
|
|
539
|
-
"status-
|
|
540
|
-
"status-info": primitiveColors.sky[500],
|
|
541
|
-
// #2196F3
|
|
542
|
-
"status-info-light": primitiveColors.sky[400],
|
|
543
|
-
// #64B6F7
|
|
544
|
-
"status-info-dark": primitiveColors.sky[700],
|
|
545
|
-
// #0B79D0
|
|
546
|
-
"status-info-subtle": primitiveColors.sky[50],
|
|
748
|
+
"status-success": primitiveRamps.green[300],
|
|
749
|
+
"status-success-light": primitiveRamps.green[200],
|
|
750
|
+
"status-success-dark": primitiveRamps.green[600],
|
|
751
|
+
"status-success-subtle": primitiveRamps.green[50],
|
|
752
|
+
"status-error": primitiveRamps.red[600],
|
|
753
|
+
"status-error-light": primitiveRamps.red[500],
|
|
754
|
+
"status-error-dark": primitiveRamps.red[700],
|
|
755
|
+
"status-error-subtle": primitiveRamps.red[50],
|
|
756
|
+
"status-error-vivid": primitiveColors.redVivid[500],
|
|
757
|
+
// vivid alert red
|
|
758
|
+
"status-error-vivid-light": primitiveColors.redVivid[400],
|
|
759
|
+
"status-error-vivid-dark": primitiveColors.redVivid[700],
|
|
760
|
+
"status-error-vivid-subtle": "rgba(255, 71, 87, 0.12)",
|
|
761
|
+
"status-warning": primitiveRamps.amber[300],
|
|
762
|
+
"status-warning-light": primitiveRamps.amber[200],
|
|
763
|
+
"status-warning-dark": primitiveRamps.amber[500],
|
|
764
|
+
"status-warning-subtle": primitiveRamps.amber[50],
|
|
765
|
+
"status-info": primitiveRamps.blue[500],
|
|
766
|
+
"status-info-light": primitiveRamps.blue[300],
|
|
767
|
+
"status-info-dark": primitiveRamps.blue[600],
|
|
768
|
+
"status-info-subtle": primitiveRamps.blue[50],
|
|
547
769
|
// Text on status backgrounds (on-status-*)
|
|
548
770
|
"on-status-success": primitiveColors.white,
|
|
549
771
|
"on-status-error": primitiveColors.white,
|
|
@@ -570,25 +792,25 @@ var semanticColorsLight = {
|
|
|
570
792
|
// Data visualization colors (data-*)
|
|
571
793
|
// First 10 colors from discrete rainbow optimized for charts
|
|
572
794
|
"data-1": discreteRainbow[9],
|
|
573
|
-
//
|
|
795
|
+
// Blue
|
|
574
796
|
"data-2": discreteRainbow[14],
|
|
575
|
-
//
|
|
797
|
+
// Green
|
|
576
798
|
"data-3": discreteRainbow[17],
|
|
577
|
-
//
|
|
799
|
+
// Yellow
|
|
578
800
|
"data-4": discreteRainbow[25],
|
|
579
|
-
//
|
|
801
|
+
// Red
|
|
580
802
|
"data-5": discreteRainbow[8],
|
|
581
|
-
//
|
|
803
|
+
// Purple
|
|
582
804
|
"data-6": discreteRainbow[20],
|
|
583
|
-
//
|
|
805
|
+
// Orange
|
|
584
806
|
"data-7": discreteRainbow[13],
|
|
585
|
-
//
|
|
807
|
+
// Light Blue
|
|
586
808
|
"data-8": discreteRainbow[15],
|
|
587
|
-
//
|
|
809
|
+
// Light Green
|
|
588
810
|
"data-9": discreteRainbow[3],
|
|
589
|
-
//
|
|
811
|
+
// Lavender
|
|
590
812
|
"data-10": discreteRainbow[22],
|
|
591
|
-
//
|
|
813
|
+
// Dark Orange
|
|
592
814
|
// Text colors (text-*)
|
|
593
815
|
"text-primary": "#121828",
|
|
594
816
|
"text-secondary": "#65748B",
|
|
@@ -600,9 +822,9 @@ var semanticColorsLight = {
|
|
|
600
822
|
// Surface colors (surface-*) - for elevated containers
|
|
601
823
|
"surface-base": primitiveColors.white,
|
|
602
824
|
"surface-elevated": primitiveColors.neutral[50],
|
|
603
|
-
//
|
|
825
|
+
// slightly off-white for elevated cards
|
|
604
826
|
"surface-raised": primitiveColors.neutral[100],
|
|
605
|
-
//
|
|
827
|
+
// light gray for raised cards
|
|
606
828
|
"surface-overlay": primitiveColors.white,
|
|
607
829
|
"surface-input": primitiveColors.neutral[50],
|
|
608
830
|
// Input field background (filled variant)
|
|
@@ -614,6 +836,8 @@ var semanticColorsLight = {
|
|
|
614
836
|
"border-default": "#E8E9EB",
|
|
615
837
|
"border-subtle": primitiveColors.neutral[100],
|
|
616
838
|
"border-strong": primitiveColors.neutral[300],
|
|
839
|
+
"border-prominent": primitiveColors.neutral[400],
|
|
840
|
+
// high-visibility divider
|
|
617
841
|
"border-focus": primitiveColors.blue[600],
|
|
618
842
|
"border-input": primitiveColors.neutral[300],
|
|
619
843
|
// Input field border
|
|
@@ -638,37 +862,41 @@ var semanticColorsLight = {
|
|
|
638
862
|
};
|
|
639
863
|
var semanticColorsDark = {
|
|
640
864
|
// Brand colors stay the same in dark mode
|
|
641
|
-
"brand-primary":
|
|
642
|
-
"brand-primary-light":
|
|
643
|
-
"brand-primary-dark":
|
|
865
|
+
"brand-primary": primitiveRamps.orange[400],
|
|
866
|
+
"brand-primary-light": primitiveRamps.orange[300],
|
|
867
|
+
"brand-primary-dark": primitiveRamps.orange[500],
|
|
644
868
|
"brand-primary-subtle": "rgba(255, 121, 0, 0.12)",
|
|
645
|
-
"brand-primary-hover":
|
|
646
|
-
"brand-primary-active":
|
|
647
|
-
"brand-secondary":
|
|
648
|
-
"brand-secondary-light":
|
|
649
|
-
"brand-secondary-dark":
|
|
650
|
-
"brand-secondary-subtle": "rgba(
|
|
651
|
-
"brand-secondary-hover":
|
|
652
|
-
"brand-secondary-active":
|
|
869
|
+
"brand-primary-hover": primitiveRamps.orange[300],
|
|
870
|
+
"brand-primary-active": primitiveRamps.orange[200],
|
|
871
|
+
"brand-secondary": primitiveRamps.cyan[600],
|
|
872
|
+
"brand-secondary-light": primitiveRamps.cyan[500],
|
|
873
|
+
"brand-secondary-dark": primitiveRamps.cyan[700],
|
|
874
|
+
"brand-secondary-subtle": "rgba(48, 123, 155, 0.12)",
|
|
875
|
+
"brand-secondary-hover": primitiveRamps.cyan[500],
|
|
876
|
+
"brand-secondary-active": primitiveRamps.cyan[400],
|
|
653
877
|
// Text on brand backgrounds
|
|
654
878
|
"on-brand-primary": primitiveColors.white,
|
|
655
879
|
"on-brand-secondary": primitiveColors.white,
|
|
656
880
|
// Status colors
|
|
657
|
-
"status-success":
|
|
658
|
-
"status-success-light":
|
|
659
|
-
"status-success-dark":
|
|
660
|
-
"status-success-subtle": "rgba(
|
|
661
|
-
"status-error":
|
|
662
|
-
"status-error-light":
|
|
663
|
-
"status-error-dark":
|
|
881
|
+
"status-success": primitiveRamps.green[300],
|
|
882
|
+
"status-success-light": primitiveRamps.green[200],
|
|
883
|
+
"status-success-dark": primitiveRamps.green[600],
|
|
884
|
+
"status-success-subtle": "rgba(46, 213, 115, 0.12)",
|
|
885
|
+
"status-error": primitiveRamps.red[600],
|
|
886
|
+
"status-error-light": primitiveRamps.red[500],
|
|
887
|
+
"status-error-dark": primitiveRamps.red[700],
|
|
664
888
|
"status-error-subtle": "rgba(209, 67, 67, 0.12)",
|
|
665
|
-
"status-
|
|
666
|
-
"status-
|
|
667
|
-
"status-
|
|
668
|
-
"status-
|
|
669
|
-
"status-
|
|
670
|
-
"status-
|
|
671
|
-
"status-
|
|
889
|
+
"status-error-vivid": primitiveColors.redVivid[500],
|
|
890
|
+
"status-error-vivid-light": primitiveColors.redVivid[400],
|
|
891
|
+
"status-error-vivid-dark": primitiveColors.redVivid[700],
|
|
892
|
+
"status-error-vivid-subtle": "rgba(255, 71, 87, 0.12)",
|
|
893
|
+
"status-warning": primitiveRamps.amber[300],
|
|
894
|
+
"status-warning-light": primitiveRamps.amber[200],
|
|
895
|
+
"status-warning-dark": primitiveRamps.amber[500],
|
|
896
|
+
"status-warning-subtle": "rgba(249, 180, 21, 0.12)",
|
|
897
|
+
"status-info": primitiveRamps.blue[500],
|
|
898
|
+
"status-info-light": primitiveRamps.blue[300],
|
|
899
|
+
"status-info-dark": primitiveRamps.blue[600],
|
|
672
900
|
"status-info-subtle": "rgba(33, 150, 243, 0.12)",
|
|
673
901
|
// Text on status backgrounds
|
|
674
902
|
"on-status-success": primitiveColors.white,
|
|
@@ -710,29 +938,31 @@ var semanticColorsDark = {
|
|
|
710
938
|
"text-link-hover": primitiveColors.blue[400],
|
|
711
939
|
// Surface colors - dark backgrounds
|
|
712
940
|
"surface-base": primitiveColors.charcoal[700],
|
|
713
|
-
//
|
|
941
|
+
// main surface
|
|
714
942
|
"surface-elevated": primitiveColors.charcoal[600],
|
|
715
|
-
//
|
|
943
|
+
// elevated surface
|
|
716
944
|
"surface-raised": primitiveColors.charcoal[500],
|
|
717
|
-
//
|
|
945
|
+
// raised surface
|
|
718
946
|
"surface-overlay": primitiveColors.charcoal[600],
|
|
719
|
-
//
|
|
947
|
+
// overlay surface
|
|
720
948
|
"surface-input": primitiveColors.charcoal[600],
|
|
721
|
-
//
|
|
949
|
+
// input surface
|
|
722
950
|
// Background colors
|
|
723
951
|
"background-base": primitiveColors.charcoal[900],
|
|
724
|
-
//
|
|
952
|
+
// darkest charcoal
|
|
725
953
|
"background-default": primitiveColors.charcoal[700],
|
|
726
|
-
//
|
|
954
|
+
// main background
|
|
727
955
|
"background-subtle": primitiveColors.charcoal[500],
|
|
728
|
-
//
|
|
956
|
+
// subtle background
|
|
729
957
|
// Border colors
|
|
730
958
|
"border-default": primitiveColors.charcoal[400],
|
|
731
|
-
//
|
|
959
|
+
// default border
|
|
732
960
|
"border-subtle": primitiveColors.charcoal[500],
|
|
733
|
-
//
|
|
961
|
+
// subtle border
|
|
734
962
|
"border-strong": primitiveColors.charcoal[300],
|
|
735
|
-
//
|
|
963
|
+
// strong border
|
|
964
|
+
"border-prominent": primitiveColors.charcoal[200],
|
|
965
|
+
// high-visibility divider
|
|
736
966
|
"border-focus": "#828DF8",
|
|
737
967
|
"border-input": primitiveColors.neutral[600],
|
|
738
968
|
"border-input-hover": primitiveColors.neutral[500],
|
|
@@ -747,7 +977,7 @@ var semanticColorsDark = {
|
|
|
747
977
|
"interactive-disabled-text": "rgba(255, 255, 255, 0.26)",
|
|
748
978
|
// Divider
|
|
749
979
|
"divider": primitiveColors.charcoal[400],
|
|
750
|
-
//
|
|
980
|
+
// divider color
|
|
751
981
|
// Avatar default
|
|
752
982
|
"avatar-background": primitiveColors.neutral[600],
|
|
753
983
|
"avatar-text": primitiveColors.white
|
|
@@ -1213,10 +1443,11 @@ var PasswordInput = React24.forwardRef(function PasswordInput2({ showIcon, hideI
|
|
|
1213
1443
|
var themeIndependentCSSVars = {
|
|
1214
1444
|
// RGB decomposed values for glow shadows
|
|
1215
1445
|
"--color-brand-primary-rgb": "255, 121, 0",
|
|
1216
|
-
"--color-brand-secondary-rgb": "
|
|
1217
|
-
"--color-status-success-rgb": "
|
|
1446
|
+
"--color-brand-secondary-rgb": "48, 123, 155",
|
|
1447
|
+
"--color-status-success-rgb": "46, 213, 115",
|
|
1218
1448
|
"--color-status-error-rgb": "209, 67, 67",
|
|
1219
|
-
"--color-status-
|
|
1449
|
+
"--color-status-error-vivid-rgb": "255, 71, 87",
|
|
1450
|
+
"--color-status-warning-rgb": "249, 180, 21",
|
|
1220
1451
|
"--color-status-info-rgb": "33, 150, 243",
|
|
1221
1452
|
"--color-background-base-rgb": "16, 16, 16",
|
|
1222
1453
|
// Font families
|
|
@@ -1251,6 +1482,10 @@ var lightThemeCSSVars = {
|
|
|
1251
1482
|
"--color-status-warning-subtle": semanticColorsLight["status-warning-subtle"],
|
|
1252
1483
|
"--color-status-info": semanticColorsLight["status-info"],
|
|
1253
1484
|
"--color-status-info-subtle": semanticColorsLight["status-info-subtle"],
|
|
1485
|
+
"--color-status-error-vivid": semanticColorsLight["status-error-vivid"],
|
|
1486
|
+
"--color-status-error-vivid-light": semanticColorsLight["status-error-vivid-light"],
|
|
1487
|
+
"--color-status-error-vivid-dark": semanticColorsLight["status-error-vivid-dark"],
|
|
1488
|
+
"--color-status-error-vivid-subtle": semanticColorsLight["status-error-vivid-subtle"],
|
|
1254
1489
|
"--color-text-primary": semanticColorsLight["text-primary"],
|
|
1255
1490
|
"--color-text-secondary": semanticColorsLight["text-secondary"],
|
|
1256
1491
|
"--color-text-tertiary": semanticColorsLight["text-tertiary"],
|
|
@@ -1266,6 +1501,7 @@ var lightThemeCSSVars = {
|
|
|
1266
1501
|
"--color-border-default": semanticColorsLight["border-default"],
|
|
1267
1502
|
"--color-border-subtle": semanticColorsLight["border-subtle"],
|
|
1268
1503
|
"--color-border-strong": semanticColorsLight["border-strong"],
|
|
1504
|
+
"--color-border-prominent": semanticColorsLight["border-prominent"],
|
|
1269
1505
|
"--color-border-focus": semanticColorsLight["border-focus"],
|
|
1270
1506
|
"--color-interactive-hover": semanticColorsLight["interactive-hover"],
|
|
1271
1507
|
"--color-interactive-focus": semanticColorsLight["interactive-focus"],
|
|
@@ -1342,6 +1578,10 @@ var darkThemeCSSVars = {
|
|
|
1342
1578
|
"--color-status-warning-subtle": semanticColorsDark["status-warning-subtle"],
|
|
1343
1579
|
"--color-status-info": semanticColorsDark["status-info"],
|
|
1344
1580
|
"--color-status-info-subtle": semanticColorsDark["status-info-subtle"],
|
|
1581
|
+
"--color-status-error-vivid": semanticColorsDark["status-error-vivid"],
|
|
1582
|
+
"--color-status-error-vivid-light": semanticColorsDark["status-error-vivid-light"],
|
|
1583
|
+
"--color-status-error-vivid-dark": semanticColorsDark["status-error-vivid-dark"],
|
|
1584
|
+
"--color-status-error-vivid-subtle": semanticColorsDark["status-error-vivid-subtle"],
|
|
1345
1585
|
"--color-text-primary": semanticColorsDark["text-primary"],
|
|
1346
1586
|
"--color-text-secondary": semanticColorsDark["text-secondary"],
|
|
1347
1587
|
"--color-text-tertiary": semanticColorsDark["text-tertiary"],
|
|
@@ -1357,6 +1597,7 @@ var darkThemeCSSVars = {
|
|
|
1357
1597
|
"--color-border-default": semanticColorsDark["border-default"],
|
|
1358
1598
|
"--color-border-subtle": semanticColorsDark["border-subtle"],
|
|
1359
1599
|
"--color-border-strong": semanticColorsDark["border-strong"],
|
|
1600
|
+
"--color-border-prominent": semanticColorsDark["border-prominent"],
|
|
1360
1601
|
"--color-border-focus": semanticColorsDark["border-focus"],
|
|
1361
1602
|
"--color-interactive-hover": semanticColorsDark["interactive-hover"],
|
|
1362
1603
|
"--color-interactive-focus": semanticColorsDark["interactive-focus"],
|
|
@@ -2161,22 +2402,21 @@ function validateCssPropertyManifest(candidate) {
|
|
|
2161
2402
|
function isCssPropertyManifest(candidate) {
|
|
2162
2403
|
return validateCssPropertyManifest(candidate).valid;
|
|
2163
2404
|
}
|
|
2164
|
-
var MODE_VARS = {
|
|
2165
|
-
dark: nativewind.vars(darkThemeCSSVars),
|
|
2166
|
-
light: nativewind.vars(lightThemeCSSVars)
|
|
2167
|
-
};
|
|
2168
|
-
function ThemeProvider({
|
|
2169
|
-
mode = "dark",
|
|
2170
|
-
style,
|
|
2171
|
-
children,
|
|
2172
|
-
...props
|
|
2173
|
-
}) {
|
|
2174
|
-
return /* @__PURE__ */ jsx(reactNative.View, { style: [MODE_VARS[mode], { flex: 1 }, style], ...props, children });
|
|
2175
|
-
}
|
|
2176
2405
|
function resolveColor(token, mode = "dark") {
|
|
2177
2406
|
return reactNative.Platform.OS === "web" ? `var(--color-${token})` : getSemanticColors(mode)[token];
|
|
2178
2407
|
}
|
|
2179
2408
|
|
|
2409
|
+
// src/theme/gradients.ts
|
|
2410
|
+
function linearGradient(from, to, angle = 180, mode = "dark") {
|
|
2411
|
+
return {
|
|
2412
|
+
backgroundImage: `linear-gradient(${angle}deg, ${resolveColor(from, mode)}, ${resolveColor(to, mode)})`
|
|
2413
|
+
};
|
|
2414
|
+
}
|
|
2415
|
+
var surfaceGradient = {
|
|
2416
|
+
/** Chrome bands (top bar, headers): elevated → base, a subtle dark wash. */
|
|
2417
|
+
chrome: (mode = "dark") => linearGradient("surface-elevated", "background-base", 180, mode)
|
|
2418
|
+
};
|
|
2419
|
+
|
|
2180
2420
|
// src/theme/presets/apply.ts
|
|
2181
2421
|
function colorKeyToVar(key) {
|
|
2182
2422
|
return `--color-${key}`;
|
|
@@ -2551,7 +2791,8 @@ var colorStyles = {
|
|
|
2551
2791
|
success: "bg-status-success",
|
|
2552
2792
|
error: "bg-status-error",
|
|
2553
2793
|
warning: "bg-status-warning",
|
|
2554
|
-
info: "bg-status-info"
|
|
2794
|
+
info: "bg-status-info",
|
|
2795
|
+
"error-vivid": "bg-status-error-vivid"
|
|
2555
2796
|
};
|
|
2556
2797
|
function Indicator({
|
|
2557
2798
|
size = "sm",
|
|
@@ -2559,14 +2800,40 @@ function Indicator({
|
|
|
2559
2800
|
customColor,
|
|
2560
2801
|
glow = false,
|
|
2561
2802
|
ring = false,
|
|
2803
|
+
pulse = false,
|
|
2562
2804
|
className,
|
|
2563
2805
|
style,
|
|
2564
2806
|
...props
|
|
2565
2807
|
}) {
|
|
2808
|
+
const pulseMode = pulse === true ? "opacity" : pulse || false;
|
|
2809
|
+
const colorClass = !customColor ? colorStyles[color] : void 0;
|
|
2810
|
+
const colorStyle = customColor ? { backgroundColor: customColor } : void 0;
|
|
2811
|
+
if (pulseMode === "ping") {
|
|
2812
|
+
return /* @__PURE__ */ jsxs(reactNative.View, { className: cn("relative", sizeStyles3[size], className), style, ...props, children: [
|
|
2813
|
+
/* @__PURE__ */ jsx(
|
|
2814
|
+
reactNative.View,
|
|
2815
|
+
{
|
|
2816
|
+
className: cn("absolute inset-0 rounded-full animate-ping", colorClass),
|
|
2817
|
+
style: colorStyle
|
|
2818
|
+
}
|
|
2819
|
+
),
|
|
2820
|
+
/* @__PURE__ */ jsx(
|
|
2821
|
+
reactNative.View,
|
|
2822
|
+
{
|
|
2823
|
+
className: cn(
|
|
2824
|
+
"relative rounded-full",
|
|
2825
|
+
sizeStyles3[size],
|
|
2826
|
+
colorClass,
|
|
2827
|
+
ring && "border-2 border-background-base"
|
|
2828
|
+
),
|
|
2829
|
+
style: colorStyle
|
|
2830
|
+
}
|
|
2831
|
+
)
|
|
2832
|
+
] });
|
|
2833
|
+
}
|
|
2566
2834
|
const dynamicStyle = {
|
|
2567
2835
|
...typeof style === "object" ? style : {},
|
|
2568
|
-
...
|
|
2569
|
-
...glow && !customColor ? {} : {},
|
|
2836
|
+
...colorStyle ?? {},
|
|
2570
2837
|
...glow && customColor ? { boxShadow: `0 0 6px ${customColor}` } : {}
|
|
2571
2838
|
};
|
|
2572
2839
|
return /* @__PURE__ */ jsx(
|
|
@@ -2575,12 +2842,14 @@ function Indicator({
|
|
|
2575
2842
|
className: cn(
|
|
2576
2843
|
"rounded-full shrink-0",
|
|
2577
2844
|
sizeStyles3[size],
|
|
2578
|
-
|
|
2845
|
+
colorClass,
|
|
2846
|
+
pulseMode === "opacity" && "animate-pulse",
|
|
2579
2847
|
ring && "border-2 border-background-base",
|
|
2580
|
-
glow && !customColor && color === "success" && "shadow-[0_0_6px_rgba(
|
|
2848
|
+
glow && !customColor && color === "success" && "shadow-[0_0_6px_rgba(46,213,115,0.6)]",
|
|
2581
2849
|
glow && !customColor && color === "error" && "shadow-[0_0_6px_rgba(239,68,68,0.6)]",
|
|
2582
2850
|
glow && !customColor && color === "warning" && "shadow-[0_0_6px_rgba(245,158,11,0.6)]",
|
|
2583
2851
|
glow && !customColor && color === "primary" && "shadow-[0_0_6px_rgba(255,121,0,0.6)]",
|
|
2852
|
+
glow && !customColor && color === "error-vivid" && "shadow-[0_0_6px_rgba(255,71,87,0.6)]",
|
|
2584
2853
|
className
|
|
2585
2854
|
),
|
|
2586
2855
|
style: Object.keys(dynamicStyle).length > 0 ? dynamicStyle : style,
|
|
@@ -2661,6 +2930,13 @@ function Badge({
|
|
|
2661
2930
|
function BadgeText({ children, className }) {
|
|
2662
2931
|
return /* @__PURE__ */ jsx(reactNative.Text, { className: cn("text-inherit font-medium", className), children });
|
|
2663
2932
|
}
|
|
2933
|
+
|
|
2934
|
+
// src/theme/extracted-colors-ui.ts
|
|
2935
|
+
var SPINNER_PRIMARY = primitiveRamps.cyan[600];
|
|
2936
|
+
var SPINNER_SECONDARY = primitiveRamps.green[400];
|
|
2937
|
+
var AVATAR_CATEGORICAL_COLORS = categoricalPalette.default;
|
|
2938
|
+
|
|
2939
|
+
// src/components/ui/spinner/Spinner.tsx
|
|
2664
2940
|
var sizeMap = {
|
|
2665
2941
|
sm: "small",
|
|
2666
2942
|
md: "small",
|
|
@@ -2668,8 +2944,8 @@ var sizeMap = {
|
|
|
2668
2944
|
xl: "large"
|
|
2669
2945
|
};
|
|
2670
2946
|
var colorMap = {
|
|
2671
|
-
primary:
|
|
2672
|
-
secondary:
|
|
2947
|
+
primary: SPINNER_PRIMARY,
|
|
2948
|
+
secondary: SPINNER_SECONDARY,
|
|
2673
2949
|
white: "#FFFFFF",
|
|
2674
2950
|
default: "#6B7280"
|
|
2675
2951
|
};
|
|
@@ -2705,15 +2981,7 @@ function Spinner({
|
|
|
2705
2981
|
}
|
|
2706
2982
|
|
|
2707
2983
|
// src/utils/avatar-color.ts
|
|
2708
|
-
var AVATAR_COLORS =
|
|
2709
|
-
"#FF6B6B",
|
|
2710
|
-
"#4ECDC4",
|
|
2711
|
-
"#45B7D1",
|
|
2712
|
-
"#96CEB4",
|
|
2713
|
-
"#FFEAA7",
|
|
2714
|
-
"#DDA0DD",
|
|
2715
|
-
"#98D8C8"
|
|
2716
|
-
];
|
|
2984
|
+
var AVATAR_COLORS = AVATAR_CATEGORICAL_COLORS;
|
|
2717
2985
|
function avatarColor(name) {
|
|
2718
2986
|
let hash = 0;
|
|
2719
2987
|
for (let i = 0; i < name.length; i++) {
|
|
@@ -4358,7 +4626,7 @@ function ToolbarButton({
|
|
|
4358
4626
|
const selected = isActive === void 0 ? isOpen : isActive;
|
|
4359
4627
|
const showActive = isActive !== false;
|
|
4360
4628
|
const getIconColor = () => {
|
|
4361
|
-
if (isActive === true) return "
|
|
4629
|
+
if (isActive === true) return resolveColor("brand-primary");
|
|
4362
4630
|
return showActive ? "#FFFFFF" : "#D1D1D1";
|
|
4363
4631
|
};
|
|
4364
4632
|
const getNeumorphicStyle = () => {
|
|
@@ -5001,7 +5269,7 @@ function ToastProvider({
|
|
|
5001
5269
|
return id;
|
|
5002
5270
|
}, [defaultDuration, maxToasts]);
|
|
5003
5271
|
const removeToast = React24.useCallback((id) => {
|
|
5004
|
-
setToasts((prev) => prev.filter((
|
|
5272
|
+
setToasts((prev) => prev.filter((t12) => t12.id !== id));
|
|
5005
5273
|
}, []);
|
|
5006
5274
|
const removeAllToasts = React24.useCallback(() => {
|
|
5007
5275
|
setToasts([]);
|
|
@@ -5883,7 +6151,10 @@ var variantStyles4 = {
|
|
|
5883
6151
|
subtitle2: "font-body text-sm font-medium leading-normal",
|
|
5884
6152
|
caption: "font-body text-xs font-normal leading-loose",
|
|
5885
6153
|
overline: "font-body text-xs font-semibold uppercase tracking-widest leading-relaxed",
|
|
5886
|
-
button: "font-sans text-sm font-semibold leading-relaxed"
|
|
6154
|
+
button: "font-sans text-sm font-semibold leading-relaxed",
|
|
6155
|
+
// Monospace technical readouts (clocks, ids, metrics) and their all-caps label form.
|
|
6156
|
+
mono: "font-mono text-xs font-normal leading-normal",
|
|
6157
|
+
monoLabel: "font-mono text-xs font-bold uppercase tracking-wide leading-normal"
|
|
5887
6158
|
};
|
|
5888
6159
|
var colorStyles7 = {
|
|
5889
6160
|
primary: "text-text-primary",
|
|
@@ -6572,7 +6843,7 @@ var colorStyles8 = {
|
|
|
6572
6843
|
tertiary: "text-text-tertiary",
|
|
6573
6844
|
inherit: ""
|
|
6574
6845
|
};
|
|
6575
|
-
function formatDate(value, format, isUTC) {
|
|
6846
|
+
function formatDate(value, format, isUTC, hour12, seconds) {
|
|
6576
6847
|
const date = value instanceof Date ? value : new Date(value);
|
|
6577
6848
|
if (isNaN(date.getTime())) {
|
|
6578
6849
|
return "Invalid Date";
|
|
@@ -6622,6 +6893,12 @@ function formatDate(value, format, isUTC) {
|
|
|
6622
6893
|
if (isUTC) {
|
|
6623
6894
|
options.timeZone = "UTC";
|
|
6624
6895
|
}
|
|
6896
|
+
if (hour12 !== void 0 && (options.hour !== void 0 || options.minute !== void 0)) {
|
|
6897
|
+
options.hour12 = hour12;
|
|
6898
|
+
}
|
|
6899
|
+
if (seconds && options.hour !== void 0) {
|
|
6900
|
+
options.second = "2-digit";
|
|
6901
|
+
}
|
|
6625
6902
|
return new Intl.DateTimeFormat(void 0, options).format(date);
|
|
6626
6903
|
}
|
|
6627
6904
|
function getRelativeTime(date) {
|
|
@@ -6691,16 +6968,28 @@ function DateTime({
|
|
|
6691
6968
|
format = "datetime",
|
|
6692
6969
|
customFormat,
|
|
6693
6970
|
isUTC = false,
|
|
6971
|
+
hour12,
|
|
6972
|
+
seconds,
|
|
6973
|
+
variant,
|
|
6974
|
+
live = false,
|
|
6975
|
+
refreshMs = 1e3,
|
|
6694
6976
|
fallback = "-",
|
|
6695
6977
|
color = "inherit",
|
|
6696
6978
|
className,
|
|
6697
6979
|
...props
|
|
6698
6980
|
}) {
|
|
6699
|
-
|
|
6700
|
-
|
|
6981
|
+
const [now, setNow] = React24.useState(() => Date.now());
|
|
6982
|
+
React24.useEffect(() => {
|
|
6983
|
+
if (!live) return;
|
|
6984
|
+
const id = setInterval(() => setNow(Date.now()), refreshMs);
|
|
6985
|
+
return () => clearInterval(id);
|
|
6986
|
+
}, [live, refreshMs]);
|
|
6987
|
+
const effectiveValue = live ? now : value;
|
|
6988
|
+
const text = effectiveValue === null || effectiveValue === void 0 ? fallback : formatDate(effectiveValue, format, isUTC, hour12, seconds);
|
|
6989
|
+
if (variant) {
|
|
6990
|
+
return /* @__PURE__ */ jsx(Typography, { variant, color, className, ...props, children: text });
|
|
6701
6991
|
}
|
|
6702
|
-
|
|
6703
|
-
return /* @__PURE__ */ jsx(reactNative.Text, { className: cn(colorStyles8[color], className), ...props, children: formattedDate });
|
|
6992
|
+
return /* @__PURE__ */ jsx(reactNative.Text, { className: cn(colorStyles8[color], className), ...props, children: text });
|
|
6704
6993
|
}
|
|
6705
6994
|
function formatDateTime(value, format = "datetime", isUTC = false, fallback = "-") {
|
|
6706
6995
|
if (value === null || value === void 0) {
|
|
@@ -6768,7 +7057,7 @@ var variantColors = {
|
|
|
6768
7057
|
plain: { backgroundColor: "#1C1C1C", borderColor: "#1F1F1F" },
|
|
6769
7058
|
pr: {
|
|
6770
7059
|
backgroundColor: "rgba(255, 121, 0, 0.12)",
|
|
6771
|
-
borderColor: "rgba(255, 121, 0, 0.
|
|
7060
|
+
borderColor: "rgba(255, 121, 0, 0.3)"
|
|
6772
7061
|
}
|
|
6773
7062
|
};
|
|
6774
7063
|
function BaseBadge({
|
|
@@ -6849,7 +7138,7 @@ function WeightBadge({
|
|
|
6849
7138
|
...props
|
|
6850
7139
|
}) {
|
|
6851
7140
|
const config = baseBadgeSizeConfig[size];
|
|
6852
|
-
const textColor = isPr ? "
|
|
7141
|
+
const textColor = isPr ? getSemanticColors("dark")["brand-primary"] : "#9CA3AF";
|
|
6853
7142
|
const iconColor = textColor;
|
|
6854
7143
|
const repMaxClause = reps != null ? `${reps} rep max` : "Estimated one rep max";
|
|
6855
7144
|
const deltaLabel = delta != null ? `, ${delta >= 0 ? "+" : ""}${delta}% change` : "";
|
|
@@ -6861,7 +7150,7 @@ function WeightBadge({
|
|
|
6861
7150
|
size,
|
|
6862
7151
|
onPress,
|
|
6863
7152
|
className,
|
|
6864
|
-
icon: showIcon ? /* @__PURE__ */ jsx(
|
|
7153
|
+
icon: showIcon ? /* @__PURE__ */ jsx(DumbbellIcon, { size: config.iconSize, color: iconColor, strokeWidth: 2 }) : void 0,
|
|
6865
7154
|
accessibilityLabel: fullLabel,
|
|
6866
7155
|
testID: "weight-badge",
|
|
6867
7156
|
...props,
|
|
@@ -6908,7 +7197,7 @@ function WeightBadge({
|
|
|
6908
7197
|
fontFamily: '"Space Grotesk", sans-serif',
|
|
6909
7198
|
fontSize: config.fontSize,
|
|
6910
7199
|
marginLeft: 4,
|
|
6911
|
-
color: delta >= 0 ? "
|
|
7200
|
+
color: delta >= 0 ? getSemanticColors("dark")["result-improve"] : getSemanticColors("dark")["result-degrade"]
|
|
6912
7201
|
},
|
|
6913
7202
|
testID: "weight-badge-delta",
|
|
6914
7203
|
children: [
|
|
@@ -6922,6 +7211,7 @@ function WeightBadge({
|
|
|
6922
7211
|
}
|
|
6923
7212
|
);
|
|
6924
7213
|
}
|
|
7214
|
+
var BRAND_PRIMARY = getSemanticColors("dark")["brand-primary"];
|
|
6925
7215
|
var typeLabels = {
|
|
6926
7216
|
e1rm: "PR e1RM",
|
|
6927
7217
|
weight: "PR Weight",
|
|
@@ -6965,7 +7255,7 @@ function PrBadge({
|
|
|
6965
7255
|
accessibilityLabel: `Personal record: ${resolvedLabel}`,
|
|
6966
7256
|
testID: "pr-badge-star",
|
|
6967
7257
|
...props,
|
|
6968
|
-
children: /* @__PURE__ */ jsx(
|
|
7258
|
+
children: /* @__PURE__ */ jsx(StarIcon, { size: 14, color: BRAND_PRIMARY, fill: BRAND_PRIMARY, strokeWidth: 2 })
|
|
6969
7259
|
}
|
|
6970
7260
|
) : /* @__PURE__ */ jsx(
|
|
6971
7261
|
BaseBadge,
|
|
@@ -6978,8 +7268,8 @@ function PrBadge({
|
|
|
6978
7268
|
reactNative.Text,
|
|
6979
7269
|
{
|
|
6980
7270
|
style: {
|
|
6981
|
-
fontSize:
|
|
6982
|
-
color:
|
|
7271
|
+
fontSize: 12,
|
|
7272
|
+
color: BRAND_PRIMARY,
|
|
6983
7273
|
fontWeight: "700",
|
|
6984
7274
|
fontFamily: "Inter, sans-serif"
|
|
6985
7275
|
},
|
|
@@ -7004,17 +7294,18 @@ function PrBadge({
|
|
|
7004
7294
|
}
|
|
7005
7295
|
return badge;
|
|
7006
7296
|
}
|
|
7297
|
+
var t = getSemanticColors("dark");
|
|
7007
7298
|
var solidVariantColors = {
|
|
7008
|
-
success: "
|
|
7009
|
-
warning: "
|
|
7010
|
-
error: "
|
|
7299
|
+
success: t["status-success"],
|
|
7300
|
+
warning: t["status-warning"],
|
|
7301
|
+
error: t["status-error"],
|
|
7011
7302
|
neutral: "#6B7280"
|
|
7012
7303
|
};
|
|
7013
7304
|
var ringVariantStyles = {
|
|
7014
7305
|
"on-track": {
|
|
7015
|
-
backgroundColor: "rgba(
|
|
7306
|
+
backgroundColor: "rgba(46,213,115,0.15)",
|
|
7016
7307
|
borderWidth: 1,
|
|
7017
|
-
borderColor: "rgba(
|
|
7308
|
+
borderColor: "rgba(46,213,115,0.3)"
|
|
7018
7309
|
},
|
|
7019
7310
|
deviation: {
|
|
7020
7311
|
backgroundColor: "rgba(245,158,11,0.15)",
|
|
@@ -7029,11 +7320,11 @@ var ringVariantStyles = {
|
|
|
7029
7320
|
}
|
|
7030
7321
|
};
|
|
7031
7322
|
var glowStyles = {
|
|
7032
|
-
success: { boxShadow: "0 0 4px rgba(
|
|
7323
|
+
success: { boxShadow: "0 0 4px rgba(46,213,115,0.4)" },
|
|
7033
7324
|
warning: { boxShadow: "0 0 4px rgba(245,158,11,0.4)" },
|
|
7034
7325
|
error: { boxShadow: "0 0 4px rgba(239,68,68,0.4)" },
|
|
7035
7326
|
neutral: { boxShadow: "0 0 4px rgba(107,114,128,0.4)" },
|
|
7036
|
-
"on-track": { boxShadow: "0 0 4px rgba(
|
|
7327
|
+
"on-track": { boxShadow: "0 0 4px rgba(46,213,115,0.4)" },
|
|
7037
7328
|
deviation: { boxShadow: "0 0 4px rgba(245,158,11,0.4)" },
|
|
7038
7329
|
future: { boxShadow: "0 0 4px rgba(107,114,128,0.4)" }
|
|
7039
7330
|
};
|
|
@@ -7047,8 +7338,8 @@ var iconColors2 = {
|
|
|
7047
7338
|
warning: "#6B4000",
|
|
7048
7339
|
error: "#5C1A1A",
|
|
7049
7340
|
neutral: "#D1D5DB",
|
|
7050
|
-
"on-track": "
|
|
7051
|
-
deviation: "
|
|
7341
|
+
"on-track": t["status-success"],
|
|
7342
|
+
deviation: t["status-warning"],
|
|
7052
7343
|
future: "#6B7280"
|
|
7053
7344
|
};
|
|
7054
7345
|
var sizeDimensions = {
|
|
@@ -7129,6 +7420,53 @@ function StatusDot({
|
|
|
7129
7420
|
}
|
|
7130
7421
|
return /* @__PURE__ */ jsx(reactNative.View, { className, ...props, children: dot });
|
|
7131
7422
|
}
|
|
7423
|
+
|
|
7424
|
+
// src/theme/workout-tokens.ts
|
|
7425
|
+
var WORKOUT_TOKENS = {
|
|
7426
|
+
// Canonical 4-band performance scale — the single source for BOTH the
|
|
7427
|
+
// VelocityStrip zone bars and the SetRow RPE color (TD-03.43). The direction
|
|
7428
|
+
// is intentionally inverted between the two consumers: for velocity, green =
|
|
7429
|
+
// fastest/best; for RPE, green = easiest. This is the [0,1,2,4] subsample of
|
|
7430
|
+
// the canonical `sequentialEffort` primitive. The `orange` key is the band
|
|
7431
|
+
// label. Consumed inline (RN).
|
|
7432
|
+
scale: {
|
|
7433
|
+
green: sequentialEffort[0],
|
|
7434
|
+
yellow: sequentialEffort[1],
|
|
7435
|
+
orange: sequentialEffort[2],
|
|
7436
|
+
// gold band
|
|
7437
|
+
red: sequentialEffort[4]
|
|
7438
|
+
},
|
|
7439
|
+
// BodyMap volume heatmap — the canonical `divergingScale` (under → optimal →
|
|
7440
|
+
// over): a true diverging shape with a light green center, cool-blue under-
|
|
7441
|
+
// trained end and warm-red over-reaching end (colorblind-robust in lightness).
|
|
7442
|
+
heatmap: {
|
|
7443
|
+
// no training data
|
|
7444
|
+
under: divergingScale[0],
|
|
7445
|
+
// below MEV
|
|
7446
|
+
maintenance: divergingScale[1],
|
|
7447
|
+
// MEV to MAV
|
|
7448
|
+
productive: divergingScale[2],
|
|
7449
|
+
// optimal center — MAV to MRV
|
|
7450
|
+
approaching: divergingScale[3],
|
|
7451
|
+
// near MRV
|
|
7452
|
+
over: divergingScale[4]
|
|
7453
|
+
// over MRV
|
|
7454
|
+
},
|
|
7455
|
+
// Surface and border colors were removed here: those flip with the theme, so
|
|
7456
|
+
// components use the CSS custom properties (var(--color-surface-*/border-*))
|
|
7457
|
+
// directly. Only theme-independent data-viz values remain below.
|
|
7458
|
+
// Intensity bar specific — over-target tiers deepen along the red ramp.
|
|
7459
|
+
intensity: {
|
|
7460
|
+
over1: primitiveRamps.red[600],
|
|
7461
|
+
// matches status-error
|
|
7462
|
+
over2: primitiveRamps.red[700],
|
|
7463
|
+
over3: primitiveRamps.red[800]},
|
|
7464
|
+
// Placeholder strip
|
|
7465
|
+
placeholder: {
|
|
7466
|
+
fill: "#3A3A3A"
|
|
7467
|
+
}};
|
|
7468
|
+
|
|
7469
|
+
// src/components/custom/Workout/PlaceholderStrip.tsx
|
|
7132
7470
|
function SingleStrip({
|
|
7133
7471
|
width,
|
|
7134
7472
|
className,
|
|
@@ -7137,14 +7475,12 @@ function SingleStrip({
|
|
|
7137
7475
|
return /* @__PURE__ */ jsx(
|
|
7138
7476
|
reactNative.View,
|
|
7139
7477
|
{
|
|
7140
|
-
className
|
|
7478
|
+
className,
|
|
7141
7479
|
style: [
|
|
7142
7480
|
{
|
|
7143
7481
|
height: 3,
|
|
7144
|
-
backgroundColor:
|
|
7145
|
-
|
|
7146
|
-
borderStyle: "dashed",
|
|
7147
|
-
borderRadius: 1,
|
|
7482
|
+
backgroundColor: WORKOUT_TOKENS.placeholder.fill,
|
|
7483
|
+
borderRadius: 2,
|
|
7148
7484
|
opacity: 0.5
|
|
7149
7485
|
},
|
|
7150
7486
|
width != null ? { width } : { flex: 1 }
|
|
@@ -7177,13 +7513,10 @@ function SegmentedStrip({
|
|
|
7177
7513
|
children: Array.from({ length: segments }, (_, i) => /* @__PURE__ */ jsx(
|
|
7178
7514
|
reactNative.View,
|
|
7179
7515
|
{
|
|
7180
|
-
className: "border-border-strong",
|
|
7181
7516
|
style: {
|
|
7182
7517
|
flex: 1,
|
|
7183
7518
|
height: 3,
|
|
7184
|
-
backgroundColor:
|
|
7185
|
-
borderWidth: 1,
|
|
7186
|
-
borderStyle: "dashed",
|
|
7519
|
+
backgroundColor: WORKOUT_TOKENS.placeholder.fill,
|
|
7187
7520
|
borderRadius: 1,
|
|
7188
7521
|
minWidth: 4
|
|
7189
7522
|
},
|
|
@@ -7206,23 +7539,6 @@ function PlaceholderStrip({
|
|
|
7206
7539
|
return /* @__PURE__ */ jsx(SingleStrip, { ...props });
|
|
7207
7540
|
}
|
|
7208
7541
|
|
|
7209
|
-
// src/theme/workout-tokens.ts
|
|
7210
|
-
var WORKOUT_TOKENS = {
|
|
7211
|
-
// Canonical 4-band performance scale — the single source for BOTH the
|
|
7212
|
-
// VelocityStrip zone bars and the SetRow RPE color (TD-03.43). The direction
|
|
7213
|
-
// is intentionally inverted between the two consumers: for velocity, green =
|
|
7214
|
-
// fastest/best; for RPE, green = easiest. Each component maps its own
|
|
7215
|
-
// thresholds onto these four colors. Kept as vivid data-viz values (distinct
|
|
7216
|
-
// from the muted status tokens) and theme-independent, so — like the heatmap
|
|
7217
|
-
// scale below — they are consumed inline as a JS import rather than CSS vars.
|
|
7218
|
-
// A JS import also resolves on native RN, unlike var(--…) strings.
|
|
7219
|
-
scale: {
|
|
7220
|
-
green: "#2ed573",
|
|
7221
|
-
yellow: "#ffd43b",
|
|
7222
|
-
orange: "#ffa502",
|
|
7223
|
-
red: "#ff4757"
|
|
7224
|
-
}};
|
|
7225
|
-
|
|
7226
7542
|
// src/utils/workout-format.ts
|
|
7227
7543
|
function roundRpe(rpe) {
|
|
7228
7544
|
return Math.round(rpe * 2) / 2;
|
|
@@ -7261,91 +7577,338 @@ function formatPrescription(p) {
|
|
|
7261
7577
|
return full.length > 0 ? full : null;
|
|
7262
7578
|
}
|
|
7263
7579
|
|
|
7264
|
-
// src/
|
|
7265
|
-
|
|
7266
|
-
var
|
|
7267
|
-
var phaseColors = {
|
|
7268
|
-
eccentric: "#FFB020",
|
|
7269
|
-
// status-warning (amber)
|
|
7270
|
-
pauseBottom: TEXT_TERTIARY,
|
|
7271
|
-
concentric: "#14B8A6",
|
|
7272
|
-
// status-success (teal)
|
|
7273
|
-
pauseTop: TEXT_TERTIARY,
|
|
7274
|
-
dash: TEXT_TERTIARY
|
|
7275
|
-
};
|
|
7276
|
-
function TempoValue({
|
|
7277
|
-
value,
|
|
7278
|
-
color,
|
|
7279
|
-
fontSize
|
|
7280
|
-
}) {
|
|
7281
|
-
return /* @__PURE__ */ jsx(
|
|
7282
|
-
reactNative.Text,
|
|
7283
|
-
{
|
|
7284
|
-
style: {
|
|
7285
|
-
fontFamily: INTER,
|
|
7286
|
-
fontSize,
|
|
7287
|
-
color,
|
|
7288
|
-
fontWeight: "600",
|
|
7289
|
-
letterSpacing: 1
|
|
7290
|
-
},
|
|
7291
|
-
children: value
|
|
7292
|
-
}
|
|
7293
|
-
);
|
|
7580
|
+
// src/utils/colors.ts
|
|
7581
|
+
function getStatusColor(status) {
|
|
7582
|
+
return `var(--color-status-${status})`;
|
|
7294
7583
|
}
|
|
7295
|
-
function
|
|
7296
|
-
return
|
|
7297
|
-
|
|
7298
|
-
|
|
7299
|
-
|
|
7300
|
-
|
|
7301
|
-
|
|
7302
|
-
|
|
7303
|
-
|
|
7304
|
-
|
|
7305
|
-
|
|
7306
|
-
|
|
7584
|
+
function getResultColor(result) {
|
|
7585
|
+
return `var(--color-result-${result})`;
|
|
7586
|
+
}
|
|
7587
|
+
function alpha(color, opacity) {
|
|
7588
|
+
const clampedOpacity = Math.max(0, Math.min(1, opacity));
|
|
7589
|
+
if (color.startsWith("#")) {
|
|
7590
|
+
const hex = color.slice(1);
|
|
7591
|
+
let r, g, b;
|
|
7592
|
+
if (hex.length === 3) {
|
|
7593
|
+
r = parseInt(hex[0] + hex[0], 16);
|
|
7594
|
+
g = parseInt(hex[1] + hex[1], 16);
|
|
7595
|
+
b = parseInt(hex[2] + hex[2], 16);
|
|
7596
|
+
} else if (hex.length === 6) {
|
|
7597
|
+
r = parseInt(hex.slice(0, 2), 16);
|
|
7598
|
+
g = parseInt(hex.slice(2, 4), 16);
|
|
7599
|
+
b = parseInt(hex.slice(4, 6), 16);
|
|
7600
|
+
} else {
|
|
7601
|
+
return color;
|
|
7307
7602
|
}
|
|
7308
|
-
|
|
7603
|
+
return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
|
|
7604
|
+
}
|
|
7605
|
+
const rgbMatch = color.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
|
|
7606
|
+
if (rgbMatch) {
|
|
7607
|
+
const [, r, g, b] = rgbMatch;
|
|
7608
|
+
return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
|
|
7609
|
+
}
|
|
7610
|
+
const rgbaMatch = color.match(/rgba\((\d+),\s*(\d+),\s*(\d+),\s*[\d.]+\)/);
|
|
7611
|
+
if (rgbaMatch) {
|
|
7612
|
+
const [, r, g, b] = rgbaMatch;
|
|
7613
|
+
return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
|
|
7614
|
+
}
|
|
7615
|
+
return color;
|
|
7309
7616
|
}
|
|
7310
|
-
function
|
|
7311
|
-
|
|
7312
|
-
|
|
7313
|
-
|
|
7314
|
-
|
|
7315
|
-
|
|
7617
|
+
function getLuminance(color) {
|
|
7618
|
+
if (!color.startsWith("#")) return "dark";
|
|
7619
|
+
const hex = color.slice(1);
|
|
7620
|
+
let r, g, b;
|
|
7621
|
+
if (hex.length === 3) {
|
|
7622
|
+
r = parseInt(hex[0] + hex[0], 16);
|
|
7623
|
+
g = parseInt(hex[1] + hex[1], 16);
|
|
7624
|
+
b = parseInt(hex[2] + hex[2], 16);
|
|
7625
|
+
} else if (hex.length === 6) {
|
|
7626
|
+
r = parseInt(hex.slice(0, 2), 16);
|
|
7627
|
+
g = parseInt(hex.slice(2, 4), 16);
|
|
7628
|
+
b = parseInt(hex.slice(4, 6), 16);
|
|
7629
|
+
} else {
|
|
7630
|
+
return "dark";
|
|
7631
|
+
}
|
|
7632
|
+
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
7633
|
+
return luminance > 0.5 ? "light" : "dark";
|
|
7634
|
+
}
|
|
7635
|
+
function getContrastText(backgroundColor) {
|
|
7636
|
+
return getLuminance(backgroundColor) === "light" ? "#000000" : "#FFFFFF";
|
|
7637
|
+
}
|
|
7638
|
+
var t2 = getSemanticColors("dark");
|
|
7639
|
+
var TEMPO_PACING = {
|
|
7640
|
+
behindThresholdPct: 0.15,
|
|
7641
|
+
minPhaseDurationMs: 500
|
|
7642
|
+
};
|
|
7643
|
+
function getTempoPacingState(elapsedMs, targetMs) {
|
|
7644
|
+
if (!targetMs || targetMs < TEMPO_PACING.minPhaseDurationMs) return "none";
|
|
7645
|
+
const ratio = elapsedMs / targetMs;
|
|
7646
|
+
if (ratio > 1 + TEMPO_PACING.behindThresholdPct) return "behind";
|
|
7647
|
+
return "on-pace";
|
|
7648
|
+
}
|
|
7649
|
+
function getTempoFillPct(elapsedMs, targetMs) {
|
|
7650
|
+
if (!targetMs) return 100;
|
|
7651
|
+
return Math.min(100, elapsedMs / targetMs * 100);
|
|
7652
|
+
}
|
|
7653
|
+
var PHASE_ORDER = ["concentric", "hold", "eccentric"];
|
|
7654
|
+
var PHASE_CONFIG = {
|
|
7655
|
+
concentric: { label: "Con", color: t2["status-success"], flex: 2 },
|
|
7656
|
+
hold: { label: "Hold", color: t2["brand-primary"], flex: 1 },
|
|
7657
|
+
eccentric: { label: "Ecc", color: t2["status-warning"], flex: 3 }
|
|
7658
|
+
};
|
|
7659
|
+
function TempoBar({
|
|
7660
|
+
activePhase,
|
|
7661
|
+
phaseElapsedMs,
|
|
7662
|
+
completed,
|
|
7663
|
+
target,
|
|
7316
7664
|
className,
|
|
7317
7665
|
...props
|
|
7318
7666
|
}) {
|
|
7319
|
-
|
|
7320
|
-
|
|
7321
|
-
|
|
7322
|
-
|
|
7323
|
-
|
|
7324
|
-
|
|
7325
|
-
|
|
7326
|
-
|
|
7327
|
-
|
|
7328
|
-
|
|
7329
|
-
|
|
7330
|
-
|
|
7331
|
-
|
|
7332
|
-
|
|
7333
|
-
|
|
7334
|
-
|
|
7335
|
-
|
|
7336
|
-
|
|
7337
|
-
|
|
7338
|
-
|
|
7339
|
-
|
|
7340
|
-
|
|
7341
|
-
|
|
7342
|
-
|
|
7343
|
-
|
|
7344
|
-
|
|
7345
|
-
|
|
7346
|
-
|
|
7347
|
-
|
|
7348
|
-
|
|
7667
|
+
return /* @__PURE__ */ jsxs(reactNative.View, { className, testID: "tempo-bar", ...props, children: [
|
|
7668
|
+
/* @__PURE__ */ jsx(reactNative.View, { style: { flexDirection: "row", marginBottom: 4 }, children: PHASE_ORDER.map((phase) => {
|
|
7669
|
+
const config = PHASE_CONFIG[phase];
|
|
7670
|
+
return /* @__PURE__ */ jsx(reactNative.View, { style: { flex: config.flex, alignItems: "center" }, children: /* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 10, color: t2["text-disabled"] }, children: config.label }) }, phase);
|
|
7671
|
+
}) }),
|
|
7672
|
+
/* @__PURE__ */ jsx(reactNative.View, { style: { flexDirection: "row", gap: 2, height: 20 }, children: PHASE_ORDER.map((phase) => {
|
|
7673
|
+
const config = PHASE_CONFIG[phase];
|
|
7674
|
+
const isActive = activePhase === phase;
|
|
7675
|
+
const completedMs = completed?.[phase];
|
|
7676
|
+
const targetSec = target?.[phase];
|
|
7677
|
+
const targetMs = targetSec != null ? targetSec * 1e3 : null;
|
|
7678
|
+
return /* @__PURE__ */ jsx(
|
|
7679
|
+
reactNative.View,
|
|
7680
|
+
{
|
|
7681
|
+
style: {
|
|
7682
|
+
flex: config.flex,
|
|
7683
|
+
backgroundColor: alpha("#ffffff", 0.06),
|
|
7684
|
+
borderRadius: 4,
|
|
7685
|
+
overflow: "hidden"
|
|
7686
|
+
},
|
|
7687
|
+
children: isActive ? /* @__PURE__ */ jsx(
|
|
7688
|
+
ActiveSegment,
|
|
7689
|
+
{
|
|
7690
|
+
config,
|
|
7691
|
+
phaseElapsedMs,
|
|
7692
|
+
targetMs
|
|
7693
|
+
}
|
|
7694
|
+
) : completedMs != null ? /* @__PURE__ */ jsx(CompletedSegment, { config, completedMs, targetMs }) : null
|
|
7695
|
+
},
|
|
7696
|
+
phase
|
|
7697
|
+
);
|
|
7698
|
+
}) })
|
|
7699
|
+
] });
|
|
7700
|
+
}
|
|
7701
|
+
function ActiveSegment({
|
|
7702
|
+
config,
|
|
7703
|
+
phaseElapsedMs,
|
|
7704
|
+
targetMs
|
|
7705
|
+
}) {
|
|
7706
|
+
const pacing = getTempoPacingState(phaseElapsedMs, targetMs);
|
|
7707
|
+
const barColor = pacing === "behind" ? t2["status-error"] : config.color;
|
|
7708
|
+
const fillPct = getTempoFillPct(phaseElapsedMs, targetMs);
|
|
7709
|
+
const label = targetMs ? `${formatDuration(phaseElapsedMs)} / ${formatDuration(targetMs)}` : formatDuration(phaseElapsedMs);
|
|
7710
|
+
return /* @__PURE__ */ jsxs(reactNative.View, { style: { height: "100%", position: "relative" }, testID: `tempo-segment-active-${config.label}`, children: [
|
|
7711
|
+
/* @__PURE__ */ jsx(
|
|
7712
|
+
reactNative.View,
|
|
7713
|
+
{
|
|
7714
|
+
style: {
|
|
7715
|
+
position: "absolute",
|
|
7716
|
+
left: 0,
|
|
7717
|
+
top: 0,
|
|
7718
|
+
bottom: 0,
|
|
7719
|
+
width: `${fillPct}%`,
|
|
7720
|
+
backgroundColor: alpha(barColor, 0.3),
|
|
7721
|
+
borderRadius: 4
|
|
7722
|
+
}
|
|
7723
|
+
}
|
|
7724
|
+
),
|
|
7725
|
+
/* @__PURE__ */ jsx(
|
|
7726
|
+
reactNative.View,
|
|
7727
|
+
{
|
|
7728
|
+
style: {
|
|
7729
|
+
height: "100%",
|
|
7730
|
+
flexDirection: "row",
|
|
7731
|
+
alignItems: "center",
|
|
7732
|
+
justifyContent: "center"
|
|
7733
|
+
},
|
|
7734
|
+
children: /* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 12, fontWeight: "700", color: barColor }, children: label })
|
|
7735
|
+
}
|
|
7736
|
+
)
|
|
7737
|
+
] });
|
|
7738
|
+
}
|
|
7739
|
+
function CompletedSegment({
|
|
7740
|
+
config,
|
|
7741
|
+
completedMs,
|
|
7742
|
+
targetMs
|
|
7743
|
+
}) {
|
|
7744
|
+
const pacing = getTempoPacingState(completedMs, targetMs);
|
|
7745
|
+
const hitTarget = pacing !== "behind";
|
|
7746
|
+
const indicator = targetMs && targetMs >= TEMPO_PACING.minPhaseDurationMs ? hitTarget ? " \u2713" : " \u2717" : "";
|
|
7747
|
+
return /* @__PURE__ */ jsx(
|
|
7748
|
+
reactNative.View,
|
|
7749
|
+
{
|
|
7750
|
+
style: {
|
|
7751
|
+
height: "100%",
|
|
7752
|
+
flexDirection: "row",
|
|
7753
|
+
alignItems: "center",
|
|
7754
|
+
justifyContent: "center",
|
|
7755
|
+
backgroundColor: alpha(config.color, 0.15)
|
|
7756
|
+
},
|
|
7757
|
+
testID: `tempo-segment-completed-${config.label}`,
|
|
7758
|
+
children: /* @__PURE__ */ jsxs(reactNative.Text, { style: { fontSize: 12, fontWeight: "500", color: alpha(config.color, 0.7) }, children: [
|
|
7759
|
+
formatDuration(completedMs),
|
|
7760
|
+
indicator
|
|
7761
|
+
] })
|
|
7762
|
+
}
|
|
7763
|
+
);
|
|
7764
|
+
}
|
|
7765
|
+
function formatDuration(ms) {
|
|
7766
|
+
const s = ms / 1e3;
|
|
7767
|
+
return s < 10 ? s.toFixed(1) : Math.round(s).toString();
|
|
7768
|
+
}
|
|
7769
|
+
|
|
7770
|
+
// src/components/custom/Workout/TempoDisplay.tsx
|
|
7771
|
+
var t3 = getSemanticColors("dark");
|
|
7772
|
+
var INTER = "Inter, sans-serif";
|
|
7773
|
+
var TEXT_TERTIARY = "#6B7280";
|
|
7774
|
+
var STATUS_ERROR = t3["status-error"];
|
|
7775
|
+
var phaseColors = {
|
|
7776
|
+
eccentric: t3["status-warning"],
|
|
7777
|
+
pauseBottom: TEXT_TERTIARY,
|
|
7778
|
+
concentric: t3["status-success"],
|
|
7779
|
+
pauseTop: TEXT_TERTIARY,
|
|
7780
|
+
dash: TEXT_TERTIARY
|
|
7781
|
+
};
|
|
7782
|
+
function TempoValue({
|
|
7783
|
+
value,
|
|
7784
|
+
color,
|
|
7785
|
+
fontSize
|
|
7786
|
+
}) {
|
|
7787
|
+
return /* @__PURE__ */ jsx(
|
|
7788
|
+
reactNative.Text,
|
|
7789
|
+
{
|
|
7790
|
+
style: {
|
|
7791
|
+
fontFamily: INTER,
|
|
7792
|
+
fontSize,
|
|
7793
|
+
color,
|
|
7794
|
+
fontWeight: "600",
|
|
7795
|
+
letterSpacing: 1
|
|
7796
|
+
},
|
|
7797
|
+
children: value
|
|
7798
|
+
}
|
|
7799
|
+
);
|
|
7800
|
+
}
|
|
7801
|
+
function TempoSeparator({ color, fontSize }) {
|
|
7802
|
+
return /* @__PURE__ */ jsx(
|
|
7803
|
+
reactNative.Text,
|
|
7804
|
+
{
|
|
7805
|
+
style: {
|
|
7806
|
+
fontFamily: INTER,
|
|
7807
|
+
fontSize,
|
|
7808
|
+
color,
|
|
7809
|
+
fontWeight: "600",
|
|
7810
|
+
letterSpacing: 1
|
|
7811
|
+
},
|
|
7812
|
+
children: "-"
|
|
7813
|
+
}
|
|
7814
|
+
);
|
|
7815
|
+
}
|
|
7816
|
+
var LIVE_PHASES = [
|
|
7817
|
+
{ key: "eccentric", color: phaseColors.eccentric },
|
|
7818
|
+
{ key: "pauseBottom", color: phaseColors.pauseBottom },
|
|
7819
|
+
{ key: "concentric", color: phaseColors.concentric },
|
|
7820
|
+
{ key: "pauseTop", color: phaseColors.pauseTop }
|
|
7821
|
+
];
|
|
7822
|
+
function LiveTempoCell({
|
|
7823
|
+
value,
|
|
7824
|
+
color,
|
|
7825
|
+
isActive,
|
|
7826
|
+
phaseElapsedMs,
|
|
7827
|
+
fontSize
|
|
7828
|
+
}) {
|
|
7829
|
+
if (!isActive) {
|
|
7830
|
+
return /* @__PURE__ */ jsx(TempoValue, { value, color: alpha(color, 0.35), fontSize });
|
|
7831
|
+
}
|
|
7832
|
+
const targetMs = value > 0 ? value * 1e3 : null;
|
|
7833
|
+
const barColor = getTempoPacingState(phaseElapsedMs, targetMs) === "behind" ? STATUS_ERROR : color;
|
|
7834
|
+
const fillPct = getTempoFillPct(phaseElapsedMs, targetMs);
|
|
7835
|
+
return /* @__PURE__ */ jsxs(reactNative.View, { style: { position: "relative" }, testID: "tempo-live-active", children: [
|
|
7836
|
+
/* @__PURE__ */ jsx(
|
|
7837
|
+
reactNative.View,
|
|
7838
|
+
{
|
|
7839
|
+
style: {
|
|
7840
|
+
position: "absolute",
|
|
7841
|
+
left: 0,
|
|
7842
|
+
top: 0,
|
|
7843
|
+
bottom: 0,
|
|
7844
|
+
width: `${fillPct}%`,
|
|
7845
|
+
backgroundColor: alpha(barColor, 0.3),
|
|
7846
|
+
borderRadius: 2
|
|
7847
|
+
}
|
|
7848
|
+
}
|
|
7849
|
+
),
|
|
7850
|
+
/* @__PURE__ */ jsx(TempoValue, { value, color: barColor, fontSize })
|
|
7851
|
+
] });
|
|
7852
|
+
}
|
|
7853
|
+
function LiveTempoRow({
|
|
7854
|
+
values,
|
|
7855
|
+
live,
|
|
7856
|
+
fontSize
|
|
7857
|
+
}) {
|
|
7858
|
+
return /* @__PURE__ */ jsx(jsxRuntime.Fragment, { children: LIVE_PHASES.map((phase, i) => /* @__PURE__ */ jsxs(reactNative.View, { style: { flexDirection: "row" }, children: [
|
|
7859
|
+
i > 0 && /* @__PURE__ */ jsx(TempoSeparator, { color: phaseColors.dash, fontSize }),
|
|
7860
|
+
/* @__PURE__ */ jsx(
|
|
7861
|
+
LiveTempoCell,
|
|
7862
|
+
{
|
|
7863
|
+
value: values[i],
|
|
7864
|
+
color: phase.color,
|
|
7865
|
+
isActive: live.activePhase === phase.key,
|
|
7866
|
+
phaseElapsedMs: live.phaseElapsedMs,
|
|
7867
|
+
fontSize
|
|
7868
|
+
}
|
|
7869
|
+
)
|
|
7870
|
+
] }, phase.key)) });
|
|
7871
|
+
}
|
|
7872
|
+
function TempoDisplay({
|
|
7873
|
+
tempo,
|
|
7874
|
+
size = "md",
|
|
7875
|
+
colored = true,
|
|
7876
|
+
showInfo = true,
|
|
7877
|
+
live,
|
|
7878
|
+
onPress,
|
|
7879
|
+
className,
|
|
7880
|
+
...props
|
|
7881
|
+
}) {
|
|
7882
|
+
const [showTooltip, setShowTooltip] = React24.useState(false);
|
|
7883
|
+
const [eccentric, pauseBottom, concentric, pauseTop] = roundTempo(tempo);
|
|
7884
|
+
const isSm = size === "sm";
|
|
7885
|
+
const fontSize = isSm ? 9 : 11;
|
|
7886
|
+
const monoColor = TEXT_TERTIARY;
|
|
7887
|
+
const handlePress = React24.useCallback(() => {
|
|
7888
|
+
if (onPress) {
|
|
7889
|
+
onPress();
|
|
7890
|
+
}
|
|
7891
|
+
if (showInfo) {
|
|
7892
|
+
setShowTooltip((prev) => !prev);
|
|
7893
|
+
}
|
|
7894
|
+
}, [onPress, showInfo]);
|
|
7895
|
+
const content = /* @__PURE__ */ jsxs(
|
|
7896
|
+
reactNative.View,
|
|
7897
|
+
{
|
|
7898
|
+
className,
|
|
7899
|
+
style: {
|
|
7900
|
+
flexDirection: "row",
|
|
7901
|
+
alignItems: "center",
|
|
7902
|
+
backgroundColor: "#1C1C1C",
|
|
7903
|
+
paddingHorizontal: isSm ? 6 : 8,
|
|
7904
|
+
paddingVertical: 3,
|
|
7905
|
+
borderRadius: 4
|
|
7906
|
+
},
|
|
7907
|
+
...props,
|
|
7908
|
+
children: [
|
|
7909
|
+
/* @__PURE__ */ jsx(
|
|
7910
|
+
reactNative.Text,
|
|
7911
|
+
{
|
|
7349
7912
|
style: {
|
|
7350
7913
|
fontFamily: INTER,
|
|
7351
7914
|
fontSize: 9,
|
|
@@ -7358,7 +7921,14 @@ function TempoDisplay({
|
|
|
7358
7921
|
children: "TEMPO"
|
|
7359
7922
|
}
|
|
7360
7923
|
),
|
|
7361
|
-
/* @__PURE__ */ jsx(reactNative.View, { style: { flexDirection: "row" }, testID: "tempo-value", children:
|
|
7924
|
+
/* @__PURE__ */ jsx(reactNative.View, { style: { flexDirection: "row" }, testID: "tempo-value", children: live ? /* @__PURE__ */ jsx(
|
|
7925
|
+
LiveTempoRow,
|
|
7926
|
+
{
|
|
7927
|
+
values: [eccentric, pauseBottom, concentric, pauseTop],
|
|
7928
|
+
live,
|
|
7929
|
+
fontSize
|
|
7930
|
+
}
|
|
7931
|
+
) : colored ? /* @__PURE__ */ jsxs(jsxRuntime.Fragment, { children: [
|
|
7362
7932
|
/* @__PURE__ */ jsx(TempoValue, { value: eccentric, color: phaseColors.eccentric, fontSize }),
|
|
7363
7933
|
/* @__PURE__ */ jsx(TempoSeparator, { color: phaseColors.dash, fontSize }),
|
|
7364
7934
|
/* @__PURE__ */ jsx(TempoValue, { value: pauseBottom, color: phaseColors.pauseBottom, fontSize }),
|
|
@@ -7470,209 +8040,18 @@ function TempoDisplay({
|
|
|
7470
8040
|
}
|
|
7471
8041
|
);
|
|
7472
8042
|
}
|
|
7473
|
-
|
|
7474
|
-
|
|
7475
|
-
|
|
7476
|
-
|
|
8043
|
+
var t4 = getSemanticColors("dark");
|
|
8044
|
+
function getDotColor(deviation) {
|
|
8045
|
+
const abs = Math.abs(deviation);
|
|
8046
|
+
if (deviation < -0.3) return t4["status-success"];
|
|
8047
|
+
if (abs <= 0.3) return "#6B7280";
|
|
8048
|
+
if (abs <= 0.7) return t4["status-warning"];
|
|
8049
|
+
return t4["status-error"];
|
|
7477
8050
|
}
|
|
7478
|
-
function
|
|
7479
|
-
|
|
7480
|
-
|
|
7481
|
-
|
|
7482
|
-
const clampedOpacity = Math.max(0, Math.min(1, opacity));
|
|
7483
|
-
if (color.startsWith("#")) {
|
|
7484
|
-
const hex = color.slice(1);
|
|
7485
|
-
let r, g, b;
|
|
7486
|
-
if (hex.length === 3) {
|
|
7487
|
-
r = parseInt(hex[0] + hex[0], 16);
|
|
7488
|
-
g = parseInt(hex[1] + hex[1], 16);
|
|
7489
|
-
b = parseInt(hex[2] + hex[2], 16);
|
|
7490
|
-
} else if (hex.length === 6) {
|
|
7491
|
-
r = parseInt(hex.slice(0, 2), 16);
|
|
7492
|
-
g = parseInt(hex.slice(2, 4), 16);
|
|
7493
|
-
b = parseInt(hex.slice(4, 6), 16);
|
|
7494
|
-
} else {
|
|
7495
|
-
return color;
|
|
7496
|
-
}
|
|
7497
|
-
return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
|
|
7498
|
-
}
|
|
7499
|
-
const rgbMatch = color.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
|
|
7500
|
-
if (rgbMatch) {
|
|
7501
|
-
const [, r, g, b] = rgbMatch;
|
|
7502
|
-
return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
|
|
7503
|
-
}
|
|
7504
|
-
const rgbaMatch = color.match(/rgba\((\d+),\s*(\d+),\s*(\d+),\s*[\d.]+\)/);
|
|
7505
|
-
if (rgbaMatch) {
|
|
7506
|
-
const [, r, g, b] = rgbaMatch;
|
|
7507
|
-
return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
|
|
7508
|
-
}
|
|
7509
|
-
return color;
|
|
7510
|
-
}
|
|
7511
|
-
function getLuminance(color) {
|
|
7512
|
-
if (!color.startsWith("#")) return "dark";
|
|
7513
|
-
const hex = color.slice(1);
|
|
7514
|
-
let r, g, b;
|
|
7515
|
-
if (hex.length === 3) {
|
|
7516
|
-
r = parseInt(hex[0] + hex[0], 16);
|
|
7517
|
-
g = parseInt(hex[1] + hex[1], 16);
|
|
7518
|
-
b = parseInt(hex[2] + hex[2], 16);
|
|
7519
|
-
} else if (hex.length === 6) {
|
|
7520
|
-
r = parseInt(hex.slice(0, 2), 16);
|
|
7521
|
-
g = parseInt(hex.slice(2, 4), 16);
|
|
7522
|
-
b = parseInt(hex.slice(4, 6), 16);
|
|
7523
|
-
} else {
|
|
7524
|
-
return "dark";
|
|
7525
|
-
}
|
|
7526
|
-
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
7527
|
-
return luminance > 0.5 ? "light" : "dark";
|
|
7528
|
-
}
|
|
7529
|
-
function getContrastText(backgroundColor) {
|
|
7530
|
-
return getLuminance(backgroundColor) === "light" ? "#000000" : "#FFFFFF";
|
|
7531
|
-
}
|
|
7532
|
-
|
|
7533
|
-
// src/components/custom/Workout/TempoBar.tsx
|
|
7534
|
-
var t = getSemanticColors("dark");
|
|
7535
|
-
var TEMPO_PACING = {
|
|
7536
|
-
behindThresholdPct: 0.15,
|
|
7537
|
-
minPhaseDurationMs: 500
|
|
7538
|
-
};
|
|
7539
|
-
function getTempoPacingState(elapsedMs, targetMs) {
|
|
7540
|
-
if (!targetMs || targetMs < TEMPO_PACING.minPhaseDurationMs) return "none";
|
|
7541
|
-
const ratio = elapsedMs / targetMs;
|
|
7542
|
-
if (ratio > 1 + TEMPO_PACING.behindThresholdPct) return "behind";
|
|
7543
|
-
return "on-pace";
|
|
7544
|
-
}
|
|
7545
|
-
function getTempoFillPct(elapsedMs, targetMs) {
|
|
7546
|
-
if (!targetMs) return 100;
|
|
7547
|
-
return Math.min(100, elapsedMs / targetMs * 100);
|
|
7548
|
-
}
|
|
7549
|
-
var PHASE_ORDER = ["concentric", "hold", "eccentric"];
|
|
7550
|
-
var PHASE_CONFIG = {
|
|
7551
|
-
concentric: { label: "Con", color: t["status-success"], flex: 2 },
|
|
7552
|
-
hold: { label: "Hold", color: t["brand-primary"], flex: 1 },
|
|
7553
|
-
eccentric: { label: "Ecc", color: t["status-warning"], flex: 3 }
|
|
7554
|
-
};
|
|
7555
|
-
function TempoBar({
|
|
7556
|
-
activePhase,
|
|
7557
|
-
phaseElapsedMs,
|
|
7558
|
-
completed,
|
|
7559
|
-
target,
|
|
7560
|
-
className,
|
|
7561
|
-
...props
|
|
7562
|
-
}) {
|
|
7563
|
-
return /* @__PURE__ */ jsxs(reactNative.View, { className, testID: "tempo-bar", ...props, children: [
|
|
7564
|
-
/* @__PURE__ */ jsx(reactNative.View, { style: { flexDirection: "row", marginBottom: 4 }, children: PHASE_ORDER.map((phase) => {
|
|
7565
|
-
const config = PHASE_CONFIG[phase];
|
|
7566
|
-
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);
|
|
7567
|
-
}) }),
|
|
7568
|
-
/* @__PURE__ */ jsx(reactNative.View, { style: { flexDirection: "row", gap: 2, height: 20 }, children: PHASE_ORDER.map((phase) => {
|
|
7569
|
-
const config = PHASE_CONFIG[phase];
|
|
7570
|
-
const isActive = activePhase === phase;
|
|
7571
|
-
const completedMs = completed?.[phase];
|
|
7572
|
-
const targetSec = target?.[phase];
|
|
7573
|
-
const targetMs = targetSec != null ? targetSec * 1e3 : null;
|
|
7574
|
-
return /* @__PURE__ */ jsx(
|
|
7575
|
-
reactNative.View,
|
|
7576
|
-
{
|
|
7577
|
-
style: {
|
|
7578
|
-
flex: config.flex,
|
|
7579
|
-
backgroundColor: alpha("#ffffff", 0.06),
|
|
7580
|
-
borderRadius: 4,
|
|
7581
|
-
overflow: "hidden"
|
|
7582
|
-
},
|
|
7583
|
-
children: isActive ? /* @__PURE__ */ jsx(
|
|
7584
|
-
ActiveSegment,
|
|
7585
|
-
{
|
|
7586
|
-
config,
|
|
7587
|
-
phaseElapsedMs,
|
|
7588
|
-
targetMs
|
|
7589
|
-
}
|
|
7590
|
-
) : completedMs != null ? /* @__PURE__ */ jsx(CompletedSegment, { config, completedMs, targetMs }) : null
|
|
7591
|
-
},
|
|
7592
|
-
phase
|
|
7593
|
-
);
|
|
7594
|
-
}) })
|
|
7595
|
-
] });
|
|
7596
|
-
}
|
|
7597
|
-
function ActiveSegment({
|
|
7598
|
-
config,
|
|
7599
|
-
phaseElapsedMs,
|
|
7600
|
-
targetMs
|
|
7601
|
-
}) {
|
|
7602
|
-
const pacing = getTempoPacingState(phaseElapsedMs, targetMs);
|
|
7603
|
-
const barColor = pacing === "behind" ? t["status-error"] : config.color;
|
|
7604
|
-
const fillPct = getTempoFillPct(phaseElapsedMs, targetMs);
|
|
7605
|
-
const label = targetMs ? `${formatDuration(phaseElapsedMs)} / ${formatDuration(targetMs)}` : formatDuration(phaseElapsedMs);
|
|
7606
|
-
return /* @__PURE__ */ jsxs(reactNative.View, { style: { height: "100%", position: "relative" }, testID: `tempo-segment-active-${config.label}`, children: [
|
|
7607
|
-
/* @__PURE__ */ jsx(
|
|
7608
|
-
reactNative.View,
|
|
7609
|
-
{
|
|
7610
|
-
style: {
|
|
7611
|
-
position: "absolute",
|
|
7612
|
-
left: 0,
|
|
7613
|
-
top: 0,
|
|
7614
|
-
bottom: 0,
|
|
7615
|
-
width: `${fillPct}%`,
|
|
7616
|
-
backgroundColor: alpha(barColor, 0.3),
|
|
7617
|
-
borderRadius: 4
|
|
7618
|
-
}
|
|
7619
|
-
}
|
|
7620
|
-
),
|
|
7621
|
-
/* @__PURE__ */ jsx(
|
|
7622
|
-
reactNative.View,
|
|
7623
|
-
{
|
|
7624
|
-
style: {
|
|
7625
|
-
height: "100%",
|
|
7626
|
-
flexDirection: "row",
|
|
7627
|
-
alignItems: "center",
|
|
7628
|
-
justifyContent: "center"
|
|
7629
|
-
},
|
|
7630
|
-
children: /* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 12, fontWeight: "700", color: barColor }, children: label })
|
|
7631
|
-
}
|
|
7632
|
-
)
|
|
7633
|
-
] });
|
|
7634
|
-
}
|
|
7635
|
-
function CompletedSegment({
|
|
7636
|
-
config,
|
|
7637
|
-
completedMs,
|
|
7638
|
-
targetMs
|
|
7639
|
-
}) {
|
|
7640
|
-
const pacing = getTempoPacingState(completedMs, targetMs);
|
|
7641
|
-
const hitTarget = pacing !== "behind";
|
|
7642
|
-
const indicator = targetMs && targetMs >= TEMPO_PACING.minPhaseDurationMs ? hitTarget ? " \u2713" : " \u2717" : "";
|
|
7643
|
-
return /* @__PURE__ */ jsx(
|
|
7644
|
-
reactNative.View,
|
|
7645
|
-
{
|
|
7646
|
-
style: {
|
|
7647
|
-
height: "100%",
|
|
7648
|
-
flexDirection: "row",
|
|
7649
|
-
alignItems: "center",
|
|
7650
|
-
justifyContent: "center",
|
|
7651
|
-
backgroundColor: alpha(config.color, 0.15)
|
|
7652
|
-
},
|
|
7653
|
-
testID: `tempo-segment-completed-${config.label}`,
|
|
7654
|
-
children: /* @__PURE__ */ jsxs(reactNative.Text, { style: { fontSize: 12, fontWeight: "500", color: alpha(config.color, 0.7) }, children: [
|
|
7655
|
-
formatDuration(completedMs),
|
|
7656
|
-
indicator
|
|
7657
|
-
] })
|
|
7658
|
-
}
|
|
7659
|
-
);
|
|
7660
|
-
}
|
|
7661
|
-
function formatDuration(ms) {
|
|
7662
|
-
const s = ms / 1e3;
|
|
7663
|
-
return s < 10 ? s.toFixed(1) : Math.round(s).toString();
|
|
7664
|
-
}
|
|
7665
|
-
function getDotColor(deviation) {
|
|
7666
|
-
const abs = Math.abs(deviation);
|
|
7667
|
-
if (deviation < -0.3) return "#14B8A6";
|
|
7668
|
-
if (abs <= 0.3) return "#6B7280";
|
|
7669
|
-
if (abs <= 0.7) return "#FFB020";
|
|
7670
|
-
return "#D14343";
|
|
7671
|
-
}
|
|
7672
|
-
function getDeviationDescription(deviation) {
|
|
7673
|
-
if (deviation < -0.3) return "lighter than planned";
|
|
7674
|
-
if (deviation > 0.3) return "harder than planned";
|
|
7675
|
-
return "on plan";
|
|
8051
|
+
function getDeviationDescription(deviation) {
|
|
8052
|
+
if (deviation < -0.3) return "lighter than planned";
|
|
8053
|
+
if (deviation > 0.3) return "harder than planned";
|
|
8054
|
+
return "on plan";
|
|
7676
8055
|
}
|
|
7677
8056
|
function DeviationBar({
|
|
7678
8057
|
deviation,
|
|
@@ -7709,7 +8088,7 @@ function DeviationBar({
|
|
|
7709
8088
|
width: resolvedWidth,
|
|
7710
8089
|
borderRadius: 3,
|
|
7711
8090
|
// react-native-web renders backgroundImage at runtime; not in RN ViewStyle types
|
|
7712
|
-
backgroundImage: "linear-gradient(90deg, rgba(
|
|
8091
|
+
backgroundImage: "linear-gradient(90deg, rgba(46,213,115,0.25) 0%, rgba(107,114,128,0.15) 50%, rgba(249,180,21,0.25) 100%)"
|
|
7713
8092
|
}
|
|
7714
8093
|
}
|
|
7715
8094
|
),
|
|
@@ -7735,19 +8114,43 @@ function DeviationBar({
|
|
|
7735
8114
|
}
|
|
7736
8115
|
);
|
|
7737
8116
|
}
|
|
7738
|
-
var
|
|
7739
|
-
var
|
|
8117
|
+
var t5 = getSemanticColors("dark");
|
|
8118
|
+
var TRACK_BG = "#333333";
|
|
7740
8119
|
var LABEL_COLOR = "#6B7280";
|
|
7741
|
-
|
|
7742
|
-
|
|
7743
|
-
|
|
7744
|
-
|
|
7745
|
-
|
|
7746
|
-
|
|
8120
|
+
var TARGET_LINE_COLOR = "rgba(33, 150, 243, 0.5)";
|
|
8121
|
+
var AT_TARGET_GLOW = "0 0 5px 1px rgba(33, 150, 243, 0.35), 0 0 10px 3px rgba(33, 150, 243, 0.15)";
|
|
8122
|
+
var ZONE = {
|
|
8123
|
+
building: t5["status-success"],
|
|
8124
|
+
// below target ramp-up
|
|
8125
|
+
approaching: t5["status-warning"],
|
|
8126
|
+
// nearing target
|
|
8127
|
+
target: t5["brand-primary"],
|
|
8128
|
+
// exactly at target
|
|
8129
|
+
over1: t5["status-error"],
|
|
8130
|
+
// mild over-target
|
|
8131
|
+
over2: WORKOUT_TOKENS.intensity.over2,
|
|
8132
|
+
// moderate over-target
|
|
8133
|
+
over3: WORKOUT_TOKENS.intensity.over3
|
|
8134
|
+
// severe over-target
|
|
8135
|
+
};
|
|
8136
|
+
var BULGE_SIZE = { 1: 8, 2: 10, 3: 11 };
|
|
8137
|
+
function zoneForPct(pct) {
|
|
8138
|
+
if (pct >= 125) return { color: ZONE.over3, over: 3 };
|
|
8139
|
+
if (pct >= 115) return { color: ZONE.over2, over: 2 };
|
|
8140
|
+
if (pct > 100) return { color: ZONE.over1, over: 1 };
|
|
8141
|
+
if (pct === 100) return { color: ZONE.target, over: 0 };
|
|
8142
|
+
if (pct >= 75) return { color: ZONE.approaching, over: 0 };
|
|
8143
|
+
return { color: ZONE.building, over: 0 };
|
|
8144
|
+
}
|
|
8145
|
+
function clampFill(value) {
|
|
7747
8146
|
if (value < 0) return 0;
|
|
7748
8147
|
if (value > 1) return 1;
|
|
7749
8148
|
return value;
|
|
7750
8149
|
}
|
|
8150
|
+
function isAtTarget(pct, threshold) {
|
|
8151
|
+
if (threshold == null) return false;
|
|
8152
|
+
return Math.abs(pct - Math.round(threshold * 100)) <= 5;
|
|
8153
|
+
}
|
|
7751
8154
|
function IntensityBar({
|
|
7752
8155
|
level,
|
|
7753
8156
|
threshold,
|
|
@@ -7759,62 +8162,62 @@ function IntensityBar({
|
|
|
7759
8162
|
...props
|
|
7760
8163
|
}) {
|
|
7761
8164
|
const isVertical = orientation === "vertical";
|
|
7762
|
-
const
|
|
7763
|
-
const
|
|
7764
|
-
const
|
|
7765
|
-
const
|
|
8165
|
+
const fillLevel = clampFill(level);
|
|
8166
|
+
const pct = Math.round(Math.max(0, level) * 100);
|
|
8167
|
+
const zone = zoneForPct(pct);
|
|
8168
|
+
const atTarget = isAtTarget(pct, threshold);
|
|
8169
|
+
const [fillAnim] = React24.useState(() => new reactNative.Animated.Value(fillLevel));
|
|
7766
8170
|
React24.useEffect(() => {
|
|
7767
8171
|
const animation = reactNative.Animated.timing(fillAnim, {
|
|
7768
|
-
toValue:
|
|
8172
|
+
toValue: fillLevel,
|
|
7769
8173
|
duration: 250,
|
|
7770
8174
|
useNativeDriver: false
|
|
7771
8175
|
});
|
|
7772
8176
|
animation.start();
|
|
7773
8177
|
return () => animation.stop();
|
|
7774
|
-
}, [
|
|
8178
|
+
}, [fillLevel, fillAnim]);
|
|
7775
8179
|
const fillSizePercent = fillAnim.interpolate({
|
|
7776
8180
|
inputRange: [0, 1],
|
|
7777
8181
|
outputRange: ["0%", "100%"]
|
|
7778
8182
|
});
|
|
7779
8183
|
const trackStyle = isVertical ? { width: thickness, height: size } : { width: size, height: thickness };
|
|
7780
|
-
const fillStyle = isVertical ? {
|
|
7781
|
-
|
|
7782
|
-
|
|
7783
|
-
left: 0,
|
|
7784
|
-
right: 0,
|
|
7785
|
-
height: fillSizePercent
|
|
7786
|
-
} : {
|
|
8184
|
+
const fillStyle = isVertical ? { position: "absolute", bottom: 0, left: 0, right: 0, height: fillSizePercent } : { position: "absolute", top: 0, bottom: 0, left: 0, width: fillSizePercent };
|
|
8185
|
+
const bulgeSize = zone.over === 0 ? 0 : BULGE_SIZE[zone.over];
|
|
8186
|
+
const bulgeStyle = {
|
|
7787
8187
|
position: "absolute",
|
|
7788
|
-
|
|
7789
|
-
|
|
7790
|
-
|
|
7791
|
-
|
|
8188
|
+
width: bulgeSize,
|
|
8189
|
+
height: bulgeSize,
|
|
8190
|
+
borderRadius: bulgeSize / 2,
|
|
8191
|
+
backgroundColor: zone.color,
|
|
8192
|
+
zIndex: 1,
|
|
8193
|
+
...isVertical ? { top: 0, left: "50%", transform: [{ translateX: -bulgeSize / 2 }] } : { right: 0, top: "50%", transform: [{ translateY: -bulgeSize / 2 }] }
|
|
7792
8194
|
};
|
|
7793
|
-
const
|
|
8195
|
+
const targetPct = `${clampFill(threshold ?? 0) * 100}%`;
|
|
8196
|
+
const targetLineStyle = isVertical ? {
|
|
7794
8197
|
position: "absolute",
|
|
7795
|
-
bottom:
|
|
7796
|
-
left: -
|
|
7797
|
-
right: -
|
|
7798
|
-
height: 1,
|
|
7799
|
-
backgroundColor:
|
|
8198
|
+
bottom: targetPct,
|
|
8199
|
+
left: -3,
|
|
8200
|
+
right: -3,
|
|
8201
|
+
height: 1.5,
|
|
8202
|
+
backgroundColor: TARGET_LINE_COLOR,
|
|
7800
8203
|
zIndex: 4
|
|
7801
8204
|
} : {
|
|
7802
8205
|
position: "absolute",
|
|
7803
|
-
left:
|
|
7804
|
-
top: -
|
|
7805
|
-
bottom: -
|
|
7806
|
-
width: 1,
|
|
7807
|
-
backgroundColor:
|
|
8206
|
+
left: targetPct,
|
|
8207
|
+
top: -3,
|
|
8208
|
+
bottom: -3,
|
|
8209
|
+
width: 1.5,
|
|
8210
|
+
backgroundColor: TARGET_LINE_COLOR,
|
|
7808
8211
|
zIndex: 4
|
|
7809
|
-
}
|
|
8212
|
+
};
|
|
7810
8213
|
return /* @__PURE__ */ jsxs(
|
|
7811
8214
|
reactNative.View,
|
|
7812
8215
|
{
|
|
7813
8216
|
className,
|
|
7814
8217
|
style: { alignItems: "center" },
|
|
7815
8218
|
accessibilityRole: "progressbar",
|
|
7816
|
-
accessibilityValue: { min: 0, max: 100, now:
|
|
7817
|
-
accessibilityLabel: `Intensity level: ${
|
|
8219
|
+
accessibilityValue: { min: 0, max: 100, now: pct },
|
|
8220
|
+
accessibilityLabel: `Intensity level: ${pct}%`,
|
|
7818
8221
|
testID: "intensity-bar",
|
|
7819
8222
|
...props,
|
|
7820
8223
|
children: [
|
|
@@ -7836,13 +8239,32 @@ function IntensityBar({
|
|
|
7836
8239
|
style: {
|
|
7837
8240
|
...fillStyle,
|
|
7838
8241
|
borderRadius: 3,
|
|
7839
|
-
backgroundColor:
|
|
7840
|
-
zIndex: 2
|
|
8242
|
+
backgroundColor: zone.color,
|
|
8243
|
+
zIndex: 2,
|
|
8244
|
+
...atTarget ? { boxShadow: AT_TARGET_GLOW } : null
|
|
7841
8245
|
},
|
|
7842
8246
|
testID: "intensity-fill"
|
|
7843
8247
|
}
|
|
7844
8248
|
),
|
|
7845
|
-
|
|
8249
|
+
zone.over !== 0 && /* @__PURE__ */ jsx(reactNative.View, { style: bulgeStyle, testID: "intensity-bulge" }),
|
|
8250
|
+
threshold != null && /* @__PURE__ */ jsx(reactNative.View, { style: targetLineStyle, testID: "intensity-target" })
|
|
8251
|
+
]
|
|
8252
|
+
}
|
|
8253
|
+
),
|
|
8254
|
+
/* @__PURE__ */ jsxs(
|
|
8255
|
+
reactNative.Text,
|
|
8256
|
+
{
|
|
8257
|
+
style: {
|
|
8258
|
+
fontSize: 8,
|
|
8259
|
+
color: LABEL_COLOR,
|
|
8260
|
+
fontFamily: '"Nunito Sans", sans-serif',
|
|
8261
|
+
marginTop: 6
|
|
8262
|
+
},
|
|
8263
|
+
accessibilityElementsHidden: true,
|
|
8264
|
+
testID: "intensity-label",
|
|
8265
|
+
children: [
|
|
8266
|
+
pct,
|
|
8267
|
+
"%"
|
|
7846
8268
|
]
|
|
7847
8269
|
}
|
|
7848
8270
|
),
|
|
@@ -7854,7 +8276,7 @@ function IntensityBar({
|
|
|
7854
8276
|
fontWeight: "500",
|
|
7855
8277
|
color: LABEL_COLOR,
|
|
7856
8278
|
fontFamily: "Inter, sans-serif",
|
|
7857
|
-
marginTop:
|
|
8279
|
+
marginTop: 2
|
|
7858
8280
|
},
|
|
7859
8281
|
accessibilityElementsHidden: true,
|
|
7860
8282
|
testID: "intensity-threshold-label",
|
|
@@ -7865,29 +8287,38 @@ function IntensityBar({
|
|
|
7865
8287
|
}
|
|
7866
8288
|
);
|
|
7867
8289
|
}
|
|
8290
|
+
|
|
8291
|
+
// src/theme/extracted-colors-dataviz.ts
|
|
8292
|
+
var DATAVIZ_CATEGORICAL_PALETTE = categoricalPalette.default;
|
|
8293
|
+
var MESO_ACCENT_GRADIENT_DARK = primitiveRamps.orange[500];
|
|
8294
|
+
var MESO_ACCENT_GRADIENT_LIGHT = primitiveRamps.orange[300];
|
|
8295
|
+
var WORKOUT_PILL_DELOAD = primitiveRamps.magenta[600];
|
|
8296
|
+
|
|
8297
|
+
// src/components/custom/Workout/WorkoutPill.tsx
|
|
8298
|
+
var t6 = getSemanticColors("dark");
|
|
7868
8299
|
var statusBgColors = {
|
|
7869
|
-
completed: "rgba(
|
|
8300
|
+
completed: "rgba(46,213,115,0.15)",
|
|
7870
8301
|
current: "rgba(255,121,0,0.15)",
|
|
7871
8302
|
next: "transparent",
|
|
7872
8303
|
upcoming: "#1C1C1C",
|
|
7873
8304
|
missed: "rgba(209,67,67,0.1)",
|
|
7874
|
-
deload: "rgba(
|
|
8305
|
+
deload: "rgba(186,41,150,0.15)"
|
|
7875
8306
|
};
|
|
7876
8307
|
var statusBorderStyles = {
|
|
7877
|
-
completed: { borderWidth: 1, borderColor: "rgba(
|
|
8308
|
+
completed: { borderWidth: 1, borderColor: "rgba(46,213,115,0.3)" },
|
|
7878
8309
|
current: { borderWidth: 1, borderColor: "rgba(255,121,0,0.3)" },
|
|
7879
8310
|
next: { borderWidth: 1, borderColor: "rgba(255,121,0,0.4)" },
|
|
7880
8311
|
upcoming: { borderWidth: 1, borderColor: "#1F1F1F" },
|
|
7881
8312
|
missed: { borderWidth: 1, borderColor: "rgba(209,67,67,0.25)" },
|
|
7882
|
-
deload: { borderWidth: 1, borderColor: "rgba(
|
|
8313
|
+
deload: { borderWidth: 1, borderColor: "rgba(186,41,150,0.3)" }
|
|
7883
8314
|
};
|
|
7884
8315
|
var textColors = {
|
|
7885
|
-
completed: "
|
|
7886
|
-
current: "
|
|
7887
|
-
next: "
|
|
8316
|
+
completed: t6["status-success"],
|
|
8317
|
+
current: t6["brand-primary"],
|
|
8318
|
+
next: t6["brand-primary"],
|
|
7888
8319
|
upcoming: "#6B7280",
|
|
7889
8320
|
missed: "rgba(209,67,67,0.7)",
|
|
7890
|
-
deload:
|
|
8321
|
+
deload: WORKOUT_PILL_DELOAD
|
|
7891
8322
|
};
|
|
7892
8323
|
function usePulse(enabled) {
|
|
7893
8324
|
const [opacity] = React24.useState(() => new reactNative.Animated.Value(1));
|
|
@@ -8018,6 +8449,13 @@ function WorkoutPill({
|
|
|
8018
8449
|
return pill;
|
|
8019
8450
|
}
|
|
8020
8451
|
var VEL_COLORS = WORKOUT_TOKENS.scale;
|
|
8452
|
+
var zoneIdToScaleToken = {
|
|
8453
|
+
speed: "green",
|
|
8454
|
+
power: "yellow",
|
|
8455
|
+
strengthSpeed: "orange",
|
|
8456
|
+
maximalStrength: "red",
|
|
8457
|
+
grinding: "red"
|
|
8458
|
+
};
|
|
8021
8459
|
function getVelocityZoneColor(velocity) {
|
|
8022
8460
|
if (velocity >= 1) return "vel-green";
|
|
8023
8461
|
if (velocity >= 0.75) return "vel-yellow";
|
|
@@ -8030,47 +8468,62 @@ function getVelocityZoneName(velocity) {
|
|
|
8030
8468
|
if (velocity >= 0.5) return "Strength-Speed";
|
|
8031
8469
|
return "Strength";
|
|
8032
8470
|
}
|
|
8471
|
+
var zoneHexMap = {
|
|
8472
|
+
"vel-green": VEL_COLORS.green,
|
|
8473
|
+
"vel-yellow": VEL_COLORS.yellow,
|
|
8474
|
+
"vel-orange": VEL_COLORS.orange,
|
|
8475
|
+
"vel-red": VEL_COLORS.red
|
|
8476
|
+
};
|
|
8033
8477
|
function calculateVelocityLoss(velocities) {
|
|
8034
8478
|
if (velocities.length < 2) return 0;
|
|
8035
|
-
const
|
|
8479
|
+
const best = Math.max(...velocities);
|
|
8480
|
+
if (best <= 0) return 0;
|
|
8036
8481
|
const last = velocities[velocities.length - 1];
|
|
8037
|
-
|
|
8038
|
-
return Math.round((first - last) / first * 100);
|
|
8482
|
+
return Math.max(0, Math.round((best - last) / best * 100));
|
|
8039
8483
|
}
|
|
8040
8484
|
function calculateMeanVelocity(velocities) {
|
|
8041
8485
|
if (velocities.length === 0) return 0;
|
|
8042
8486
|
const sum = velocities.reduce((acc, v) => acc + v, 0);
|
|
8043
8487
|
return sum / velocities.length;
|
|
8044
8488
|
}
|
|
8045
|
-
function
|
|
8046
|
-
|
|
8047
|
-
|
|
8048
|
-
return VEL_COLORS.green;
|
|
8049
|
-
case "vel-yellow":
|
|
8050
|
-
return VEL_COLORS.yellow;
|
|
8051
|
-
case "vel-orange":
|
|
8052
|
-
return VEL_COLORS.orange;
|
|
8053
|
-
case "vel-red":
|
|
8054
|
-
return VEL_COLORS.red;
|
|
8055
|
-
default:
|
|
8056
|
-
return VEL_COLORS.green;
|
|
8489
|
+
function classifyBand(velocity, bands) {
|
|
8490
|
+
for (const band of bands) {
|
|
8491
|
+
if (band.max === null || velocity < band.max) return band;
|
|
8057
8492
|
}
|
|
8493
|
+
return bands[bands.length - 1];
|
|
8494
|
+
}
|
|
8495
|
+
function bandColor(band) {
|
|
8496
|
+
const token = zoneIdToScaleToken[band.id];
|
|
8497
|
+
return token ? VEL_COLORS[token] : VEL_COLORS.green;
|
|
8058
8498
|
}
|
|
8059
|
-
var zoneHexMap = {
|
|
8060
|
-
"vel-green": VEL_COLORS.green,
|
|
8061
|
-
"vel-yellow": VEL_COLORS.yellow,
|
|
8062
|
-
"vel-orange": VEL_COLORS.orange,
|
|
8063
|
-
"vel-red": VEL_COLORS.red
|
|
8064
|
-
};
|
|
8065
8499
|
function getLossStyle(loss) {
|
|
8066
8500
|
if (loss > 25) return { color: VEL_COLORS.red };
|
|
8067
8501
|
if (loss > 20) return { color: VEL_COLORS.orange };
|
|
8068
8502
|
return null;
|
|
8069
8503
|
}
|
|
8504
|
+
function getReducedMotionPreference() {
|
|
8505
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
|
|
8506
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
8507
|
+
}
|
|
8508
|
+
function usePrefersReducedMotion() {
|
|
8509
|
+
const [reduced, setReduced] = React24.useState(getReducedMotionPreference);
|
|
8510
|
+
React24.useEffect(() => {
|
|
8511
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
8512
|
+
const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
8513
|
+
const handler = () => setReduced(mq.matches);
|
|
8514
|
+
handler();
|
|
8515
|
+
mq.addEventListener?.("change", handler);
|
|
8516
|
+
return () => mq.removeEventListener?.("change", handler);
|
|
8517
|
+
}, []);
|
|
8518
|
+
return reduced;
|
|
8519
|
+
}
|
|
8070
8520
|
var ANIMATION_DURATION = 400;
|
|
8071
8521
|
var ANIMATION_EASING = reactNative.Easing.bezier(0.22, 1, 0.36, 1);
|
|
8522
|
+
var POP_EASING = reactNative.Easing.bezier(0.34, 1.56, 0.64, 1);
|
|
8072
8523
|
function VelocityStrip({
|
|
8073
8524
|
velocities,
|
|
8525
|
+
zones,
|
|
8526
|
+
liveRepIndex,
|
|
8074
8527
|
expanded = false,
|
|
8075
8528
|
onToggle,
|
|
8076
8529
|
onRepPress,
|
|
@@ -8082,10 +8535,48 @@ function VelocityStrip({
|
|
|
8082
8535
|
const maxVelocity = Math.max(...velocities, 0);
|
|
8083
8536
|
const meanVelocity = calculateMeanVelocity(velocities);
|
|
8084
8537
|
const loss = calculateVelocityLoss(velocities);
|
|
8085
|
-
const
|
|
8538
|
+
const hasZones = zones != null && zones.length > 0;
|
|
8539
|
+
const barColorFor = (v) => hasZones ? bandColor(classifyBand(v, zones)) : zoneHexMap[getVelocityZoneColor(v)];
|
|
8540
|
+
const meanZone = hasZones ? classifyBand(meanVelocity, zones)?.label ?? "" : getVelocityZoneName(meanVelocity);
|
|
8541
|
+
const prefersReducedMotion = usePrefersReducedMotion();
|
|
8086
8542
|
const [heightAnim] = React24.useState(() => new reactNative.Animated.Value(expanded ? 60 : 3));
|
|
8087
8543
|
const [labelOpacity] = React24.useState(() => new reactNative.Animated.Value(expanded ? 1 : 0));
|
|
8088
8544
|
const [infoOpacity] = React24.useState(() => new reactNative.Animated.Value(expanded ? 1 : 0));
|
|
8545
|
+
const [liveScale] = React24.useState(() => new reactNative.Animated.Value(1));
|
|
8546
|
+
const liveVelocity = liveRepIndex != null ? velocities[liveRepIndex] : void 0;
|
|
8547
|
+
const isNewPeak = liveVelocity != null && maxVelocity > 0 && liveVelocity === maxVelocity;
|
|
8548
|
+
React24.useEffect(() => {
|
|
8549
|
+
if (variant === "mini" || liveRepIndex == null || liveVelocity == null) return;
|
|
8550
|
+
if (prefersReducedMotion) {
|
|
8551
|
+
liveScale.setValue(1);
|
|
8552
|
+
return;
|
|
8553
|
+
}
|
|
8554
|
+
if (isNewPeak) {
|
|
8555
|
+
liveScale.setValue(1);
|
|
8556
|
+
reactNative.Animated.sequence([
|
|
8557
|
+
reactNative.Animated.timing(liveScale, {
|
|
8558
|
+
toValue: 1.25,
|
|
8559
|
+
duration: 150,
|
|
8560
|
+
easing: reactNative.Easing.out(reactNative.Easing.quad),
|
|
8561
|
+
useNativeDriver: true
|
|
8562
|
+
}),
|
|
8563
|
+
reactNative.Animated.spring(liveScale, {
|
|
8564
|
+
toValue: 1,
|
|
8565
|
+
friction: 3,
|
|
8566
|
+
tension: 140,
|
|
8567
|
+
useNativeDriver: true
|
|
8568
|
+
})
|
|
8569
|
+
]).start();
|
|
8570
|
+
} else {
|
|
8571
|
+
liveScale.setValue(0.8);
|
|
8572
|
+
reactNative.Animated.timing(liveScale, {
|
|
8573
|
+
toValue: 1,
|
|
8574
|
+
duration: 300,
|
|
8575
|
+
easing: POP_EASING,
|
|
8576
|
+
useNativeDriver: true
|
|
8577
|
+
}).start();
|
|
8578
|
+
}
|
|
8579
|
+
}, [variant, liveRepIndex, liveVelocity, isNewPeak, prefersReducedMotion, liveScale]);
|
|
8089
8580
|
React24.useEffect(() => {
|
|
8090
8581
|
if (variant === "mini") return;
|
|
8091
8582
|
reactNative.Animated.parallel([
|
|
@@ -8125,7 +8616,7 @@ function VelocityStrip({
|
|
|
8125
8616
|
{
|
|
8126
8617
|
style: {
|
|
8127
8618
|
flex: 1,
|
|
8128
|
-
backgroundColor:
|
|
8619
|
+
backgroundColor: barColorFor(v),
|
|
8129
8620
|
borderRadius: 1,
|
|
8130
8621
|
minWidth: 4,
|
|
8131
8622
|
height: "100%"
|
|
@@ -8168,8 +8659,35 @@ function VelocityStrip({
|
|
|
8168
8659
|
{
|
|
8169
8660
|
style: { flexDirection: "row", flex: 1, gap: 2, alignItems: "flex-end" },
|
|
8170
8661
|
children: velocities.map((v, i) => {
|
|
8171
|
-
const
|
|
8662
|
+
const barBackground = barColorFor(v);
|
|
8172
8663
|
const barHeightPct = maxVelocity > 0 ? Math.round(v / (maxVelocity * 1.15) * 100) : 0;
|
|
8664
|
+
const isLive = liveRepIndex === i;
|
|
8665
|
+
const liveLabelSuffix = isLive ? isNewPeak ? ", latest rep, new set peak" : ", latest rep" : "";
|
|
8666
|
+
const barStyle = expanded ? { height: `${barHeightPct}%`, minHeight: 2, borderTopLeftRadius: 2, borderTopRightRadius: 2, backgroundColor: barBackground } : {
|
|
8667
|
+
minHeight: "100%",
|
|
8668
|
+
borderTopLeftRadius: 2,
|
|
8669
|
+
borderTopRightRadius: 2,
|
|
8670
|
+
borderBottomLeftRadius: 0,
|
|
8671
|
+
borderBottomRightRadius: 0,
|
|
8672
|
+
backgroundColor: barBackground
|
|
8673
|
+
};
|
|
8674
|
+
const barInner = isLive ? /* @__PURE__ */ jsx(
|
|
8675
|
+
reactNative.Animated.View,
|
|
8676
|
+
{
|
|
8677
|
+
style: [barStyle, { transform: [{ scale: liveScale }] }],
|
|
8678
|
+
testID: `velocity-bar-${i}`,
|
|
8679
|
+
accessibilityRole: "image",
|
|
8680
|
+
accessibilityLabel: `Rep ${i + 1}: ${formatVelocity(v)} meters per second${liveLabelSuffix}`
|
|
8681
|
+
}
|
|
8682
|
+
) : /* @__PURE__ */ jsx(
|
|
8683
|
+
reactNative.View,
|
|
8684
|
+
{
|
|
8685
|
+
style: barStyle,
|
|
8686
|
+
testID: `velocity-bar-${i}`,
|
|
8687
|
+
accessibilityRole: "image",
|
|
8688
|
+
accessibilityLabel: `Rep ${i + 1}: ${formatVelocity(v)} meters per second`
|
|
8689
|
+
}
|
|
8690
|
+
);
|
|
8173
8691
|
const bar = /* @__PURE__ */ jsxs(
|
|
8174
8692
|
reactNative.View,
|
|
8175
8693
|
{
|
|
@@ -8184,22 +8702,7 @@ function VelocityStrip({
|
|
|
8184
8702
|
children: formatVelocity(v)
|
|
8185
8703
|
}
|
|
8186
8704
|
) }),
|
|
8187
|
-
|
|
8188
|
-
reactNative.View,
|
|
8189
|
-
{
|
|
8190
|
-
style: expanded ? { height: `${barHeightPct}%`, minHeight: 2, borderTopLeftRadius: 2, borderTopRightRadius: 2, backgroundColor: zoneHexMap[zone] } : {
|
|
8191
|
-
minHeight: "100%",
|
|
8192
|
-
borderTopLeftRadius: 2,
|
|
8193
|
-
borderTopRightRadius: 2,
|
|
8194
|
-
borderBottomLeftRadius: 0,
|
|
8195
|
-
borderBottomRightRadius: 0,
|
|
8196
|
-
backgroundColor: zoneHexMap[zone]
|
|
8197
|
-
},
|
|
8198
|
-
testID: `velocity-bar-${i}`,
|
|
8199
|
-
accessibilityRole: "image",
|
|
8200
|
-
accessibilityLabel: `Rep ${i + 1}: ${formatVelocity(v)} meters per second`
|
|
8201
|
-
}
|
|
8202
|
-
)
|
|
8705
|
+
barInner
|
|
8203
8706
|
]
|
|
8204
8707
|
},
|
|
8205
8708
|
i
|
|
@@ -8290,12 +8793,13 @@ function VelocityStrip({
|
|
|
8290
8793
|
}
|
|
8291
8794
|
return stripContent;
|
|
8292
8795
|
}
|
|
8796
|
+
var t7 = getSemanticColors("dark");
|
|
8293
8797
|
var dotColorMap = {
|
|
8294
8798
|
untrained: "#2C2C2C",
|
|
8295
|
-
behind: "
|
|
8296
|
-
ontrack: "
|
|
8297
|
-
target: "
|
|
8298
|
-
over: "
|
|
8799
|
+
behind: t7["brand-secondary"],
|
|
8800
|
+
ontrack: t7["status-success"],
|
|
8801
|
+
target: t7["brand-primary"],
|
|
8802
|
+
over: t7["status-error"]
|
|
8299
8803
|
};
|
|
8300
8804
|
function MuscleGroupChip({
|
|
8301
8805
|
name,
|
|
@@ -8367,7 +8871,7 @@ function MuscleGroupChip({
|
|
|
8367
8871
|
}
|
|
8368
8872
|
return content;
|
|
8369
8873
|
}
|
|
8370
|
-
var
|
|
8874
|
+
var BRAND_PRIMARY2 = getSemanticColors("dark")["brand-primary"];
|
|
8371
8875
|
function normalizeData(data, height) {
|
|
8372
8876
|
if (data.length === 0) return [];
|
|
8373
8877
|
const min = Math.min(...data);
|
|
@@ -8404,7 +8908,7 @@ function Sparkline({
|
|
|
8404
8908
|
}
|
|
8405
8909
|
);
|
|
8406
8910
|
}
|
|
8407
|
-
const resolvedColor = color ??
|
|
8911
|
+
const resolvedColor = color ?? BRAND_PRIMARY2;
|
|
8408
8912
|
const normalized = normalizeData(data, height);
|
|
8409
8913
|
const stepX = data.length > 1 ? width / (data.length - 1) : 0;
|
|
8410
8914
|
const dotSize = 3;
|
|
@@ -8532,6 +9036,8 @@ function SetRow({
|
|
|
8532
9036
|
rpe,
|
|
8533
9037
|
unit,
|
|
8534
9038
|
velocities,
|
|
9039
|
+
velocityZones,
|
|
9040
|
+
velocityLiveRepIndex,
|
|
8535
9041
|
velocityExpanded,
|
|
8536
9042
|
onVelocityToggle,
|
|
8537
9043
|
setType,
|
|
@@ -8581,7 +9087,7 @@ function SetRow({
|
|
|
8581
9087
|
fontSize: 10,
|
|
8582
9088
|
fontWeight: "700",
|
|
8583
9089
|
fontFamily: "Inter, sans-serif",
|
|
8584
|
-
color:
|
|
9090
|
+
color: WORKOUT_TOKENS.scale.orange,
|
|
8585
9091
|
backgroundColor: "rgba(255,165,2,0.12)",
|
|
8586
9092
|
paddingVertical: 1,
|
|
8587
9093
|
paddingHorizontal: 5,
|
|
@@ -8734,6 +9240,8 @@ function SetRow({
|
|
|
8734
9240
|
VelocityStrip,
|
|
8735
9241
|
{
|
|
8736
9242
|
velocities,
|
|
9243
|
+
zones: velocityZones,
|
|
9244
|
+
liveRepIndex: velocityLiveRepIndex,
|
|
8737
9245
|
expanded: velocityExpanded,
|
|
8738
9246
|
onToggle: onVelocityToggle,
|
|
8739
9247
|
variant: onVelocityToggle ? "full" : "mini"
|
|
@@ -8745,7 +9253,7 @@ function SetRow({
|
|
|
8745
9253
|
}
|
|
8746
9254
|
);
|
|
8747
9255
|
}
|
|
8748
|
-
var
|
|
9256
|
+
var BRAND_PRIMARY3 = getSemanticColors("dark")["brand-primary"];
|
|
8749
9257
|
var INPUT_CLASSNAME = "bg-surface-raised border-border-strong text-text-primary";
|
|
8750
9258
|
var inputStyle = {
|
|
8751
9259
|
fontSize: 14,
|
|
@@ -8874,7 +9382,7 @@ function InputBar({
|
|
|
8874
9382
|
onPress: onRecord,
|
|
8875
9383
|
disabled: !canRecord,
|
|
8876
9384
|
style: ({ pressed }) => ({
|
|
8877
|
-
backgroundColor:
|
|
9385
|
+
backgroundColor: BRAND_PRIMARY3,
|
|
8878
9386
|
borderRadius: 8,
|
|
8879
9387
|
paddingVertical: 10,
|
|
8880
9388
|
paddingHorizontal: 16,
|
|
@@ -8901,14 +9409,15 @@ function InputBar({
|
|
|
8901
9409
|
}
|
|
8902
9410
|
);
|
|
8903
9411
|
}
|
|
8904
|
-
var
|
|
9412
|
+
var BRAND_PRIMARY4 = getSemanticColors("dark")["brand-primary"];
|
|
8905
9413
|
function RestTimer({
|
|
8906
9414
|
totalSeconds,
|
|
8907
9415
|
elapsedMs,
|
|
8908
9416
|
onSkip,
|
|
8909
9417
|
onAddTime,
|
|
8910
9418
|
nextSetInfo,
|
|
8911
|
-
visible
|
|
9419
|
+
visible,
|
|
9420
|
+
displayOnly = false
|
|
8912
9421
|
}) {
|
|
8913
9422
|
if (!visible) return null;
|
|
8914
9423
|
const remainingMs = Math.max(0, totalSeconds * 1e3 - elapsedMs);
|
|
@@ -9006,7 +9515,7 @@ function RestTimer({
|
|
|
9006
9515
|
{
|
|
9007
9516
|
style: {
|
|
9008
9517
|
height: "100%",
|
|
9009
|
-
backgroundColor:
|
|
9518
|
+
backgroundColor: BRAND_PRIMARY4,
|
|
9010
9519
|
borderRadius: 2,
|
|
9011
9520
|
width: `${progressPct}%`
|
|
9012
9521
|
},
|
|
@@ -9015,7 +9524,7 @@ function RestTimer({
|
|
|
9015
9524
|
)
|
|
9016
9525
|
}
|
|
9017
9526
|
),
|
|
9018
|
-
/* @__PURE__ */ jsxs(reactNative.View, { style: { flexDirection: "row", gap: 8 }, children: [
|
|
9527
|
+
!displayOnly && /* @__PURE__ */ jsxs(reactNative.View, { style: { flexDirection: "row", gap: 8 }, children: [
|
|
9019
9528
|
/* @__PURE__ */ jsx(
|
|
9020
9529
|
reactNative.Pressable,
|
|
9021
9530
|
{
|
|
@@ -9063,7 +9572,7 @@ function RestTimer({
|
|
|
9063
9572
|
fontSize: 11,
|
|
9064
9573
|
fontFamily: "Inter, sans-serif",
|
|
9065
9574
|
fontWeight: "600",
|
|
9066
|
-
color:
|
|
9575
|
+
color: BRAND_PRIMARY4
|
|
9067
9576
|
},
|
|
9068
9577
|
children: "Skip"
|
|
9069
9578
|
}
|
|
@@ -9132,6 +9641,7 @@ function CollapsedCard({
|
|
|
9132
9641
|
e1rm,
|
|
9133
9642
|
isPR,
|
|
9134
9643
|
setVelocities,
|
|
9644
|
+
velocityZones,
|
|
9135
9645
|
totalPlannedSets,
|
|
9136
9646
|
supersetPosition
|
|
9137
9647
|
}) {
|
|
@@ -9219,6 +9729,7 @@ function CollapsedCard({
|
|
|
9219
9729
|
VelocityStrip,
|
|
9220
9730
|
{
|
|
9221
9731
|
velocities,
|
|
9732
|
+
zones: velocityZones,
|
|
9222
9733
|
variant: "mini",
|
|
9223
9734
|
testID: `exercise-card-velocity-strip-${i}`
|
|
9224
9735
|
},
|
|
@@ -9454,7 +9965,7 @@ function ExerciseCard(props) {
|
|
|
9454
9965
|
}
|
|
9455
9966
|
var DEFAULTS = {
|
|
9456
9967
|
label: "SS",
|
|
9457
|
-
color: "
|
|
9968
|
+
color: getSemanticColors("dark")["brand-primary"],
|
|
9458
9969
|
bgBase: "#101010"
|
|
9459
9970
|
};
|
|
9460
9971
|
function SupersetWrapper({
|
|
@@ -9505,9 +10016,9 @@ function SupersetWrapper({
|
|
|
9505
10016
|
}
|
|
9506
10017
|
);
|
|
9507
10018
|
}
|
|
9508
|
-
var
|
|
10019
|
+
var BRAND_PRIMARY5 = getSemanticColors("dark")["brand-primary"];
|
|
9509
10020
|
var segmentBgColors = {
|
|
9510
|
-
completed: "rgba(
|
|
10021
|
+
completed: "rgba(46,213,115,0.3)",
|
|
9511
10022
|
current: "rgba(255,121,0,0.5)",
|
|
9512
10023
|
upcoming: "rgba(255,255,255,0.06)"
|
|
9513
10024
|
};
|
|
@@ -9557,7 +10068,7 @@ function MesoSegment({ meso, isActive, onPress }) {
|
|
|
9557
10068
|
},
|
|
9558
10069
|
isActive ? {
|
|
9559
10070
|
borderWidth: 2,
|
|
9560
|
-
borderColor:
|
|
10071
|
+
borderColor: BRAND_PRIMARY5,
|
|
9561
10072
|
transform: [{ scale: 1.02 }, { scale: pressScale }]
|
|
9562
10073
|
} : void 0
|
|
9563
10074
|
],
|
|
@@ -9571,7 +10082,7 @@ function MesoSegment({ meso, isActive, onPress }) {
|
|
|
9571
10082
|
top: 0,
|
|
9572
10083
|
bottom: 0,
|
|
9573
10084
|
width: `${progress * 100}%`,
|
|
9574
|
-
backgroundColor:
|
|
10085
|
+
backgroundColor: BRAND_PRIMARY5
|
|
9575
10086
|
},
|
|
9576
10087
|
testID: `meso-segment-fill-${meso.id}`
|
|
9577
10088
|
}
|
|
@@ -9612,7 +10123,7 @@ function MesoProgressBar({
|
|
|
9612
10123
|
}
|
|
9613
10124
|
);
|
|
9614
10125
|
}
|
|
9615
|
-
var
|
|
10126
|
+
var BRAND_PRIMARY6 = getSemanticColors("dark")["brand-primary"];
|
|
9616
10127
|
function WeekRow({
|
|
9617
10128
|
weekNumber,
|
|
9618
10129
|
totalWeeks,
|
|
@@ -9632,12 +10143,12 @@ function WeekRow({
|
|
|
9632
10143
|
gap: 12
|
|
9633
10144
|
};
|
|
9634
10145
|
if (isDeload) {
|
|
9635
|
-
rowStyle.backgroundColor = "rgba(
|
|
10146
|
+
rowStyle.backgroundColor = "rgba(186,41,150,0.06)";
|
|
9636
10147
|
}
|
|
9637
10148
|
if (isCurrent) {
|
|
9638
10149
|
rowStyle.backgroundColor = "rgba(255,121,0,0.04)";
|
|
9639
10150
|
rowStyle.borderLeftWidth = 2;
|
|
9640
|
-
rowStyle.borderLeftColor =
|
|
10151
|
+
rowStyle.borderLeftColor = BRAND_PRIMARY6;
|
|
9641
10152
|
}
|
|
9642
10153
|
return /* @__PURE__ */ jsxs(
|
|
9643
10154
|
reactNative.View,
|
|
@@ -9661,7 +10172,7 @@ function WeekRow({
|
|
|
9661
10172
|
width: 6,
|
|
9662
10173
|
height: 6,
|
|
9663
10174
|
borderRadius: 3,
|
|
9664
|
-
backgroundColor:
|
|
10175
|
+
backgroundColor: BRAND_PRIMARY6
|
|
9665
10176
|
},
|
|
9666
10177
|
accessibilityElementsHidden: true,
|
|
9667
10178
|
testID: "week-row-current-dot"
|
|
@@ -9675,7 +10186,7 @@ function WeekRow({
|
|
|
9675
10186
|
fontSize: 13,
|
|
9676
10187
|
fontWeight: "700",
|
|
9677
10188
|
fontFamily: "Inter, sans-serif",
|
|
9678
|
-
color: isCurrent ?
|
|
10189
|
+
color: isCurrent ? BRAND_PRIMARY6 : void 0
|
|
9679
10190
|
},
|
|
9680
10191
|
accessibilityElementsHidden: true,
|
|
9681
10192
|
children: `W${weekNumber}`
|
|
@@ -9714,9 +10225,10 @@ function WeekRow({
|
|
|
9714
10225
|
}
|
|
9715
10226
|
);
|
|
9716
10227
|
}
|
|
10228
|
+
var t8 = getSemanticColors("dark");
|
|
9717
10229
|
var COLORS = {
|
|
9718
|
-
statusSuccess: "
|
|
9719
|
-
brandPrimary: "
|
|
10230
|
+
statusSuccess: t8["status-success"],
|
|
10231
|
+
brandPrimary: t8["brand-primary"],
|
|
9720
10232
|
borderDefault: "#1F1F1F",
|
|
9721
10233
|
brandPrimarySubtle: "rgba(255,121,0,0.06)"
|
|
9722
10234
|
};
|
|
@@ -9858,11 +10370,11 @@ function WorkoutCard({
|
|
|
9858
10370
|
}
|
|
9859
10371
|
);
|
|
9860
10372
|
}
|
|
9861
|
-
var
|
|
9862
|
-
var BRAND_PRIMARY_DARK =
|
|
9863
|
-
var BRAND_PRIMARY_LIGHT =
|
|
10373
|
+
var BRAND_PRIMARY7 = getSemanticColors("dark")["brand-primary"];
|
|
10374
|
+
var BRAND_PRIMARY_DARK = MESO_ACCENT_GRADIENT_DARK;
|
|
10375
|
+
var BRAND_PRIMARY_LIGHT = MESO_ACCENT_GRADIENT_LIGHT;
|
|
9864
10376
|
var BORDER_DEFAULT = "#1F1F1F";
|
|
9865
|
-
var ACCENT_STOPS = [BRAND_PRIMARY_DARK,
|
|
10377
|
+
var ACCENT_STOPS = [BRAND_PRIMARY_DARK, BRAND_PRIMARY7, BRAND_PRIMARY_LIGHT];
|
|
9866
10378
|
function heatmapColor(percentage) {
|
|
9867
10379
|
const clamped = Math.max(0, Math.min(100, percentage));
|
|
9868
10380
|
const opacity = 0.12 + clamped / 100 * 0.78;
|
|
@@ -9897,7 +10409,7 @@ function MesoCard({
|
|
|
9897
10409
|
}, [highlighted, highlight]);
|
|
9898
10410
|
const borderColor = highlight.interpolate({
|
|
9899
10411
|
inputRange: [0, 1],
|
|
9900
|
-
outputRange: [BORDER_DEFAULT,
|
|
10412
|
+
outputRange: [BORDER_DEFAULT, BRAND_PRIMARY7]
|
|
9901
10413
|
});
|
|
9902
10414
|
const header = /* @__PURE__ */ jsxs(reactNative.View, { style: { paddingHorizontal: 14, paddingTop: 12, paddingBottom: 10 }, testID: "meso-card-body", children: [
|
|
9903
10415
|
/* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", style: { gap: 8 }, testID: "meso-card-header", children: [
|
|
@@ -9957,7 +10469,7 @@ function MesoCard({
|
|
|
9957
10469
|
{
|
|
9958
10470
|
variant: "outline",
|
|
9959
10471
|
elevation: 2,
|
|
9960
|
-
borderColor: highlighted ?
|
|
10472
|
+
borderColor: highlighted ? BRAND_PRIMARY7 : BORDER_DEFAULT,
|
|
9961
10473
|
className,
|
|
9962
10474
|
style: [
|
|
9963
10475
|
{ borderColor },
|
|
@@ -10014,9 +10526,9 @@ function MesoCard({
|
|
|
10014
10526
|
}
|
|
10015
10527
|
) });
|
|
10016
10528
|
}
|
|
10017
|
-
var
|
|
10018
|
-
var RECENT_BORDER = "rgba(
|
|
10019
|
-
var RECENT_GLOW = "0 0 12px rgba(
|
|
10529
|
+
var BRAND_PRIMARY8 = getSemanticColors("dark")["brand-primary"];
|
|
10530
|
+
var RECENT_BORDER = "rgba(249,180,21,0.3)";
|
|
10531
|
+
var RECENT_GLOW = "0 0 12px rgba(249,180,21,0.06)";
|
|
10020
10532
|
var BORDER_DEFAULT2 = resolveColor("border-default");
|
|
10021
10533
|
var TYPE_LABELS = {
|
|
10022
10534
|
e1rm: "e1RM",
|
|
@@ -10056,7 +10568,7 @@ function PrRecordRow({ record, index }) {
|
|
|
10056
10568
|
},
|
|
10057
10569
|
testID: `pr-history-modal-record-${index}`,
|
|
10058
10570
|
children: [
|
|
10059
|
-
/* @__PURE__ */ jsx(
|
|
10571
|
+
/* @__PURE__ */ jsx(StarIcon, { size: 16, color: BRAND_PRIMARY8, fill: BRAND_PRIMARY8, strokeWidth: 2 }),
|
|
10060
10572
|
/* @__PURE__ */ jsx(
|
|
10061
10573
|
reactNative.Text,
|
|
10062
10574
|
{
|
|
@@ -10200,11 +10712,12 @@ function PrHistoryModal({
|
|
|
10200
10712
|
}
|
|
10201
10713
|
);
|
|
10202
10714
|
}
|
|
10203
|
-
var
|
|
10715
|
+
var t9 = getSemanticColors("dark");
|
|
10716
|
+
var BRAND_PRIMARY9 = t9["brand-primary"];
|
|
10204
10717
|
var BRAND_PRIMARY_SUBTLE = "rgba(255,121,0,0.12)";
|
|
10205
|
-
var STATUS_SUCCESS = "
|
|
10206
|
-
var STATUS_WARNING = "
|
|
10207
|
-
var
|
|
10718
|
+
var STATUS_SUCCESS = t9["status-success"];
|
|
10719
|
+
var STATUS_WARNING = t9["status-warning"];
|
|
10720
|
+
var STATUS_ERROR2 = t9["status-error"];
|
|
10208
10721
|
var EMOJI_SETS = {
|
|
10209
10722
|
sleep: ["\u{1F634}", "\u{1F610}", "\u{1F642}", "\u{1F60A}", "\u{1F929}"],
|
|
10210
10723
|
soreness: ["\u{1F635}", "\u{1F623}", "\u{1F610}", "\u{1F642}", "\u{1F4AA}"],
|
|
@@ -10213,7 +10726,7 @@ var EMOJI_SETS = {
|
|
|
10213
10726
|
};
|
|
10214
10727
|
var DEFAULT_EMOJI_SET = ["\u{1F61E}", "\u{1F615}", "\u{1F610}", "\u{1F642}", "\u{1F604}"];
|
|
10215
10728
|
function scoreColor(score) {
|
|
10216
|
-
if (score < 40) return
|
|
10729
|
+
if (score < 40) return STATUS_ERROR2;
|
|
10217
10730
|
if (score < 70) return STATUS_WARNING;
|
|
10218
10731
|
return STATUS_SUCCESS;
|
|
10219
10732
|
}
|
|
@@ -10268,7 +10781,7 @@ function EmojiSlider({ factor }) {
|
|
|
10268
10781
|
paddingVertical: 8,
|
|
10269
10782
|
borderRadius: 8,
|
|
10270
10783
|
borderWidth: 1,
|
|
10271
|
-
borderColor: selected ?
|
|
10784
|
+
borderColor: selected ? BRAND_PRIMARY9 : void 0,
|
|
10272
10785
|
backgroundColor: selected ? BRAND_PRIMARY_SUBTLE : void 0,
|
|
10273
10786
|
opacity: selected ? 1 : pressed ? 0.8 : 0.55,
|
|
10274
10787
|
transform: [{ scale: selected ? 1.06 : 1 }]
|
|
@@ -10384,7 +10897,7 @@ function ReadinessCheck({
|
|
|
10384
10897
|
marginTop: 16,
|
|
10385
10898
|
width: "100%",
|
|
10386
10899
|
alignItems: "center",
|
|
10387
|
-
backgroundColor:
|
|
10900
|
+
backgroundColor: BRAND_PRIMARY9,
|
|
10388
10901
|
borderRadius: 8,
|
|
10389
10902
|
paddingVertical: 12,
|
|
10390
10903
|
opacity: pressed ? 0.8 : 1
|
|
@@ -10394,21 +10907,22 @@ function ReadinessCheck({
|
|
|
10394
10907
|
)
|
|
10395
10908
|
] }) });
|
|
10396
10909
|
}
|
|
10397
|
-
var
|
|
10398
|
-
var
|
|
10399
|
-
var
|
|
10400
|
-
var
|
|
10401
|
-
var
|
|
10402
|
-
var
|
|
10403
|
-
var
|
|
10910
|
+
var t10 = getSemanticColors("dark");
|
|
10911
|
+
var BRAND_PRIMARY10 = t10["brand-primary"];
|
|
10912
|
+
var BRAND_PRIMARY_DARK2 = MESO_ACCENT_GRADIENT_DARK;
|
|
10913
|
+
var BRAND_PRIMARY_LIGHT2 = MESO_ACCENT_GRADIENT_LIGHT;
|
|
10914
|
+
var SUCCESS = t10["status-success"];
|
|
10915
|
+
var WARNING = t10["status-warning"];
|
|
10916
|
+
var ERROR = t10["status-error"];
|
|
10917
|
+
var ACCENT_STOPS2 = [BRAND_PRIMARY_DARK2, BRAND_PRIMARY10, BRAND_PRIMARY_LIGHT2];
|
|
10404
10918
|
var CARD_GRADIENT = `linear-gradient(135deg, ${resolveColor("surface-elevated")} 0%, ${resolveColor("surface-raised")} 100%)`;
|
|
10405
|
-
var GAUGE_GRADIENT = "linear-gradient(90deg, rgba(
|
|
10919
|
+
var GAUGE_GRADIENT = "linear-gradient(90deg, rgba(46,213,115,0.25) 0%, rgba(249,180,21,0.25) 50%, rgba(209,67,67,0.25) 100%)";
|
|
10406
10920
|
var STATUS_VARIANTS = {
|
|
10407
|
-
success: { bg: "rgba(
|
|
10408
|
-
warning: { bg: "rgba(
|
|
10921
|
+
success: { bg: "rgba(46,213,115,0.15)", border: "rgba(46,213,115,0.3)", text: SUCCESS },
|
|
10922
|
+
warning: { bg: "rgba(249,180,21,0.15)", border: "rgba(249,180,21,0.3)", text: WARNING },
|
|
10409
10923
|
error: { bg: "rgba(209,67,67,0.15)", border: "rgba(209,67,67,0.25)", text: ERROR }
|
|
10410
10924
|
};
|
|
10411
|
-
function
|
|
10925
|
+
function clamp01(value) {
|
|
10412
10926
|
if (!Number.isFinite(value)) return 0;
|
|
10413
10927
|
if (value < 0) return 0;
|
|
10414
10928
|
if (value > 1) return 1;
|
|
@@ -10503,7 +11017,7 @@ function MetricCell({ metric }) {
|
|
|
10503
11017
|
] });
|
|
10504
11018
|
}
|
|
10505
11019
|
function Gauge({ gauge }) {
|
|
10506
|
-
const level =
|
|
11020
|
+
const level = clamp01(gauge.level);
|
|
10507
11021
|
const percentage = Math.round(level * 100);
|
|
10508
11022
|
const markerColor = getGaugeZoneColor(level);
|
|
10509
11023
|
return /* @__PURE__ */ jsxs(
|
|
@@ -10697,9 +11211,9 @@ function MesoStatusCard({
|
|
|
10697
11211
|
reactNative.View,
|
|
10698
11212
|
{
|
|
10699
11213
|
style: {
|
|
10700
|
-
backgroundColor: "rgba(
|
|
11214
|
+
backgroundColor: "rgba(249,180,21,0.06)",
|
|
10701
11215
|
borderWidth: 1,
|
|
10702
|
-
borderColor: "rgba(
|
|
11216
|
+
borderColor: "rgba(249,180,21,0.15)",
|
|
10703
11217
|
borderRadius: 8,
|
|
10704
11218
|
paddingVertical: 10,
|
|
10705
11219
|
paddingHorizontal: 12
|
|
@@ -10725,9 +11239,9 @@ function MesoStatusCard({
|
|
|
10725
11239
|
className: "flex-row items-center",
|
|
10726
11240
|
style: {
|
|
10727
11241
|
gap: 8,
|
|
10728
|
-
backgroundColor: "rgba(
|
|
11242
|
+
backgroundColor: "rgba(46,213,115,0.06)",
|
|
10729
11243
|
borderWidth: 1,
|
|
10730
|
-
borderColor: "rgba(
|
|
11244
|
+
borderColor: "rgba(46,213,115,0.2)",
|
|
10731
11245
|
borderRadius: 8,
|
|
10732
11246
|
paddingVertical: 10,
|
|
10733
11247
|
paddingHorizontal: 12
|
|
@@ -10756,21 +11270,22 @@ function MesoStatusCard({
|
|
|
10756
11270
|
}
|
|
10757
11271
|
);
|
|
10758
11272
|
}
|
|
10759
|
-
var
|
|
11273
|
+
var sem = getSemanticColors("dark");
|
|
11274
|
+
var BRAND_PRIMARY11 = sem["brand-primary"];
|
|
10760
11275
|
var PROJECTION_LINE_COLOR = resolveColor("text-tertiary");
|
|
10761
|
-
var STATUS_SUCCESS2 = "
|
|
10762
|
-
var
|
|
10763
|
-
var STATUS_WARNING2 = "
|
|
11276
|
+
var STATUS_SUCCESS2 = sem["status-success"];
|
|
11277
|
+
var STATUS_ERROR3 = sem["status-error"];
|
|
11278
|
+
var STATUS_WARNING2 = sem["status-warning"];
|
|
10764
11279
|
var GRID_LINE = "rgba(255,255,255,0.06)";
|
|
10765
|
-
var SUCCESS_PILL_BG = "rgba(
|
|
10766
|
-
var SUCCESS_PILL_BORDER = "rgba(
|
|
11280
|
+
var SUCCESS_PILL_BG = "rgba(46,213,115,0.10)";
|
|
11281
|
+
var SUCCESS_PILL_BORDER = "rgba(46,213,115,0.20)";
|
|
10767
11282
|
var ERROR_PILL_BG = "rgba(209,67,67,0.10)";
|
|
10768
11283
|
var ERROR_PILL_BORDER = "rgba(209,67,67,0.20)";
|
|
10769
11284
|
var PLOT_LEFT = 26;
|
|
10770
11285
|
var TOOLTIP_WIDTH = 124;
|
|
10771
11286
|
function timeOf(dateStr) {
|
|
10772
|
-
const
|
|
10773
|
-
return Number.isNaN(
|
|
11287
|
+
const t12 = Date.parse(dateStr);
|
|
11288
|
+
return Number.isNaN(t12) ? 0 : t12;
|
|
10774
11289
|
}
|
|
10775
11290
|
function formatValue(value) {
|
|
10776
11291
|
return `${Math.round(value)}`;
|
|
@@ -11047,7 +11562,7 @@ function StrengthTrendChart({
|
|
|
11047
11562
|
ChartLine,
|
|
11048
11563
|
{
|
|
11049
11564
|
coords: geometry.actual,
|
|
11050
|
-
color:
|
|
11565
|
+
color: BRAND_PRIMARY11,
|
|
11051
11566
|
strokeWidth: 2.5,
|
|
11052
11567
|
testID: "strength-trend-chart-actual-segment"
|
|
11053
11568
|
}
|
|
@@ -11100,7 +11615,7 @@ function StrengthTrendChart({
|
|
|
11100
11615
|
width: 8,
|
|
11101
11616
|
height: 8,
|
|
11102
11617
|
borderRadius: 1,
|
|
11103
|
-
backgroundColor:
|
|
11618
|
+
backgroundColor: BRAND_PRIMARY11
|
|
11104
11619
|
}
|
|
11105
11620
|
},
|
|
11106
11621
|
`point-${c.index}`
|
|
@@ -11159,7 +11674,7 @@ function StrengthTrendChart({
|
|
|
11159
11674
|
marginTop: 1,
|
|
11160
11675
|
fontSize: 10,
|
|
11161
11676
|
fontFamily: "Inter, sans-serif",
|
|
11162
|
-
color: selectedCoord.point.e1rm - geometry.actual[selected - 1].point.e1rm >= 0 ? STATUS_SUCCESS2 :
|
|
11677
|
+
color: selectedCoord.point.e1rm - geometry.actual[selected - 1].point.e1rm >= 0 ? STATUS_SUCCESS2 : STATUS_ERROR3
|
|
11163
11678
|
},
|
|
11164
11679
|
children: `${selectedCoord.point.e1rm - geometry.actual[selected - 1].point.e1rm >= 0 ? "+" : "-"}${Math.abs(
|
|
11165
11680
|
selectedCoord.point.e1rm - geometry.actual[selected - 1].point.e1rm
|
|
@@ -11215,7 +11730,7 @@ function StrengthTrendChart({
|
|
|
11215
11730
|
fontSize: 11,
|
|
11216
11731
|
fontFamily: "Inter, sans-serif",
|
|
11217
11732
|
fontWeight: "600",
|
|
11218
|
-
color: trend.positive ? STATUS_SUCCESS2 :
|
|
11733
|
+
color: trend.positive ? STATUS_SUCCESS2 : STATUS_ERROR3
|
|
11219
11734
|
},
|
|
11220
11735
|
children: trendText
|
|
11221
11736
|
}
|
|
@@ -11230,7 +11745,7 @@ function StrengthTrendChart({
|
|
|
11230
11745
|
testID: "strength-trend-chart-legend",
|
|
11231
11746
|
children: [
|
|
11232
11747
|
/* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", style: { gap: 5 }, children: [
|
|
11233
|
-
/* @__PURE__ */ jsx(reactNative.View, { style: { width: 14, height: 2.5, borderRadius: 1.5, backgroundColor:
|
|
11748
|
+
/* @__PURE__ */ jsx(reactNative.View, { style: { width: 14, height: 2.5, borderRadius: 1.5, backgroundColor: BRAND_PRIMARY11 } }),
|
|
11234
11749
|
/* @__PURE__ */ jsx(reactNative.Text, { className: "text-text-secondary", style: { fontSize: 10, fontFamily: "Inter, sans-serif" }, children: "Actual" })
|
|
11235
11750
|
] }),
|
|
11236
11751
|
/* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", style: { gap: 5 }, children: [
|
|
@@ -11259,13 +11774,14 @@ function StrengthTrendChart({
|
|
|
11259
11774
|
}
|
|
11260
11775
|
);
|
|
11261
11776
|
}
|
|
11262
|
-
var
|
|
11263
|
-
var
|
|
11264
|
-
var
|
|
11777
|
+
var t11 = getSemanticColors("dark");
|
|
11778
|
+
var STATUS_SUCCESS3 = t11["status-success"];
|
|
11779
|
+
var STATUS_WARNING3 = t11["status-warning"];
|
|
11780
|
+
var STATUS_INFO = t11["status-info"];
|
|
11265
11781
|
var DOT_BORDER = "#F3F4F6";
|
|
11266
|
-
var BAND_FILL = "rgba(
|
|
11267
|
-
var BAND_EDGE = "rgba(
|
|
11268
|
-
var PROJECTION_FILL = "rgba(
|
|
11782
|
+
var BAND_FILL = "rgba(46,213,115,0.1)";
|
|
11783
|
+
var BAND_EDGE = "rgba(46,213,115,0.45)";
|
|
11784
|
+
var PROJECTION_FILL = "rgba(46,213,115,0.05)";
|
|
11269
11785
|
var PADDING_LEFT = 28;
|
|
11270
11786
|
var PADDING_RIGHT = 10;
|
|
11271
11787
|
var PADDING_TOP = 8;
|
|
@@ -11304,8 +11820,8 @@ function interpEdge(pixels, x, key) {
|
|
|
11304
11820
|
const a = pixels[i];
|
|
11305
11821
|
const b = pixels[i + 1];
|
|
11306
11822
|
if (x >= a.x && x <= b.x) {
|
|
11307
|
-
const
|
|
11308
|
-
return a[key] +
|
|
11823
|
+
const t12 = b.x === a.x ? 0 : (x - a.x) / (b.x - a.x);
|
|
11824
|
+
return a[key] + t12 * (b[key] - a[key]);
|
|
11309
11825
|
}
|
|
11310
11826
|
}
|
|
11311
11827
|
return pixels[pixels.length - 1][key];
|
|
@@ -11464,1188 +11980,178 @@ function CapacityBandChart({
|
|
|
11464
11980
|
transformOrigin: "0 0",
|
|
11465
11981
|
transform: [{ rotate: `${seg.angle}deg` }]
|
|
11466
11982
|
},
|
|
11467
|
-
accessibilityElementsHidden: true,
|
|
11468
|
-
importantForAccessibility: "no-hide-descendants",
|
|
11469
|
-
testID: key
|
|
11470
|
-
},
|
|
11471
|
-
`${key}-${i}`
|
|
11472
|
-
));
|
|
11473
|
-
return /* @__PURE__ */ jsxs(
|
|
11474
|
-
reactNative.View,
|
|
11475
|
-
{
|
|
11476
|
-
style: { width, height, position: "relative" },
|
|
11477
|
-
className,
|
|
11478
|
-
testID: "capacity-band-chart-root",
|
|
11479
|
-
...props,
|
|
11480
|
-
children: [
|
|
11481
|
-
/* @__PURE__ */ jsxs(
|
|
11482
|
-
reactNative.View,
|
|
11483
|
-
{
|
|
11484
|
-
style: { position: "absolute", top: 0, left: 0, width, height },
|
|
11485
|
-
accessibilityRole: "image",
|
|
11486
|
-
accessibilityLabel: `Training capacity band chart. Current capacity: ${currentStatus(
|
|
11487
|
-
workouts
|
|
11488
|
-
)}. ${workouts.length} workout${workouts.length === 1 ? "" : "s"} shown.`,
|
|
11489
|
-
testID: "capacity-band-chart",
|
|
11490
|
-
children: [
|
|
11491
|
-
/* @__PURE__ */ jsx(
|
|
11492
|
-
reactNative.Animated.View,
|
|
11493
|
-
{
|
|
11494
|
-
style: { position: "absolute", top: 0, left: 0, height, width: revealWidth, overflow: "hidden" },
|
|
11495
|
-
accessibilityElementsHidden: true,
|
|
11496
|
-
importantForAccessibility: "no-hide-descendants",
|
|
11497
|
-
testID: "capacity-band-chart-reveal",
|
|
11498
|
-
children: /* @__PURE__ */ jsxs(reactNative.View, { style: { width, height, position: "relative" }, children: [
|
|
11499
|
-
projection && /* @__PURE__ */ jsxs(reactNative.View, { testID: "capacity-band-chart-projection", children: [
|
|
11500
|
-
renderColumns(buildColumns(trainingPixels, COLUMN_STEP), PROJECTION_FILL, "capacity-band-chart-projection-fill"),
|
|
11501
|
-
renderColumns(buildColumns(restPixels, COLUMN_STEP), PROJECTION_FILL, "capacity-band-chart-projection-fill"),
|
|
11502
|
-
renderEdges(buildEdges(trainingPixels, "yHigh"), STATUS_SUCCESS3, true, "capacity-band-chart-projection-training"),
|
|
11503
|
-
renderEdges(buildEdges(trainingPixels, "yLow"), STATUS_SUCCESS3, true, "capacity-band-chart-projection-training"),
|
|
11504
|
-
renderEdges(buildEdges(restPixels, "yHigh"), STATUS_INFO, true, "capacity-band-chart-projection-rest"),
|
|
11505
|
-
renderEdges(buildEdges(restPixels, "yLow"), STATUS_INFO, true, "capacity-band-chart-projection-rest"),
|
|
11506
|
-
/* @__PURE__ */ jsx(
|
|
11507
|
-
reactNative.Text,
|
|
11508
|
-
{
|
|
11509
|
-
style: {
|
|
11510
|
-
position: "absolute",
|
|
11511
|
-
left: trainingPixels[trainingPixels.length - 1]?.x + 2,
|
|
11512
|
-
top: trainingPixels[trainingPixels.length - 1]?.yHigh - 12,
|
|
11513
|
-
fontSize: 9,
|
|
11514
|
-
fontFamily: "Inter, sans-serif",
|
|
11515
|
-
color: STATUS_SUCCESS3
|
|
11516
|
-
},
|
|
11517
|
-
testID: "capacity-band-chart-projection-training-label",
|
|
11518
|
-
children: "Training"
|
|
11519
|
-
}
|
|
11520
|
-
),
|
|
11521
|
-
/* @__PURE__ */ jsx(
|
|
11522
|
-
reactNative.Text,
|
|
11523
|
-
{
|
|
11524
|
-
style: {
|
|
11525
|
-
position: "absolute",
|
|
11526
|
-
left: restPixels[restPixels.length - 1]?.x + 2,
|
|
11527
|
-
top: restPixels[restPixels.length - 1]?.yLow + 2,
|
|
11528
|
-
fontSize: 9,
|
|
11529
|
-
fontFamily: "Inter, sans-serif",
|
|
11530
|
-
color: STATUS_INFO
|
|
11531
|
-
},
|
|
11532
|
-
testID: "capacity-band-chart-projection-rest-label",
|
|
11533
|
-
children: "Rest"
|
|
11534
|
-
}
|
|
11535
|
-
)
|
|
11536
|
-
] }),
|
|
11537
|
-
/* @__PURE__ */ jsx(reactNative.View, { testID: "capacity-band-chart-band", children: renderColumns(columns, BAND_FILL, "capacity-band-chart-band-cell") }),
|
|
11538
|
-
renderEdges(topEdge, BAND_EDGE, false, "capacity-band-chart-edge-top"),
|
|
11539
|
-
renderEdges(bottomEdge, BAND_EDGE, false, "capacity-band-chart-edge-bottom")
|
|
11540
|
-
] })
|
|
11541
|
-
}
|
|
11542
|
-
),
|
|
11543
|
-
/* @__PURE__ */ jsx(
|
|
11544
|
-
reactNative.Text,
|
|
11545
|
-
{
|
|
11546
|
-
className: "text-text-tertiary",
|
|
11547
|
-
style: {
|
|
11548
|
-
position: "absolute",
|
|
11549
|
-
left: PADDING_LEFT / 2 - 14,
|
|
11550
|
-
top: PADDING_TOP + plotHeight / 2 - 7,
|
|
11551
|
-
width: 32,
|
|
11552
|
-
textAlign: "center",
|
|
11553
|
-
fontSize: 9,
|
|
11554
|
-
fontFamily: "Inter, sans-serif",
|
|
11555
|
-
transform: [{ rotate: "-90deg" }]
|
|
11556
|
-
},
|
|
11557
|
-
accessibilityElementsHidden: true,
|
|
11558
|
-
importantForAccessibility: "no-hide-descendants",
|
|
11559
|
-
testID: "capacity-band-chart-y-axis-label",
|
|
11560
|
-
children: "Load"
|
|
11561
|
-
}
|
|
11562
|
-
),
|
|
11563
|
-
band.map((point, i) => {
|
|
11564
|
-
if (i % labelStride !== 0 && i !== band.length - 1) return null;
|
|
11565
|
-
return /* @__PURE__ */ jsx(
|
|
11566
|
-
reactNative.Text,
|
|
11567
|
-
{
|
|
11568
|
-
className: "text-text-tertiary",
|
|
11569
|
-
style: {
|
|
11570
|
-
position: "absolute",
|
|
11571
|
-
left: toX(point.date) - 14,
|
|
11572
|
-
top: height - PADDING_BOTTOM + 2,
|
|
11573
|
-
width: 28,
|
|
11574
|
-
textAlign: "center",
|
|
11575
|
-
fontSize: 10,
|
|
11576
|
-
fontFamily: "Inter, sans-serif"
|
|
11577
|
-
},
|
|
11578
|
-
accessibilityElementsHidden: true,
|
|
11579
|
-
importantForAccessibility: "no-hide-descendants",
|
|
11580
|
-
testID: "capacity-band-chart-x-label",
|
|
11581
|
-
children: formatDate2(point.date)
|
|
11582
|
-
},
|
|
11583
|
-
`x-${point.date}`
|
|
11584
|
-
);
|
|
11585
|
-
})
|
|
11586
|
-
]
|
|
11587
|
-
}
|
|
11588
|
-
),
|
|
11589
|
-
workouts.map((workout, i) => {
|
|
11590
|
-
const cx = toX(workout.date);
|
|
11591
|
-
const cy = toY(workout.load);
|
|
11592
|
-
const color = DOT_COLORS[workout.status];
|
|
11593
|
-
const dotStyle = {
|
|
11594
|
-
width: DOT_SIZE,
|
|
11595
|
-
height: DOT_SIZE,
|
|
11596
|
-
borderRadius: DOT_SIZE / 2,
|
|
11597
|
-
backgroundColor: color,
|
|
11598
|
-
borderWidth: 2,
|
|
11599
|
-
borderColor: DOT_BORDER
|
|
11600
|
-
};
|
|
11601
|
-
const label = `Workout on ${formatDate2(workout.date)}, load ${workout.load}, ${STATUS_PHRASES[workout.status]}`;
|
|
11602
|
-
return /* @__PURE__ */ jsx(
|
|
11603
|
-
reactNative.Animated.View,
|
|
11604
|
-
{
|
|
11605
|
-
style: {
|
|
11606
|
-
position: "absolute",
|
|
11607
|
-
left: cx - DOT_SIZE / 2,
|
|
11608
|
-
top: cy - DOT_SIZE / 2,
|
|
11609
|
-
transform: [{ scale: dotAnims[i] ?? 1 }]
|
|
11610
|
-
},
|
|
11611
|
-
testID: "capacity-band-chart-dot-wrapper",
|
|
11612
|
-
children: onWorkoutPress ? /* @__PURE__ */ jsx(
|
|
11613
|
-
reactNative.Pressable,
|
|
11614
|
-
{
|
|
11615
|
-
onPress: () => onWorkoutPress(workout),
|
|
11616
|
-
accessibilityRole: "button",
|
|
11617
|
-
accessibilityLabel: label,
|
|
11618
|
-
style: dotStyle,
|
|
11619
|
-
testID: "capacity-band-chart-dot"
|
|
11620
|
-
}
|
|
11621
|
-
) : /* @__PURE__ */ jsx(
|
|
11622
|
-
reactNative.View,
|
|
11623
|
-
{
|
|
11624
|
-
accessibilityElementsHidden: true,
|
|
11625
|
-
importantForAccessibility: "no-hide-descendants",
|
|
11626
|
-
style: dotStyle,
|
|
11627
|
-
testID: "capacity-band-chart-dot"
|
|
11628
|
-
}
|
|
11629
|
-
)
|
|
11630
|
-
},
|
|
11631
|
-
`dot-${workout.date}-${i}`
|
|
11632
|
-
);
|
|
11633
|
-
})
|
|
11634
|
-
]
|
|
11635
|
-
}
|
|
11636
|
-
);
|
|
11637
|
-
}
|
|
11638
|
-
var BRAND_PRIMARY11 = "#FF7900";
|
|
11639
|
-
var WORKOUT_PILL_STATUS = {
|
|
11640
|
-
completed: "completed",
|
|
11641
|
-
today: "current",
|
|
11642
|
-
upcoming: "upcoming"
|
|
11643
|
-
};
|
|
11644
|
-
function deriveNavLevel(selection) {
|
|
11645
|
-
if (selection.workoutId != null) return "workout";
|
|
11646
|
-
if (selection.weekNumber != null) return "week";
|
|
11647
|
-
return "meso";
|
|
11648
|
-
}
|
|
11649
|
-
function toProgressBarMesos(mesos) {
|
|
11650
|
-
return mesos.map(({ id, name, weekCount, status, currentWeek }) => ({
|
|
11651
|
-
id,
|
|
11652
|
-
name,
|
|
11653
|
-
weekCount,
|
|
11654
|
-
status,
|
|
11655
|
-
currentWeek
|
|
11656
|
-
}));
|
|
11657
|
-
}
|
|
11658
|
-
function findMeso(mesos, id) {
|
|
11659
|
-
if (id == null) return null;
|
|
11660
|
-
return mesos.find((meso) => meso.id === id) ?? null;
|
|
11661
|
-
}
|
|
11662
|
-
function findWeek(meso, weekNumber) {
|
|
11663
|
-
if (meso == null || weekNumber == null) return null;
|
|
11664
|
-
return meso.weeks.find((week) => week.weekNumber === weekNumber) ?? null;
|
|
11665
|
-
}
|
|
11666
|
-
function findWorkout(week, workoutId) {
|
|
11667
|
-
if (week == null || workoutId == null) return null;
|
|
11668
|
-
return week.workouts.find((workout) => workout.id === workoutId) ?? null;
|
|
11669
|
-
}
|
|
11670
|
-
function buildBreadcrumbs(meso, weekNumber, workout) {
|
|
11671
|
-
const crumbs = [{ key: "meso", label: meso.name, level: "meso" }];
|
|
11672
|
-
if (weekNumber != null) {
|
|
11673
|
-
crumbs.push({ key: "week", label: `Week ${weekNumber}`, level: "week" });
|
|
11674
|
-
}
|
|
11675
|
-
if (workout != null) {
|
|
11676
|
-
crumbs.push({ key: "workout", label: workout.name, level: "workout" });
|
|
11677
|
-
}
|
|
11678
|
-
return crumbs;
|
|
11679
|
-
}
|
|
11680
|
-
function Breadcrumbs2({ crumbs, onNavigate }) {
|
|
11681
|
-
return /* @__PURE__ */ jsx(
|
|
11682
|
-
reactNative.View,
|
|
11683
|
-
{
|
|
11684
|
-
className: "flex-row items-center flex-wrap",
|
|
11685
|
-
style: { gap: 4 },
|
|
11686
|
-
testID: "program-planning-page-breadcrumbs",
|
|
11687
|
-
children: crumbs.map((crumb, index) => {
|
|
11688
|
-
const isLast = index === crumbs.length - 1;
|
|
11689
|
-
return /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", style: { gap: 4 }, children: [
|
|
11690
|
-
index > 0 && /* @__PURE__ */ jsx(reactNative.Text, { className: "text-text-tertiary", style: { fontSize: 12 }, children: "\u203A" }),
|
|
11691
|
-
/* @__PURE__ */ jsx(
|
|
11692
|
-
reactNative.Pressable,
|
|
11693
|
-
{
|
|
11694
|
-
onPress: () => onNavigate(crumb.level),
|
|
11695
|
-
disabled: isLast,
|
|
11696
|
-
accessibilityRole: "button",
|
|
11697
|
-
testID: `program-planning-page-crumb-${crumb.key}`,
|
|
11698
|
-
children: /* @__PURE__ */ jsx(
|
|
11699
|
-
reactNative.Text,
|
|
11700
|
-
{
|
|
11701
|
-
className: isLast ? "text-text-primary" : void 0,
|
|
11702
|
-
style: {
|
|
11703
|
-
fontSize: 12,
|
|
11704
|
-
fontFamily: "Inter, sans-serif",
|
|
11705
|
-
fontWeight: isLast ? "700" : "500",
|
|
11706
|
-
color: isLast ? void 0 : BRAND_PRIMARY11
|
|
11707
|
-
},
|
|
11708
|
-
children: crumb.label
|
|
11709
|
-
}
|
|
11710
|
-
)
|
|
11711
|
-
}
|
|
11712
|
-
)
|
|
11713
|
-
] }, crumb.key);
|
|
11714
|
-
})
|
|
11715
|
-
}
|
|
11716
|
-
);
|
|
11717
|
-
}
|
|
11718
|
-
function toWeekRow(week, meso, onSelectWeek) {
|
|
11719
|
-
const workouts = week.workouts.map((workout) => ({
|
|
11720
|
-
name: workout.name,
|
|
11721
|
-
status: WORKOUT_PILL_STATUS[workout.status],
|
|
11722
|
-
onPress: () => onSelectWeek(week.weekNumber)
|
|
11723
|
-
}));
|
|
11724
|
-
return {
|
|
11725
|
-
weekNumber: week.weekNumber,
|
|
11726
|
-
totalWeeks: meso.weekCount,
|
|
11727
|
-
workouts,
|
|
11728
|
-
intensityLevel: week.intensityLevel,
|
|
11729
|
-
intensityThreshold: week.intensityThreshold,
|
|
11730
|
-
isCurrent: week.isCurrent ?? week.weekNumber === meso.currentWeek,
|
|
11731
|
-
isDeload: week.isDeload
|
|
11732
|
-
};
|
|
11733
|
-
}
|
|
11734
|
-
function MesoLevel({ mesos, activeMesoId, onSelectMeso, onSelectWeek }) {
|
|
11735
|
-
return /* @__PURE__ */ jsx(reactNative.View, { style: { gap: 12 }, testID: "program-planning-page-meso-level", children: mesos.map((meso) => {
|
|
11736
|
-
const expanded = meso.id === activeMesoId;
|
|
11737
|
-
return /* @__PURE__ */ jsx(
|
|
11738
|
-
MesoCard,
|
|
11739
|
-
{
|
|
11740
|
-
name: meso.name,
|
|
11741
|
-
goal: meso.goal,
|
|
11742
|
-
split: meso.split,
|
|
11743
|
-
weekRange: meso.weekRange,
|
|
11744
|
-
currentWeek: meso.currentWeek,
|
|
11745
|
-
totalWeeks: meso.weekCount,
|
|
11746
|
-
weeks: expanded ? meso.weeks.map((week) => toWeekRow(week, meso, onSelectWeek)) : [],
|
|
11747
|
-
volumeHeatmap: meso.volumeHeatmap,
|
|
11748
|
-
expanded,
|
|
11749
|
-
onToggle: () => onSelectMeso(meso.id),
|
|
11750
|
-
highlighted: expanded
|
|
11751
|
-
},
|
|
11752
|
-
meso.id
|
|
11753
|
-
);
|
|
11754
|
-
}) });
|
|
11755
|
-
}
|
|
11756
|
-
function WeekLevel({ week, onSelectWorkout }) {
|
|
11757
|
-
return /* @__PURE__ */ jsx(reactNative.View, { style: { gap: 10 }, testID: "program-planning-page-week-level", children: week.workouts.map((workout) => /* @__PURE__ */ jsx(
|
|
11758
|
-
WorkoutCard,
|
|
11759
|
-
{
|
|
11760
|
-
name: workout.name,
|
|
11761
|
-
date: workout.date,
|
|
11762
|
-
duration: workout.duration,
|
|
11763
|
-
status: workout.status,
|
|
11764
|
-
muscleGroups: workout.muscleGroups,
|
|
11765
|
-
totalSets: workout.totalSets,
|
|
11766
|
-
totalVolume: workout.totalVolume,
|
|
11767
|
-
unit: workout.unit,
|
|
11768
|
-
exercises: workout.exercises,
|
|
11769
|
-
expanded: false,
|
|
11770
|
-
onToggle: () => onSelectWorkout(workout.id)
|
|
11771
|
-
},
|
|
11772
|
-
workout.id
|
|
11773
|
-
)) });
|
|
11774
|
-
}
|
|
11775
|
-
function WorkoutLevel({ workout, expandedExercise, onToggleExercise }) {
|
|
11776
|
-
const exercises = workout.exercises.map((exercise, index) => ({
|
|
11777
|
-
...exercise,
|
|
11778
|
-
state: exercise.state === "upcoming" ? exercise.state : index === expandedExercise ? "expanded" : "collapsed",
|
|
11779
|
-
onToggle: () => onToggleExercise(index)
|
|
11780
|
-
}));
|
|
11781
|
-
return /* @__PURE__ */ jsx(reactNative.View, { testID: "program-planning-page-workout-level", children: /* @__PURE__ */ jsx(
|
|
11782
|
-
WorkoutCard,
|
|
11783
|
-
{
|
|
11784
|
-
name: workout.name,
|
|
11785
|
-
date: workout.date,
|
|
11786
|
-
duration: workout.duration,
|
|
11787
|
-
status: workout.status,
|
|
11788
|
-
muscleGroups: workout.muscleGroups,
|
|
11789
|
-
totalSets: workout.totalSets,
|
|
11790
|
-
totalVolume: workout.totalVolume,
|
|
11791
|
-
unit: workout.unit,
|
|
11792
|
-
exercises,
|
|
11793
|
-
expanded: true,
|
|
11794
|
-
onToggle: () => void 0
|
|
11795
|
-
}
|
|
11796
|
-
) });
|
|
11797
|
-
}
|
|
11798
|
-
function ProgramPlanningPage({
|
|
11799
|
-
title = "Program Plan",
|
|
11800
|
-
mesos,
|
|
11801
|
-
className,
|
|
11802
|
-
...props
|
|
11803
|
-
}) {
|
|
11804
|
-
const [activeMesoId, setActiveMesoId] = React24.useState(mesos[0]?.id ?? null);
|
|
11805
|
-
const [selectedWeek, setSelectedWeek] = React24.useState(null);
|
|
11806
|
-
const [selectedWorkoutId, setSelectedWorkoutId] = React24.useState(null);
|
|
11807
|
-
const [expandedExercise, setExpandedExercise] = React24.useState(null);
|
|
11808
|
-
const progressMesos = React24.useMemo(() => toProgressBarMesos(mesos), [mesos]);
|
|
11809
|
-
const activeMeso = findMeso(mesos, activeMesoId);
|
|
11810
|
-
const level = deriveNavLevel({ weekNumber: selectedWeek, workoutId: selectedWorkoutId });
|
|
11811
|
-
const activeWeek = findWeek(activeMeso, selectedWeek);
|
|
11812
|
-
const activeWorkout = findWorkout(activeWeek, selectedWorkoutId);
|
|
11813
|
-
const selectMeso = (id) => {
|
|
11814
|
-
setActiveMesoId(id);
|
|
11815
|
-
setSelectedWeek(null);
|
|
11816
|
-
setSelectedWorkoutId(null);
|
|
11817
|
-
};
|
|
11818
|
-
const selectWeek = (weekNumber) => {
|
|
11819
|
-
setSelectedWeek(weekNumber);
|
|
11820
|
-
setSelectedWorkoutId(null);
|
|
11821
|
-
setExpandedExercise(null);
|
|
11822
|
-
};
|
|
11823
|
-
const selectWorkout = (id) => {
|
|
11824
|
-
setSelectedWorkoutId(id);
|
|
11825
|
-
setExpandedExercise(null);
|
|
11826
|
-
};
|
|
11827
|
-
const toggleExercise = (index) => setExpandedExercise((current) => current === index ? null : index);
|
|
11828
|
-
const navigateTo = (target) => {
|
|
11829
|
-
if (target === "meso") selectMeso(activeMesoId ?? mesos[0]?.id);
|
|
11830
|
-
else if (target === "week" && selectedWeek != null) selectWeek(selectedWeek);
|
|
11831
|
-
};
|
|
11832
|
-
return /* @__PURE__ */ jsx(
|
|
11833
|
-
reactNative.View,
|
|
11834
|
-
{
|
|
11835
|
-
className: cn(className, "bg-background-base"),
|
|
11836
|
-
style: { width: 390 },
|
|
11837
|
-
accessibilityRole: "main",
|
|
11838
|
-
"aria-label": title,
|
|
11839
|
-
testID: "program-planning-page",
|
|
11840
|
-
...props,
|
|
11841
|
-
children: /* @__PURE__ */ jsxs(reactNative.View, { style: { padding: 16, gap: 14 }, testID: "program-planning-page-content", children: [
|
|
11842
|
-
/* @__PURE__ */ jsx(
|
|
11843
|
-
reactNative.Text,
|
|
11844
|
-
{
|
|
11845
|
-
accessibilityRole: "header",
|
|
11846
|
-
className: "text-text-primary",
|
|
11847
|
-
style: {
|
|
11848
|
-
fontSize: 20,
|
|
11849
|
-
fontFamily: '"Space Grotesk", sans-serif',
|
|
11850
|
-
fontWeight: "700"
|
|
11851
|
-
},
|
|
11852
|
-
testID: "program-planning-page-title",
|
|
11853
|
-
children: title
|
|
11854
|
-
}
|
|
11855
|
-
),
|
|
11856
|
-
/* @__PURE__ */ jsx(reactNative.View, { style: { marginHorizontal: -16 }, children: /* @__PURE__ */ jsx(
|
|
11857
|
-
MesoProgressBar,
|
|
11858
|
-
{
|
|
11859
|
-
mesos: progressMesos,
|
|
11860
|
-
activeMesoId,
|
|
11861
|
-
onMesoPress: selectMeso
|
|
11862
|
-
}
|
|
11863
|
-
) }),
|
|
11864
|
-
activeMeso != null && /* @__PURE__ */ jsx(
|
|
11865
|
-
Breadcrumbs2,
|
|
11866
|
-
{
|
|
11867
|
-
crumbs: buildBreadcrumbs(activeMeso, selectedWeek, activeWorkout),
|
|
11868
|
-
onNavigate: navigateTo
|
|
11869
|
-
}
|
|
11870
|
-
),
|
|
11871
|
-
/* @__PURE__ */ jsxs(
|
|
11872
|
-
reactNative.View,
|
|
11873
|
-
{
|
|
11874
|
-
className: "bg-surface-elevated border-border",
|
|
11875
|
-
style: {
|
|
11876
|
-
borderWidth: 1,
|
|
11877
|
-
borderRadius: 12,
|
|
11878
|
-
padding: 12
|
|
11879
|
-
},
|
|
11880
|
-
testID: "program-planning-page-body",
|
|
11881
|
-
children: [
|
|
11882
|
-
level === "meso" && /* @__PURE__ */ jsx(
|
|
11883
|
-
MesoLevel,
|
|
11884
|
-
{
|
|
11885
|
-
mesos,
|
|
11886
|
-
activeMesoId,
|
|
11887
|
-
onSelectMeso: selectMeso,
|
|
11888
|
-
onSelectWeek: selectWeek
|
|
11889
|
-
}
|
|
11890
|
-
),
|
|
11891
|
-
level === "week" && activeWeek != null && /* @__PURE__ */ jsx(WeekLevel, { week: activeWeek, onSelectWorkout: selectWorkout }),
|
|
11892
|
-
level === "workout" && activeWorkout != null && /* @__PURE__ */ jsx(
|
|
11893
|
-
WorkoutLevel,
|
|
11894
|
-
{
|
|
11895
|
-
workout: activeWorkout,
|
|
11896
|
-
expandedExercise,
|
|
11897
|
-
onToggleExercise: toggleExercise
|
|
11898
|
-
}
|
|
11899
|
-
)
|
|
11900
|
-
]
|
|
11901
|
-
}
|
|
11902
|
-
)
|
|
11903
|
-
] })
|
|
11904
|
-
}
|
|
11905
|
-
);
|
|
11906
|
-
}
|
|
11907
|
-
var BRAND_PRIMARY12 = "#FF7900";
|
|
11908
|
-
var CHART_WIDTH = 326;
|
|
11909
|
-
var CHART_HEIGHT = 150;
|
|
11910
|
-
var EXERCISE_DETAIL_TABS = [
|
|
11911
|
-
{ key: "progress", label: "Progress" },
|
|
11912
|
-
{ key: "history", label: "History" },
|
|
11913
|
-
{ key: "advanced", label: "Advanced" }
|
|
11914
|
-
];
|
|
11915
|
-
function deriveExerciseStats(entries) {
|
|
11916
|
-
let bestE1rm = null;
|
|
11917
|
-
let prCount = 0;
|
|
11918
|
-
for (const entry of entries) {
|
|
11919
|
-
if (entry.e1rm != null && (bestE1rm == null || entry.e1rm.value > bestE1rm)) {
|
|
11920
|
-
bestE1rm = entry.e1rm.value;
|
|
11921
|
-
}
|
|
11922
|
-
if (entry.isPR) prCount += 1;
|
|
11923
|
-
}
|
|
11924
|
-
return { sessions: entries.length, bestE1rm, prCount };
|
|
11925
|
-
}
|
|
11926
|
-
function toExerciseCardProps(entry, expanded, onToggle) {
|
|
11927
|
-
return {
|
|
11928
|
-
name: entry.title,
|
|
11929
|
-
state: expanded ? "expanded" : "collapsed",
|
|
11930
|
-
onToggle,
|
|
11931
|
-
summary: entry.summary,
|
|
11932
|
-
e1rm: entry.e1rm,
|
|
11933
|
-
isPR: entry.isPR,
|
|
11934
|
-
tempo: entry.tempo,
|
|
11935
|
-
sets: expanded ? entry.sets : void 0
|
|
11936
|
-
};
|
|
11937
|
-
}
|
|
11938
|
-
function summarizeVbt(sets) {
|
|
11939
|
-
const allReps = sets.flatMap((set) => set.velocities);
|
|
11940
|
-
const meanVelocity = calculateMeanVelocity(allReps);
|
|
11941
|
-
let velocityLoss = 0;
|
|
11942
|
-
for (const set of sets) {
|
|
11943
|
-
velocityLoss = Math.max(velocityLoss, calculateVelocityLoss(set.velocities));
|
|
11944
|
-
}
|
|
11945
|
-
return { meanVelocity, velocityLoss };
|
|
11946
|
-
}
|
|
11947
|
-
function TabBar({ active, onSelect }) {
|
|
11948
|
-
return /* @__PURE__ */ jsx(
|
|
11949
|
-
reactNative.View,
|
|
11950
|
-
{
|
|
11951
|
-
className: "flex-row",
|
|
11952
|
-
style: {
|
|
11953
|
-
borderBottomWidth: 1,
|
|
11954
|
-
borderBottomColor: resolveColor("border-default")
|
|
11955
|
-
},
|
|
11956
|
-
accessibilityRole: "tablist",
|
|
11957
|
-
testID: "exercise-detail-page-tabs",
|
|
11958
|
-
children: EXERCISE_DETAIL_TABS.map(({ key, label }) => {
|
|
11959
|
-
const isActive = key === active;
|
|
11960
|
-
return /* @__PURE__ */ jsx(
|
|
11961
|
-
reactNative.Pressable,
|
|
11962
|
-
{
|
|
11963
|
-
onPress: () => onSelect(key),
|
|
11964
|
-
accessibilityRole: "tab",
|
|
11965
|
-
accessibilityState: { selected: isActive },
|
|
11966
|
-
style: {
|
|
11967
|
-
flex: 1,
|
|
11968
|
-
alignItems: "center",
|
|
11969
|
-
paddingVertical: 10,
|
|
11970
|
-
borderBottomWidth: 2,
|
|
11971
|
-
borderBottomColor: isActive ? BRAND_PRIMARY12 : "transparent"
|
|
11972
|
-
},
|
|
11973
|
-
testID: `exercise-detail-page-tab-${key}`,
|
|
11974
|
-
children: /* @__PURE__ */ jsx(
|
|
11975
|
-
reactNative.Text,
|
|
11976
|
-
{
|
|
11977
|
-
className: isActive ? "text-text-primary" : "text-text-tertiary",
|
|
11978
|
-
style: {
|
|
11979
|
-
fontSize: 13,
|
|
11980
|
-
fontFamily: "Inter, sans-serif",
|
|
11981
|
-
fontWeight: isActive ? "700" : "500"
|
|
11982
|
-
},
|
|
11983
|
-
children: label
|
|
11984
|
-
}
|
|
11985
|
-
)
|
|
11986
|
-
},
|
|
11987
|
-
key
|
|
11988
|
-
);
|
|
11989
|
-
})
|
|
11990
|
-
}
|
|
11991
|
-
);
|
|
11992
|
-
}
|
|
11993
|
-
var STAT_CARDS = [
|
|
11994
|
-
{ key: "sessions", label: "Sessions" },
|
|
11995
|
-
{ key: "bestE1rm", label: "Best e1RM" },
|
|
11996
|
-
{ key: "prCount", label: "PRs" }
|
|
11997
|
-
];
|
|
11998
|
-
function StatStrip({ stats, unit }) {
|
|
11999
|
-
return /* @__PURE__ */ jsx(reactNative.View, { className: "flex-row", style: { gap: 8 }, testID: "exercise-detail-page-stats", children: STAT_CARDS.map(({ key, label }) => {
|
|
12000
|
-
const raw = stats[key];
|
|
12001
|
-
const value = key === "bestE1rm" ? raw == null ? "\u2014" : `${raw} ${unit}` : `${raw}`;
|
|
12002
|
-
return /* @__PURE__ */ jsxs(
|
|
12003
|
-
reactNative.View,
|
|
12004
|
-
{
|
|
12005
|
-
className: "bg-surface-elevated border-border",
|
|
12006
|
-
style: {
|
|
12007
|
-
flex: 1,
|
|
12008
|
-
padding: 12,
|
|
12009
|
-
borderRadius: 10,
|
|
12010
|
-
borderWidth: 1
|
|
12011
|
-
},
|
|
12012
|
-
testID: `exercise-detail-page-stat-${key}`,
|
|
12013
|
-
children: [
|
|
12014
|
-
/* @__PURE__ */ jsx(
|
|
12015
|
-
reactNative.Text,
|
|
12016
|
-
{
|
|
12017
|
-
className: "text-text-primary",
|
|
12018
|
-
style: {
|
|
12019
|
-
fontSize: 18,
|
|
12020
|
-
fontFamily: '"Space Grotesk", sans-serif',
|
|
12021
|
-
fontWeight: "700"
|
|
12022
|
-
},
|
|
12023
|
-
children: value
|
|
12024
|
-
}
|
|
12025
|
-
),
|
|
12026
|
-
/* @__PURE__ */ jsx(
|
|
12027
|
-
reactNative.Text,
|
|
12028
|
-
{
|
|
12029
|
-
className: "text-text-tertiary",
|
|
12030
|
-
style: {
|
|
12031
|
-
marginTop: 2,
|
|
12032
|
-
fontSize: 10,
|
|
12033
|
-
fontFamily: "Inter, sans-serif",
|
|
12034
|
-
fontWeight: "600",
|
|
12035
|
-
letterSpacing: 0.4,
|
|
12036
|
-
textTransform: "uppercase"
|
|
12037
|
-
},
|
|
12038
|
-
children: label
|
|
12039
|
-
}
|
|
12040
|
-
)
|
|
12041
|
-
]
|
|
12042
|
-
},
|
|
12043
|
-
key
|
|
12044
|
-
);
|
|
12045
|
-
}) });
|
|
12046
|
-
}
|
|
12047
|
-
function SectionCard({
|
|
12048
|
-
title,
|
|
12049
|
-
children,
|
|
12050
|
-
testID
|
|
12051
|
-
}) {
|
|
12052
|
-
return /* @__PURE__ */ jsxs(
|
|
12053
|
-
reactNative.View,
|
|
12054
|
-
{
|
|
12055
|
-
className: "bg-surface-elevated border-border",
|
|
12056
|
-
style: {
|
|
12057
|
-
borderWidth: 1,
|
|
12058
|
-
borderRadius: 12,
|
|
12059
|
-
padding: 12,
|
|
12060
|
-
gap: 10
|
|
12061
|
-
},
|
|
12062
|
-
testID,
|
|
12063
|
-
children: [
|
|
12064
|
-
/* @__PURE__ */ jsx(
|
|
12065
|
-
reactNative.Text,
|
|
12066
|
-
{
|
|
12067
|
-
className: "text-text-tertiary",
|
|
12068
|
-
style: {
|
|
12069
|
-
fontSize: 11,
|
|
12070
|
-
fontFamily: "Inter, sans-serif",
|
|
12071
|
-
fontWeight: "600",
|
|
12072
|
-
letterSpacing: 0.6,
|
|
12073
|
-
textTransform: "uppercase"
|
|
12074
|
-
},
|
|
12075
|
-
children: title
|
|
12076
|
-
}
|
|
12077
|
-
),
|
|
12078
|
-
children
|
|
12079
|
-
]
|
|
12080
|
-
}
|
|
12081
|
-
);
|
|
12082
|
-
}
|
|
12083
|
-
function EntryList({ entries, expandedId, onToggle, emptyLabel, testID }) {
|
|
12084
|
-
if (entries.length === 0) {
|
|
12085
|
-
return /* @__PURE__ */ jsx(
|
|
12086
|
-
reactNative.Text,
|
|
12087
|
-
{
|
|
12088
|
-
className: "text-text-tertiary",
|
|
12089
|
-
style: { fontSize: 12, fontFamily: "Inter, sans-serif" },
|
|
12090
|
-
testID: `${testID}-empty`,
|
|
12091
|
-
children: emptyLabel
|
|
12092
|
-
}
|
|
12093
|
-
);
|
|
12094
|
-
}
|
|
12095
|
-
return /* @__PURE__ */ jsx(reactNative.View, { style: { gap: 8 }, testID, children: entries.map((entry) => /* @__PURE__ */ jsx(
|
|
12096
|
-
ExerciseCard,
|
|
12097
|
-
{
|
|
12098
|
-
...toExerciseCardProps(entry, entry.id === expandedId, () => onToggle(entry.id))
|
|
12099
|
-
},
|
|
12100
|
-
entry.id
|
|
12101
|
-
)) });
|
|
12102
|
-
}
|
|
12103
|
-
function VbtBreakdown({ sets }) {
|
|
12104
|
-
return /* @__PURE__ */ jsx(reactNative.View, { style: { gap: 10 }, testID: "exercise-detail-page-vbt-breakdown", children: sets.map((set) => {
|
|
12105
|
-
const mean = calculateMeanVelocity(set.velocities);
|
|
12106
|
-
const loss = calculateVelocityLoss(set.velocities);
|
|
12107
|
-
return /* @__PURE__ */ jsxs(
|
|
12108
|
-
reactNative.View,
|
|
12109
|
-
{
|
|
12110
|
-
className: "flex-row items-center",
|
|
12111
|
-
style: { gap: 10 },
|
|
12112
|
-
testID: "exercise-detail-page-vbt-set",
|
|
12113
|
-
children: [
|
|
12114
|
-
/* @__PURE__ */ jsx(
|
|
12115
|
-
reactNative.Text,
|
|
12116
|
-
{
|
|
12117
|
-
className: "text-text-secondary",
|
|
12118
|
-
style: {
|
|
12119
|
-
width: 44,
|
|
12120
|
-
fontSize: 11,
|
|
12121
|
-
fontFamily: "Inter, sans-serif",
|
|
12122
|
-
fontWeight: "600"
|
|
12123
|
-
},
|
|
12124
|
-
children: set.label
|
|
12125
|
-
}
|
|
12126
|
-
),
|
|
12127
|
-
/* @__PURE__ */ jsx(reactNative.View, { className: "flex-1", style: { height: 8, justifyContent: "center" }, children: /* @__PURE__ */ jsx(VelocityStrip, { velocities: set.velocities, variant: "mini" }) }),
|
|
12128
|
-
/* @__PURE__ */ jsx(
|
|
12129
|
-
reactNative.Text,
|
|
12130
|
-
{
|
|
12131
|
-
className: "text-text-tertiary",
|
|
12132
|
-
style: {
|
|
12133
|
-
fontSize: 11,
|
|
12134
|
-
fontFamily: "Inter, sans-serif",
|
|
12135
|
-
fontVariant: ["tabular-nums"]
|
|
12136
|
-
},
|
|
12137
|
-
children: `${mean.toFixed(2)} \xB7 -${loss}%`
|
|
12138
|
-
}
|
|
12139
|
-
)
|
|
12140
|
-
]
|
|
12141
|
-
},
|
|
12142
|
-
set.label
|
|
12143
|
-
);
|
|
12144
|
-
}) });
|
|
12145
|
-
}
|
|
12146
|
-
function VbtSummaryRow({ summary }) {
|
|
12147
|
-
const cells = [
|
|
12148
|
-
{ label: "Mean Velocity", value: `${summary.meanVelocity.toFixed(2)} m/s` },
|
|
12149
|
-
{ label: "Peak Vel. Loss", value: `-${summary.velocityLoss}%` }
|
|
12150
|
-
];
|
|
12151
|
-
return /* @__PURE__ */ jsx(reactNative.View, { className: "flex-row", style: { gap: 8 }, testID: "exercise-detail-page-vbt-summary", children: cells.map((cell) => /* @__PURE__ */ jsxs(
|
|
12152
|
-
reactNative.View,
|
|
12153
|
-
{
|
|
12154
|
-
className: "bg-surface-elevated border-border",
|
|
12155
|
-
style: {
|
|
12156
|
-
flex: 1,
|
|
12157
|
-
padding: 12,
|
|
12158
|
-
borderRadius: 10,
|
|
12159
|
-
borderWidth: 1
|
|
12160
|
-
},
|
|
12161
|
-
children: [
|
|
12162
|
-
/* @__PURE__ */ jsx(
|
|
12163
|
-
reactNative.Text,
|
|
12164
|
-
{
|
|
12165
|
-
className: "text-text-primary",
|
|
12166
|
-
style: {
|
|
12167
|
-
fontSize: 16,
|
|
12168
|
-
fontFamily: '"Space Grotesk", sans-serif',
|
|
12169
|
-
fontWeight: "700"
|
|
12170
|
-
},
|
|
12171
|
-
children: cell.value
|
|
12172
|
-
}
|
|
12173
|
-
),
|
|
12174
|
-
/* @__PURE__ */ jsx(
|
|
12175
|
-
reactNative.Text,
|
|
12176
|
-
{
|
|
12177
|
-
className: "text-text-tertiary",
|
|
12178
|
-
style: {
|
|
12179
|
-
marginTop: 2,
|
|
12180
|
-
fontSize: 10,
|
|
12181
|
-
fontFamily: "Inter, sans-serif",
|
|
12182
|
-
fontWeight: "600",
|
|
12183
|
-
letterSpacing: 0.4,
|
|
12184
|
-
textTransform: "uppercase"
|
|
12185
|
-
},
|
|
12186
|
-
children: cell.label
|
|
12187
|
-
}
|
|
12188
|
-
)
|
|
12189
|
-
]
|
|
12190
|
-
},
|
|
12191
|
-
cell.label
|
|
12192
|
-
)) });
|
|
12193
|
-
}
|
|
12194
|
-
function ExerciseDetailPage({
|
|
12195
|
-
exercise,
|
|
12196
|
-
meso,
|
|
12197
|
-
trend,
|
|
12198
|
-
progression,
|
|
12199
|
-
history,
|
|
12200
|
-
vbt,
|
|
12201
|
-
className,
|
|
12202
|
-
...props
|
|
12203
|
-
}) {
|
|
12204
|
-
const [tab, setTab] = React24.useState("progress");
|
|
12205
|
-
const [expandedProgressId, setExpandedProgressId] = React24.useState(null);
|
|
12206
|
-
const [expandedHistoryId, setExpandedHistoryId] = React24.useState(null);
|
|
12207
|
-
const stats = React24.useMemo(() => deriveExerciseStats(history), [history]);
|
|
12208
|
-
const vbtSummary = React24.useMemo(() => summarizeVbt(vbt.sets), [vbt.sets]);
|
|
12209
|
-
const toggle = (setId) => (id) => setId((current) => current === id ? null : id);
|
|
12210
|
-
return /* @__PURE__ */ jsx(
|
|
12211
|
-
reactNative.View,
|
|
12212
|
-
{
|
|
12213
|
-
className: cn("bg-background-base", className),
|
|
12214
|
-
style: { width: 390 },
|
|
12215
|
-
accessibilityRole: "main",
|
|
12216
|
-
"aria-label": exercise.name,
|
|
12217
|
-
testID: "exercise-detail-page",
|
|
12218
|
-
...props,
|
|
12219
|
-
children: /* @__PURE__ */ jsxs(reactNative.View, { style: { padding: 16, gap: 14 }, testID: "exercise-detail-page-content", children: [
|
|
12220
|
-
/* @__PURE__ */ jsxs(
|
|
12221
|
-
reactNative.View,
|
|
12222
|
-
{
|
|
12223
|
-
className: "flex-row items-start justify-between",
|
|
12224
|
-
style: { gap: 8 },
|
|
12225
|
-
testID: "exercise-detail-page-header",
|
|
12226
|
-
children: [
|
|
12227
|
-
/* @__PURE__ */ jsxs(reactNative.View, { style: { flexShrink: 1 }, children: [
|
|
12228
|
-
/* @__PURE__ */ jsx(
|
|
12229
|
-
reactNative.Text,
|
|
12230
|
-
{
|
|
12231
|
-
accessibilityRole: "header",
|
|
12232
|
-
className: "text-text-primary",
|
|
12233
|
-
style: {
|
|
12234
|
-
fontSize: 20,
|
|
12235
|
-
fontFamily: '"Space Grotesk", sans-serif',
|
|
12236
|
-
fontWeight: "700"
|
|
12237
|
-
},
|
|
12238
|
-
testID: "exercise-detail-page-title",
|
|
12239
|
-
children: exercise.name
|
|
12240
|
-
}
|
|
12241
|
-
),
|
|
12242
|
-
/* @__PURE__ */ jsx(
|
|
12243
|
-
reactNative.Text,
|
|
12244
|
-
{
|
|
12245
|
-
className: "text-text-secondary",
|
|
12246
|
-
style: {
|
|
12247
|
-
marginTop: 2,
|
|
12248
|
-
fontSize: 12,
|
|
12249
|
-
fontFamily: "Inter, sans-serif"
|
|
12250
|
-
},
|
|
12251
|
-
testID: "exercise-detail-page-subtitle",
|
|
12252
|
-
children: exercise.subtitle
|
|
12253
|
-
}
|
|
12254
|
-
)
|
|
12255
|
-
] }),
|
|
12256
|
-
exercise.currentE1rm != null && /* @__PURE__ */ jsxs(
|
|
12257
|
-
reactNative.View,
|
|
12258
|
-
{
|
|
12259
|
-
style: {
|
|
12260
|
-
paddingVertical: 4,
|
|
12261
|
-
paddingHorizontal: 10,
|
|
12262
|
-
borderRadius: 6,
|
|
12263
|
-
backgroundColor: "rgba(255,121,0,0.10)",
|
|
12264
|
-
borderWidth: 1,
|
|
12265
|
-
borderColor: "rgba(255,121,0,0.25)"
|
|
12266
|
-
},
|
|
12267
|
-
testID: "exercise-detail-page-e1rm",
|
|
12268
|
-
children: [
|
|
12269
|
-
/* @__PURE__ */ jsx(
|
|
12270
|
-
reactNative.Text,
|
|
12271
|
-
{
|
|
12272
|
-
className: "text-text-tertiary",
|
|
12273
|
-
style: {
|
|
12274
|
-
fontSize: 9,
|
|
12275
|
-
fontFamily: "Inter, sans-serif",
|
|
12276
|
-
fontWeight: "600",
|
|
12277
|
-
letterSpacing: 0.4,
|
|
12278
|
-
textTransform: "uppercase"
|
|
12279
|
-
},
|
|
12280
|
-
children: "e1RM"
|
|
12281
|
-
}
|
|
12282
|
-
),
|
|
12283
|
-
/* @__PURE__ */ jsx(
|
|
12284
|
-
reactNative.Text,
|
|
12285
|
-
{
|
|
12286
|
-
style: {
|
|
12287
|
-
fontSize: 15,
|
|
12288
|
-
fontFamily: '"Space Grotesk", sans-serif',
|
|
12289
|
-
fontWeight: "700",
|
|
12290
|
-
color: BRAND_PRIMARY12
|
|
12291
|
-
},
|
|
12292
|
-
children: `${exercise.currentE1rm} ${exercise.unit}`
|
|
12293
|
-
}
|
|
12294
|
-
)
|
|
12295
|
-
]
|
|
12296
|
-
}
|
|
12297
|
-
)
|
|
12298
|
-
]
|
|
12299
|
-
}
|
|
12300
|
-
),
|
|
12301
|
-
/* @__PURE__ */ jsx(TabBar, { active: tab, onSelect: setTab }),
|
|
12302
|
-
tab === "progress" && /* @__PURE__ */ jsxs(reactNative.View, { style: { gap: 14 }, testID: "exercise-detail-page-panel-progress", children: [
|
|
12303
|
-
/* @__PURE__ */ jsx(MesoStatusCard, { ...meso }),
|
|
12304
|
-
/* @__PURE__ */ jsx(StatStrip, { stats, unit: exercise.unit }),
|
|
12305
|
-
/* @__PURE__ */ jsx(SectionCard, { title: "Strength Trend", testID: "exercise-detail-page-trend", children: /* @__PURE__ */ jsx(
|
|
12306
|
-
StrengthTrendChart,
|
|
12307
|
-
{
|
|
12308
|
-
data: trend.data,
|
|
12309
|
-
projection: trend.projection,
|
|
12310
|
-
mesoBoundaries: trend.mesoBoundaries,
|
|
12311
|
-
width: CHART_WIDTH,
|
|
12312
|
-
height: CHART_HEIGHT,
|
|
12313
|
-
unit: exercise.unit,
|
|
12314
|
-
animateOnMount: false
|
|
12315
|
-
}
|
|
12316
|
-
) }),
|
|
12317
|
-
/* @__PURE__ */ jsx(SectionCard, { title: "Week-by-Week", testID: "exercise-detail-page-progression", children: /* @__PURE__ */ jsx(
|
|
12318
|
-
EntryList,
|
|
12319
|
-
{
|
|
12320
|
-
entries: progression,
|
|
12321
|
-
expandedId: expandedProgressId,
|
|
12322
|
-
onToggle: toggle(setExpandedProgressId),
|
|
12323
|
-
emptyLabel: "No progression logged yet",
|
|
12324
|
-
testID: "exercise-detail-page-progression-list"
|
|
12325
|
-
}
|
|
12326
|
-
) })
|
|
12327
|
-
] }),
|
|
12328
|
-
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(
|
|
12329
|
-
EntryList,
|
|
12330
|
-
{
|
|
12331
|
-
entries: history,
|
|
12332
|
-
expandedId: expandedHistoryId,
|
|
12333
|
-
onToggle: toggle(setExpandedHistoryId),
|
|
12334
|
-
emptyLabel: "No sessions logged yet",
|
|
12335
|
-
testID: "exercise-detail-page-history-list"
|
|
12336
|
-
}
|
|
12337
|
-
) }) }),
|
|
12338
|
-
tab === "advanced" && /* @__PURE__ */ jsxs(reactNative.View, { style: { gap: 14 }, testID: "exercise-detail-page-panel-advanced", children: [
|
|
12339
|
-
/* @__PURE__ */ jsx(SectionCard, { title: "Capacity Band", testID: "exercise-detail-page-capacity", children: /* @__PURE__ */ jsx(
|
|
12340
|
-
CapacityBandChart,
|
|
12341
|
-
{
|
|
12342
|
-
band: vbt.band,
|
|
12343
|
-
workouts: vbt.workouts,
|
|
12344
|
-
projection: vbt.projection,
|
|
12345
|
-
width: CHART_WIDTH,
|
|
12346
|
-
height: CHART_HEIGHT
|
|
12347
|
-
}
|
|
12348
|
-
) }),
|
|
12349
|
-
/* @__PURE__ */ jsx(VbtSummaryRow, { summary: vbtSummary }),
|
|
12350
|
-
/* @__PURE__ */ jsx(SectionCard, { title: "Velocity Breakdown", testID: "exercise-detail-page-velocity", children: /* @__PURE__ */ jsx(VbtBreakdown, { sets: vbt.sets }) })
|
|
12351
|
-
] })
|
|
12352
|
-
] })
|
|
12353
|
-
}
|
|
12354
|
-
);
|
|
12355
|
-
}
|
|
12356
|
-
var BRAND_PRIMARY13 = "#FF7900";
|
|
12357
|
-
function countCompletedSets(exercise) {
|
|
12358
|
-
if (exercise.setVelocities != null) return exercise.setVelocities.length;
|
|
12359
|
-
if (exercise.status === "completed") return exercise.totalPlannedSets;
|
|
12360
|
-
return 0;
|
|
12361
|
-
}
|
|
12362
|
-
function deriveWorkoutProgress(exercises) {
|
|
12363
|
-
let completedExercises = 0;
|
|
12364
|
-
let completedSets = 0;
|
|
12365
|
-
let totalSets = 0;
|
|
12366
|
-
for (const exercise of exercises) {
|
|
12367
|
-
if (exercise.status === "completed") completedExercises += 1;
|
|
12368
|
-
completedSets += countCompletedSets(exercise);
|
|
12369
|
-
totalSets += exercise.totalPlannedSets;
|
|
12370
|
-
}
|
|
12371
|
-
return {
|
|
12372
|
-
completedExercises,
|
|
12373
|
-
totalExercises: exercises.length,
|
|
12374
|
-
completedSets,
|
|
12375
|
-
totalSets,
|
|
12376
|
-
fraction: totalSets === 0 ? 0 : completedSets / totalSets
|
|
12377
|
-
};
|
|
12378
|
-
}
|
|
12379
|
-
function findActiveExercise(exercises) {
|
|
12380
|
-
return exercises.find((exercise) => exercise.status === "active") ?? null;
|
|
12381
|
-
}
|
|
12382
|
-
function statusToCardState(status, focused) {
|
|
12383
|
-
if (status === "upcoming") return "upcoming";
|
|
12384
|
-
return focused ? "expanded" : "collapsed";
|
|
12385
|
-
}
|
|
12386
|
-
function toActiveCardProps(exercise, focused, onToggle, supersetPosition = null, supersetColor) {
|
|
12387
|
-
const state = statusToCardState(exercise.status, focused);
|
|
12388
|
-
return {
|
|
12389
|
-
name: exercise.name,
|
|
12390
|
-
state,
|
|
12391
|
-
onToggle,
|
|
12392
|
-
summary: exercise.summary,
|
|
12393
|
-
e1rm: exercise.e1rm,
|
|
12394
|
-
isPR: exercise.isPR,
|
|
12395
|
-
tempo: exercise.tempo,
|
|
12396
|
-
setVelocities: exercise.setVelocities,
|
|
12397
|
-
totalPlannedSets: exercise.totalPlannedSets,
|
|
12398
|
-
sets: state === "expanded" ? exercise.sets : void 0,
|
|
12399
|
-
prescription: exercise.prescription,
|
|
12400
|
-
previousBest: exercise.previousBest,
|
|
12401
|
-
supersetPosition,
|
|
12402
|
-
supersetColor
|
|
12403
|
-
};
|
|
12404
|
-
}
|
|
12405
|
-
function groupExercises(exercises, supersets) {
|
|
12406
|
-
const byId = new Map(supersets.map((superset) => [superset.id, superset]));
|
|
12407
|
-
const groups = [];
|
|
12408
|
-
for (const exercise of exercises) {
|
|
12409
|
-
const superset = exercise.supersetId != null ? byId.get(exercise.supersetId) : void 0;
|
|
12410
|
-
const last = groups[groups.length - 1];
|
|
12411
|
-
if (superset != null && last?.type === "superset" && last.superset.id === superset.id) {
|
|
12412
|
-
last.exercises.push(exercise);
|
|
12413
|
-
} else if (superset != null) {
|
|
12414
|
-
groups.push({ type: "superset", superset, exercises: [exercise] });
|
|
12415
|
-
} else {
|
|
12416
|
-
groups.push({ type: "single", exercise });
|
|
12417
|
-
}
|
|
12418
|
-
}
|
|
12419
|
-
return groups;
|
|
12420
|
-
}
|
|
12421
|
-
function supersetPositionAt(index, length) {
|
|
12422
|
-
if (length === 1) return null;
|
|
12423
|
-
if (index === 0) return "first";
|
|
12424
|
-
if (index === length - 1) return "last";
|
|
12425
|
-
return "middle";
|
|
12426
|
-
}
|
|
12427
|
-
function WorkoutHeader({
|
|
12428
|
-
title,
|
|
12429
|
-
subtitle,
|
|
12430
|
-
progress
|
|
12431
|
-
}) {
|
|
12432
|
-
return /* @__PURE__ */ jsxs(reactNative.View, { style: { gap: 10 }, testID: "active-workout-page-header", children: [
|
|
12433
|
-
/* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-start justify-between", style: { gap: 8 }, children: [
|
|
12434
|
-
/* @__PURE__ */ jsxs(reactNative.View, { style: { flexShrink: 1 }, children: [
|
|
12435
|
-
/* @__PURE__ */ jsx(
|
|
12436
|
-
reactNative.Text,
|
|
12437
|
-
{
|
|
12438
|
-
accessibilityRole: "header",
|
|
12439
|
-
className: "text-text-primary",
|
|
12440
|
-
style: {
|
|
12441
|
-
fontSize: 20,
|
|
12442
|
-
fontFamily: '"Space Grotesk", sans-serif',
|
|
12443
|
-
fontWeight: "700"
|
|
12444
|
-
},
|
|
12445
|
-
testID: "active-workout-page-title",
|
|
12446
|
-
children: title
|
|
12447
|
-
}
|
|
12448
|
-
),
|
|
12449
|
-
subtitle != null && /* @__PURE__ */ jsx(
|
|
12450
|
-
reactNative.Text,
|
|
12451
|
-
{
|
|
12452
|
-
className: "text-text-secondary",
|
|
12453
|
-
style: {
|
|
12454
|
-
marginTop: 2,
|
|
12455
|
-
fontSize: 12,
|
|
12456
|
-
fontFamily: "Inter, sans-serif"
|
|
12457
|
-
},
|
|
12458
|
-
testID: "active-workout-page-subtitle",
|
|
12459
|
-
children: subtitle
|
|
12460
|
-
}
|
|
12461
|
-
)
|
|
12462
|
-
] }),
|
|
12463
|
-
/* @__PURE__ */ jsxs(reactNative.View, { style: { alignItems: "flex-end" }, testID: "active-workout-page-progress-count", children: [
|
|
12464
|
-
/* @__PURE__ */ jsx(
|
|
12465
|
-
reactNative.Text,
|
|
12466
|
-
{
|
|
12467
|
-
style: {
|
|
12468
|
-
fontSize: 15,
|
|
12469
|
-
fontFamily: '"Space Grotesk", sans-serif',
|
|
12470
|
-
fontWeight: "700",
|
|
12471
|
-
color: BRAND_PRIMARY13,
|
|
12472
|
-
fontVariant: ["tabular-nums"]
|
|
12473
|
-
},
|
|
12474
|
-
children: `${progress.completedExercises}/${progress.totalExercises}`
|
|
12475
|
-
}
|
|
12476
|
-
),
|
|
12477
|
-
/* @__PURE__ */ jsx(
|
|
12478
|
-
reactNative.Text,
|
|
12479
|
-
{
|
|
12480
|
-
className: "text-text-tertiary",
|
|
12481
|
-
style: {
|
|
12482
|
-
fontSize: 10,
|
|
12483
|
-
fontFamily: "Inter, sans-serif",
|
|
12484
|
-
fontWeight: "600",
|
|
12485
|
-
letterSpacing: 0.4,
|
|
12486
|
-
textTransform: "uppercase"
|
|
12487
|
-
},
|
|
12488
|
-
children: `${progress.completedSets}/${progress.totalSets} sets`
|
|
12489
|
-
}
|
|
12490
|
-
)
|
|
12491
|
-
] })
|
|
12492
|
-
] }),
|
|
12493
|
-
/* @__PURE__ */ jsx(
|
|
12494
|
-
reactNative.View,
|
|
12495
|
-
{
|
|
12496
|
-
className: "bg-border",
|
|
12497
|
-
style: { height: 4, borderRadius: 2 },
|
|
12498
|
-
testID: "active-workout-page-progress-track",
|
|
12499
|
-
children: /* @__PURE__ */ jsx(
|
|
12500
|
-
reactNative.View,
|
|
12501
|
-
{
|
|
12502
|
-
style: {
|
|
12503
|
-
height: "100%",
|
|
12504
|
-
width: `${Math.round(progress.fraction * 100)}%`,
|
|
12505
|
-
backgroundColor: BRAND_PRIMARY13,
|
|
12506
|
-
borderRadius: 2
|
|
12507
|
-
},
|
|
12508
|
-
testID: "active-workout-page-progress-fill"
|
|
12509
|
-
}
|
|
12510
|
-
)
|
|
12511
|
-
}
|
|
12512
|
-
)
|
|
12513
|
-
] });
|
|
12514
|
-
}
|
|
12515
|
-
function ExerciseList({ groups, focusedId, onToggle }) {
|
|
12516
|
-
return /* @__PURE__ */ jsx(reactNative.View, { style: { gap: 10 }, testID: "active-workout-page-exercises", children: groups.map((group) => {
|
|
12517
|
-
if (group.type === "single") {
|
|
12518
|
-
return /* @__PURE__ */ jsx(
|
|
12519
|
-
reactNative.View,
|
|
12520
|
-
{
|
|
12521
|
-
className: "bg-surface-elevated border-border",
|
|
12522
|
-
style: {
|
|
12523
|
-
borderWidth: 1,
|
|
12524
|
-
borderRadius: 12
|
|
12525
|
-
},
|
|
12526
|
-
children: /* @__PURE__ */ jsx(
|
|
12527
|
-
ExerciseCard,
|
|
12528
|
-
{
|
|
12529
|
-
...toActiveCardProps(
|
|
12530
|
-
group.exercise,
|
|
12531
|
-
group.exercise.id === focusedId,
|
|
12532
|
-
() => onToggle(group.exercise.id)
|
|
12533
|
-
)
|
|
12534
|
-
}
|
|
12535
|
-
)
|
|
12536
|
-
},
|
|
12537
|
-
group.exercise.id
|
|
12538
|
-
);
|
|
12539
|
-
}
|
|
12540
|
-
return /* @__PURE__ */ jsx(
|
|
12541
|
-
SupersetWrapper,
|
|
12542
|
-
{
|
|
12543
|
-
label: group.superset.label,
|
|
12544
|
-
color: group.superset.color,
|
|
12545
|
-
children: group.exercises.map((exercise, index) => /* @__PURE__ */ jsx(
|
|
12546
|
-
ExerciseCard,
|
|
12547
|
-
{
|
|
12548
|
-
...toActiveCardProps(
|
|
12549
|
-
exercise,
|
|
12550
|
-
exercise.id === focusedId,
|
|
12551
|
-
() => onToggle(exercise.id),
|
|
12552
|
-
supersetPositionAt(index, group.exercises.length),
|
|
12553
|
-
group.superset.color
|
|
12554
|
-
)
|
|
12555
|
-
},
|
|
12556
|
-
exercise.id
|
|
12557
|
-
))
|
|
12558
|
-
},
|
|
12559
|
-
group.superset.id
|
|
12560
|
-
);
|
|
12561
|
-
}) });
|
|
12562
|
-
}
|
|
12563
|
-
function ActiveWorkoutPage({
|
|
12564
|
-
title = "Active Workout",
|
|
12565
|
-
subtitle,
|
|
12566
|
-
exercises,
|
|
12567
|
-
supersets = [],
|
|
12568
|
-
input,
|
|
12569
|
-
rest,
|
|
12570
|
-
initialResting = false,
|
|
12571
|
-
className,
|
|
12572
|
-
...props
|
|
12573
|
-
}) {
|
|
12574
|
-
const active = findActiveExercise(exercises);
|
|
12575
|
-
const [focusedId, setFocusedId] = React24.useState(active?.id ?? null);
|
|
12576
|
-
const [resting, setResting] = React24.useState(initialResting);
|
|
12577
|
-
const [reps, setReps] = React24.useState(input?.reps ?? "");
|
|
12578
|
-
const [weight, setWeight] = React24.useState(input?.weight ?? "");
|
|
12579
|
-
const progress = React24.useMemo(() => deriveWorkoutProgress(exercises), [exercises]);
|
|
12580
|
-
const groups = React24.useMemo(() => groupExercises(exercises, supersets), [exercises, supersets]);
|
|
12581
|
-
const toggleFocus = (id) => setFocusedId((current) => current === id ? null : id);
|
|
12582
|
-
const nextSetNumber = active != null ? countCompletedSets(active) + 1 : 1;
|
|
12583
|
-
const canRecord = reps.trim() !== "" && weight.trim() !== "";
|
|
12584
|
-
const showRest = resting && rest != null;
|
|
12585
|
-
const showInput = !showRest && active != null;
|
|
11983
|
+
accessibilityElementsHidden: true,
|
|
11984
|
+
importantForAccessibility: "no-hide-descendants",
|
|
11985
|
+
testID: key
|
|
11986
|
+
},
|
|
11987
|
+
`${key}-${i}`
|
|
11988
|
+
));
|
|
12586
11989
|
return /* @__PURE__ */ jsxs(
|
|
12587
11990
|
reactNative.View,
|
|
12588
11991
|
{
|
|
12589
|
-
|
|
12590
|
-
|
|
12591
|
-
|
|
12592
|
-
"aria-label": title,
|
|
12593
|
-
testID: "active-workout-page",
|
|
11992
|
+
style: { width, height, position: "relative" },
|
|
11993
|
+
className,
|
|
11994
|
+
testID: "capacity-band-chart-root",
|
|
12594
11995
|
...props,
|
|
12595
11996
|
children: [
|
|
12596
|
-
/* @__PURE__ */ jsxs(
|
|
12597
|
-
/* @__PURE__ */ jsx(WorkoutHeader, { title, subtitle, progress }),
|
|
12598
|
-
/* @__PURE__ */ jsx(ExerciseList, { groups, focusedId, onToggle: toggleFocus })
|
|
12599
|
-
] }),
|
|
12600
|
-
(showRest || showInput) && /* @__PURE__ */ jsx(
|
|
11997
|
+
/* @__PURE__ */ jsxs(
|
|
12601
11998
|
reactNative.View,
|
|
12602
11999
|
{
|
|
12603
|
-
style: {
|
|
12604
|
-
|
|
12605
|
-
|
|
12606
|
-
|
|
12607
|
-
|
|
12608
|
-
|
|
12609
|
-
|
|
12610
|
-
|
|
12611
|
-
|
|
12612
|
-
|
|
12613
|
-
|
|
12614
|
-
|
|
12615
|
-
|
|
12616
|
-
|
|
12617
|
-
|
|
12618
|
-
|
|
12619
|
-
|
|
12620
|
-
|
|
12621
|
-
|
|
12622
|
-
|
|
12623
|
-
|
|
12624
|
-
|
|
12625
|
-
|
|
12626
|
-
|
|
12627
|
-
|
|
12628
|
-
|
|
12629
|
-
|
|
12630
|
-
|
|
12631
|
-
|
|
12632
|
-
|
|
12000
|
+
style: { position: "absolute", top: 0, left: 0, width, height },
|
|
12001
|
+
accessibilityRole: "image",
|
|
12002
|
+
accessibilityLabel: `Training capacity band chart. Current capacity: ${currentStatus(
|
|
12003
|
+
workouts
|
|
12004
|
+
)}. ${workouts.length} workout${workouts.length === 1 ? "" : "s"} shown.`,
|
|
12005
|
+
testID: "capacity-band-chart",
|
|
12006
|
+
children: [
|
|
12007
|
+
/* @__PURE__ */ jsx(
|
|
12008
|
+
reactNative.Animated.View,
|
|
12009
|
+
{
|
|
12010
|
+
style: { position: "absolute", top: 0, left: 0, height, width: revealWidth, overflow: "hidden" },
|
|
12011
|
+
accessibilityElementsHidden: true,
|
|
12012
|
+
importantForAccessibility: "no-hide-descendants",
|
|
12013
|
+
testID: "capacity-band-chart-reveal",
|
|
12014
|
+
children: /* @__PURE__ */ jsxs(reactNative.View, { style: { width, height, position: "relative" }, children: [
|
|
12015
|
+
projection && /* @__PURE__ */ jsxs(reactNative.View, { testID: "capacity-band-chart-projection", children: [
|
|
12016
|
+
renderColumns(buildColumns(trainingPixels, COLUMN_STEP), PROJECTION_FILL, "capacity-band-chart-projection-fill"),
|
|
12017
|
+
renderColumns(buildColumns(restPixels, COLUMN_STEP), PROJECTION_FILL, "capacity-band-chart-projection-fill"),
|
|
12018
|
+
renderEdges(buildEdges(trainingPixels, "yHigh"), STATUS_SUCCESS3, true, "capacity-band-chart-projection-training"),
|
|
12019
|
+
renderEdges(buildEdges(trainingPixels, "yLow"), STATUS_SUCCESS3, true, "capacity-band-chart-projection-training"),
|
|
12020
|
+
renderEdges(buildEdges(restPixels, "yHigh"), STATUS_INFO, true, "capacity-band-chart-projection-rest"),
|
|
12021
|
+
renderEdges(buildEdges(restPixels, "yLow"), STATUS_INFO, true, "capacity-band-chart-projection-rest"),
|
|
12022
|
+
/* @__PURE__ */ jsx(
|
|
12023
|
+
reactNative.Text,
|
|
12024
|
+
{
|
|
12025
|
+
style: {
|
|
12026
|
+
position: "absolute",
|
|
12027
|
+
left: trainingPixels[trainingPixels.length - 1]?.x + 2,
|
|
12028
|
+
top: trainingPixels[trainingPixels.length - 1]?.yHigh - 12,
|
|
12029
|
+
fontSize: 9,
|
|
12030
|
+
fontFamily: "Inter, sans-serif",
|
|
12031
|
+
color: STATUS_SUCCESS3
|
|
12032
|
+
},
|
|
12033
|
+
testID: "capacity-band-chart-projection-training-label",
|
|
12034
|
+
children: "Training"
|
|
12035
|
+
}
|
|
12036
|
+
),
|
|
12037
|
+
/* @__PURE__ */ jsx(
|
|
12038
|
+
reactNative.Text,
|
|
12039
|
+
{
|
|
12040
|
+
style: {
|
|
12041
|
+
position: "absolute",
|
|
12042
|
+
left: restPixels[restPixels.length - 1]?.x + 2,
|
|
12043
|
+
top: restPixels[restPixels.length - 1]?.yLow + 2,
|
|
12044
|
+
fontSize: 9,
|
|
12045
|
+
fontFamily: "Inter, sans-serif",
|
|
12046
|
+
color: STATUS_INFO
|
|
12047
|
+
},
|
|
12048
|
+
testID: "capacity-band-chart-projection-rest-label",
|
|
12049
|
+
children: "Rest"
|
|
12050
|
+
}
|
|
12051
|
+
)
|
|
12052
|
+
] }),
|
|
12053
|
+
/* @__PURE__ */ jsx(reactNative.View, { testID: "capacity-band-chart-band", children: renderColumns(columns, BAND_FILL, "capacity-band-chart-band-cell") }),
|
|
12054
|
+
renderEdges(topEdge, BAND_EDGE, false, "capacity-band-chart-edge-top"),
|
|
12055
|
+
renderEdges(bottomEdge, BAND_EDGE, false, "capacity-band-chart-edge-bottom")
|
|
12056
|
+
] })
|
|
12057
|
+
}
|
|
12058
|
+
),
|
|
12059
|
+
/* @__PURE__ */ jsx(
|
|
12060
|
+
reactNative.Text,
|
|
12061
|
+
{
|
|
12062
|
+
className: "text-text-tertiary",
|
|
12063
|
+
style: {
|
|
12064
|
+
position: "absolute",
|
|
12065
|
+
left: PADDING_LEFT / 2 - 14,
|
|
12066
|
+
top: PADDING_TOP + plotHeight / 2 - 7,
|
|
12067
|
+
width: 32,
|
|
12068
|
+
textAlign: "center",
|
|
12069
|
+
fontSize: 9,
|
|
12070
|
+
fontFamily: "Inter, sans-serif",
|
|
12071
|
+
transform: [{ rotate: "-90deg" }]
|
|
12072
|
+
},
|
|
12073
|
+
accessibilityElementsHidden: true,
|
|
12074
|
+
importantForAccessibility: "no-hide-descendants",
|
|
12075
|
+
testID: "capacity-band-chart-y-axis-label",
|
|
12076
|
+
children: "Load"
|
|
12077
|
+
}
|
|
12078
|
+
),
|
|
12079
|
+
band.map((point, i) => {
|
|
12080
|
+
if (i % labelStride !== 0 && i !== band.length - 1) return null;
|
|
12081
|
+
return /* @__PURE__ */ jsx(
|
|
12082
|
+
reactNative.Text,
|
|
12083
|
+
{
|
|
12084
|
+
className: "text-text-tertiary",
|
|
12085
|
+
style: {
|
|
12086
|
+
position: "absolute",
|
|
12087
|
+
left: toX(point.date) - 14,
|
|
12088
|
+
top: height - PADDING_BOTTOM + 2,
|
|
12089
|
+
width: 28,
|
|
12090
|
+
textAlign: "center",
|
|
12091
|
+
fontSize: 10,
|
|
12092
|
+
fontFamily: "Inter, sans-serif"
|
|
12093
|
+
},
|
|
12094
|
+
accessibilityElementsHidden: true,
|
|
12095
|
+
importantForAccessibility: "no-hide-descendants",
|
|
12096
|
+
testID: "capacity-band-chart-x-label",
|
|
12097
|
+
children: formatDate2(point.date)
|
|
12098
|
+
},
|
|
12099
|
+
`x-${point.date}`
|
|
12100
|
+
);
|
|
12101
|
+
})
|
|
12102
|
+
]
|
|
12633
12103
|
}
|
|
12634
|
-
)
|
|
12104
|
+
),
|
|
12105
|
+
workouts.map((workout, i) => {
|
|
12106
|
+
const cx = toX(workout.date);
|
|
12107
|
+
const cy = toY(workout.load);
|
|
12108
|
+
const color = DOT_COLORS[workout.status];
|
|
12109
|
+
const dotStyle = {
|
|
12110
|
+
width: DOT_SIZE,
|
|
12111
|
+
height: DOT_SIZE,
|
|
12112
|
+
borderRadius: DOT_SIZE / 2,
|
|
12113
|
+
backgroundColor: color,
|
|
12114
|
+
borderWidth: 2,
|
|
12115
|
+
borderColor: DOT_BORDER
|
|
12116
|
+
};
|
|
12117
|
+
const label = `Workout on ${formatDate2(workout.date)}, load ${workout.load}, ${STATUS_PHRASES[workout.status]}`;
|
|
12118
|
+
return /* @__PURE__ */ jsx(
|
|
12119
|
+
reactNative.Animated.View,
|
|
12120
|
+
{
|
|
12121
|
+
style: {
|
|
12122
|
+
position: "absolute",
|
|
12123
|
+
left: cx - DOT_SIZE / 2,
|
|
12124
|
+
top: cy - DOT_SIZE / 2,
|
|
12125
|
+
transform: [{ scale: dotAnims[i] ?? 1 }]
|
|
12126
|
+
},
|
|
12127
|
+
testID: "capacity-band-chart-dot-wrapper",
|
|
12128
|
+
children: onWorkoutPress ? /* @__PURE__ */ jsx(
|
|
12129
|
+
reactNative.Pressable,
|
|
12130
|
+
{
|
|
12131
|
+
onPress: () => onWorkoutPress(workout),
|
|
12132
|
+
accessibilityRole: "button",
|
|
12133
|
+
accessibilityLabel: label,
|
|
12134
|
+
style: dotStyle,
|
|
12135
|
+
testID: "capacity-band-chart-dot"
|
|
12136
|
+
}
|
|
12137
|
+
) : /* @__PURE__ */ jsx(
|
|
12138
|
+
reactNative.View,
|
|
12139
|
+
{
|
|
12140
|
+
accessibilityElementsHidden: true,
|
|
12141
|
+
importantForAccessibility: "no-hide-descendants",
|
|
12142
|
+
style: dotStyle,
|
|
12143
|
+
testID: "capacity-band-chart-dot"
|
|
12144
|
+
}
|
|
12145
|
+
)
|
|
12146
|
+
},
|
|
12147
|
+
`dot-${workout.date}-${i}`
|
|
12148
|
+
);
|
|
12149
|
+
})
|
|
12635
12150
|
]
|
|
12636
12151
|
}
|
|
12637
12152
|
);
|
|
12638
12153
|
}
|
|
12639
|
-
var PALETTE =
|
|
12640
|
-
"#5B9BD5",
|
|
12641
|
-
"#14B8A6",
|
|
12642
|
-
"#F4A736",
|
|
12643
|
-
"#F83030",
|
|
12644
|
-
"#823CA0",
|
|
12645
|
-
"#D4A520",
|
|
12646
|
-
"#406D87",
|
|
12647
|
-
"#43C6B7"
|
|
12648
|
-
];
|
|
12154
|
+
var PALETTE = DATAVIZ_CATEGORICAL_PALETTE;
|
|
12649
12155
|
function scaleValue(v, scale) {
|
|
12650
12156
|
if (v <= 0) return 0;
|
|
12651
12157
|
if (scale === "sqrt") return Math.sqrt(v);
|
|
@@ -12761,16 +12267,7 @@ function Treemap({
|
|
|
12761
12267
|
);
|
|
12762
12268
|
}) });
|
|
12763
12269
|
}
|
|
12764
|
-
var PALETTE2 =
|
|
12765
|
-
"#5B9BD5",
|
|
12766
|
-
"#14B8A6",
|
|
12767
|
-
"#F4A736",
|
|
12768
|
-
"#F83030",
|
|
12769
|
-
"#823CA0",
|
|
12770
|
-
"#D4A520",
|
|
12771
|
-
"#406D87",
|
|
12772
|
-
"#43C6B7"
|
|
12773
|
-
];
|
|
12270
|
+
var PALETTE2 = DATAVIZ_CATEGORICAL_PALETTE;
|
|
12774
12271
|
var GRID_LINE2 = "rgba(255,255,255,0.07)";
|
|
12775
12272
|
var AXIS_LINE = "rgba(255,255,255,0.18)";
|
|
12776
12273
|
var DIAGONAL_LINE = "rgba(255,255,255,0.28)";
|
|
@@ -12860,28 +12357,28 @@ function Scatter({
|
|
|
12860
12357
|
testID: "scatter-canvas",
|
|
12861
12358
|
style: { position: "absolute", top: 0, left: 0, width, height, overflow: "hidden" },
|
|
12862
12359
|
children: [
|
|
12863
|
-
ticksOf(yd, TICK_COUNT).map((
|
|
12864
|
-
const y = toY(
|
|
12360
|
+
ticksOf(yd, TICK_COUNT).map((t12, i) => {
|
|
12361
|
+
const y = toY(t12);
|
|
12865
12362
|
return /* @__PURE__ */ jsx(
|
|
12866
12363
|
reactNative.View,
|
|
12867
12364
|
{
|
|
12868
12365
|
accessibilityElementsHidden: true,
|
|
12869
12366
|
testID: "scatter-gridline-y",
|
|
12870
12367
|
style: { position: "absolute", left: PLOT_LEFT2, width: innerW, top: y, height: 1, backgroundColor: GRID_LINE2 },
|
|
12871
|
-
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(
|
|
12368
|
+
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(t12) })
|
|
12872
12369
|
},
|
|
12873
12370
|
`y-${i}`
|
|
12874
12371
|
);
|
|
12875
12372
|
}),
|
|
12876
|
-
ticksOf(xd, TICK_COUNT).map((
|
|
12877
|
-
const x = toX(
|
|
12373
|
+
ticksOf(xd, TICK_COUNT).map((t12, i) => {
|
|
12374
|
+
const x = toX(t12);
|
|
12878
12375
|
return /* @__PURE__ */ jsx(
|
|
12879
12376
|
reactNative.View,
|
|
12880
12377
|
{
|
|
12881
12378
|
accessibilityElementsHidden: true,
|
|
12882
12379
|
testID: "scatter-gridline-x",
|
|
12883
12380
|
style: { position: "absolute", top: PLOT_TOP, height: innerH, left: x, width: 1, backgroundColor: GRID_LINE2 },
|
|
12884
|
-
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(
|
|
12381
|
+
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(t12) })
|
|
12885
12382
|
},
|
|
12886
12383
|
`x-${i}`
|
|
12887
12384
|
);
|
|
@@ -12941,26 +12438,27 @@ function Scatter({
|
|
|
12941
12438
|
}) })
|
|
12942
12439
|
] });
|
|
12943
12440
|
}
|
|
12944
|
-
var
|
|
12945
|
-
var
|
|
12946
|
-
var
|
|
12441
|
+
var sem2 = getSemanticColors("dark");
|
|
12442
|
+
var STATUS_SUCCESS4 = sem2["status-success"];
|
|
12443
|
+
var STATUS_WARNING4 = sem2["status-warning"];
|
|
12444
|
+
var STATUS_ERROR4 = sem2["status-error"];
|
|
12947
12445
|
var TRACK = "rgba(255,255,255,0.08)";
|
|
12948
12446
|
var DEFAULT_THRESHOLDS = [
|
|
12949
|
-
{ value: 0, color:
|
|
12447
|
+
{ value: 0, color: STATUS_ERROR4 },
|
|
12950
12448
|
{ value: 60, color: STATUS_WARNING4 },
|
|
12951
12449
|
{ value: 80, color: STATUS_SUCCESS4 }
|
|
12952
12450
|
];
|
|
12953
12451
|
var ARC_START = 135;
|
|
12954
12452
|
var ARC_SWEEP = 270;
|
|
12955
12453
|
var SEGMENTS = 40;
|
|
12956
|
-
function
|
|
12454
|
+
function clamp012(n) {
|
|
12957
12455
|
if (Number.isNaN(n)) return 0;
|
|
12958
12456
|
return Math.max(0, Math.min(1, n));
|
|
12959
12457
|
}
|
|
12960
12458
|
function formatValue2(v) {
|
|
12961
12459
|
return Number.isInteger(v) ? `${v}` : v.toFixed(1);
|
|
12962
12460
|
}
|
|
12963
|
-
function
|
|
12461
|
+
function bandColor2(fraction, bands, min, max) {
|
|
12964
12462
|
const value = min + fraction * (max - min);
|
|
12965
12463
|
const sorted = [...bands].sort((a, b) => a.value - b.value);
|
|
12966
12464
|
let color = sorted[0]?.color ?? STATUS_SUCCESS4;
|
|
@@ -12998,10 +12496,10 @@ function Gauge2({
|
|
|
12998
12496
|
...props
|
|
12999
12497
|
}) {
|
|
13000
12498
|
const span = max - min || 1;
|
|
13001
|
-
const fill =
|
|
13002
|
-
const activeColor = (f) => color ??
|
|
12499
|
+
const fill = clamp012((value - min) / span);
|
|
12500
|
+
const activeColor = (f) => color ?? bandColor2(f, thresholds, min, max);
|
|
13003
12501
|
const ticks = buildTicks(fill, size, activeColor);
|
|
13004
|
-
const displayColor = color ??
|
|
12502
|
+
const displayColor = color ?? bandColor2(fill, thresholds, min, max);
|
|
13005
12503
|
const tickLength = size * 0.11;
|
|
13006
12504
|
const tickThickness = Math.max(2, size * 0.9 / SEGMENTS);
|
|
13007
12505
|
const ariaLabel = `${label ? `${label}: ` : ""}${formatValue2(value)}${unit ?? ""} of ${formatValue2(max)}`;
|
|
@@ -13015,23 +12513,23 @@ function Gauge2({
|
|
|
13015
12513
|
testID: "gauge",
|
|
13016
12514
|
...props,
|
|
13017
12515
|
children: [
|
|
13018
|
-
ticks.map((
|
|
12516
|
+
ticks.map((t12) => /* @__PURE__ */ jsx(
|
|
13019
12517
|
reactNative.View,
|
|
13020
12518
|
{
|
|
13021
12519
|
accessibilityElementsHidden: true,
|
|
13022
12520
|
testID: "gauge-segment",
|
|
13023
12521
|
style: {
|
|
13024
12522
|
position: "absolute",
|
|
13025
|
-
left:
|
|
13026
|
-
top:
|
|
12523
|
+
left: t12.left - tickThickness / 2,
|
|
12524
|
+
top: t12.top - tickLength / 2,
|
|
13027
12525
|
width: tickThickness,
|
|
13028
12526
|
height: tickLength,
|
|
13029
12527
|
borderRadius: tickThickness / 2,
|
|
13030
|
-
backgroundColor:
|
|
13031
|
-
transform: [{ rotate:
|
|
12528
|
+
backgroundColor: t12.color,
|
|
12529
|
+
transform: [{ rotate: t12.rotate }]
|
|
13032
12530
|
}
|
|
13033
12531
|
},
|
|
13034
|
-
|
|
12532
|
+
t12.key
|
|
13035
12533
|
)),
|
|
13036
12534
|
/* @__PURE__ */ jsxs(reactNative.View, { style: { position: "absolute", top: 0, left: 0, width: size, height: size }, className: "items-center justify-center", children: [
|
|
13037
12535
|
/* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-baseline gap-0.5", children: [
|
|
@@ -13044,6 +12542,203 @@ function Gauge2({
|
|
|
13044
12542
|
}
|
|
13045
12543
|
);
|
|
13046
12544
|
}
|
|
12545
|
+
function BrandLockup({
|
|
12546
|
+
subtitle = "wall dashboard",
|
|
12547
|
+
showSubtitle = true,
|
|
12548
|
+
className,
|
|
12549
|
+
...props
|
|
12550
|
+
}) {
|
|
12551
|
+
return /* @__PURE__ */ jsxs(reactNative.View, { className: cn("flex-row items-center gap-[7px]", className), ...props, children: [
|
|
12552
|
+
/* @__PURE__ */ jsx(reactNative.View, { className: "text-brand-primary", children: /* @__PURE__ */ jsx(VoltrasMark, { size: 14, color: "currentColor" }) }),
|
|
12553
|
+
/* @__PURE__ */ jsx(
|
|
12554
|
+
Typography,
|
|
12555
|
+
{
|
|
12556
|
+
variant: "button",
|
|
12557
|
+
color: "primary",
|
|
12558
|
+
className: "text-[12px] font-extrabold tracking-[1.5px]",
|
|
12559
|
+
children: "VOLTRAS"
|
|
12560
|
+
}
|
|
12561
|
+
),
|
|
12562
|
+
showSubtitle && subtitle ? /* @__PURE__ */ jsxs(
|
|
12563
|
+
Typography,
|
|
12564
|
+
{
|
|
12565
|
+
variant: "button",
|
|
12566
|
+
color: "tertiary",
|
|
12567
|
+
className: "text-[10px] font-semibold tracking-[0.4px]",
|
|
12568
|
+
children: [
|
|
12569
|
+
"/ ",
|
|
12570
|
+
subtitle
|
|
12571
|
+
]
|
|
12572
|
+
}
|
|
12573
|
+
) : null
|
|
12574
|
+
] });
|
|
12575
|
+
}
|
|
12576
|
+
var stateConfig = {
|
|
12577
|
+
// live = vivid green with an expanding ring; rest = solid amber (no pulse — operator); idle is dim.
|
|
12578
|
+
live: { label: "LIVE", color: "success", pulse: "ping", textColor: "primary" },
|
|
12579
|
+
rest: { label: "REST", color: "warning", pulse: false, textColor: "primary" },
|
|
12580
|
+
idle: { label: "IDLE", color: "default", pulse: false, textColor: "secondary" }
|
|
12581
|
+
};
|
|
12582
|
+
function SessionStatePill({ state, label, className, ...props }) {
|
|
12583
|
+
const cfg = stateConfig[state];
|
|
12584
|
+
return /* @__PURE__ */ jsxs(reactNative.View, { className: cn("flex-row items-center gap-2", className), ...props, children: [
|
|
12585
|
+
/* @__PURE__ */ jsx(Indicator, { size: "md", color: cfg.color, pulse: cfg.pulse }),
|
|
12586
|
+
/* @__PURE__ */ jsx(Typography, { variant: "monoLabel", color: cfg.textColor, className: "text-[11px]", children: label ?? cfg.label })
|
|
12587
|
+
] });
|
|
12588
|
+
}
|
|
12589
|
+
var statusTextClass = {
|
|
12590
|
+
connected: "text-status-success",
|
|
12591
|
+
degraded: "text-status-warning",
|
|
12592
|
+
lost: "text-status-error-vivid"
|
|
12593
|
+
};
|
|
12594
|
+
function DeviceIndicator({
|
|
12595
|
+
status = "connected",
|
|
12596
|
+
onPress,
|
|
12597
|
+
label = "Devices",
|
|
12598
|
+
className,
|
|
12599
|
+
...props
|
|
12600
|
+
}) {
|
|
12601
|
+
const Wrapper = onPress ? reactNative.Pressable : reactNative.View;
|
|
12602
|
+
return /* @__PURE__ */ jsx(
|
|
12603
|
+
Wrapper,
|
|
12604
|
+
{
|
|
12605
|
+
accessibilityLabel: label,
|
|
12606
|
+
...onPress ? { onPress, accessibilityRole: "button" } : {},
|
|
12607
|
+
className: cn(
|
|
12608
|
+
"w-[26px] h-[28px] items-center justify-center rounded-[7px]",
|
|
12609
|
+
statusTextClass[status],
|
|
12610
|
+
className
|
|
12611
|
+
),
|
|
12612
|
+
...props,
|
|
12613
|
+
children: /* @__PURE__ */ jsx(BluetoothIcon, { size: 18, color: "currentColor", title: label })
|
|
12614
|
+
}
|
|
12615
|
+
);
|
|
12616
|
+
}
|
|
12617
|
+
var stateColor = {
|
|
12618
|
+
connected: "success",
|
|
12619
|
+
available: "info",
|
|
12620
|
+
degraded: "warning",
|
|
12621
|
+
lost: "error-vivid"
|
|
12622
|
+
};
|
|
12623
|
+
function DeviceRow({ device, onPress, className, ...props }) {
|
|
12624
|
+
const Wrapper = onPress ? reactNative.Pressable : reactNative.View;
|
|
12625
|
+
return /* @__PURE__ */ jsxs(
|
|
12626
|
+
Wrapper,
|
|
12627
|
+
{
|
|
12628
|
+
...onPress ? { onPress, accessibilityRole: "button" } : {},
|
|
12629
|
+
className: cn("flex-row items-center gap-[10px] px-2 py-[9px] rounded-[7px]", className),
|
|
12630
|
+
...props,
|
|
12631
|
+
children: [
|
|
12632
|
+
/* @__PURE__ */ jsx(Indicator, { size: "md", color: stateColor[device.state] }),
|
|
12633
|
+
/* @__PURE__ */ jsx(
|
|
12634
|
+
Typography,
|
|
12635
|
+
{
|
|
12636
|
+
variant: "body2",
|
|
12637
|
+
color: device.slot ? "primary" : "secondary",
|
|
12638
|
+
className: "flex-1 font-bold text-[12px]",
|
|
12639
|
+
children: device.nickname
|
|
12640
|
+
}
|
|
12641
|
+
),
|
|
12642
|
+
/* @__PURE__ */ jsx(Typography, { variant: "mono", color: "tertiary", className: "text-[10px]", children: device.id })
|
|
12643
|
+
]
|
|
12644
|
+
}
|
|
12645
|
+
);
|
|
12646
|
+
}
|
|
12647
|
+
function aggregateStatus(devices) {
|
|
12648
|
+
const bound = devices.filter((d) => d.slot);
|
|
12649
|
+
if (bound.some((d) => d.state === "lost")) return "lost";
|
|
12650
|
+
if (bound.some((d) => d.state === "degraded")) return "degraded";
|
|
12651
|
+
return "connected";
|
|
12652
|
+
}
|
|
12653
|
+
function DeviceMenu({
|
|
12654
|
+
devices,
|
|
12655
|
+
isOpen,
|
|
12656
|
+
onOpenChange,
|
|
12657
|
+
onSelectDevice,
|
|
12658
|
+
className
|
|
12659
|
+
}) {
|
|
12660
|
+
const status = aggregateStatus(devices);
|
|
12661
|
+
const boundCount = devices.filter((d) => d.slot).length;
|
|
12662
|
+
const availCount = devices.filter((d) => !d.slot).length;
|
|
12663
|
+
return /* @__PURE__ */ jsxs(Popover, { placement: "bottom", isOpen, onOpenChange, className, children: [
|
|
12664
|
+
/* @__PURE__ */ jsx(PopoverTrigger, { children: /* @__PURE__ */ jsx(DeviceIndicator, { status }) }),
|
|
12665
|
+
/* @__PURE__ */ jsxs(PopoverContent, { className: "right-0 left-auto mt-[10px] w-[326px] bg-surface-elevated border border-border-strong rounded-[10px] p-[7px]", children: [
|
|
12666
|
+
/* @__PURE__ */ jsxs(
|
|
12667
|
+
Typography,
|
|
12668
|
+
{
|
|
12669
|
+
variant: "monoLabel",
|
|
12670
|
+
color: "tertiary",
|
|
12671
|
+
className: "text-[9px] tracking-[0.8px] px-2 pt-[6px] pb-2",
|
|
12672
|
+
children: [
|
|
12673
|
+
"Devices \u2014 ",
|
|
12674
|
+
boundCount,
|
|
12675
|
+
" bound \xB7 ",
|
|
12676
|
+
availCount,
|
|
12677
|
+
" available"
|
|
12678
|
+
]
|
|
12679
|
+
}
|
|
12680
|
+
),
|
|
12681
|
+
devices.map((device, i) => /* @__PURE__ */ jsx(reactNative.View, { className: cn(i > 0 && "border-t border-border"), children: /* @__PURE__ */ jsx(
|
|
12682
|
+
DeviceRow,
|
|
12683
|
+
{
|
|
12684
|
+
device,
|
|
12685
|
+
onPress: onSelectDevice ? () => onSelectDevice(device) : void 0
|
|
12686
|
+
}
|
|
12687
|
+
) }, device.id))
|
|
12688
|
+
] })
|
|
12689
|
+
] });
|
|
12690
|
+
}
|
|
12691
|
+
var SUBTITLE_MIN = 1024;
|
|
12692
|
+
var CLOCK_MIN = 720;
|
|
12693
|
+
function TopBar({
|
|
12694
|
+
state,
|
|
12695
|
+
devices,
|
|
12696
|
+
time,
|
|
12697
|
+
subtitle = "wall dashboard",
|
|
12698
|
+
showSubtitle,
|
|
12699
|
+
showClock,
|
|
12700
|
+
onSelectDevice,
|
|
12701
|
+
className
|
|
12702
|
+
}) {
|
|
12703
|
+
const [width, setWidth] = React24.useState(SUBTITLE_MIN);
|
|
12704
|
+
const onLayout = (e) => setWidth(e.nativeEvent.layout.width);
|
|
12705
|
+
const subtitleVisible = showSubtitle ?? width >= SUBTITLE_MIN;
|
|
12706
|
+
const clockVisible = showClock ?? width >= CLOCK_MIN;
|
|
12707
|
+
return /* @__PURE__ */ jsxs(
|
|
12708
|
+
reactNative.View,
|
|
12709
|
+
{
|
|
12710
|
+
onLayout,
|
|
12711
|
+
style: surfaceGradient.chrome(),
|
|
12712
|
+
className: cn(
|
|
12713
|
+
"h-[46px] flex-row items-center gap-[14px] px-4 bg-surface-elevated border-b border-border",
|
|
12714
|
+
className
|
|
12715
|
+
),
|
|
12716
|
+
children: [
|
|
12717
|
+
/* @__PURE__ */ jsx(BrandLockup, { subtitle, showSubtitle: subtitleVisible }),
|
|
12718
|
+
/* @__PURE__ */ jsxs(reactNative.View, { className: "ml-auto flex-row items-center gap-[12px]", children: [
|
|
12719
|
+
/* @__PURE__ */ jsx(SessionStatePill, { state }),
|
|
12720
|
+
/* @__PURE__ */ jsx(Divider, { orientation: "vertical", className: "h-4 bg-border-prominent" }),
|
|
12721
|
+
/* @__PURE__ */ jsx(DeviceMenu, { devices, onSelectDevice }),
|
|
12722
|
+
clockVisible ? /* @__PURE__ */ jsxs(jsxRuntime.Fragment, { children: [
|
|
12723
|
+
/* @__PURE__ */ jsx(Divider, { orientation: "vertical", className: "h-4 bg-border-prominent" }),
|
|
12724
|
+
/* @__PURE__ */ jsx(
|
|
12725
|
+
DateTime,
|
|
12726
|
+
{
|
|
12727
|
+
value: time,
|
|
12728
|
+
live: time == null,
|
|
12729
|
+
format: "time",
|
|
12730
|
+
hour12: false,
|
|
12731
|
+
variant: "mono",
|
|
12732
|
+
color: "secondary",
|
|
12733
|
+
className: "text-[11px] min-w-[38px] text-right"
|
|
12734
|
+
}
|
|
12735
|
+
)
|
|
12736
|
+
] }) : null
|
|
12737
|
+
] })
|
|
12738
|
+
]
|
|
12739
|
+
}
|
|
12740
|
+
);
|
|
12741
|
+
}
|
|
13047
12742
|
|
|
13048
12743
|
// src/utils/form.ts
|
|
13049
12744
|
function getFieldValidationProps(state) {
|
|
@@ -13137,7 +12832,6 @@ exports.Accordion = Accordion;
|
|
|
13137
12832
|
exports.AccordionButton = AccordionButton;
|
|
13138
12833
|
exports.AccordionItem = AccordionItem;
|
|
13139
12834
|
exports.AccordionPanel = AccordionPanel;
|
|
13140
|
-
exports.ActiveWorkoutPage = ActiveWorkoutPage;
|
|
13141
12835
|
exports.Alert = Alert;
|
|
13142
12836
|
exports.AlertDescription = AlertDescription;
|
|
13143
12837
|
exports.AlertTitle = AlertTitle;
|
|
@@ -13148,12 +12842,15 @@ exports.AvatarGroup = AvatarGroup;
|
|
|
13148
12842
|
exports.Badge = Badge;
|
|
13149
12843
|
exports.BadgeText = BadgeText;
|
|
13150
12844
|
exports.BaseBadge = BaseBadge;
|
|
12845
|
+
exports.BluetoothIcon = BluetoothIcon;
|
|
12846
|
+
exports.BrandLockup = BrandLockup;
|
|
13151
12847
|
exports.BreadcrumbItem = BreadcrumbItem;
|
|
13152
12848
|
exports.Breadcrumbs = Breadcrumbs;
|
|
13153
12849
|
exports.Button = Button;
|
|
13154
12850
|
exports.ButtonIcon = ButtonIcon;
|
|
13155
12851
|
exports.ButtonSpinner = ButtonSpinner;
|
|
13156
12852
|
exports.ButtonText = ButtonText;
|
|
12853
|
+
exports.CATEGORICAL_CVD_SAFE_MAX = CATEGORICAL_CVD_SAFE_MAX;
|
|
13157
12854
|
exports.CapacityBandChart = CapacityBandChart;
|
|
13158
12855
|
exports.Caption = Caption;
|
|
13159
12856
|
exports.Card = Card;
|
|
@@ -13173,15 +12870,17 @@ exports.CollapseContent = CollapseContent;
|
|
|
13173
12870
|
exports.DataRow = DataRow;
|
|
13174
12871
|
exports.DateTime = DateTime;
|
|
13175
12872
|
exports.DeviationBar = DeviationBar;
|
|
12873
|
+
exports.DeviceIndicator = DeviceIndicator;
|
|
12874
|
+
exports.DeviceMenu = DeviceMenu;
|
|
12875
|
+
exports.DeviceRow = DeviceRow;
|
|
13176
12876
|
exports.Divider = Divider;
|
|
13177
12877
|
exports.Drawer = Drawer;
|
|
13178
12878
|
exports.DrawerBody = DrawerBody;
|
|
13179
12879
|
exports.DrawerFooter = DrawerFooter;
|
|
13180
12880
|
exports.DrawerHeader = DrawerHeader;
|
|
13181
|
-
exports.
|
|
12881
|
+
exports.DumbbellIcon = DumbbellIcon;
|
|
13182
12882
|
exports.EmptyState = EmptyState;
|
|
13183
12883
|
exports.ExerciseCard = ExerciseCard;
|
|
13184
|
-
exports.ExerciseDetailPage = ExerciseDetailPage;
|
|
13185
12884
|
exports.FormActions = FormActions;
|
|
13186
12885
|
exports.FormField = FormField;
|
|
13187
12886
|
exports.FormRow = FormRow;
|
|
@@ -13234,7 +12933,6 @@ exports.PopoverContent = PopoverContent;
|
|
|
13234
12933
|
exports.PopoverTrigger = PopoverTrigger;
|
|
13235
12934
|
exports.PrBadge = PrBadge;
|
|
13236
12935
|
exports.PrHistoryModal = PrHistoryModal;
|
|
13237
|
-
exports.ProgramPlanningPage = ProgramPlanningPage;
|
|
13238
12936
|
exports.Progress = Progress;
|
|
13239
12937
|
exports.ProgressSteps = ProgressSteps;
|
|
13240
12938
|
exports.Radio = Radio;
|
|
@@ -13246,6 +12944,7 @@ exports.Section = Section;
|
|
|
13246
12944
|
exports.SectionContent = SectionContent;
|
|
13247
12945
|
exports.SectionHeader = SectionHeader;
|
|
13248
12946
|
exports.Select = Select;
|
|
12947
|
+
exports.SessionStatePill = SessionStatePill;
|
|
13249
12948
|
exports.SetRow = SetRow;
|
|
13250
12949
|
exports.Sidebar = Sidebar;
|
|
13251
12950
|
exports.SidebarContent = SidebarContent;
|
|
@@ -13262,6 +12961,7 @@ exports.SkeletonText = SkeletonText;
|
|
|
13262
12961
|
exports.Sparkline = Sparkline;
|
|
13263
12962
|
exports.Spinner = Spinner;
|
|
13264
12963
|
exports.Stack = Stack;
|
|
12964
|
+
exports.StarIcon = StarIcon;
|
|
13265
12965
|
exports.StatusDot = StatusDot;
|
|
13266
12966
|
exports.StepContent = StepContent;
|
|
13267
12967
|
exports.StepIndicator = StepIndicator;
|
|
@@ -13271,6 +12971,7 @@ exports.StepperStep = Step;
|
|
|
13271
12971
|
exports.StrengthTrendChart = StrengthTrendChart;
|
|
13272
12972
|
exports.SupersetWrapper = SupersetWrapper;
|
|
13273
12973
|
exports.Surface = Surface;
|
|
12974
|
+
exports.SvgIcon = SvgIcon;
|
|
13274
12975
|
exports.Switch = Switch;
|
|
13275
12976
|
exports.TEMPO_PACING = TEMPO_PACING;
|
|
13276
12977
|
exports.Tab = Tab;
|
|
@@ -13287,16 +12988,17 @@ exports.TableRow = TableRow;
|
|
|
13287
12988
|
exports.Tabs = Tabs;
|
|
13288
12989
|
exports.TempoBar = TempoBar;
|
|
13289
12990
|
exports.TempoDisplay = TempoDisplay;
|
|
13290
|
-
exports.ThemeProvider = ThemeProvider;
|
|
13291
12991
|
exports.Toast = Toast;
|
|
13292
12992
|
exports.ToastProvider = ToastProvider;
|
|
13293
12993
|
exports.ToolbarButton = ToolbarButton;
|
|
13294
12994
|
exports.ToolbarButtonGroup = ToolbarButtonGroup;
|
|
13295
12995
|
exports.Tooltip = Tooltip;
|
|
12996
|
+
exports.TopBar = TopBar;
|
|
13296
12997
|
exports.Treemap = Treemap;
|
|
13297
12998
|
exports.Typography = Typography;
|
|
13298
12999
|
exports.VStack = VStack;
|
|
13299
13000
|
exports.VelocityStrip = VelocityStrip;
|
|
13001
|
+
exports.VoltrasMark = VoltrasMark;
|
|
13300
13002
|
exports.WeekRow = WeekRow;
|
|
13301
13003
|
exports.WeightBadge = WeightBadge;
|
|
13302
13004
|
exports.WorkoutCard = WorkoutCard;
|
|
@@ -13304,14 +13006,14 @@ exports.WorkoutPill = WorkoutPill;
|
|
|
13304
13006
|
exports.alpha = alpha;
|
|
13305
13007
|
exports.applyThemePreset = applyThemePreset;
|
|
13306
13008
|
exports.audiobookPreset = audiobookPreset;
|
|
13307
|
-
exports.
|
|
13009
|
+
exports.bestTextColor = bestTextColor;
|
|
13308
13010
|
exports.buttonSizes = buttonSizes;
|
|
13309
13011
|
exports.calculateMeanVelocity = calculateMeanVelocity;
|
|
13310
13012
|
exports.calculateVelocityLoss = calculateVelocityLoss;
|
|
13013
|
+
exports.categoricalPalette = categoricalPalette;
|
|
13311
13014
|
exports.cn = cn;
|
|
13312
13015
|
exports.componentElevationRanges = componentElevationRanges;
|
|
13313
13016
|
exports.composeValidators = composeValidators;
|
|
13314
|
-
exports.countCompletedSets = countCompletedSets;
|
|
13315
13017
|
exports.createFieldId = createFieldId;
|
|
13316
13018
|
exports.createFlatShadow = createFlatShadow;
|
|
13317
13019
|
exports.createPressedHoverShadow = createPressedHoverShadow;
|
|
@@ -13321,20 +13023,15 @@ exports.createRaisedShadow = createRaisedShadow;
|
|
|
13321
13023
|
exports.darkThemeCSSVars = darkThemeCSSVars;
|
|
13322
13024
|
exports.darken = darken;
|
|
13323
13025
|
exports.defaultPreset = defaultPreset;
|
|
13324
|
-
exports.deriveExerciseStats = deriveExerciseStats;
|
|
13325
|
-
exports.deriveNavLevel = deriveNavLevel;
|
|
13326
|
-
exports.deriveWorkoutProgress = deriveWorkoutProgress;
|
|
13327
13026
|
exports.discreteRainbow = discreteRainbow;
|
|
13027
|
+
exports.divergingScale = divergingScale;
|
|
13328
13028
|
exports.elevationSystem = elevationSystem;
|
|
13329
|
-
exports.findActiveExercise = findActiveExercise;
|
|
13330
|
-
exports.findMeso = findMeso;
|
|
13331
|
-
exports.findWeek = findWeek;
|
|
13332
|
-
exports.findWorkout = findWorkout;
|
|
13333
13029
|
exports.formatDateTime = formatDateTime;
|
|
13334
13030
|
exports.formatPrescription = formatPrescription;
|
|
13335
13031
|
exports.formatSignedPct = formatSignedPct;
|
|
13336
13032
|
exports.formatVelocity = formatVelocity;
|
|
13337
13033
|
exports.getBaseSurfaceColor = getBaseSurfaceColor;
|
|
13034
|
+
exports.getCategoricalColor = getCategoricalColor;
|
|
13338
13035
|
exports.getContrastText = getContrastText;
|
|
13339
13036
|
exports.getDiscreteRainbowColor = getDiscreteRainbowColor;
|
|
13340
13037
|
exports.getElevationConfig = getElevationConfig;
|
|
@@ -13355,7 +13052,6 @@ exports.getValidatedElevation = getValidatedElevation;
|
|
|
13355
13052
|
exports.getVelocityZoneColor = getVelocityZoneColor;
|
|
13356
13053
|
exports.getVelocityZoneName = getVelocityZoneName;
|
|
13357
13054
|
exports.gluestackConfig = gluestackConfig;
|
|
13358
|
-
exports.groupExercises = groupExercises;
|
|
13359
13055
|
exports.hasMaxLength = hasMaxLength;
|
|
13360
13056
|
exports.hasMinLength = hasMinLength;
|
|
13361
13057
|
exports.hexToRgb = hexToRgb;
|
|
@@ -13366,10 +13062,12 @@ exports.isEmpty = isEmpty;
|
|
|
13366
13062
|
exports.isValidEmail = isValidEmail;
|
|
13367
13063
|
exports.lightThemeCSSVars = lightThemeCSSVars;
|
|
13368
13064
|
exports.lighten = lighten;
|
|
13065
|
+
exports.linearGradient = linearGradient;
|
|
13369
13066
|
exports.neumorphicShadows = neumorphicShadows;
|
|
13370
13067
|
exports.primitiveBorderRadius = primitiveBorderRadius;
|
|
13371
13068
|
exports.primitiveBreakpoints = primitiveBreakpoints;
|
|
13372
13069
|
exports.primitiveColors = primitiveColors;
|
|
13070
|
+
exports.primitiveRamps = primitiveRamps;
|
|
13373
13071
|
exports.primitiveShadows = primitiveShadows;
|
|
13374
13072
|
exports.primitiveSpacing = primitiveSpacing;
|
|
13375
13073
|
exports.primitiveTypography = primitiveTypography;
|
|
@@ -13384,12 +13082,9 @@ exports.rpeColor = rpeColor;
|
|
|
13384
13082
|
exports.semanticColorsDark = semanticColorsDark;
|
|
13385
13083
|
exports.semanticColorsLight = semanticColorsLight;
|
|
13386
13084
|
exports.semanticTypography = semanticTypography;
|
|
13085
|
+
exports.sequentialEffort = sequentialEffort;
|
|
13387
13086
|
exports.shadowColors = shadowColors;
|
|
13388
|
-
exports.
|
|
13389
|
-
exports.summarizeVbt = summarizeVbt;
|
|
13390
|
-
exports.toActiveCardProps = toActiveCardProps;
|
|
13391
|
-
exports.toExerciseCardProps = toExerciseCardProps;
|
|
13392
|
-
exports.toProgressBarMesos = toProgressBarMesos;
|
|
13087
|
+
exports.surfaceGradient = surfaceGradient;
|
|
13393
13088
|
exports.useTable = useTable;
|
|
13394
13089
|
exports.useToast = useToast;
|
|
13395
13090
|
exports.useToolbarButton = useToolbarButton;
|