@titan-design/react-ui 0.5.0 → 0.7.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/bodymap.js +241 -189
- package/dist/bodymap.js.map +1 -1
- package/dist/bodymap.mjs +241 -189
- package/dist/bodymap.mjs.map +1 -1
- package/dist/index.d.mts +1017 -130
- package/dist/index.d.ts +1017 -130
- package/dist/index.js +3058 -1090
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2992 -1091
- package/dist/index.mjs.map +1 -1
- package/dist/{pages-MO0JCySL.d.mts → pages-8u_4WbL-.d.mts} +280 -57
- package/dist/{pages-D7Jlssvp.d.ts → pages-DaWiBOGa.d.ts} +280 -57
- package/dist/pages.d.mts +1 -1
- package/dist/pages.d.ts +1 -1
- package/dist/pages.js +1797 -1292
- package/dist/pages.js.map +1 -1
- package/dist/pages.mjs +1797 -1292
- package/dist/pages.mjs.map +1 -1
- package/dist/theme/index.d.mts +464 -268
- package/dist/theme/index.d.ts +464 -268
- package/dist/theme/index.js +303 -191
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/index.mjs +295 -192
- package/dist/theme/index.mjs.map +1 -1
- package/dist/theme/tokens-css.js +160 -143
- package/dist/theme/tokens-css.js.map +1 -1
- package/dist/theme/tokens-css.mjs +160 -143
- package/dist/theme/tokens-css.mjs.map +1 -1
- package/package.json +3 -1
- package/src/arch/Architecture.stories.tsx +870 -0
- package/src/arch/annotations.json +48 -0
- package/src/arch/arch-graph.json +4301 -0
- package/src/components/custom/DateTime/DateTime.stories.tsx +83 -7
- package/src/components/custom/DateTime/DateTime.test.tsx +29 -3
- package/src/components/custom/DateTime/DateTime.tsx +55 -15
- package/src/components/custom/EmptyState/EmptyState.stories.tsx +1 -1
- package/src/components/custom/Gauge/Gauge.stories.tsx +1 -1
- package/src/components/custom/Gauge/Gauge.test.tsx +2 -2
- package/src/components/custom/Gauge/Gauge.tsx +6 -3
- package/src/components/custom/Metric/Metric.stories.tsx +1 -1
- package/src/components/custom/Scatter/Scatter.stories.tsx +1 -1
- package/src/components/custom/Scatter/Scatter.tsx +3 -5
- package/src/components/custom/Sidebar/Sidebar.stories.tsx +1 -1
- package/src/components/custom/Table/Table.stories.tsx +1 -1
- package/src/components/custom/TimerReadout/TimerReadout.stories.tsx +62 -0
- package/src/components/custom/TimerReadout/TimerReadout.test.tsx +72 -0
- package/src/components/custom/TimerReadout/TimerReadout.tsx +75 -0
- package/src/components/custom/TimerReadout/index.ts +1 -0
- package/src/components/custom/Treemap/Treemap.stories.tsx +1 -1
- package/src/components/custom/Treemap/Treemap.tsx +3 -5
- package/src/components/custom/Typography/Typography.stories.tsx +46 -28
- 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.stories.tsx +21 -13
- package/src/components/custom/Workout/ActiveWorkoutPage.test.tsx +16 -13
- package/src/components/custom/Workout/ActiveWorkoutPage.tsx +11 -16
- package/src/components/custom/Workout/BaseBadge.stories.tsx +1 -1
- package/src/components/custom/Workout/BodyMap.stories.tsx +1 -1
- package/src/components/custom/Workout/BodyMap.tsx +6 -3
- package/src/components/custom/Workout/BodyMapDetailPanel.stories.tsx +1 -1
- package/src/components/custom/Workout/BodyMapDetailPanel.tsx +6 -3
- package/src/components/custom/Workout/CapacityBandChart.stories.tsx +1 -1
- 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.stories.tsx +1 -1
- 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.stories.tsx +51 -66
- package/src/components/custom/Workout/ExerciseCard.test.tsx +146 -143
- package/src/components/custom/Workout/ExerciseCard.tsx +176 -198
- package/src/components/custom/Workout/ExerciseCardHeading.stories.tsx +99 -0
- package/src/components/custom/Workout/ExerciseCardHeading.test.tsx +72 -0
- package/src/components/custom/Workout/ExerciseCardHeading.tsx +43 -0
- package/src/components/custom/Workout/ExerciseCardUnified.stories.tsx +151 -0
- package/src/components/custom/Workout/ExerciseDetailPage.stories.tsx +5 -3
- package/src/components/custom/Workout/ExerciseDetailPage.test.tsx +4 -4
- package/src/components/custom/Workout/ExerciseDetailPage.tsx +6 -6
- package/src/components/custom/Workout/ExerciseHeading.stories.tsx +81 -0
- package/src/components/custom/Workout/ExerciseHeading.test.tsx +77 -0
- package/src/components/custom/Workout/ExerciseHeading.tsx +85 -0
- package/src/components/custom/Workout/ExerciseIndicator.stories.tsx +110 -0
- package/src/components/custom/Workout/ExerciseIndicator.test.tsx +93 -0
- package/src/components/custom/Workout/ExerciseIndicator.tsx +120 -0
- package/src/components/custom/Workout/FatigueMeter.stories.tsx +51 -0
- package/src/components/custom/Workout/FatigueMeter.test.tsx +73 -0
- package/src/components/custom/Workout/FatigueMeter.tsx +82 -0
- package/src/components/custom/Workout/InputBar.stories.tsx +1 -1
- package/src/components/custom/Workout/InputBar.tsx +2 -1
- package/src/components/custom/Workout/IntensityBar.stories.tsx +1 -1
- package/src/components/custom/Workout/IntensityBar.test.tsx +8 -8
- package/src/components/custom/Workout/IntensityBar.tsx +10 -6
- package/src/components/custom/Workout/LiveAuraFrame.stories.tsx +153 -0
- package/src/components/custom/Workout/LiveAuraFrame.test.tsx +74 -0
- package/src/components/custom/Workout/LiveAuraFrame.tsx +105 -0
- package/src/components/custom/Workout/MesoCard.stories.tsx +1 -1
- package/src/components/custom/Workout/MesoCard.tsx +8 -3
- package/src/components/custom/Workout/MesoProgressBar.stories.tsx +1 -1
- 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.stories.tsx +1 -1
- package/src/components/custom/Workout/MesoStatusCard.tsx +20 -13
- package/src/components/custom/Workout/MetricTiles.stories.tsx +60 -0
- package/src/components/custom/Workout/MetricTiles.test.tsx +58 -0
- package/src/components/custom/Workout/MetricTiles.tsx +48 -0
- package/src/components/custom/Workout/MuscleGroupChip.stories.tsx +1 -1
- package/src/components/custom/Workout/MuscleGroupChip.tsx +7 -4
- package/src/components/custom/Workout/PlaceholderStrip.stories.tsx +1 -1
- package/src/components/custom/Workout/PrBadge.stories.tsx +1 -1
- package/src/components/custom/Workout/PrBadge.tsx +5 -2
- package/src/components/custom/Workout/PrHistoryModal.stories.tsx +1 -1
- package/src/components/custom/Workout/PrHistoryModal.tsx +4 -3
- package/src/components/custom/Workout/ProgramPlanningPage.stories.tsx +4 -16
- package/src/components/custom/Workout/ProgramPlanningPage.tsx +10 -7
- package/src/components/custom/Workout/README.md +146 -4
- package/src/components/custom/Workout/ReadinessCheck.stories.tsx +1 -1
- package/src/components/custom/Workout/ReadinessCheck.tsx +7 -4
- package/src/components/custom/Workout/RestTimer.stories.tsx +1 -1
- package/src/components/custom/Workout/RestTimer.tsx +17 -11
- package/src/components/custom/Workout/RowInventory.stories.tsx +405 -0
- package/src/components/custom/Workout/S3FullRail.stories.tsx +34 -0
- package/src/components/custom/Workout/S3SessionPace.stories.tsx +95 -0
- package/src/components/custom/Workout/S3SessionRailHeading.stories.tsx +61 -0
- package/src/components/custom/Workout/S3SetTypes.stories.tsx +176 -0
- package/src/components/custom/Workout/S3WorkoutExpansion.stories.tsx +240 -0
- package/src/components/custom/Workout/ScheduleTiles.stories.tsx +40 -0
- package/src/components/custom/Workout/ScheduleTiles.test.tsx +34 -0
- package/src/components/custom/Workout/ScheduleTiles.tsx +70 -0
- package/src/components/custom/Workout/SegmentedBar.stories.tsx +99 -0
- package/src/components/custom/Workout/SegmentedBar.test.tsx +77 -0
- package/src/components/custom/Workout/SegmentedBar.tsx +172 -0
- package/src/components/custom/Workout/SegmentedProgressBar.stories.tsx +50 -0
- package/src/components/custom/Workout/SegmentedProgressBar.test.tsx +80 -0
- package/src/components/custom/Workout/SegmentedProgressBar.tsx +67 -0
- package/src/components/custom/Workout/SessionHeader.stories.tsx +121 -0
- package/src/components/custom/Workout/SessionHeader.test.tsx +122 -0
- package/src/components/custom/Workout/SessionHeader.tsx +152 -0
- package/src/components/custom/Workout/SessionRail.stories.tsx +153 -0
- package/src/components/custom/Workout/SessionRail.test.tsx +86 -0
- package/src/components/custom/Workout/SessionRail.tsx +126 -0
- package/src/components/custom/Workout/SetBar.stories.tsx +124 -0
- package/src/components/custom/Workout/SetBar.test.tsx +123 -0
- package/src/components/custom/Workout/SetBar.tsx +171 -0
- package/src/components/custom/Workout/SetRow.stories.tsx +50 -100
- package/src/components/custom/Workout/SetRow.test.tsx +94 -166
- package/src/components/custom/Workout/SetRow.tsx +170 -232
- package/src/components/custom/Workout/SetStrip.stories.tsx +154 -0
- package/src/components/custom/Workout/SetStrip.test.tsx +109 -0
- package/src/components/custom/Workout/SetStrip.tsx +71 -0
- package/src/components/custom/Workout/SetTableHeader.stories.tsx +66 -0
- package/src/components/custom/Workout/SetTableHeader.test.tsx +47 -0
- package/src/components/custom/Workout/SetTableHeader.tsx +88 -0
- package/src/components/custom/Workout/SetsRepsLoad.stories.tsx +47 -0
- package/src/components/custom/Workout/SetsRepsLoad.test.tsx +44 -0
- package/src/components/custom/Workout/SetsRepsLoad.tsx +52 -0
- package/src/components/custom/Workout/Sparkline.stories.tsx +1 -1
- package/src/components/custom/Workout/Sparkline.tsx +2 -1
- package/src/components/custom/Workout/StatusDot.stories.tsx +1 -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/StatusPill.stories.tsx +59 -0
- package/src/components/custom/Workout/StatusPill.test.tsx +63 -0
- package/src/components/custom/Workout/StatusPill.tsx +88 -0
- package/src/components/custom/Workout/StrengthTrendChart.stories.tsx +1 -1
- package/src/components/custom/Workout/StrengthTrendChart.tsx +9 -6
- package/src/components/custom/Workout/SupersetWrapper.stories.tsx +1 -1
- package/src/components/custom/Workout/SupersetWrapper.tsx +2 -1
- package/src/components/custom/Workout/TempoBar.stories.tsx +1 -1
- package/src/components/custom/Workout/TempoDisplay.stories.tsx +12 -1
- package/src/components/custom/Workout/TempoDisplay.tsx +29 -36
- package/src/components/custom/Workout/TrainingStatusPage.stories.tsx +1 -1
- package/src/components/custom/Workout/VelocityStrip.modalities.stories.tsx +254 -0
- package/src/components/custom/Workout/VelocityStrip.responsive.stories.tsx +145 -0
- package/src/components/custom/Workout/VelocityStrip.stories.tsx +129 -66
- package/src/components/custom/Workout/VelocityStrip.test.tsx +379 -144
- package/src/components/custom/Workout/VelocityStrip.tsx +508 -120
- package/src/components/custom/Workout/VolumeLandmarkBar.stories.tsx +73 -0
- package/src/components/custom/Workout/VolumeLandmarkBar.test.tsx +119 -0
- package/src/components/custom/Workout/VolumeLandmarkBar.tsx +154 -0
- package/src/components/custom/Workout/WeekRow.stories.tsx +1 -1
- package/src/components/custom/Workout/WeekRow.tsx +3 -2
- package/src/components/custom/Workout/WeightBadge.stories.tsx +1 -1
- package/src/components/custom/Workout/WeightBadge.tsx +6 -2
- package/src/components/custom/Workout/WorkoutCard.stories.tsx +2 -6
- package/src/components/custom/Workout/WorkoutCard.test.tsx +13 -46
- package/src/components/custom/Workout/WorkoutCard.tsx +5 -2
- package/src/components/custom/Workout/WorkoutPill.stories.tsx +1 -1
- package/src/components/custom/Workout/WorkoutPill.tsx +12 -8
- package/src/components/custom/Workout/ZoneTrack.stories.tsx +140 -0
- package/src/components/custom/Workout/ZoneTrack.test.tsx +200 -0
- package/src/components/custom/Workout/ZoneTrack.tsx +315 -0
- package/src/components/custom/Workout/icons.tsx +6 -67
- package/src/components/custom/Workout/index.ts +55 -2
- package/src/components/custom/Workout/metricText.stories.tsx +69 -0
- package/src/components/custom/Workout/metricText.tsx +34 -0
- package/src/components/custom/Workout/paceTone.test.ts +29 -0
- package/src/components/custom/Workout/paceTone.ts +27 -0
- package/src/components/custom/Workout/setHeadingKit.tsx +177 -0
- package/src/components/custom/index.ts +1 -0
- package/src/components/custom/stepper/Stepper.stories.tsx +1 -1
- package/src/components/icons/SvgIcon.tsx +50 -0
- package/src/components/icons/icons.stories.tsx +122 -0
- package/src/components/icons/icons.test.tsx +73 -0
- package/src/components/icons/icons.tsx +153 -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/DashboardShell.stories.tsx +65 -0
- package/src/components/shell/DashboardShell.test.tsx +42 -0
- package/src/components/shell/DashboardShell.tsx +74 -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/NavItem.stories.tsx +52 -0
- package/src/components/shell/NavItem.test.tsx +35 -0
- package/src/components/shell/NavItem.tsx +75 -0
- package/src/components/shell/README.md +116 -0
- package/src/components/shell/SessionRailSpecimen.stories.tsx +753 -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/SideNav.stories.tsx +81 -0
- package/src/components/shell/SideNav.test.tsx +51 -0
- package/src/components/shell/SideNav.tsx +74 -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 +13 -0
- package/src/components/ui/alert/Alert.stories.tsx +1 -1
- package/src/components/ui/autocomplete/Autocomplete.stories.tsx +1 -1
- package/src/components/ui/avatar/Avatar.stories.tsx +1 -1
- package/src/components/ui/badge/Badge.stories.tsx +1 -1
- package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +1 -1
- package/src/components/ui/button/Button.stories.tsx +1 -1
- package/src/components/ui/card/Card.stories.tsx +1 -1
- package/src/components/ui/checkbox/Checkbox.stories.tsx +1 -1
- package/src/components/ui/chip/Chip.stories.tsx +1 -1
- package/src/components/ui/collapse/Collapse.stories.tsx +1 -1
- package/src/components/ui/data-row/DataRow.stories.tsx +1 -1
- package/src/components/ui/divider/Divider.stories.tsx +1 -1
- package/src/components/ui/drawer/Drawer.stories.tsx +1 -1
- package/src/components/ui/form-field/FormField.stories.tsx +1 -1
- package/src/components/ui/help-tip/HelpTip.stories.tsx +1 -1
- package/src/components/ui/icon-box/IconBox.stories.tsx +1 -1
- package/src/components/ui/index.ts +1 -0
- package/src/components/ui/indicator/Indicator.stories.tsx +38 -2
- package/src/components/ui/indicator/Indicator.test.tsx +20 -1
- package/src/components/ui/indicator/Indicator.tsx +50 -6
- package/src/components/ui/indicator/index.ts +1 -1
- package/src/components/ui/input/Input.stories.tsx +1 -1
- package/src/components/ui/link/Link.stories.tsx +1 -1
- package/src/components/ui/list-item/ListItem.stories.tsx +1 -1
- package/src/components/ui/menu/Menu.stories.tsx +1 -1
- package/src/components/ui/modal/Modal.stories.tsx +1 -1
- package/src/components/ui/pill/Pill.stories.tsx +1 -1
- package/src/components/ui/popover/Popover.stories.tsx +1 -1
- package/src/components/ui/progress/Progress.stories.tsx +1 -1
- package/src/components/ui/radio/Radio.stories.tsx +1 -1
- package/src/components/ui/section/Section.stories.tsx +1 -1
- package/src/components/ui/select/Select.stories.tsx +1 -1
- package/src/components/ui/skeleton/Skeleton.stories.tsx +1 -1
- package/src/components/ui/spinner/Spinner.stories.tsx +1 -1
- package/src/components/ui/spinner/Spinner.tsx +3 -2
- package/src/components/ui/stack/Stack.stories.tsx +1 -1
- package/src/components/ui/surface/Surface.stories.tsx +1 -1
- package/src/components/ui/switch/Switch.stories.tsx +1 -1
- package/src/components/ui/tabs/Tabs.stories.tsx +1 -1
- package/src/components/ui/tile/Tile.stories.tsx +79 -0
- package/src/components/ui/tile/Tile.test.tsx +48 -0
- package/src/components/ui/tile/Tile.tsx +64 -0
- package/src/components/ui/tile/index.ts +2 -0
- package/src/components/ui/toast/Toast.stories.tsx +1 -1
- package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +1 -1
- package/src/components/ui/toolbar-button/ToolbarButton.tsx +2 -1
- package/src/components/ui/tooltip/Tooltip.stories.tsx +1 -1
- package/src/examples/react-hook-form/ReactHookForm.stories.tsx +1 -1
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useTimer.test.ts +150 -0
- package/src/hooks/useTimer.ts +77 -0
- package/src/index.ts +3 -0
- package/src/pages.ts +1 -1
- package/src/stories/PresetShowcase.stories.tsx +1 -1
- package/src/stories/ThemePresets.stories.tsx +1 -1
- package/src/theme/ColorSystem.stories.tsx +323 -0
- package/src/theme/Colors.stories.tsx +74 -9
- package/src/theme/barrel.ts +1 -0
- package/src/theme/config.ts +20 -3
- package/src/theme/elevation.stories.tsx +1 -1
- package/src/theme/extracted-colors-dataviz.ts +21 -0
- package/src/theme/extracted-colors-ui.ts +20 -0
- package/src/theme/global.css +69 -53
- package/src/theme/gradients.test.ts +25 -0
- package/src/theme/gradients.ts +36 -0
- package/src/theme/shadows.stories.tsx +1 -1
- package/src/theme/tokens/primitives.test.ts +232 -0
- package/src/theme/tokens/primitives.ts +238 -87
- package/src/theme/tokens/semantic.ts +101 -81
- package/src/theme/workout-tokens.ts +26 -21
- package/src/utils/avatar-color.ts +3 -3
- package/tailwind.config.js +15 -3
package/dist/pages.js
CHANGED
|
@@ -8,22 +8,160 @@ var tailwindMerge = require('tailwind-merge');
|
|
|
8
8
|
|
|
9
9
|
// src/components/custom/Workout/ActiveWorkoutPage.tsx
|
|
10
10
|
|
|
11
|
+
// src/theme/tokens/primitives.ts
|
|
12
|
+
var primitiveColors = {
|
|
13
|
+
// Blue scale
|
|
14
|
+
blue: {
|
|
15
|
+
400: "#60A5FA",
|
|
16
|
+
600: "#5048E5",
|
|
17
|
+
700: "#3832A0"},
|
|
18
|
+
// Red scale
|
|
19
|
+
red: {
|
|
20
|
+
500: "#EF4444",
|
|
21
|
+
600: "#D14343"},
|
|
22
|
+
// Vivid red scale
|
|
23
|
+
redVivid: {
|
|
24
|
+
400: "#FF6070",
|
|
25
|
+
500: "#FF4757",
|
|
26
|
+
700: "#C42539"},
|
|
27
|
+
// Neutral/Gray scale
|
|
28
|
+
neutral: {
|
|
29
|
+
50: "#FAFAFA",
|
|
30
|
+
100: "#F3F4F6",
|
|
31
|
+
300: "#D1D5DB",
|
|
32
|
+
400: "#9CA3AF",
|
|
33
|
+
500: "#6B7280",
|
|
34
|
+
600: "#4B5563",
|
|
35
|
+
900: "#111827"},
|
|
36
|
+
// Charcoal scale (dark backgrounds)
|
|
37
|
+
charcoal: {
|
|
38
|
+
200: "#3C3C3C",
|
|
39
|
+
300: "#2C2C2C",
|
|
40
|
+
400: "#1F1F1F",
|
|
41
|
+
500: "#1C1C1C",
|
|
42
|
+
600: "#191919",
|
|
43
|
+
700: "#161616",
|
|
44
|
+
900: "#101010"
|
|
45
|
+
},
|
|
46
|
+
// Pure colors
|
|
47
|
+
white: "#FFFFFF"};
|
|
48
|
+
var primitiveRamps = {
|
|
49
|
+
red: {
|
|
50
|
+
50: "#FFF4F4",
|
|
51
|
+
500: "#E05254",
|
|
52
|
+
600: "#D14343",
|
|
53
|
+
// pin
|
|
54
|
+
700: "#A4221C",
|
|
55
|
+
800: "#7E1002"},
|
|
56
|
+
orange: {
|
|
57
|
+
200: "#FFC7A2",
|
|
58
|
+
300: "#FFA063",
|
|
59
|
+
400: "#FF7900",
|
|
60
|
+
// pin
|
|
61
|
+
500: "#DA5F00",
|
|
62
|
+
600: "#B94A00"},
|
|
63
|
+
amber: {
|
|
64
|
+
50: "#FFF7DD",
|
|
65
|
+
200: "#FFD352",
|
|
66
|
+
300: "#F9B415",
|
|
67
|
+
// pin
|
|
68
|
+
400: "#E08C00",
|
|
69
|
+
500: "#C27400"},
|
|
70
|
+
green: {
|
|
71
|
+
50: "#E3FFEE",
|
|
72
|
+
200: "#58F69E",
|
|
73
|
+
300: "#2ED573",
|
|
74
|
+
// pin
|
|
75
|
+
400: "#21C05D",
|
|
76
|
+
500: "#22A444",
|
|
77
|
+
600: "#298732"},
|
|
78
|
+
cyan: {
|
|
79
|
+
// pin
|
|
80
|
+
400: "#01B5D1",
|
|
81
|
+
500: "#2697B7",
|
|
82
|
+
600: "#307B9B",
|
|
83
|
+
700: "#2A617F",
|
|
84
|
+
800: "#22465F",
|
|
85
|
+
900: "#0B3149"},
|
|
86
|
+
blue: {
|
|
87
|
+
50: "#EFF8FF",
|
|
88
|
+
300: "#78C2FF",
|
|
89
|
+
500: "#2196F3",
|
|
90
|
+
// pin
|
|
91
|
+
600: "#1072CB"},
|
|
92
|
+
magenta: {
|
|
93
|
+
600: "#BA2996"}
|
|
94
|
+
};
|
|
95
|
+
var sequentialEffort = [
|
|
96
|
+
primitiveRamps.green[300],
|
|
97
|
+
primitiveRamps.amber[200],
|
|
98
|
+
primitiveRamps.amber[300],
|
|
99
|
+
primitiveRamps.orange[400],
|
|
100
|
+
primitiveRamps.red[600],
|
|
101
|
+
primitiveRamps.red[700]
|
|
102
|
+
];
|
|
103
|
+
var discreteRainbow = [
|
|
104
|
+
"#E8ECFB",
|
|
105
|
+
"#D9CCE3",
|
|
106
|
+
"#D1BBD7",
|
|
107
|
+
"#CAACCB",
|
|
108
|
+
"#BA8DB4",
|
|
109
|
+
"#AE76A3",
|
|
110
|
+
"#AA6F9E",
|
|
111
|
+
"#994F88",
|
|
112
|
+
"#882E72",
|
|
113
|
+
"#1965B0",
|
|
114
|
+
"#437DBF",
|
|
115
|
+
"#5289C7",
|
|
116
|
+
"#6195CF",
|
|
117
|
+
"#7BAFDE",
|
|
118
|
+
"#4EB265",
|
|
119
|
+
"#90C987",
|
|
120
|
+
"#CAE0AB",
|
|
121
|
+
"#F7F056",
|
|
122
|
+
"#F7CB45",
|
|
123
|
+
"#F6C141",
|
|
124
|
+
"#F4A736",
|
|
125
|
+
"#F1932D",
|
|
126
|
+
"#EE8026",
|
|
127
|
+
"#E8601C",
|
|
128
|
+
"#E65518",
|
|
129
|
+
"#DC050C",
|
|
130
|
+
"#A5170E",
|
|
131
|
+
"#72190E",
|
|
132
|
+
"#42150A"
|
|
133
|
+
];
|
|
134
|
+
|
|
11
135
|
// src/theme/workout-tokens.ts
|
|
12
136
|
var WORKOUT_TOKENS = {
|
|
13
137
|
// Canonical 4-band performance scale — the single source for BOTH the
|
|
14
138
|
// VelocityStrip zone bars and the SetRow RPE color (TD-03.43). The direction
|
|
15
139
|
// is intentionally inverted between the two consumers: for velocity, green =
|
|
16
|
-
// fastest/best; for RPE, green = easiest.
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
140
|
+
// fastest/best; for RPE, green = easiest. This is the [0,2,3,4] subsample of
|
|
141
|
+
// the canonical `sequentialEffort` primitive: an EVEN hue walk across the ramp
|
|
142
|
+
// (green → gold → orange → red). The earlier [0,1,2,4] spent two of its four
|
|
143
|
+
// bands on adjacent yellows (amber-200 + amber-300) and skipped orange, reading
|
|
144
|
+
// yellow-heavy with an abrupt jump to red; sampling amber-300 + orange-400
|
|
145
|
+
// instead gives four cleanly separable bands that hold at 3px strip scale.
|
|
146
|
+
// Consumed inline (RN).
|
|
21
147
|
scale: {
|
|
22
|
-
green:
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
148
|
+
green: sequentialEffort[0],
|
|
149
|
+
// green-300
|
|
150
|
+
yellow: sequentialEffort[2],
|
|
151
|
+
// amber-300 (gold)
|
|
152
|
+
orange: sequentialEffort[3],
|
|
153
|
+
// orange-400 (true orange)
|
|
154
|
+
red: sequentialEffort[4]
|
|
155
|
+
// red-600
|
|
26
156
|
},
|
|
157
|
+
// Surface and border colors were removed here: those flip with the theme, so
|
|
158
|
+
// components use the CSS custom properties (var(--color-surface-*/border-*))
|
|
159
|
+
// directly. Only theme-independent data-viz values remain below.
|
|
160
|
+
// Intensity bar specific — over-target tiers deepen along the red ramp.
|
|
161
|
+
intensity: {
|
|
162
|
+
// matches status-error
|
|
163
|
+
over2: primitiveRamps.red[700],
|
|
164
|
+
over3: primitiveRamps.red[800]},
|
|
27
165
|
// Placeholder strip
|
|
28
166
|
placeholder: {
|
|
29
167
|
fill: "#3A3A3A"
|
|
@@ -33,12 +171,6 @@ var WORKOUT_TOKENS = {
|
|
|
33
171
|
function roundRpe(rpe) {
|
|
34
172
|
return Math.round(rpe * 2) / 2;
|
|
35
173
|
}
|
|
36
|
-
function rpeColor(rpe) {
|
|
37
|
-
if (rpe >= 9.5) return WORKOUT_TOKENS.scale.red;
|
|
38
|
-
if (rpe >= 8.5) return WORKOUT_TOKENS.scale.orange;
|
|
39
|
-
if (rpe >= 7) return WORKOUT_TOKENS.scale.yellow;
|
|
40
|
-
return WORKOUT_TOKENS.scale.green;
|
|
41
|
-
}
|
|
42
174
|
function roundWeight(weight) {
|
|
43
175
|
return Math.round(weight);
|
|
44
176
|
}
|
|
@@ -66,14 +198,258 @@ function wrapJsx(fn) {
|
|
|
66
198
|
var jsx = wrapJsx(jsxRuntime.jsx);
|
|
67
199
|
var jsxs = wrapJsx(jsxRuntime.jsxs);
|
|
68
200
|
|
|
201
|
+
// src/components/custom/Workout/SegmentedBar.tsx
|
|
202
|
+
var PULSE_HALF_MS = 950;
|
|
203
|
+
var PULSE_MIN_OPACITY = 0.45;
|
|
204
|
+
var SEGMENTED_BAR_GAP = 5;
|
|
205
|
+
function usePulse(active) {
|
|
206
|
+
const [value] = react.useState(() => new reactNative.Animated.Value(0));
|
|
207
|
+
react.useEffect(() => {
|
|
208
|
+
if (!active) return;
|
|
209
|
+
const loop = reactNative.Animated.loop(
|
|
210
|
+
reactNative.Animated.sequence([
|
|
211
|
+
reactNative.Animated.timing(value, {
|
|
212
|
+
toValue: 1,
|
|
213
|
+
duration: PULSE_HALF_MS,
|
|
214
|
+
easing: reactNative.Easing.inOut(reactNative.Easing.ease),
|
|
215
|
+
useNativeDriver: false
|
|
216
|
+
}),
|
|
217
|
+
reactNative.Animated.timing(value, {
|
|
218
|
+
toValue: 0,
|
|
219
|
+
duration: PULSE_HALF_MS,
|
|
220
|
+
easing: reactNative.Easing.inOut(reactNative.Easing.ease),
|
|
221
|
+
useNativeDriver: false
|
|
222
|
+
})
|
|
223
|
+
])
|
|
224
|
+
);
|
|
225
|
+
loop.start();
|
|
226
|
+
return () => loop.stop();
|
|
227
|
+
}, [active, value]);
|
|
228
|
+
return value;
|
|
229
|
+
}
|
|
230
|
+
function SegmentedBar({
|
|
231
|
+
segments,
|
|
232
|
+
height = 8,
|
|
233
|
+
gap = SEGMENTED_BAR_GAP,
|
|
234
|
+
radius = 2,
|
|
235
|
+
marker = null,
|
|
236
|
+
segmentTestID,
|
|
237
|
+
style,
|
|
238
|
+
...props
|
|
239
|
+
}) {
|
|
240
|
+
const pulse = usePulse(segments.some((s) => s.pulse));
|
|
241
|
+
return /* @__PURE__ */ jsxs(reactNative.View, { style: [{ flexDirection: "row", height, gap, position: "relative" }, style], ...props, children: [
|
|
242
|
+
segments.map((seg, i) => {
|
|
243
|
+
const fillStyle = {
|
|
244
|
+
width: `${(seg.fill ?? 1) * 100}%`,
|
|
245
|
+
height: "100%",
|
|
246
|
+
backgroundColor: seg.color,
|
|
247
|
+
opacity: seg.opacity
|
|
248
|
+
};
|
|
249
|
+
const testID = segmentTestID?.(seg, i) ?? "segmented-bar-segment";
|
|
250
|
+
return /* @__PURE__ */ jsx(
|
|
251
|
+
reactNative.View,
|
|
252
|
+
{
|
|
253
|
+
style: {
|
|
254
|
+
flex: seg.weight ?? 1,
|
|
255
|
+
minWidth: 0,
|
|
256
|
+
height: "100%",
|
|
257
|
+
marginLeft: seg.leadingGap,
|
|
258
|
+
borderRadius: radius,
|
|
259
|
+
overflow: "hidden"
|
|
260
|
+
},
|
|
261
|
+
children: seg.pulse ? /* @__PURE__ */ jsx(
|
|
262
|
+
reactNative.Animated.View,
|
|
263
|
+
{
|
|
264
|
+
style: {
|
|
265
|
+
...fillStyle,
|
|
266
|
+
...seg.pulseColor ? {
|
|
267
|
+
backgroundColor: pulse.interpolate({
|
|
268
|
+
inputRange: [0, 1],
|
|
269
|
+
outputRange: seg.pulseColor
|
|
270
|
+
})
|
|
271
|
+
} : {
|
|
272
|
+
opacity: pulse.interpolate({
|
|
273
|
+
inputRange: [0, 1],
|
|
274
|
+
outputRange: [PULSE_MIN_OPACITY, 1]
|
|
275
|
+
})
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
accessibilityElementsHidden: true,
|
|
279
|
+
testID
|
|
280
|
+
}
|
|
281
|
+
) : /* @__PURE__ */ jsx(reactNative.View, { style: fillStyle, accessibilityElementsHidden: true, testID })
|
|
282
|
+
},
|
|
283
|
+
i
|
|
284
|
+
);
|
|
285
|
+
}),
|
|
286
|
+
marker ? /* @__PURE__ */ jsx(
|
|
287
|
+
reactNative.View,
|
|
288
|
+
{
|
|
289
|
+
style: {
|
|
290
|
+
position: "absolute",
|
|
291
|
+
left: `${marker.position * 100}%`,
|
|
292
|
+
top: 0,
|
|
293
|
+
bottom: 0,
|
|
294
|
+
width: 2,
|
|
295
|
+
backgroundColor: marker.color
|
|
296
|
+
},
|
|
297
|
+
accessibilityElementsHidden: true,
|
|
298
|
+
testID: "segmented-bar-marker"
|
|
299
|
+
}
|
|
300
|
+
) : null
|
|
301
|
+
] });
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// src/components/custom/Workout/SetBar.tsx
|
|
305
|
+
var SET_STRIP_ZONES = {
|
|
306
|
+
slow: primitiveRamps.red[600],
|
|
307
|
+
moderate: primitiveRamps.orange[400],
|
|
308
|
+
fast: primitiveRamps.amber[300],
|
|
309
|
+
fastest: primitiveRamps.green[300]
|
|
310
|
+
};
|
|
311
|
+
var TODO_COLOR = primitiveColors.charcoal[300];
|
|
312
|
+
var SET_STRIP_VARIABLE_COLOR = primitiveRamps.cyan[900];
|
|
313
|
+
var NOTCH_GAP = 2;
|
|
314
|
+
var CLUSTER_GAP = 3;
|
|
315
|
+
var MYO_UPCOMING_CLUSTERS = 3;
|
|
316
|
+
var MYO_UPCOMING_CLUSTER_LEN = 5;
|
|
317
|
+
var MYO_UPCOMING_FADE = 0.6;
|
|
318
|
+
var PULSE_RANGE = {
|
|
319
|
+
[SET_STRIP_ZONES.slow]: [primitiveRamps.red[500], primitiveRamps.red[700]],
|
|
320
|
+
[SET_STRIP_ZONES.moderate]: [primitiveRamps.orange[300], primitiveRamps.orange[500]],
|
|
321
|
+
[SET_STRIP_ZONES.fast]: [primitiveRamps.amber[200], primitiveRamps.amber[400]],
|
|
322
|
+
[SET_STRIP_ZONES.fastest]: [primitiveRamps.green[200], primitiveRamps.green[400]]
|
|
323
|
+
};
|
|
324
|
+
function velocityZoneColor(v) {
|
|
325
|
+
if (v < 0.5) return SET_STRIP_ZONES.slow;
|
|
326
|
+
if (v < 0.75) return SET_STRIP_ZONES.moderate;
|
|
327
|
+
if (v < 1) return SET_STRIP_ZONES.fast;
|
|
328
|
+
return SET_STRIP_ZONES.fastest;
|
|
329
|
+
}
|
|
330
|
+
function chunkedSegments(chunks, gap) {
|
|
331
|
+
return chunks.flatMap(
|
|
332
|
+
(vels, ci) => vels.map((v, ri) => ({
|
|
333
|
+
color: velocityZoneColor(v),
|
|
334
|
+
...ci > 0 && ri === 0 ? { leadingGap: gap } : {}
|
|
335
|
+
}))
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
function rangeSegments(floor, max, doneVels) {
|
|
339
|
+
return Array.from({ length: max }, (_, i) => {
|
|
340
|
+
if (i < doneVels.length) return { color: velocityZoneColor(doneVels[i]) };
|
|
341
|
+
return { color: i < floor ? TODO_COLOR : SET_STRIP_VARIABLE_COLOR };
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
function myoUpcomingSegments(activationLen, clusterCount) {
|
|
345
|
+
const activation = Array.from({ length: activationLen }, () => ({ color: TODO_COLOR }));
|
|
346
|
+
const trail = Array.from(
|
|
347
|
+
{ length: clusterCount },
|
|
348
|
+
(_, ci) => Array.from({ length: MYO_UPCOMING_CLUSTER_LEN }, (_2, ri) => ({
|
|
349
|
+
color: SET_STRIP_VARIABLE_COLOR,
|
|
350
|
+
opacity: MYO_UPCOMING_FADE ** ci,
|
|
351
|
+
...ri === 0 ? { leadingGap: CLUSTER_GAP } : {}
|
|
352
|
+
}))
|
|
353
|
+
).flat();
|
|
354
|
+
return [...activation, ...trail];
|
|
355
|
+
}
|
|
356
|
+
function setSegments(set) {
|
|
357
|
+
if (set.status === "todo") {
|
|
358
|
+
return [{ color: TODO_COLOR }];
|
|
359
|
+
}
|
|
360
|
+
if (set.status === "done") {
|
|
361
|
+
return set.velocities.map((v) => ({ color: velocityZoneColor(v) }));
|
|
362
|
+
}
|
|
363
|
+
if (set.status === "range") {
|
|
364
|
+
return rangeSegments(set.floor, set.max, set.doneVels);
|
|
365
|
+
}
|
|
366
|
+
if (set.status === "drop") {
|
|
367
|
+
return chunkedSegments(set.subloads, NOTCH_GAP);
|
|
368
|
+
}
|
|
369
|
+
if (set.status === "myo") {
|
|
370
|
+
return chunkedSegments([set.activation, ...set.clusters], CLUSTER_GAP);
|
|
371
|
+
}
|
|
372
|
+
if (set.status === "myo-upcoming") {
|
|
373
|
+
return myoUpcomingSegments(set.activationLen, set.clusterCount ?? MYO_UPCOMING_CLUSTERS);
|
|
374
|
+
}
|
|
375
|
+
const performed = set.velocities.map((v) => {
|
|
376
|
+
const color = velocityZoneColor(v);
|
|
377
|
+
return { color, pulse: true, pulseColor: PULSE_RANGE[color] };
|
|
378
|
+
});
|
|
379
|
+
const remaining = Math.max(0, set.planned - set.velocities.length);
|
|
380
|
+
return [...performed, ...Array.from({ length: remaining }, () => ({ color: TODO_COLOR }))];
|
|
381
|
+
}
|
|
382
|
+
function setBarSegmentTestID(seg) {
|
|
383
|
+
if (seg.pulse) return "set-strip-pulse";
|
|
384
|
+
if (seg.color === SET_STRIP_VARIABLE_COLOR) return "set-strip-variable";
|
|
385
|
+
return seg.color === TODO_COLOR ? "set-strip-empty" : "set-strip-fill";
|
|
386
|
+
}
|
|
387
|
+
function SetBar({ set, height = 8 }) {
|
|
388
|
+
return /* @__PURE__ */ jsx(
|
|
389
|
+
SegmentedBar,
|
|
390
|
+
{
|
|
391
|
+
segments: setSegments(set),
|
|
392
|
+
height,
|
|
393
|
+
gap: 0,
|
|
394
|
+
radius: 0,
|
|
395
|
+
segmentTestID: setBarSegmentTestID,
|
|
396
|
+
style: { flex: 1, minWidth: 0, borderRadius: 2, overflow: "hidden" },
|
|
397
|
+
testID: "set-strip-set"
|
|
398
|
+
}
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// src/components/custom/Workout/SetStrip.tsx
|
|
403
|
+
var SET_STRIP_GAP = 5;
|
|
404
|
+
function setCategory(set) {
|
|
405
|
+
switch (set.status) {
|
|
406
|
+
case "done":
|
|
407
|
+
case "drop":
|
|
408
|
+
case "myo":
|
|
409
|
+
return "done";
|
|
410
|
+
case "active":
|
|
411
|
+
return "active";
|
|
412
|
+
case "range":
|
|
413
|
+
return set.doneVels.length > 0 ? "active" : "upcoming";
|
|
414
|
+
case "todo":
|
|
415
|
+
case "myo-upcoming":
|
|
416
|
+
return "upcoming";
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
function describeSets(sets) {
|
|
420
|
+
const done = sets.filter((s) => setCategory(s) === "done").length;
|
|
421
|
+
const active = sets.filter((s) => setCategory(s) === "active").length;
|
|
422
|
+
const upcoming = sets.filter((s) => setCategory(s) === "upcoming").length;
|
|
423
|
+
return `Set progress: ${done} done, ${active} in progress, ${upcoming} upcoming`;
|
|
424
|
+
}
|
|
425
|
+
function SetStrip({ sets, height = 8, className, ...props }) {
|
|
426
|
+
return /* @__PURE__ */ jsx(
|
|
427
|
+
reactNative.View,
|
|
428
|
+
{
|
|
429
|
+
className,
|
|
430
|
+
style: { flexDirection: "row", width: "100%", height, gap: SET_STRIP_GAP },
|
|
431
|
+
accessibilityRole: "image",
|
|
432
|
+
accessibilityLabel: describeSets(sets),
|
|
433
|
+
testID: "set-strip",
|
|
434
|
+
...props,
|
|
435
|
+
children: sets.map((set, i) => /* @__PURE__ */ jsx(SetBar, { set, height }, i))
|
|
436
|
+
}
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
|
|
69
440
|
// src/components/custom/Workout/VelocityStrip.tsx
|
|
70
441
|
var VEL_COLORS = WORKOUT_TOKENS.scale;
|
|
71
|
-
var
|
|
72
|
-
speed:
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
442
|
+
var bandIdToEffortColor = {
|
|
443
|
+
speed: sequentialEffort[0],
|
|
444
|
+
// green-300
|
|
445
|
+
power: sequentialEffort[2],
|
|
446
|
+
// amber-300 (gold)
|
|
447
|
+
strengthSpeed: sequentialEffort[3],
|
|
448
|
+
// orange-400
|
|
449
|
+
maximalStrength: sequentialEffort[4],
|
|
450
|
+
// red-600
|
|
451
|
+
grinding: sequentialEffort[5]
|
|
452
|
+
// red-700 — the distinct 5th band
|
|
77
453
|
};
|
|
78
454
|
function getVelocityZoneColor(velocity) {
|
|
79
455
|
if (velocity >= 1) return "vel-green";
|
|
@@ -112,14 +488,132 @@ function classifyBand(velocity, bands) {
|
|
|
112
488
|
return bands[bands.length - 1];
|
|
113
489
|
}
|
|
114
490
|
function bandColor(band) {
|
|
115
|
-
|
|
116
|
-
return token ? VEL_COLORS[token] : VEL_COLORS.green;
|
|
491
|
+
return bandIdToEffortColor[band.id] ?? VEL_COLORS.green;
|
|
117
492
|
}
|
|
118
493
|
function getLossStyle(loss) {
|
|
119
494
|
if (loss > 25) return { color: VEL_COLORS.red };
|
|
120
495
|
if (loss > 20) return { color: VEL_COLORS.orange };
|
|
121
496
|
return null;
|
|
122
497
|
}
|
|
498
|
+
var REP_GAP = 2;
|
|
499
|
+
var WIDE_GAP = 8;
|
|
500
|
+
var TODO_COLOR2 = primitiveColors.charcoal[300];
|
|
501
|
+
var CONTINUE_OUTLINE = primitiveRamps.cyan[800];
|
|
502
|
+
function deriveDoneVelocities(set) {
|
|
503
|
+
switch (set.type) {
|
|
504
|
+
case "drop":
|
|
505
|
+
return set.subloads.flat();
|
|
506
|
+
case "myo":
|
|
507
|
+
return [...set.activation, ...set.clusters.flat()];
|
|
508
|
+
default:
|
|
509
|
+
return set.velocities;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
function chunkedRepSlots(chunks) {
|
|
513
|
+
const slots = [];
|
|
514
|
+
chunks.forEach((chunk) => {
|
|
515
|
+
chunk.forEach((velocity, ri) => {
|
|
516
|
+
const first = slots.length === 0;
|
|
517
|
+
slots.push({ kind: "rep", velocity, leadingGap: first ? 0 : ri === 0 ? WIDE_GAP : REP_GAP });
|
|
518
|
+
});
|
|
519
|
+
});
|
|
520
|
+
return slots;
|
|
521
|
+
}
|
|
522
|
+
function buildSlots(set) {
|
|
523
|
+
switch (set.type) {
|
|
524
|
+
case "straight": {
|
|
525
|
+
const total = Math.max(set.velocities.length, set.planned ?? set.velocities.length);
|
|
526
|
+
return Array.from({ length: total }, (_, i) => {
|
|
527
|
+
const done = i < set.velocities.length;
|
|
528
|
+
return {
|
|
529
|
+
kind: done ? "rep" : "todo",
|
|
530
|
+
velocity: done ? set.velocities[i] : void 0,
|
|
531
|
+
leadingGap: i === 0 ? 0 : REP_GAP
|
|
532
|
+
};
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
case "range": {
|
|
536
|
+
const total = Math.max(set.max, set.velocities.length);
|
|
537
|
+
return Array.from({ length: total }, (_, i) => {
|
|
538
|
+
const kind = i < set.velocities.length ? "rep" : i < set.floor ? "todo" : "variable";
|
|
539
|
+
return {
|
|
540
|
+
kind,
|
|
541
|
+
velocity: kind === "rep" ? set.velocities[i] : void 0,
|
|
542
|
+
leadingGap: i === 0 ? 0 : REP_GAP
|
|
543
|
+
};
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
case "amrap": {
|
|
547
|
+
const reps = set.velocities.map((velocity, i) => ({
|
|
548
|
+
kind: "rep",
|
|
549
|
+
velocity,
|
|
550
|
+
leadingGap: i === 0 ? 0 : REP_GAP
|
|
551
|
+
}));
|
|
552
|
+
reps.push({ kind: "continue", leadingGap: reps.length === 0 ? 0 : REP_GAP });
|
|
553
|
+
return reps;
|
|
554
|
+
}
|
|
555
|
+
case "drop":
|
|
556
|
+
return chunkedRepSlots(set.subloads);
|
|
557
|
+
case "myo": {
|
|
558
|
+
const slots = chunkedRepSlots([set.activation, ...set.clusters]);
|
|
559
|
+
if (set.open) slots.push({ kind: "continue", leadingGap: slots.length === 0 ? 0 : REP_GAP });
|
|
560
|
+
return slots;
|
|
561
|
+
}
|
|
562
|
+
case "cluster": {
|
|
563
|
+
const total = Math.max(set.velocities.length, set.planned ?? set.velocities.length);
|
|
564
|
+
return Array.from({ length: total }, (_, i) => {
|
|
565
|
+
const done = i < set.velocities.length;
|
|
566
|
+
const boundary = i > 0 && i % set.groupSize === 0;
|
|
567
|
+
return {
|
|
568
|
+
kind: done ? "rep" : "todo",
|
|
569
|
+
velocity: done ? set.velocities[i] : void 0,
|
|
570
|
+
leadingGap: i === 0 ? 0 : boundary ? WIDE_GAP : REP_GAP
|
|
571
|
+
};
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
function setAccessibilityLabel(set, repCount) {
|
|
577
|
+
switch (set.type) {
|
|
578
|
+
case "straight":
|
|
579
|
+
return `Velocity strip, straight set, ${repCount} reps`;
|
|
580
|
+
case "range":
|
|
581
|
+
return `Velocity strip, rep-range set, floor ${set.floor} to ${set.max}, ${repCount} reps done`;
|
|
582
|
+
case "amrap":
|
|
583
|
+
return `Velocity strip, AMRAP set, ${repCount} reps and counting`;
|
|
584
|
+
case "drop":
|
|
585
|
+
return `Velocity strip, drop set, ${set.subloads.length} loads, ${repCount} reps`;
|
|
586
|
+
case "myo":
|
|
587
|
+
return `Velocity strip, myo-reps set, ${set.clusters.length} clusters${set.open ? ", open" : ""}, ${repCount} reps`;
|
|
588
|
+
case "cluster":
|
|
589
|
+
return `Velocity strip, cluster set, groups of ${set.groupSize}, ${repCount} reps`;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
function slotAccessibilityLabel(slot, index) {
|
|
593
|
+
switch (slot.kind) {
|
|
594
|
+
case "rep":
|
|
595
|
+
return `Rep ${index + 1}: ${formatVelocity(slot.velocity ?? 0)} meters per second`;
|
|
596
|
+
case "todo":
|
|
597
|
+
return `Rep ${index + 1}: planned`;
|
|
598
|
+
case "variable":
|
|
599
|
+
return `Rep ${index + 1}: variable`;
|
|
600
|
+
case "continue":
|
|
601
|
+
return "Keep going";
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
var EXPANDED_TODO_STUB_PCT = 16;
|
|
605
|
+
var EXPANDED_ENCODED_PCT = 45;
|
|
606
|
+
var EXPANDED_HEIGHT = 60;
|
|
607
|
+
var FIXED_MAX_VELOCITY = 1.15;
|
|
608
|
+
var BARE_STUB_HEIGHT = 3;
|
|
609
|
+
function scaleDenominator(scale, maxVelocity) {
|
|
610
|
+
return scale === "fixed" ? FIXED_MAX_VELOCITY : maxVelocity * 1.15;
|
|
611
|
+
}
|
|
612
|
+
function bareSlotHeight(slot, height, denom) {
|
|
613
|
+
if (slot.kind !== "rep" || denom <= 0) return BARE_STUB_HEIGHT;
|
|
614
|
+
const ratio = Math.min(1, (slot.velocity ?? 0) / denom);
|
|
615
|
+
return Math.max(BARE_STUB_HEIGHT, ratio * height);
|
|
616
|
+
}
|
|
123
617
|
function getReducedMotionPreference() {
|
|
124
618
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
|
|
125
619
|
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
@@ -141,31 +635,48 @@ var ANIMATION_EASING = reactNative.Easing.bezier(0.22, 1, 0.36, 1);
|
|
|
141
635
|
var POP_EASING = reactNative.Easing.bezier(0.34, 1.56, 0.64, 1);
|
|
142
636
|
function VelocityStrip({
|
|
143
637
|
velocities,
|
|
638
|
+
set,
|
|
144
639
|
zones,
|
|
145
640
|
liveRepIndex,
|
|
146
|
-
expanded =
|
|
641
|
+
expanded = true,
|
|
147
642
|
onToggle,
|
|
148
643
|
onRepPress,
|
|
149
|
-
variant = "
|
|
644
|
+
variant = "expanded",
|
|
645
|
+
height = EXPANDED_HEIGHT,
|
|
646
|
+
scale = "peak",
|
|
647
|
+
showNumbers = true,
|
|
150
648
|
showInfo = true,
|
|
151
649
|
className,
|
|
152
650
|
...props
|
|
153
651
|
}) {
|
|
154
|
-
const
|
|
155
|
-
const
|
|
156
|
-
|
|
652
|
+
const doneVelocities = set ? deriveDoneVelocities(set) : velocities ?? [];
|
|
653
|
+
const slots = set ? buildSlots(set) : doneVelocities.map((v, i) => ({
|
|
654
|
+
kind: "rep",
|
|
655
|
+
velocity: v,
|
|
656
|
+
leadingGap: i === 0 ? 0 : REP_GAP
|
|
657
|
+
}));
|
|
658
|
+
const maxVelocity = Math.max(...doneVelocities, 0);
|
|
659
|
+
const meanVelocity = calculateMeanVelocity(doneVelocities);
|
|
660
|
+
const loss = calculateVelocityLoss(doneVelocities);
|
|
661
|
+
const framed = showNumbers || showInfo;
|
|
662
|
+
const scaleDenom = scaleDenominator(scale, maxVelocity);
|
|
157
663
|
const hasZones = zones != null && zones.length > 0;
|
|
158
664
|
const barColorFor = (v) => hasZones ? bandColor(classifyBand(v, zones)) : zoneHexMap[getVelocityZoneColor(v)];
|
|
665
|
+
const slotColor = (slot) => {
|
|
666
|
+
if (slot.kind === "rep") return barColorFor(slot.velocity ?? 0);
|
|
667
|
+
if (slot.kind === "todo") return TODO_COLOR2;
|
|
668
|
+
return SET_STRIP_VARIABLE_COLOR;
|
|
669
|
+
};
|
|
159
670
|
const meanZone = hasZones ? classifyBand(meanVelocity, zones)?.label ?? "" : getVelocityZoneName(meanVelocity);
|
|
160
671
|
const prefersReducedMotion = usePrefersReducedMotion();
|
|
161
|
-
const [heightAnim] = react.useState(() => new reactNative.Animated.Value(expanded ?
|
|
672
|
+
const [heightAnim] = react.useState(() => new reactNative.Animated.Value(expanded ? height : 3));
|
|
162
673
|
const [labelOpacity] = react.useState(() => new reactNative.Animated.Value(expanded ? 1 : 0));
|
|
163
674
|
const [infoOpacity] = react.useState(() => new reactNative.Animated.Value(expanded ? 1 : 0));
|
|
164
675
|
const [liveScale] = react.useState(() => new reactNative.Animated.Value(1));
|
|
165
|
-
const liveVelocity = liveRepIndex != null ?
|
|
676
|
+
const liveVelocity = liveRepIndex != null ? doneVelocities[liveRepIndex] : void 0;
|
|
166
677
|
const isNewPeak = liveVelocity != null && maxVelocity > 0 && liveVelocity === maxVelocity;
|
|
167
678
|
react.useEffect(() => {
|
|
168
|
-
if (variant
|
|
679
|
+
if (variant !== "expanded" || !framed || liveRepIndex == null || liveVelocity == null) return;
|
|
169
680
|
if (prefersReducedMotion) {
|
|
170
681
|
liveScale.setValue(1);
|
|
171
682
|
return;
|
|
@@ -195,12 +706,12 @@ function VelocityStrip({
|
|
|
195
706
|
useNativeDriver: true
|
|
196
707
|
}).start();
|
|
197
708
|
}
|
|
198
|
-
}, [variant, liveRepIndex, liveVelocity, isNewPeak, prefersReducedMotion, liveScale]);
|
|
709
|
+
}, [variant, framed, liveRepIndex, liveVelocity, isNewPeak, prefersReducedMotion, liveScale]);
|
|
199
710
|
react.useEffect(() => {
|
|
200
|
-
if (variant
|
|
711
|
+
if (variant !== "expanded" || !framed) return;
|
|
201
712
|
reactNative.Animated.parallel([
|
|
202
713
|
reactNative.Animated.timing(heightAnim, {
|
|
203
|
-
toValue: expanded ?
|
|
714
|
+
toValue: expanded ? height : 3,
|
|
204
715
|
duration: ANIMATION_DURATION,
|
|
205
716
|
easing: ANIMATION_EASING,
|
|
206
717
|
useNativeDriver: false
|
|
@@ -218,39 +729,118 @@ function VelocityStrip({
|
|
|
218
729
|
useNativeDriver: false
|
|
219
730
|
})
|
|
220
731
|
]).start();
|
|
221
|
-
}, [expanded, variant, heightAnim, labelOpacity, infoOpacity]);
|
|
732
|
+
}, [expanded, variant, framed, height, heightAnim, labelOpacity, infoOpacity]);
|
|
733
|
+
if (set == null && velocities == null) return null;
|
|
734
|
+
const repCount = doneVelocities.length;
|
|
735
|
+
const miniLabel = set ? setAccessibilityLabel(set, repCount) : `Velocity strip, ${repCount} reps`;
|
|
222
736
|
if (variant === "mini") {
|
|
223
737
|
const { style: externalStyle, ...restProps } = props;
|
|
224
738
|
return /* @__PURE__ */ jsx(
|
|
225
739
|
reactNative.View,
|
|
226
740
|
{
|
|
227
741
|
className,
|
|
228
|
-
style: [
|
|
742
|
+
style: [
|
|
743
|
+
{ flexDirection: "row", height: 3, gap: REP_GAP, borderRadius: 2, overflow: "hidden" },
|
|
744
|
+
externalStyle
|
|
745
|
+
],
|
|
229
746
|
accessibilityRole: "image",
|
|
230
|
-
accessibilityLabel:
|
|
747
|
+
accessibilityLabel: miniLabel,
|
|
231
748
|
testID: "velocity-strip-mini",
|
|
232
749
|
...restProps,
|
|
233
|
-
children:
|
|
750
|
+
children: slots.map((slot, i) => /* @__PURE__ */ jsx(
|
|
234
751
|
reactNative.View,
|
|
235
752
|
{
|
|
236
753
|
style: {
|
|
237
754
|
flex: 1,
|
|
238
|
-
backgroundColor:
|
|
755
|
+
backgroundColor: slotColor(slot),
|
|
239
756
|
borderRadius: 1,
|
|
240
757
|
minWidth: 4,
|
|
241
|
-
height: "100%"
|
|
758
|
+
height: "100%",
|
|
759
|
+
// The container's uniform 2px gap covers rep spacing; a wide slot adds
|
|
760
|
+
// only the EXTRA (WIDE_GAP − REP_GAP) so the notch totals WIDE_GAP.
|
|
761
|
+
marginLeft: Math.max(0, slot.leadingGap - REP_GAP),
|
|
762
|
+
...slot.kind === "continue" ? { borderWidth: 1, borderColor: CONTINUE_OUTLINE } : {}
|
|
763
|
+
},
|
|
764
|
+
accessibilityElementsHidden: true,
|
|
765
|
+
testID: slot.kind === "rep" ? `velocity-bar-${i}` : `velocity-slot-${slot.kind}`
|
|
766
|
+
},
|
|
767
|
+
i
|
|
768
|
+
))
|
|
769
|
+
}
|
|
770
|
+
);
|
|
771
|
+
}
|
|
772
|
+
if (!framed) {
|
|
773
|
+
const { style: externalStyle, ...restProps } = props;
|
|
774
|
+
return /* @__PURE__ */ jsx(
|
|
775
|
+
reactNative.View,
|
|
776
|
+
{
|
|
777
|
+
className,
|
|
778
|
+
style: [
|
|
779
|
+
{ flexDirection: "row", height, gap: REP_GAP, alignItems: "flex-end" },
|
|
780
|
+
externalStyle
|
|
781
|
+
],
|
|
782
|
+
accessibilityRole: "image",
|
|
783
|
+
accessibilityLabel: miniLabel,
|
|
784
|
+
testID: "velocity-strip-compact",
|
|
785
|
+
...restProps,
|
|
786
|
+
children: slots.map((slot, i) => /* @__PURE__ */ jsx(
|
|
787
|
+
reactNative.View,
|
|
788
|
+
{
|
|
789
|
+
style: {
|
|
790
|
+
flex: 1,
|
|
791
|
+
minWidth: 4,
|
|
792
|
+
height: bareSlotHeight(slot, height, scaleDenom),
|
|
793
|
+
// Top-rounded to match the framed chart's bars (the "rounded tops from
|
|
794
|
+
// the numbers one"); square bottoms since bars sit on the baseline.
|
|
795
|
+
borderTopLeftRadius: 2,
|
|
796
|
+
borderTopRightRadius: 2,
|
|
797
|
+
backgroundColor: slotColor(slot),
|
|
798
|
+
marginLeft: Math.max(0, slot.leadingGap - REP_GAP),
|
|
799
|
+
...slot.kind === "continue" ? { borderWidth: 1, borderColor: CONTINUE_OUTLINE } : {}
|
|
242
800
|
},
|
|
243
801
|
accessibilityElementsHidden: true,
|
|
244
|
-
testID: `velocity-bar-${i}`
|
|
802
|
+
testID: slot.kind === "rep" ? `velocity-bar-${i}` : `velocity-slot-${slot.kind}`
|
|
245
803
|
},
|
|
246
804
|
i
|
|
247
805
|
))
|
|
248
806
|
}
|
|
249
807
|
);
|
|
250
808
|
}
|
|
251
|
-
const stripLabel = `Velocity chart for set, ${
|
|
809
|
+
const stripLabel = set ? `${setAccessibilityLabel(set, repCount)}, tap to ${expanded ? "collapse" : "expand"}` : `Velocity chart for set, ${repCount} reps, tap to ${expanded ? "collapse" : "expand"}`;
|
|
252
810
|
const hasInteractiveContainer = onToggle != null;
|
|
253
811
|
const hasInteractiveReps = onRepPress != null && expanded;
|
|
812
|
+
const setBars = set != null && slots.map((slot, i) => {
|
|
813
|
+
const isStraightRep = set.type === "straight" && slot.kind === "rep";
|
|
814
|
+
const heightPct = isStraightRep ? scaleDenom > 0 ? Math.round((slot.velocity ?? 0) / scaleDenom * 100) : 0 : set.type === "straight" ? EXPANDED_TODO_STUB_PCT : EXPANDED_ENCODED_PCT;
|
|
815
|
+
return /* @__PURE__ */ jsx(
|
|
816
|
+
reactNative.View,
|
|
817
|
+
{
|
|
818
|
+
style: {
|
|
819
|
+
flex: 1,
|
|
820
|
+
height: "100%",
|
|
821
|
+
justifyContent: "flex-end",
|
|
822
|
+
marginLeft: slot.leadingGap
|
|
823
|
+
},
|
|
824
|
+
children: /* @__PURE__ */ jsx(
|
|
825
|
+
reactNative.View,
|
|
826
|
+
{
|
|
827
|
+
style: {
|
|
828
|
+
height: `${heightPct}%`,
|
|
829
|
+
minHeight: 2,
|
|
830
|
+
borderTopLeftRadius: 2,
|
|
831
|
+
borderTopRightRadius: 2,
|
|
832
|
+
backgroundColor: slotColor(slot),
|
|
833
|
+
...slot.kind === "continue" ? { borderWidth: 1, borderColor: CONTINUE_OUTLINE } : {}
|
|
834
|
+
},
|
|
835
|
+
testID: slot.kind === "rep" ? `velocity-bar-${i}` : `velocity-slot-${slot.kind}`,
|
|
836
|
+
accessibilityRole: "image",
|
|
837
|
+
accessibilityLabel: slotAccessibilityLabel(slot, i)
|
|
838
|
+
}
|
|
839
|
+
)
|
|
840
|
+
},
|
|
841
|
+
i
|
|
842
|
+
);
|
|
843
|
+
});
|
|
254
844
|
const stripContent = /* @__PURE__ */ jsxs(
|
|
255
845
|
reactNative.Animated.View,
|
|
256
846
|
{
|
|
@@ -263,7 +853,9 @@ function VelocityStrip({
|
|
|
263
853
|
borderRadius: expanded ? 6 : 2,
|
|
264
854
|
paddingTop: expanded ? 16 : 0,
|
|
265
855
|
paddingBottom: expanded ? 24 : 0,
|
|
266
|
-
|
|
856
|
+
// No horizontal inset — the framed chart's bars span full width, matching
|
|
857
|
+
// the bare spotlight and mini. Numbers/info sit in the vertical padding.
|
|
858
|
+
paddingHorizontal: 0,
|
|
267
859
|
paddingVertical: expanded ? void 0 : 8,
|
|
268
860
|
overflow: expanded ? "visible" : "hidden"
|
|
269
861
|
}
|
|
@@ -273,46 +865,65 @@ function VelocityStrip({
|
|
|
273
865
|
testID: "velocity-strip",
|
|
274
866
|
...props,
|
|
275
867
|
children: [
|
|
276
|
-
/* @__PURE__ */ jsx(
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
)
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
868
|
+
/* @__PURE__ */ jsx(reactNative.View, { style: { flexDirection: "row", flex: 1, gap: set ? 0 : 2, alignItems: "flex-end" }, children: set ? setBars : doneVelocities.map((v, i) => {
|
|
869
|
+
const barBackground = barColorFor(v);
|
|
870
|
+
const barHeightPct = scaleDenom > 0 ? Math.round(v / scaleDenom * 100) : 0;
|
|
871
|
+
const isLive = liveRepIndex === i;
|
|
872
|
+
const liveLabelSuffix = isLive ? isNewPeak ? ", latest rep, new set peak" : ", latest rep" : "";
|
|
873
|
+
const barStyle = expanded ? {
|
|
874
|
+
height: `${barHeightPct}%`,
|
|
875
|
+
minHeight: 2,
|
|
876
|
+
borderTopLeftRadius: 2,
|
|
877
|
+
borderTopRightRadius: 2,
|
|
878
|
+
backgroundColor: barBackground
|
|
879
|
+
} : {
|
|
880
|
+
minHeight: "100%",
|
|
881
|
+
borderTopLeftRadius: 2,
|
|
882
|
+
borderTopRightRadius: 2,
|
|
883
|
+
borderBottomLeftRadius: 0,
|
|
884
|
+
borderBottomRightRadius: 0,
|
|
885
|
+
backgroundColor: barBackground
|
|
886
|
+
};
|
|
887
|
+
const barInner = isLive ? /* @__PURE__ */ jsx(
|
|
888
|
+
reactNative.Animated.View,
|
|
889
|
+
{
|
|
890
|
+
style: [barStyle, { transform: [{ scale: liveScale }] }],
|
|
891
|
+
testID: `velocity-bar-${i}`,
|
|
892
|
+
accessibilityRole: "image",
|
|
893
|
+
accessibilityLabel: `Rep ${i + 1}: ${formatVelocity(v)} meters per second${liveLabelSuffix}`
|
|
894
|
+
}
|
|
895
|
+
) : /* @__PURE__ */ jsx(
|
|
896
|
+
reactNative.View,
|
|
897
|
+
{
|
|
898
|
+
style: barStyle,
|
|
899
|
+
testID: `velocity-bar-${i}`,
|
|
900
|
+
accessibilityRole: "image",
|
|
901
|
+
accessibilityLabel: `Rep ${i + 1}: ${formatVelocity(v)} meters per second`
|
|
902
|
+
}
|
|
903
|
+
);
|
|
904
|
+
const bar = /* @__PURE__ */ jsxs(
|
|
905
|
+
reactNative.View,
|
|
906
|
+
{
|
|
907
|
+
style: {
|
|
908
|
+
flex: 1,
|
|
909
|
+
height: "100%",
|
|
910
|
+
justifyContent: "flex-end",
|
|
911
|
+
position: "relative"
|
|
912
|
+
},
|
|
913
|
+
children: [
|
|
914
|
+
expanded && showNumbers && /* @__PURE__ */ jsx(
|
|
915
|
+
reactNative.Animated.View,
|
|
916
|
+
{
|
|
917
|
+
style: {
|
|
918
|
+
opacity: labelOpacity,
|
|
919
|
+
alignItems: "center",
|
|
920
|
+
position: "absolute",
|
|
921
|
+
top: -13,
|
|
922
|
+
left: 0,
|
|
923
|
+
right: 0
|
|
924
|
+
},
|
|
925
|
+
accessibilityElementsHidden: true,
|
|
926
|
+
children: /* @__PURE__ */ jsx(
|
|
316
927
|
reactNative.Text,
|
|
317
928
|
{
|
|
318
929
|
className: "text-text-secondary",
|
|
@@ -320,30 +931,30 @@ function VelocityStrip({
|
|
|
320
931
|
testID: `velocity-label-${i}`,
|
|
321
932
|
children: formatVelocity(v)
|
|
322
933
|
}
|
|
323
|
-
)
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
})
|
|
934
|
+
)
|
|
935
|
+
}
|
|
936
|
+
),
|
|
937
|
+
barInner
|
|
938
|
+
]
|
|
939
|
+
},
|
|
940
|
+
i
|
|
941
|
+
);
|
|
942
|
+
if (onRepPress && expanded) {
|
|
943
|
+
return /* @__PURE__ */ jsx(
|
|
944
|
+
reactNative.Pressable,
|
|
945
|
+
{
|
|
946
|
+
style: { flex: 1, height: "100%" },
|
|
947
|
+
onPress: () => onRepPress(i, v),
|
|
948
|
+
accessibilityRole: "button",
|
|
949
|
+
accessibilityLabel: `Rep ${i + 1}: ${formatVelocity(v)} meters per second, tap for details`,
|
|
950
|
+
testID: `velocity-bar-pressable-${i}`,
|
|
951
|
+
children: bar
|
|
952
|
+
},
|
|
953
|
+
i
|
|
954
|
+
);
|
|
345
955
|
}
|
|
346
|
-
|
|
956
|
+
return bar;
|
|
957
|
+
}) }),
|
|
347
958
|
expanded && showInfo && /* @__PURE__ */ jsxs(
|
|
348
959
|
reactNative.Animated.View,
|
|
349
960
|
{
|
|
@@ -489,12 +1100,14 @@ function PlaceholderStrip({
|
|
|
489
1100
|
return /* @__PURE__ */ jsx(SingleStrip, { ...props });
|
|
490
1101
|
}
|
|
491
1102
|
|
|
492
|
-
// src/components/
|
|
493
|
-
function
|
|
1103
|
+
// src/components/icons/SvgIcon.tsx
|
|
1104
|
+
function SvgIcon({
|
|
494
1105
|
size = 24,
|
|
495
1106
|
color = "currentColor",
|
|
1107
|
+
strokeWidth = 2,
|
|
496
1108
|
fill = "none",
|
|
497
|
-
|
|
1109
|
+
title,
|
|
1110
|
+
children
|
|
498
1111
|
}) {
|
|
499
1112
|
return /* @__PURE__ */ jsxs(
|
|
500
1113
|
"svg",
|
|
@@ -507,36 +1120,59 @@ function DumbbellIcon({
|
|
|
507
1120
|
strokeWidth,
|
|
508
1121
|
strokeLinecap: "round",
|
|
509
1122
|
strokeLinejoin: "round",
|
|
1123
|
+
...title ? { role: "img", "aria-label": title } : { "aria-hidden": true },
|
|
510
1124
|
children: [
|
|
511
|
-
/* @__PURE__ */ jsx("
|
|
512
|
-
|
|
513
|
-
/* @__PURE__ */ jsx("path", { d: "m21.5 21.5-1.4-1.4" }),
|
|
514
|
-
/* @__PURE__ */ jsx("path", { d: "M3.9 3.9 2.5 2.5" }),
|
|
515
|
-
/* @__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" })
|
|
1125
|
+
title ? /* @__PURE__ */ jsx("title", { children: title }) : null,
|
|
1126
|
+
children
|
|
516
1127
|
]
|
|
517
1128
|
}
|
|
518
1129
|
);
|
|
519
1130
|
}
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
return /* @__PURE__ */
|
|
527
|
-
"
|
|
528
|
-
{
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
}
|
|
539
|
-
);
|
|
1131
|
+
|
|
1132
|
+
// src/components/icons/icons.tsx
|
|
1133
|
+
function StarIcon(props) {
|
|
1134
|
+
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" }) });
|
|
1135
|
+
}
|
|
1136
|
+
function ScaleIcon(props) {
|
|
1137
|
+
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
1138
|
+
/* @__PURE__ */ jsx("path", { d: "m16 16 3-8 3 8c-.87.65-1.92 1-3 1s-2.13-.35-3-1Z" }),
|
|
1139
|
+
/* @__PURE__ */ jsx("path", { d: "m2 16 3-8 3 8c-.87.65-1.92 1-3 1s-2.13-.35-3-1Z" }),
|
|
1140
|
+
/* @__PURE__ */ jsx("path", { d: "M7 21h10" }),
|
|
1141
|
+
/* @__PURE__ */ jsx("path", { d: "M12 3v18" }),
|
|
1142
|
+
/* @__PURE__ */ jsx("path", { d: "M3 7h2c2 0 5-1 7-2 2 1 5 2 7 2h2" })
|
|
1143
|
+
] });
|
|
1144
|
+
}
|
|
1145
|
+
function AlertTriangleIcon(props) {
|
|
1146
|
+
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
1147
|
+
/* @__PURE__ */ jsx("path", { d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z" }),
|
|
1148
|
+
/* @__PURE__ */ jsx("path", { d: "M12 9v4" }),
|
|
1149
|
+
/* @__PURE__ */ jsx("path", { d: "M12 17h.01" })
|
|
1150
|
+
] });
|
|
1151
|
+
}
|
|
1152
|
+
function TrendingDownIcon(props) {
|
|
1153
|
+
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
1154
|
+
/* @__PURE__ */ jsx("path", { d: "M16 17h6v-6" }),
|
|
1155
|
+
/* @__PURE__ */ jsx("path", { d: "m22 17-8.5-8.5-5 5L2 7" })
|
|
1156
|
+
] });
|
|
1157
|
+
}
|
|
1158
|
+
function CircleSlashIcon(props) {
|
|
1159
|
+
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
1160
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
1161
|
+
/* @__PURE__ */ jsx("path", { d: "m9 15 6-6" })
|
|
1162
|
+
] });
|
|
1163
|
+
}
|
|
1164
|
+
function AwardIcon(props) {
|
|
1165
|
+
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
1166
|
+
/* @__PURE__ */ jsx("path", { d: "m15.477 12.89 1.515 8.526a.5.5 0 0 1-.81.47l-3.58-2.687a1 1 0 0 0-1.197 0l-3.586 2.686a.5.5 0 0 1-.81-.469l1.514-8.526" }),
|
|
1167
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "8", r: "6" })
|
|
1168
|
+
] });
|
|
1169
|
+
}
|
|
1170
|
+
function InfoIcon(props) {
|
|
1171
|
+
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
1172
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
1173
|
+
/* @__PURE__ */ jsx("path", { d: "M12 16v-4" }),
|
|
1174
|
+
/* @__PURE__ */ jsx("path", { d: "M12 8h.01" })
|
|
1175
|
+
] });
|
|
540
1176
|
}
|
|
541
1177
|
var baseBadgeSizeConfig = {
|
|
542
1178
|
sm: { fontSize: 9, paddingH: 6, paddingV: 2, iconSize: 10 },
|
|
@@ -616,105 +1252,286 @@ function BaseBadge({
|
|
|
616
1252
|
return badge;
|
|
617
1253
|
}
|
|
618
1254
|
|
|
619
|
-
// src/
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
1255
|
+
// src/theme/tokens/semantic.ts
|
|
1256
|
+
var semanticColorsLight = {
|
|
1257
|
+
// Brand colors (brand-*)
|
|
1258
|
+
"brand-primary": primitiveRamps.orange[400],
|
|
1259
|
+
"brand-primary-light": primitiveRamps.orange[300],
|
|
1260
|
+
"brand-primary-dark": primitiveRamps.orange[500],
|
|
1261
|
+
"brand-primary-subtle": "rgba(255, 121, 0, 0.08)",
|
|
1262
|
+
"brand-primary-hover": primitiveRamps.orange[500],
|
|
1263
|
+
"brand-primary-active": primitiveRamps.orange[600],
|
|
1264
|
+
"brand-secondary": primitiveRamps.cyan[600],
|
|
1265
|
+
"brand-secondary-light": primitiveRamps.cyan[500],
|
|
1266
|
+
"brand-secondary-dark": primitiveRamps.cyan[700],
|
|
1267
|
+
"brand-secondary-subtle": "rgba(48, 123, 155, 0.08)",
|
|
1268
|
+
"brand-secondary-hover": primitiveRamps.cyan[700],
|
|
1269
|
+
"brand-secondary-active": primitiveRamps.cyan[800],
|
|
1270
|
+
// Text on brand backgrounds (on-*)
|
|
1271
|
+
"on-brand-primary": primitiveColors.white,
|
|
1272
|
+
"on-brand-secondary": primitiveColors.white,
|
|
1273
|
+
// Status colors (status-*)
|
|
1274
|
+
"status-success": primitiveRamps.green[300],
|
|
1275
|
+
"status-success-light": primitiveRamps.green[200],
|
|
1276
|
+
"status-success-dark": primitiveRamps.green[600],
|
|
1277
|
+
"status-success-subtle": primitiveRamps.green[50],
|
|
1278
|
+
// Live-session accent — its OWN role, decoupled from success so the two can diverge
|
|
1279
|
+
"status-live": primitiveRamps.green[300],
|
|
1280
|
+
"status-live-muted": primitiveRamps.green[500],
|
|
1281
|
+
"status-error": primitiveRamps.red[600],
|
|
1282
|
+
"status-error-light": primitiveRamps.red[500],
|
|
1283
|
+
"status-error-dark": primitiveRamps.red[700],
|
|
1284
|
+
"status-error-subtle": primitiveRamps.red[50],
|
|
1285
|
+
"status-error-vivid": primitiveColors.redVivid[500],
|
|
1286
|
+
// vivid alert red
|
|
1287
|
+
"status-error-vivid-light": primitiveColors.redVivid[400],
|
|
1288
|
+
"status-error-vivid-dark": primitiveColors.redVivid[700],
|
|
1289
|
+
"status-error-vivid-subtle": "rgba(255, 71, 87, 0.12)",
|
|
1290
|
+
"status-warning": primitiveRamps.amber[300],
|
|
1291
|
+
"status-warning-light": primitiveRamps.amber[200],
|
|
1292
|
+
"status-warning-dark": primitiveRamps.amber[500],
|
|
1293
|
+
"status-warning-subtle": primitiveRamps.amber[50],
|
|
1294
|
+
"status-info": primitiveRamps.blue[500],
|
|
1295
|
+
"status-info-light": primitiveRamps.blue[300],
|
|
1296
|
+
"status-info-dark": primitiveRamps.blue[600],
|
|
1297
|
+
"status-info-subtle": primitiveRamps.blue[50],
|
|
1298
|
+
// Text on status backgrounds (on-status-*)
|
|
1299
|
+
"on-status-success": primitiveColors.white,
|
|
1300
|
+
"on-status-error": primitiveColors.white,
|
|
1301
|
+
"on-status-warning": primitiveColors.white,
|
|
1302
|
+
"on-status-info": primitiveColors.white,
|
|
1303
|
+
// Result/outcome indicators (result-*)
|
|
1304
|
+
"result-improve": "#4caf50",
|
|
1305
|
+
// Green - positive outcome
|
|
1306
|
+
"result-improve-light": "rgba(76, 175, 80, 0.12)",
|
|
1307
|
+
"result-improve-dark": "#248a24",
|
|
1308
|
+
"result-degrade": "#ef5350",
|
|
1309
|
+
// Red - negative outcome
|
|
1310
|
+
"result-degrade-light": "rgba(239, 83, 80, 0.12)",
|
|
1311
|
+
"result-degrade-dark": "#b30000",
|
|
1312
|
+
"result-inconclusive": "#9E9A97",
|
|
1313
|
+
// Gray - no clear result
|
|
1314
|
+
"result-inconclusive-light": "rgba(158, 154, 151, 0.12)",
|
|
1315
|
+
"result-neutral": primitiveColors.neutral[500],
|
|
1316
|
+
// Neutral baseline
|
|
1317
|
+
// Text on result backgrounds (on-result-*)
|
|
1318
|
+
"on-result-improve": primitiveColors.white,
|
|
1319
|
+
"on-result-degrade": primitiveColors.white,
|
|
1320
|
+
"on-result-inconclusive": primitiveColors.white,
|
|
1321
|
+
// Data visualization colors (data-*)
|
|
1322
|
+
// First 10 colors from discrete rainbow optimized for charts
|
|
1323
|
+
"data-1": discreteRainbow[9],
|
|
1324
|
+
// Blue
|
|
1325
|
+
"data-2": discreteRainbow[14],
|
|
1326
|
+
// Green
|
|
1327
|
+
"data-3": discreteRainbow[17],
|
|
1328
|
+
// Yellow
|
|
1329
|
+
"data-4": discreteRainbow[25],
|
|
1330
|
+
// Red
|
|
1331
|
+
"data-5": discreteRainbow[8],
|
|
1332
|
+
// Purple
|
|
1333
|
+
"data-6": discreteRainbow[20],
|
|
1334
|
+
// Orange
|
|
1335
|
+
"data-7": discreteRainbow[13],
|
|
1336
|
+
// Light Blue
|
|
1337
|
+
"data-8": discreteRainbow[15],
|
|
1338
|
+
// Light Green
|
|
1339
|
+
"data-9": discreteRainbow[3],
|
|
1340
|
+
// Lavender
|
|
1341
|
+
"data-10": discreteRainbow[22],
|
|
1342
|
+
// Dark Orange
|
|
1343
|
+
// Text colors (text-*)
|
|
1344
|
+
"text-primary": "#121828",
|
|
1345
|
+
"text-secondary": "#65748B",
|
|
1346
|
+
"text-tertiary": primitiveColors.neutral[400],
|
|
1347
|
+
"text-disabled": "rgba(55, 65, 81, 0.48)",
|
|
1348
|
+
"text-inverse": primitiveColors.white,
|
|
1349
|
+
"text-link": primitiveColors.blue[600],
|
|
1350
|
+
"text-link-hover": primitiveColors.blue[700],
|
|
1351
|
+
// Surface colors (surface-*) - for elevated containers
|
|
1352
|
+
"surface-base": primitiveColors.white,
|
|
1353
|
+
"surface-elevated": primitiveColors.neutral[50],
|
|
1354
|
+
// slightly off-white for elevated cards
|
|
1355
|
+
"surface-raised": primitiveColors.neutral[100],
|
|
1356
|
+
// light gray for raised cards
|
|
1357
|
+
"surface-overlay": primitiveColors.white,
|
|
1358
|
+
"surface-input": primitiveColors.neutral[50],
|
|
1359
|
+
// Input field background (filled variant)
|
|
1360
|
+
// Background colors (background-*)
|
|
1361
|
+
"background-base": "#EBEBEB",
|
|
1362
|
+
"background-default": primitiveColors.white,
|
|
1363
|
+
"background-subtle": primitiveColors.neutral[50],
|
|
1364
|
+
// Border colors (border-*)
|
|
1365
|
+
"border-default": "#E8E9EB",
|
|
1366
|
+
"border-subtle": primitiveColors.neutral[100],
|
|
1367
|
+
"border-strong": primitiveColors.neutral[300],
|
|
1368
|
+
"border-prominent": primitiveColors.neutral[400],
|
|
1369
|
+
// high-visibility divider
|
|
1370
|
+
"border-focus": primitiveColors.blue[600],
|
|
1371
|
+
"border-input": primitiveColors.neutral[300],
|
|
1372
|
+
// Input field border
|
|
1373
|
+
"border-input-hover": primitiveColors.neutral[400],
|
|
1374
|
+
// Input field border on hover
|
|
1375
|
+
"border-input-focus": primitiveColors.blue[600],
|
|
1376
|
+
// Input field border on focus
|
|
1377
|
+
"border-input-error": primitiveColors.red[600],
|
|
1378
|
+
// Input field border on error
|
|
1379
|
+
// Interactive states (interactive-*)
|
|
1380
|
+
"interactive-hover": "rgba(55, 65, 81, 0.04)",
|
|
1381
|
+
"interactive-focus": "rgba(55, 65, 81, 0.12)",
|
|
1382
|
+
"interactive-active": "rgba(55, 65, 81, 0.16)",
|
|
1383
|
+
"interactive-selected": "rgba(55, 65, 81, 0.08)",
|
|
1384
|
+
"interactive-disabled": "rgba(55, 65, 81, 0.12)",
|
|
1385
|
+
"interactive-disabled-text": "rgba(55, 65, 81, 0.26)",
|
|
1386
|
+
// Divider
|
|
1387
|
+
"divider": "#E8E9EB",
|
|
1388
|
+
// Avatar default
|
|
1389
|
+
"avatar-background": primitiveColors.neutral[500],
|
|
1390
|
+
"avatar-text": primitiveColors.white
|
|
1391
|
+
};
|
|
1392
|
+
var semanticColorsDark = {
|
|
1393
|
+
// Brand colors stay the same in dark mode
|
|
1394
|
+
"brand-primary": primitiveRamps.orange[400],
|
|
1395
|
+
"brand-primary-light": primitiveRamps.orange[300],
|
|
1396
|
+
"brand-primary-dark": primitiveRamps.orange[500],
|
|
1397
|
+
"brand-primary-subtle": "rgba(255, 121, 0, 0.12)",
|
|
1398
|
+
"brand-primary-hover": primitiveRamps.orange[300],
|
|
1399
|
+
"brand-primary-active": primitiveRamps.orange[200],
|
|
1400
|
+
"brand-secondary": primitiveRamps.cyan[600],
|
|
1401
|
+
"brand-secondary-light": primitiveRamps.cyan[500],
|
|
1402
|
+
"brand-secondary-dark": primitiveRamps.cyan[700],
|
|
1403
|
+
"brand-secondary-subtle": "rgba(48, 123, 155, 0.12)",
|
|
1404
|
+
"brand-secondary-hover": primitiveRamps.cyan[500],
|
|
1405
|
+
"brand-secondary-active": primitiveRamps.cyan[400],
|
|
1406
|
+
// Text on brand backgrounds
|
|
1407
|
+
"on-brand-primary": primitiveColors.white,
|
|
1408
|
+
"on-brand-secondary": primitiveColors.white,
|
|
1409
|
+
// Status colors
|
|
1410
|
+
"status-success": primitiveRamps.green[300],
|
|
1411
|
+
"status-success-light": primitiveRamps.green[200],
|
|
1412
|
+
"status-success-dark": primitiveRamps.green[600],
|
|
1413
|
+
"status-success-subtle": "rgba(46, 213, 115, 0.12)",
|
|
1414
|
+
// Live-session accent — its OWN role, decoupled from success so the two can diverge
|
|
1415
|
+
"status-live": primitiveRamps.green[300],
|
|
1416
|
+
"status-live-muted": primitiveRamps.green[500],
|
|
1417
|
+
"status-error": primitiveRamps.red[600],
|
|
1418
|
+
"status-error-light": primitiveRamps.red[500],
|
|
1419
|
+
"status-error-dark": primitiveRamps.red[700],
|
|
1420
|
+
"status-error-subtle": "rgba(209, 67, 67, 0.12)",
|
|
1421
|
+
"status-error-vivid": primitiveColors.redVivid[500],
|
|
1422
|
+
"status-error-vivid-light": primitiveColors.redVivid[400],
|
|
1423
|
+
"status-error-vivid-dark": primitiveColors.redVivid[700],
|
|
1424
|
+
"status-error-vivid-subtle": "rgba(255, 71, 87, 0.12)",
|
|
1425
|
+
"status-warning": primitiveRamps.amber[300],
|
|
1426
|
+
"status-warning-light": primitiveRamps.amber[200],
|
|
1427
|
+
"status-warning-dark": primitiveRamps.amber[500],
|
|
1428
|
+
"status-warning-subtle": "rgba(249, 180, 21, 0.12)",
|
|
1429
|
+
"status-info": primitiveRamps.blue[500],
|
|
1430
|
+
"status-info-light": primitiveRamps.blue[300],
|
|
1431
|
+
"status-info-dark": primitiveRamps.blue[600],
|
|
1432
|
+
"status-info-subtle": "rgba(33, 150, 243, 0.12)",
|
|
1433
|
+
// Text on status backgrounds
|
|
1434
|
+
"on-status-success": primitiveColors.white,
|
|
1435
|
+
"on-status-error": primitiveColors.white,
|
|
1436
|
+
"on-status-warning": primitiveColors.white,
|
|
1437
|
+
"on-status-info": primitiveColors.white,
|
|
1438
|
+
// Result/outcome indicators (result-*)
|
|
1439
|
+
"result-improve": "#4caf50",
|
|
1440
|
+
"result-improve-light": "rgba(76, 175, 80, 0.16)",
|
|
1441
|
+
"result-improve-dark": "#248a24",
|
|
1442
|
+
"result-degrade": "#ef5350",
|
|
1443
|
+
"result-degrade-light": "rgba(239, 83, 80, 0.16)",
|
|
1444
|
+
"result-degrade-dark": "#b30000",
|
|
1445
|
+
"result-inconclusive": "#9E9A97",
|
|
1446
|
+
"result-inconclusive-light": "rgba(158, 154, 151, 0.16)",
|
|
1447
|
+
"result-neutral": primitiveColors.neutral[400],
|
|
1448
|
+
// Text on result backgrounds
|
|
1449
|
+
"on-result-improve": primitiveColors.white,
|
|
1450
|
+
"on-result-degrade": primitiveColors.white,
|
|
1451
|
+
"on-result-inconclusive": primitiveColors.white,
|
|
1452
|
+
// Data visualization colors (same in dark mode for consistency)
|
|
1453
|
+
"data-1": discreteRainbow[9],
|
|
1454
|
+
"data-2": discreteRainbow[14],
|
|
1455
|
+
"data-3": discreteRainbow[17],
|
|
1456
|
+
"data-4": discreteRainbow[25],
|
|
1457
|
+
"data-5": discreteRainbow[8],
|
|
1458
|
+
"data-6": discreteRainbow[20],
|
|
1459
|
+
"data-7": discreteRainbow[13],
|
|
1460
|
+
"data-8": discreteRainbow[15],
|
|
1461
|
+
"data-9": discreteRainbow[3],
|
|
1462
|
+
"data-10": discreteRainbow[22],
|
|
1463
|
+
// Text colors - inverted for dark mode
|
|
1464
|
+
"text-primary": primitiveColors.neutral[100],
|
|
1465
|
+
"text-secondary": primitiveColors.neutral[400],
|
|
1466
|
+
"text-tertiary": primitiveColors.neutral[500],
|
|
1467
|
+
"text-disabled": "rgba(255, 255, 255, 0.38)",
|
|
1468
|
+
"text-inverse": primitiveColors.neutral[900],
|
|
1469
|
+
"text-link": "#828DF8",
|
|
1470
|
+
"text-link-hover": primitiveColors.blue[400],
|
|
1471
|
+
// Surface colors - dark backgrounds
|
|
1472
|
+
"surface-base": primitiveColors.charcoal[700],
|
|
1473
|
+
// main surface
|
|
1474
|
+
"surface-elevated": primitiveColors.charcoal[600],
|
|
1475
|
+
// elevated surface
|
|
1476
|
+
"surface-raised": primitiveColors.charcoal[500],
|
|
1477
|
+
// raised surface
|
|
1478
|
+
"surface-overlay": primitiveColors.charcoal[600],
|
|
1479
|
+
// overlay surface
|
|
1480
|
+
"surface-input": primitiveColors.charcoal[600],
|
|
1481
|
+
// input surface
|
|
1482
|
+
// Background colors
|
|
1483
|
+
"background-base": primitiveColors.charcoal[900],
|
|
1484
|
+
// darkest charcoal
|
|
1485
|
+
"background-default": primitiveColors.charcoal[700],
|
|
1486
|
+
// main background
|
|
1487
|
+
"background-subtle": primitiveColors.charcoal[500],
|
|
1488
|
+
// subtle background
|
|
1489
|
+
// Border colors
|
|
1490
|
+
"border-default": primitiveColors.charcoal[400],
|
|
1491
|
+
// default border
|
|
1492
|
+
"border-subtle": primitiveColors.charcoal[500],
|
|
1493
|
+
// subtle border
|
|
1494
|
+
"border-strong": primitiveColors.charcoal[300],
|
|
1495
|
+
// strong border
|
|
1496
|
+
"border-prominent": primitiveColors.charcoal[200],
|
|
1497
|
+
// high-visibility divider
|
|
1498
|
+
"border-focus": "#828DF8",
|
|
1499
|
+
"border-input": primitiveColors.neutral[600],
|
|
1500
|
+
"border-input-hover": primitiveColors.neutral[500],
|
|
1501
|
+
"border-input-focus": "#828DF8",
|
|
1502
|
+
"border-input-error": primitiveColors.red[500],
|
|
1503
|
+
// Interactive states
|
|
1504
|
+
"interactive-hover": "rgba(255, 255, 255, 0.04)",
|
|
1505
|
+
"interactive-focus": "rgba(255, 255, 255, 0.12)",
|
|
1506
|
+
"interactive-active": "rgba(255, 255, 255, 0.16)",
|
|
1507
|
+
"interactive-selected": "rgba(255, 255, 255, 0.08)",
|
|
1508
|
+
"interactive-disabled": "rgba(255, 255, 255, 0.12)",
|
|
1509
|
+
"interactive-disabled-text": "rgba(255, 255, 255, 0.26)",
|
|
1510
|
+
// Divider
|
|
1511
|
+
"divider": primitiveColors.charcoal[400],
|
|
1512
|
+
// divider color
|
|
1513
|
+
// Avatar default
|
|
1514
|
+
"avatar-background": primitiveColors.neutral[600],
|
|
1515
|
+
"avatar-text": primitiveColors.white
|
|
1516
|
+
};
|
|
1517
|
+
function getSemanticColors(mode) {
|
|
1518
|
+
return mode === "dark" ? semanticColorsDark : semanticColorsLight;
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
// src/components/custom/Workout/PrBadge.tsx
|
|
1522
|
+
var BRAND_PRIMARY = getSemanticColors("dark")["brand-primary"];
|
|
1523
|
+
var typeLabels = {
|
|
1524
|
+
e1rm: "PR e1RM",
|
|
1525
|
+
weight: "PR Weight",
|
|
1526
|
+
reps: "PR Reps",
|
|
1527
|
+
volume: "PR Volume",
|
|
1528
|
+
velocity: "PR Velocity"
|
|
1529
|
+
};
|
|
1530
|
+
function PrBadge({
|
|
1531
|
+
type = "e1rm",
|
|
1532
|
+
label: labelProp,
|
|
1533
|
+
compact = false,
|
|
1534
|
+
animate = true,
|
|
718
1535
|
className,
|
|
719
1536
|
...props
|
|
720
1537
|
}) {
|
|
@@ -746,7 +1563,7 @@ function PrBadge({
|
|
|
746
1563
|
accessibilityLabel: `Personal record: ${resolvedLabel}`,
|
|
747
1564
|
testID: "pr-badge-star",
|
|
748
1565
|
...props,
|
|
749
|
-
children: /* @__PURE__ */ jsx(StarIcon, { size: 14, color:
|
|
1566
|
+
children: /* @__PURE__ */ jsx(StarIcon, { size: 14, color: BRAND_PRIMARY, fill: BRAND_PRIMARY, strokeWidth: 2 })
|
|
750
1567
|
}
|
|
751
1568
|
) : /* @__PURE__ */ jsx(
|
|
752
1569
|
BaseBadge,
|
|
@@ -760,7 +1577,7 @@ function PrBadge({
|
|
|
760
1577
|
{
|
|
761
1578
|
style: {
|
|
762
1579
|
fontSize: 12,
|
|
763
|
-
color:
|
|
1580
|
+
color: BRAND_PRIMARY,
|
|
764
1581
|
fontWeight: "700",
|
|
765
1582
|
fontFamily: "Inter, sans-serif"
|
|
766
1583
|
},
|
|
@@ -785,6 +1602,204 @@ function PrBadge({
|
|
|
785
1602
|
}
|
|
786
1603
|
return badge;
|
|
787
1604
|
}
|
|
1605
|
+
var DARK = getSemanticColors("dark");
|
|
1606
|
+
var TEXT_ACTIVE = DARK["text-primary"];
|
|
1607
|
+
var TEXT_MUTED = DARK["text-secondary"];
|
|
1608
|
+
var COL = { set: 36, reps: 44, load: 56, rpe: 36 };
|
|
1609
|
+
var cellText = { fontFamily: "Inter, sans-serif", fontSize: 13, fontWeight: "600" };
|
|
1610
|
+
var typeBadge = {
|
|
1611
|
+
fontSize: 10,
|
|
1612
|
+
fontWeight: "700",
|
|
1613
|
+
fontFamily: "Inter, sans-serif",
|
|
1614
|
+
color: WORKOUT_TOKENS.scale.orange,
|
|
1615
|
+
backgroundColor: "rgba(255,165,2,0.12)",
|
|
1616
|
+
paddingVertical: 1,
|
|
1617
|
+
paddingHorizontal: 5,
|
|
1618
|
+
borderRadius: 3,
|
|
1619
|
+
overflow: "hidden"
|
|
1620
|
+
};
|
|
1621
|
+
function displayReps(set) {
|
|
1622
|
+
return set.state === "done" ? set.reps : set.target.reps;
|
|
1623
|
+
}
|
|
1624
|
+
function displayWeight(set) {
|
|
1625
|
+
return set.state === "done" ? set.weight : set.target.weight;
|
|
1626
|
+
}
|
|
1627
|
+
function plannedReps(set) {
|
|
1628
|
+
if (set.state === "done") return set.velocities.length;
|
|
1629
|
+
if (set.state === "live") return set.target.reps;
|
|
1630
|
+
return set.planned ?? set.target.reps;
|
|
1631
|
+
}
|
|
1632
|
+
function accessibilityLabel(set) {
|
|
1633
|
+
const base = `Set ${set.setNumber}: ${displayReps(set)} reps at ${roundWeight(displayWeight(set))} ${set.unit}`;
|
|
1634
|
+
if (set.state === "live") return `${base}, in progress`;
|
|
1635
|
+
if (set.state === "todo") return `${base}, upcoming`;
|
|
1636
|
+
return base;
|
|
1637
|
+
}
|
|
1638
|
+
function Cell({
|
|
1639
|
+
width,
|
|
1640
|
+
children,
|
|
1641
|
+
testID
|
|
1642
|
+
}) {
|
|
1643
|
+
return /* @__PURE__ */ jsx(reactNative.View, { style: { width, alignItems: "center", justifyContent: "center" }, testID, children });
|
|
1644
|
+
}
|
|
1645
|
+
function RowStrip({ set }) {
|
|
1646
|
+
const zones = set.velocityZones;
|
|
1647
|
+
if (set.state === "live") {
|
|
1648
|
+
return /* @__PURE__ */ jsx(
|
|
1649
|
+
VelocityStrip,
|
|
1650
|
+
{
|
|
1651
|
+
variant: "expanded",
|
|
1652
|
+
showNumbers: false,
|
|
1653
|
+
showInfo: false,
|
|
1654
|
+
height: 24,
|
|
1655
|
+
scale: "fixed",
|
|
1656
|
+
set: { type: "straight", velocities: set.velocities, planned: set.target.reps },
|
|
1657
|
+
zones
|
|
1658
|
+
}
|
|
1659
|
+
);
|
|
1660
|
+
}
|
|
1661
|
+
const velocities = set.state === "done" ? set.velocities : [];
|
|
1662
|
+
return /* @__PURE__ */ jsx(
|
|
1663
|
+
VelocityStrip,
|
|
1664
|
+
{
|
|
1665
|
+
variant: "mini",
|
|
1666
|
+
set: { type: "straight", velocities, planned: plannedReps(set) },
|
|
1667
|
+
zones
|
|
1668
|
+
}
|
|
1669
|
+
);
|
|
1670
|
+
}
|
|
1671
|
+
function SetRow(set) {
|
|
1672
|
+
const live = set.state === "live";
|
|
1673
|
+
const valueColor = live ? TEXT_ACTIVE : TEXT_MUTED;
|
|
1674
|
+
const rpe = set.state === "todo" ? null : set.rpe;
|
|
1675
|
+
return /* @__PURE__ */ jsxs(
|
|
1676
|
+
reactNative.View,
|
|
1677
|
+
{
|
|
1678
|
+
style: { paddingVertical: 6, paddingHorizontal: 8 },
|
|
1679
|
+
accessibilityLabel: accessibilityLabel(set),
|
|
1680
|
+
testID: "set-row",
|
|
1681
|
+
children: [
|
|
1682
|
+
/* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", style: { justifyContent: "space-between" }, children: [
|
|
1683
|
+
/* @__PURE__ */ jsx(Cell, { width: COL.set, testID: "set-row-set-number", children: set.setType ? /* @__PURE__ */ jsx(reactNative.Text, { style: typeBadge, testID: "set-row-type-badge", children: set.setType }) : /* @__PURE__ */ jsx(reactNative.Text, { style: { ...cellText, color: valueColor, fontWeight: live ? "700" : "600" }, children: set.setNumber }) }),
|
|
1684
|
+
/* @__PURE__ */ jsx(Cell, { width: COL.reps, testID: "set-row-reps", children: /* @__PURE__ */ jsx(reactNative.Text, { style: { ...cellText, color: valueColor }, children: displayReps(set) }) }),
|
|
1685
|
+
/* @__PURE__ */ jsx(Cell, { width: COL.load, testID: "set-row-weight", children: /* @__PURE__ */ jsx(reactNative.Text, { style: { ...cellText, color: valueColor }, children: roundWeight(displayWeight(set)) }) }),
|
|
1686
|
+
/* @__PURE__ */ jsx(Cell, { width: COL.rpe, testID: "set-row-rpe", children: /* @__PURE__ */ jsx(reactNative.Text, { style: { ...cellText, color: TEXT_MUTED }, children: rpe != null ? roundRpe(rpe) : "\u2014" }) })
|
|
1687
|
+
] }),
|
|
1688
|
+
/* @__PURE__ */ jsx(reactNative.View, { style: { marginTop: live ? 6 : 4 }, testID: "set-row-strip", children: /* @__PURE__ */ jsx(RowStrip, { set }) })
|
|
1689
|
+
]
|
|
1690
|
+
}
|
|
1691
|
+
);
|
|
1692
|
+
}
|
|
1693
|
+
var PREV_COLUMN = { label: "PREV", width: void 0 };
|
|
1694
|
+
function buildColumns(unit, showPrevious) {
|
|
1695
|
+
return [
|
|
1696
|
+
{ label: "SET", width: 36 },
|
|
1697
|
+
...showPrevious ? [PREV_COLUMN] : [],
|
|
1698
|
+
{ label: "REPS", width: 44 },
|
|
1699
|
+
{ label: unit.toUpperCase(), width: 56 },
|
|
1700
|
+
{ label: "RPE", width: 36 }
|
|
1701
|
+
];
|
|
1702
|
+
}
|
|
1703
|
+
function SetTableHeader({
|
|
1704
|
+
unit = "lbs",
|
|
1705
|
+
showPrevious = true,
|
|
1706
|
+
testID = "table-header"
|
|
1707
|
+
}) {
|
|
1708
|
+
const columns = buildColumns(unit, showPrevious);
|
|
1709
|
+
return /* @__PURE__ */ jsx(
|
|
1710
|
+
reactNative.View,
|
|
1711
|
+
{
|
|
1712
|
+
className: "flex-row",
|
|
1713
|
+
style: {
|
|
1714
|
+
paddingVertical: 8,
|
|
1715
|
+
paddingHorizontal: 8,
|
|
1716
|
+
paddingBottom: 4,
|
|
1717
|
+
...showPrevious ? {} : { justifyContent: "space-between" }
|
|
1718
|
+
},
|
|
1719
|
+
testID,
|
|
1720
|
+
children: columns.map(({ label, width }) => {
|
|
1721
|
+
const isFlex = width === void 0;
|
|
1722
|
+
return /* @__PURE__ */ jsx(
|
|
1723
|
+
reactNative.View,
|
|
1724
|
+
{
|
|
1725
|
+
style: {
|
|
1726
|
+
...isFlex ? { minWidth: 44 } : { width, flexShrink: 1 },
|
|
1727
|
+
alignItems: "center",
|
|
1728
|
+
justifyContent: "center",
|
|
1729
|
+
gap: 8
|
|
1730
|
+
},
|
|
1731
|
+
...isFlex ? { className: "flex-1" } : {},
|
|
1732
|
+
children: /* @__PURE__ */ jsx(
|
|
1733
|
+
reactNative.Text,
|
|
1734
|
+
{
|
|
1735
|
+
className: "text-text-tertiary",
|
|
1736
|
+
style: {
|
|
1737
|
+
fontSize: 10,
|
|
1738
|
+
fontWeight: "600",
|
|
1739
|
+
fontFamily: "Inter, sans-serif",
|
|
1740
|
+
textTransform: "uppercase",
|
|
1741
|
+
letterSpacing: 0.8
|
|
1742
|
+
},
|
|
1743
|
+
children: label
|
|
1744
|
+
}
|
|
1745
|
+
)
|
|
1746
|
+
},
|
|
1747
|
+
label
|
|
1748
|
+
);
|
|
1749
|
+
})
|
|
1750
|
+
}
|
|
1751
|
+
);
|
|
1752
|
+
}
|
|
1753
|
+
var METRIC_FONT = "Inter, sans-serif";
|
|
1754
|
+
function MetricCell({ children, color, fontSize = 11 }) {
|
|
1755
|
+
return /* @__PURE__ */ jsx(
|
|
1756
|
+
reactNative.Text,
|
|
1757
|
+
{
|
|
1758
|
+
style: {
|
|
1759
|
+
fontFamily: METRIC_FONT,
|
|
1760
|
+
fontSize,
|
|
1761
|
+
color,
|
|
1762
|
+
fontWeight: "600",
|
|
1763
|
+
letterSpacing: 1
|
|
1764
|
+
},
|
|
1765
|
+
children
|
|
1766
|
+
}
|
|
1767
|
+
);
|
|
1768
|
+
}
|
|
1769
|
+
|
|
1770
|
+
// src/components/custom/Workout/SetsRepsLoad.tsx
|
|
1771
|
+
var t = getSemanticColors("dark");
|
|
1772
|
+
var TIMES = "\xD7";
|
|
1773
|
+
var AT = "@";
|
|
1774
|
+
function SetsRepsLoad({
|
|
1775
|
+
sets,
|
|
1776
|
+
reps,
|
|
1777
|
+
load,
|
|
1778
|
+
unit = "lb",
|
|
1779
|
+
className,
|
|
1780
|
+
...props
|
|
1781
|
+
}) {
|
|
1782
|
+
const value = t["text-primary"];
|
|
1783
|
+
const sep = t["text-tertiary"];
|
|
1784
|
+
return /* @__PURE__ */ jsxs(
|
|
1785
|
+
reactNative.View,
|
|
1786
|
+
{
|
|
1787
|
+
className,
|
|
1788
|
+
style: { flexDirection: "row", alignItems: "baseline" },
|
|
1789
|
+
accessibilityLabel: `${sets} sets of ${reps} reps at ${load} ${unit}`,
|
|
1790
|
+
testID: "sets-reps-load",
|
|
1791
|
+
...props,
|
|
1792
|
+
children: [
|
|
1793
|
+
/* @__PURE__ */ jsx(MetricCell, { color: value, children: sets }),
|
|
1794
|
+
/* @__PURE__ */ jsx(MetricCell, { color: sep, children: ` ${TIMES} ` }),
|
|
1795
|
+
/* @__PURE__ */ jsx(MetricCell, { color: value, children: reps }),
|
|
1796
|
+
/* @__PURE__ */ jsx(MetricCell, { color: sep, children: ` ${AT} ` }),
|
|
1797
|
+
/* @__PURE__ */ jsx(MetricCell, { color: value, children: load }),
|
|
1798
|
+
/* @__PURE__ */ jsx(MetricCell, { color: sep, children: ` ${unit}` })
|
|
1799
|
+
]
|
|
1800
|
+
}
|
|
1801
|
+
);
|
|
1802
|
+
}
|
|
788
1803
|
function hexToRgb(hex) {
|
|
789
1804
|
const cleaned = hex.replace("#", "");
|
|
790
1805
|
let r, g, b;
|
|
@@ -1094,452 +2109,54 @@ function alpha(color, opacity) {
|
|
|
1094
2109
|
}
|
|
1095
2110
|
return color;
|
|
1096
2111
|
}
|
|
2112
|
+
var t2 = getSemanticColors("dark");
|
|
2113
|
+
var TEMPO_PACING = {
|
|
2114
|
+
behindThresholdPct: 0.15,
|
|
2115
|
+
minPhaseDurationMs: 500
|
|
2116
|
+
};
|
|
2117
|
+
function getTempoPacingState(elapsedMs, targetMs) {
|
|
2118
|
+
if (!targetMs || targetMs < TEMPO_PACING.minPhaseDurationMs) return "none";
|
|
2119
|
+
const ratio = elapsedMs / targetMs;
|
|
2120
|
+
if (ratio > 1 + TEMPO_PACING.behindThresholdPct) return "behind";
|
|
2121
|
+
return "on-pace";
|
|
2122
|
+
}
|
|
2123
|
+
function getTempoFillPct(elapsedMs, targetMs) {
|
|
2124
|
+
if (!targetMs) return 100;
|
|
2125
|
+
return Math.min(100, elapsedMs / targetMs * 100);
|
|
2126
|
+
}
|
|
2127
|
+
({
|
|
2128
|
+
concentric: { color: t2["status-success"]},
|
|
2129
|
+
hold: { color: t2["brand-primary"]},
|
|
2130
|
+
eccentric: { color: t2["status-warning"]}
|
|
2131
|
+
});
|
|
1097
2132
|
|
|
1098
|
-
// src/
|
|
1099
|
-
var
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
400: "#FFBF4C",
|
|
1126
|
-
// Warning light
|
|
1127
|
-
500: "#FFB020",
|
|
1128
|
-
// Warning main
|
|
1129
|
-
600: "#B27B16"},
|
|
1130
|
-
// Sky/Blue scale (info)
|
|
1131
|
-
sky: {
|
|
1132
|
-
50: "#F0F9FF",
|
|
1133
|
-
400: "#64B6F7",
|
|
1134
|
-
// Info light
|
|
1135
|
-
500: "#2196F3",
|
|
1136
|
-
700: "#0B79D0"},
|
|
1137
|
-
// Neutral/Gray scale
|
|
1138
|
-
neutral: {
|
|
1139
|
-
50: "#FAFAFA",
|
|
1140
|
-
100: "#F3F4F6",
|
|
1141
|
-
300: "#D1D5DB",
|
|
1142
|
-
400: "#9CA3AF",
|
|
1143
|
-
500: "#6B7280",
|
|
1144
|
-
600: "#4B5563",
|
|
1145
|
-
900: "#111827"},
|
|
1146
|
-
// Orange scale (accent/brand color)
|
|
1147
|
-
accent: {
|
|
1148
|
-
200: "#FF9630",
|
|
1149
|
-
300: "#FF8500",
|
|
1150
|
-
400: "#FF7900",
|
|
1151
|
-
500: "#F56C00",
|
|
1152
|
-
600: "#E06D10",
|
|
1153
|
-
700: "#D0620C"},
|
|
1154
|
-
// Charcoal scale (dark backgrounds)
|
|
1155
|
-
charcoal: {
|
|
1156
|
-
300: "#2C2C2C",
|
|
1157
|
-
400: "#1F1F1F",
|
|
1158
|
-
500: "#1C1C1C",
|
|
1159
|
-
600: "#191919",
|
|
1160
|
-
700: "#161616",
|
|
1161
|
-
900: "#101010"
|
|
1162
|
-
},
|
|
1163
|
-
// Steel scale (cool accent)
|
|
1164
|
-
steel: {
|
|
1165
|
-
300: "#678498",
|
|
1166
|
-
400: "#557488",
|
|
1167
|
-
500: "#406D87",
|
|
1168
|
-
600: "#39617A",
|
|
1169
|
-
700: "#32556D"},
|
|
1170
|
-
// Pure colors
|
|
1171
|
-
white: "#FFFFFF"};
|
|
1172
|
-
var discreteRainbow = [
|
|
1173
|
-
"#E8ECFB",
|
|
1174
|
-
"#D9CCE3",
|
|
1175
|
-
"#D1BBD7",
|
|
1176
|
-
"#CAACCB",
|
|
1177
|
-
"#BA8DB4",
|
|
1178
|
-
"#AE76A3",
|
|
1179
|
-
"#AA6F9E",
|
|
1180
|
-
"#994F88",
|
|
1181
|
-
"#882E72",
|
|
1182
|
-
"#1965B0",
|
|
1183
|
-
"#437DBF",
|
|
1184
|
-
"#5289C7",
|
|
1185
|
-
"#6195CF",
|
|
1186
|
-
"#7BAFDE",
|
|
1187
|
-
"#4EB265",
|
|
1188
|
-
"#90C987",
|
|
1189
|
-
"#CAE0AB",
|
|
1190
|
-
"#F7F056",
|
|
1191
|
-
"#F7CB45",
|
|
1192
|
-
"#F6C141",
|
|
1193
|
-
"#F4A736",
|
|
1194
|
-
"#F1932D",
|
|
1195
|
-
"#EE8026",
|
|
1196
|
-
"#E8601C",
|
|
1197
|
-
"#E65518",
|
|
1198
|
-
"#DC050C",
|
|
1199
|
-
"#A5170E",
|
|
1200
|
-
"#72190E",
|
|
1201
|
-
"#42150A"
|
|
1202
|
-
];
|
|
1203
|
-
|
|
1204
|
-
// src/theme/tokens/semantic.ts
|
|
1205
|
-
var semanticColorsLight = {
|
|
1206
|
-
// Brand colors (brand-*)
|
|
1207
|
-
"brand-primary": primitiveColors.accent[400],
|
|
1208
|
-
// #FF7900
|
|
1209
|
-
"brand-primary-light": primitiveColors.accent[200],
|
|
1210
|
-
// #FF9630
|
|
1211
|
-
"brand-primary-dark": primitiveColors.accent[700],
|
|
1212
|
-
// #D0620C
|
|
1213
|
-
"brand-primary-subtle": "rgba(255, 121, 0, 0.08)",
|
|
1214
|
-
"brand-primary-hover": primitiveColors.accent[500],
|
|
1215
|
-
"brand-primary-active": primitiveColors.accent[600],
|
|
1216
|
-
"brand-secondary": primitiveColors.steel[500],
|
|
1217
|
-
// #406D87
|
|
1218
|
-
"brand-secondary-light": primitiveColors.steel[300],
|
|
1219
|
-
// #678498
|
|
1220
|
-
"brand-secondary-dark": primitiveColors.steel[700],
|
|
1221
|
-
// #32556D
|
|
1222
|
-
"brand-secondary-subtle": "rgba(64, 109, 135, 0.08)",
|
|
1223
|
-
"brand-secondary-hover": primitiveColors.steel[600],
|
|
1224
|
-
"brand-secondary-active": primitiveColors.steel[700],
|
|
1225
|
-
// Text on brand backgrounds (on-*)
|
|
1226
|
-
"on-brand-primary": primitiveColors.white,
|
|
1227
|
-
"on-brand-secondary": primitiveColors.white,
|
|
1228
|
-
// Status colors (status-*)
|
|
1229
|
-
"status-success": primitiveColors.teal[500],
|
|
1230
|
-
// #14B8A6
|
|
1231
|
-
"status-success-light": primitiveColors.teal[400],
|
|
1232
|
-
// #43C6B7
|
|
1233
|
-
"status-success-dark": primitiveColors.teal[700],
|
|
1234
|
-
// #0E8074
|
|
1235
|
-
"status-success-subtle": primitiveColors.teal[50],
|
|
1236
|
-
"status-error": primitiveColors.red[600],
|
|
1237
|
-
// #D14343
|
|
1238
|
-
"status-error-light": primitiveColors.red[400],
|
|
1239
|
-
// #DA6868
|
|
1240
|
-
"status-error-dark": primitiveColors.red[700],
|
|
1241
|
-
// #922E2E
|
|
1242
|
-
"status-error-subtle": primitiveColors.red[50],
|
|
1243
|
-
"status-warning": primitiveColors.amber[500],
|
|
1244
|
-
// #FFB020
|
|
1245
|
-
"status-warning-light": primitiveColors.amber[400],
|
|
1246
|
-
// #FFBF4C
|
|
1247
|
-
"status-warning-dark": primitiveColors.amber[600],
|
|
1248
|
-
// #B27B16
|
|
1249
|
-
"status-warning-subtle": primitiveColors.amber[50],
|
|
1250
|
-
"status-info": primitiveColors.sky[500],
|
|
1251
|
-
// #2196F3
|
|
1252
|
-
"status-info-light": primitiveColors.sky[400],
|
|
1253
|
-
// #64B6F7
|
|
1254
|
-
"status-info-dark": primitiveColors.sky[700],
|
|
1255
|
-
// #0B79D0
|
|
1256
|
-
"status-info-subtle": primitiveColors.sky[50],
|
|
1257
|
-
// Text on status backgrounds (on-status-*)
|
|
1258
|
-
"on-status-success": primitiveColors.white,
|
|
1259
|
-
"on-status-error": primitiveColors.white,
|
|
1260
|
-
"on-status-warning": primitiveColors.white,
|
|
1261
|
-
"on-status-info": primitiveColors.white,
|
|
1262
|
-
// Result/outcome indicators (result-*)
|
|
1263
|
-
"result-improve": "#4caf50",
|
|
1264
|
-
// Green - positive outcome
|
|
1265
|
-
"result-improve-light": "rgba(76, 175, 80, 0.12)",
|
|
1266
|
-
"result-improve-dark": "#248a24",
|
|
1267
|
-
"result-degrade": "#ef5350",
|
|
1268
|
-
// Red - negative outcome
|
|
1269
|
-
"result-degrade-light": "rgba(239, 83, 80, 0.12)",
|
|
1270
|
-
"result-degrade-dark": "#b30000",
|
|
1271
|
-
"result-inconclusive": "#9E9A97",
|
|
1272
|
-
// Gray - no clear result
|
|
1273
|
-
"result-inconclusive-light": "rgba(158, 154, 151, 0.12)",
|
|
1274
|
-
"result-neutral": primitiveColors.neutral[500],
|
|
1275
|
-
// Neutral baseline
|
|
1276
|
-
// Text on result backgrounds (on-result-*)
|
|
1277
|
-
"on-result-improve": primitiveColors.white,
|
|
1278
|
-
"on-result-degrade": primitiveColors.white,
|
|
1279
|
-
"on-result-inconclusive": primitiveColors.white,
|
|
1280
|
-
// Data visualization colors (data-*)
|
|
1281
|
-
// First 10 colors from discrete rainbow optimized for charts
|
|
1282
|
-
"data-1": discreteRainbow[9],
|
|
1283
|
-
// #1965B0 - Blue
|
|
1284
|
-
"data-2": discreteRainbow[14],
|
|
1285
|
-
// #4EB265 - Green
|
|
1286
|
-
"data-3": discreteRainbow[17],
|
|
1287
|
-
// #F7F056 - Yellow
|
|
1288
|
-
"data-4": discreteRainbow[25],
|
|
1289
|
-
// #DC050C - Red
|
|
1290
|
-
"data-5": discreteRainbow[8],
|
|
1291
|
-
// #882E72 - Purple
|
|
1292
|
-
"data-6": discreteRainbow[20],
|
|
1293
|
-
// #F4A736 - Orange
|
|
1294
|
-
"data-7": discreteRainbow[13],
|
|
1295
|
-
// #7BAFDE - Light Blue
|
|
1296
|
-
"data-8": discreteRainbow[15],
|
|
1297
|
-
// #90C987 - Light Green
|
|
1298
|
-
"data-9": discreteRainbow[3],
|
|
1299
|
-
// #CAACCB - Lavender
|
|
1300
|
-
"data-10": discreteRainbow[22],
|
|
1301
|
-
// #EE8026 - Dark Orange
|
|
1302
|
-
// Text colors (text-*)
|
|
1303
|
-
"text-primary": "#121828",
|
|
1304
|
-
"text-secondary": "#65748B",
|
|
1305
|
-
"text-tertiary": primitiveColors.neutral[400],
|
|
1306
|
-
"text-disabled": "rgba(55, 65, 81, 0.48)",
|
|
1307
|
-
"text-inverse": primitiveColors.white,
|
|
1308
|
-
"text-link": primitiveColors.blue[600],
|
|
1309
|
-
"text-link-hover": primitiveColors.blue[700],
|
|
1310
|
-
// Surface colors (surface-*) - for elevated containers
|
|
1311
|
-
"surface-base": primitiveColors.white,
|
|
1312
|
-
"surface-elevated": primitiveColors.neutral[50],
|
|
1313
|
-
// #FAFAFA - slightly off-white for elevated cards
|
|
1314
|
-
"surface-raised": primitiveColors.neutral[100],
|
|
1315
|
-
// #F3F4F6 - light gray for raised cards
|
|
1316
|
-
"surface-overlay": primitiveColors.white,
|
|
1317
|
-
"surface-input": primitiveColors.neutral[50],
|
|
1318
|
-
// Input field background (filled variant)
|
|
1319
|
-
// Background colors (background-*)
|
|
1320
|
-
"background-base": "#EBEBEB",
|
|
1321
|
-
"background-default": primitiveColors.white,
|
|
1322
|
-
"background-subtle": primitiveColors.neutral[50],
|
|
1323
|
-
// Border colors (border-*)
|
|
1324
|
-
"border-default": "#E8E9EB",
|
|
1325
|
-
"border-subtle": primitiveColors.neutral[100],
|
|
1326
|
-
"border-strong": primitiveColors.neutral[300],
|
|
1327
|
-
"border-focus": primitiveColors.blue[600],
|
|
1328
|
-
"border-input": primitiveColors.neutral[300],
|
|
1329
|
-
// Input field border
|
|
1330
|
-
"border-input-hover": primitiveColors.neutral[400],
|
|
1331
|
-
// Input field border on hover
|
|
1332
|
-
"border-input-focus": primitiveColors.blue[600],
|
|
1333
|
-
// Input field border on focus
|
|
1334
|
-
"border-input-error": primitiveColors.red[600],
|
|
1335
|
-
// Input field border on error
|
|
1336
|
-
// Interactive states (interactive-*)
|
|
1337
|
-
"interactive-hover": "rgba(55, 65, 81, 0.04)",
|
|
1338
|
-
"interactive-focus": "rgba(55, 65, 81, 0.12)",
|
|
1339
|
-
"interactive-active": "rgba(55, 65, 81, 0.16)",
|
|
1340
|
-
"interactive-selected": "rgba(55, 65, 81, 0.08)",
|
|
1341
|
-
"interactive-disabled": "rgba(55, 65, 81, 0.12)",
|
|
1342
|
-
"interactive-disabled-text": "rgba(55, 65, 81, 0.26)",
|
|
1343
|
-
// Divider
|
|
1344
|
-
"divider": "#E8E9EB",
|
|
1345
|
-
// Avatar default
|
|
1346
|
-
"avatar-background": primitiveColors.neutral[500],
|
|
1347
|
-
"avatar-text": primitiveColors.white
|
|
1348
|
-
};
|
|
1349
|
-
var semanticColorsDark = {
|
|
1350
|
-
// Brand colors stay the same in dark mode
|
|
1351
|
-
"brand-primary": primitiveColors.accent[400],
|
|
1352
|
-
"brand-primary-light": primitiveColors.accent[200],
|
|
1353
|
-
"brand-primary-dark": primitiveColors.accent[700],
|
|
1354
|
-
"brand-primary-subtle": "rgba(255, 121, 0, 0.12)",
|
|
1355
|
-
"brand-primary-hover": primitiveColors.accent[300],
|
|
1356
|
-
"brand-primary-active": primitiveColors.accent[200],
|
|
1357
|
-
"brand-secondary": primitiveColors.steel[500],
|
|
1358
|
-
"brand-secondary-light": primitiveColors.steel[300],
|
|
1359
|
-
"brand-secondary-dark": primitiveColors.steel[700],
|
|
1360
|
-
"brand-secondary-subtle": "rgba(64, 109, 135, 0.12)",
|
|
1361
|
-
"brand-secondary-hover": primitiveColors.steel[400],
|
|
1362
|
-
"brand-secondary-active": primitiveColors.steel[300],
|
|
1363
|
-
// Text on brand backgrounds
|
|
1364
|
-
"on-brand-primary": primitiveColors.white,
|
|
1365
|
-
"on-brand-secondary": primitiveColors.white,
|
|
1366
|
-
// Status colors
|
|
1367
|
-
"status-success": primitiveColors.teal[500],
|
|
1368
|
-
"status-success-light": primitiveColors.teal[400],
|
|
1369
|
-
"status-success-dark": primitiveColors.teal[700],
|
|
1370
|
-
"status-success-subtle": "rgba(20, 184, 166, 0.12)",
|
|
1371
|
-
"status-error": primitiveColors.red[600],
|
|
1372
|
-
"status-error-light": primitiveColors.red[400],
|
|
1373
|
-
"status-error-dark": primitiveColors.red[700],
|
|
1374
|
-
"status-error-subtle": "rgba(209, 67, 67, 0.12)",
|
|
1375
|
-
"status-warning": primitiveColors.amber[500],
|
|
1376
|
-
"status-warning-light": primitiveColors.amber[400],
|
|
1377
|
-
"status-warning-dark": primitiveColors.amber[600],
|
|
1378
|
-
"status-warning-subtle": "rgba(255, 176, 32, 0.12)",
|
|
1379
|
-
"status-info": primitiveColors.sky[500],
|
|
1380
|
-
"status-info-light": primitiveColors.sky[400],
|
|
1381
|
-
"status-info-dark": primitiveColors.sky[700],
|
|
1382
|
-
"status-info-subtle": "rgba(33, 150, 243, 0.12)",
|
|
1383
|
-
// Text on status backgrounds
|
|
1384
|
-
"on-status-success": primitiveColors.white,
|
|
1385
|
-
"on-status-error": primitiveColors.white,
|
|
1386
|
-
"on-status-warning": primitiveColors.white,
|
|
1387
|
-
"on-status-info": primitiveColors.white,
|
|
1388
|
-
// Result/outcome indicators (result-*)
|
|
1389
|
-
"result-improve": "#4caf50",
|
|
1390
|
-
"result-improve-light": "rgba(76, 175, 80, 0.16)",
|
|
1391
|
-
"result-improve-dark": "#248a24",
|
|
1392
|
-
"result-degrade": "#ef5350",
|
|
1393
|
-
"result-degrade-light": "rgba(239, 83, 80, 0.16)",
|
|
1394
|
-
"result-degrade-dark": "#b30000",
|
|
1395
|
-
"result-inconclusive": "#9E9A97",
|
|
1396
|
-
"result-inconclusive-light": "rgba(158, 154, 151, 0.16)",
|
|
1397
|
-
"result-neutral": primitiveColors.neutral[400],
|
|
1398
|
-
// Text on result backgrounds
|
|
1399
|
-
"on-result-improve": primitiveColors.white,
|
|
1400
|
-
"on-result-degrade": primitiveColors.white,
|
|
1401
|
-
"on-result-inconclusive": primitiveColors.white,
|
|
1402
|
-
// Data visualization colors (same in dark mode for consistency)
|
|
1403
|
-
"data-1": discreteRainbow[9],
|
|
1404
|
-
"data-2": discreteRainbow[14],
|
|
1405
|
-
"data-3": discreteRainbow[17],
|
|
1406
|
-
"data-4": discreteRainbow[25],
|
|
1407
|
-
"data-5": discreteRainbow[8],
|
|
1408
|
-
"data-6": discreteRainbow[20],
|
|
1409
|
-
"data-7": discreteRainbow[13],
|
|
1410
|
-
"data-8": discreteRainbow[15],
|
|
1411
|
-
"data-9": discreteRainbow[3],
|
|
1412
|
-
"data-10": discreteRainbow[22],
|
|
1413
|
-
// Text colors - inverted for dark mode
|
|
1414
|
-
"text-primary": primitiveColors.neutral[100],
|
|
1415
|
-
"text-secondary": primitiveColors.neutral[400],
|
|
1416
|
-
"text-tertiary": primitiveColors.neutral[500],
|
|
1417
|
-
"text-disabled": "rgba(255, 255, 255, 0.38)",
|
|
1418
|
-
"text-inverse": primitiveColors.neutral[900],
|
|
1419
|
-
"text-link": "#828DF8",
|
|
1420
|
-
"text-link-hover": primitiveColors.blue[400],
|
|
1421
|
-
// Surface colors - dark backgrounds
|
|
1422
|
-
"surface-base": primitiveColors.charcoal[700],
|
|
1423
|
-
// #161616 - main surface
|
|
1424
|
-
"surface-elevated": primitiveColors.charcoal[600],
|
|
1425
|
-
// #191919 - elevated surface
|
|
1426
|
-
"surface-raised": primitiveColors.charcoal[500],
|
|
1427
|
-
// #1C1C1C - raised surface
|
|
1428
|
-
"surface-overlay": primitiveColors.charcoal[600],
|
|
1429
|
-
// #191919 - overlay surface
|
|
1430
|
-
"surface-input": primitiveColors.charcoal[600],
|
|
1431
|
-
// #191919 - input surface
|
|
1432
|
-
// Background colors
|
|
1433
|
-
"background-base": primitiveColors.charcoal[900],
|
|
1434
|
-
// #101010 - darkest charcoal
|
|
1435
|
-
"background-default": primitiveColors.charcoal[700],
|
|
1436
|
-
// #161616 - main background
|
|
1437
|
-
"background-subtle": primitiveColors.charcoal[500],
|
|
1438
|
-
// #1C1C1C - subtle background
|
|
1439
|
-
// Border colors
|
|
1440
|
-
"border-default": primitiveColors.charcoal[400],
|
|
1441
|
-
// #1F1F1F - default border
|
|
1442
|
-
"border-subtle": primitiveColors.charcoal[500],
|
|
1443
|
-
// #1C1C1C - subtle border
|
|
1444
|
-
"border-strong": primitiveColors.charcoal[300],
|
|
1445
|
-
// #2C2C2C - strong border
|
|
1446
|
-
"border-focus": "#828DF8",
|
|
1447
|
-
"border-input": primitiveColors.neutral[600],
|
|
1448
|
-
"border-input-hover": primitiveColors.neutral[500],
|
|
1449
|
-
"border-input-focus": "#828DF8",
|
|
1450
|
-
"border-input-error": primitiveColors.red[500],
|
|
1451
|
-
// Interactive states
|
|
1452
|
-
"interactive-hover": "rgba(255, 255, 255, 0.04)",
|
|
1453
|
-
"interactive-focus": "rgba(255, 255, 255, 0.12)",
|
|
1454
|
-
"interactive-active": "rgba(255, 255, 255, 0.16)",
|
|
1455
|
-
"interactive-selected": "rgba(255, 255, 255, 0.08)",
|
|
1456
|
-
"interactive-disabled": "rgba(255, 255, 255, 0.12)",
|
|
1457
|
-
"interactive-disabled-text": "rgba(255, 255, 255, 0.26)",
|
|
1458
|
-
// Divider
|
|
1459
|
-
"divider": primitiveColors.charcoal[400],
|
|
1460
|
-
// #1F1F1F - divider color
|
|
1461
|
-
// Avatar default
|
|
1462
|
-
"avatar-background": primitiveColors.neutral[600],
|
|
1463
|
-
"avatar-text": primitiveColors.white
|
|
1464
|
-
};
|
|
1465
|
-
function getSemanticColors(mode) {
|
|
1466
|
-
return mode === "dark" ? semanticColorsDark : semanticColorsLight;
|
|
1467
|
-
}
|
|
1468
|
-
|
|
1469
|
-
// src/components/custom/Workout/TempoBar.tsx
|
|
1470
|
-
var t = getSemanticColors("dark");
|
|
1471
|
-
var TEMPO_PACING = {
|
|
1472
|
-
behindThresholdPct: 0.15,
|
|
1473
|
-
minPhaseDurationMs: 500
|
|
1474
|
-
};
|
|
1475
|
-
function getTempoPacingState(elapsedMs, targetMs) {
|
|
1476
|
-
if (!targetMs || targetMs < TEMPO_PACING.minPhaseDurationMs) return "none";
|
|
1477
|
-
const ratio = elapsedMs / targetMs;
|
|
1478
|
-
if (ratio > 1 + TEMPO_PACING.behindThresholdPct) return "behind";
|
|
1479
|
-
return "on-pace";
|
|
1480
|
-
}
|
|
1481
|
-
function getTempoFillPct(elapsedMs, targetMs) {
|
|
1482
|
-
if (!targetMs) return 100;
|
|
1483
|
-
return Math.min(100, elapsedMs / targetMs * 100);
|
|
1484
|
-
}
|
|
1485
|
-
({
|
|
1486
|
-
concentric: { color: t["status-success"]},
|
|
1487
|
-
hold: { color: t["brand-primary"]},
|
|
1488
|
-
eccentric: { color: t["status-warning"]}
|
|
1489
|
-
});
|
|
1490
|
-
|
|
1491
|
-
// src/components/custom/Workout/TempoDisplay.tsx
|
|
1492
|
-
var INTER = "Inter, sans-serif";
|
|
1493
|
-
var TEXT_TERTIARY = "#6B7280";
|
|
1494
|
-
var STATUS_ERROR = "#D14343";
|
|
1495
|
-
var phaseColors = {
|
|
1496
|
-
eccentric: "#FFB020",
|
|
1497
|
-
// status-warning (amber)
|
|
1498
|
-
pauseBottom: TEXT_TERTIARY,
|
|
1499
|
-
concentric: "#14B8A6",
|
|
1500
|
-
// status-success (teal)
|
|
1501
|
-
pauseTop: TEXT_TERTIARY,
|
|
1502
|
-
dash: TEXT_TERTIARY
|
|
1503
|
-
};
|
|
1504
|
-
function TempoValue({
|
|
1505
|
-
value,
|
|
1506
|
-
color,
|
|
1507
|
-
fontSize
|
|
1508
|
-
}) {
|
|
1509
|
-
return /* @__PURE__ */ jsx(
|
|
1510
|
-
reactNative.Text,
|
|
1511
|
-
{
|
|
1512
|
-
style: {
|
|
1513
|
-
fontFamily: INTER,
|
|
1514
|
-
fontSize,
|
|
1515
|
-
color,
|
|
1516
|
-
fontWeight: "600",
|
|
1517
|
-
letterSpacing: 1
|
|
1518
|
-
},
|
|
1519
|
-
children: value
|
|
1520
|
-
}
|
|
1521
|
-
);
|
|
1522
|
-
}
|
|
1523
|
-
function TempoSeparator({ color, fontSize }) {
|
|
1524
|
-
return /* @__PURE__ */ jsx(
|
|
1525
|
-
reactNative.Text,
|
|
1526
|
-
{
|
|
1527
|
-
style: {
|
|
1528
|
-
fontFamily: INTER,
|
|
1529
|
-
fontSize,
|
|
1530
|
-
color,
|
|
1531
|
-
fontWeight: "600",
|
|
1532
|
-
letterSpacing: 1
|
|
1533
|
-
},
|
|
1534
|
-
children: "-"
|
|
1535
|
-
}
|
|
1536
|
-
);
|
|
1537
|
-
}
|
|
1538
|
-
var LIVE_PHASES = [
|
|
1539
|
-
{ key: "eccentric", color: phaseColors.eccentric },
|
|
1540
|
-
{ key: "pauseBottom", color: phaseColors.pauseBottom },
|
|
1541
|
-
{ key: "concentric", color: phaseColors.concentric },
|
|
1542
|
-
{ key: "pauseTop", color: phaseColors.pauseTop }
|
|
2133
|
+
// src/components/custom/Workout/TempoDisplay.tsx
|
|
2134
|
+
var t3 = getSemanticColors("dark");
|
|
2135
|
+
var INTER = "Inter, sans-serif";
|
|
2136
|
+
var TEXT_TERTIARY = "#6B7280";
|
|
2137
|
+
var STATUS_ERROR = t3["status-error"];
|
|
2138
|
+
var phaseColors = {
|
|
2139
|
+
eccentric: t3["status-warning"],
|
|
2140
|
+
pauseBottom: TEXT_TERTIARY,
|
|
2141
|
+
concentric: t3["status-success"],
|
|
2142
|
+
pauseTop: TEXT_TERTIARY,
|
|
2143
|
+
dash: TEXT_TERTIARY
|
|
2144
|
+
};
|
|
2145
|
+
function TempoValue({
|
|
2146
|
+
value,
|
|
2147
|
+
color,
|
|
2148
|
+
fontSize
|
|
2149
|
+
}) {
|
|
2150
|
+
return /* @__PURE__ */ jsx(MetricCell, { color, fontSize, children: value });
|
|
2151
|
+
}
|
|
2152
|
+
function TempoSeparator({ color, fontSize }) {
|
|
2153
|
+
return /* @__PURE__ */ jsx(MetricCell, { color, fontSize, children: "-" });
|
|
2154
|
+
}
|
|
2155
|
+
var LIVE_PHASES = [
|
|
2156
|
+
{ key: "eccentric", color: phaseColors.eccentric },
|
|
2157
|
+
{ key: "pauseBottom", color: phaseColors.pauseBottom },
|
|
2158
|
+
{ key: "concentric", color: phaseColors.concentric },
|
|
2159
|
+
{ key: "pauseTop", color: phaseColors.pauseTop }
|
|
1543
2160
|
];
|
|
1544
2161
|
function LiveTempoCell({
|
|
1545
2162
|
value,
|
|
@@ -1595,6 +2212,7 @@ function TempoDisplay({
|
|
|
1595
2212
|
tempo,
|
|
1596
2213
|
size = "md",
|
|
1597
2214
|
colored = true,
|
|
2215
|
+
showLabel = true,
|
|
1598
2216
|
showInfo = true,
|
|
1599
2217
|
live,
|
|
1600
2218
|
onPress,
|
|
@@ -1628,7 +2246,7 @@ function TempoDisplay({
|
|
|
1628
2246
|
},
|
|
1629
2247
|
...props,
|
|
1630
2248
|
children: [
|
|
1631
|
-
/* @__PURE__ */ jsx(
|
|
2249
|
+
showLabel && /* @__PURE__ */ jsx(
|
|
1632
2250
|
reactNative.Text,
|
|
1633
2251
|
{
|
|
1634
2252
|
style: {
|
|
@@ -1706,301 +2324,177 @@ function TempoDisplay({
|
|
|
1706
2324
|
testID: "tempo-tooltip",
|
|
1707
2325
|
children: [
|
|
1708
2326
|
/* @__PURE__ */ jsxs(
|
|
1709
|
-
reactNative.View,
|
|
1710
|
-
{
|
|
1711
|
-
style: {
|
|
1712
|
-
backgroundColor: "#191919",
|
|
1713
|
-
borderRadius: 6,
|
|
1714
|
-
paddingVertical: 8,
|
|
1715
|
-
paddingHorizontal: 12,
|
|
1716
|
-
borderWidth: 1,
|
|
1717
|
-
borderColor: "#2C2C2C"
|
|
1718
|
-
},
|
|
1719
|
-
children: [
|
|
1720
|
-
/* @__PURE__ */ jsxs(reactNative.Text, { style: { fontSize: 10, lineHeight: 16, color: "#9CA3AF", fontFamily: INTER }, children: [
|
|
1721
|
-
"Eccentric: ",
|
|
1722
|
-
eccentric,
|
|
1723
|
-
"s"
|
|
1724
|
-
] }),
|
|
1725
|
-
/* @__PURE__ */ jsxs(reactNative.Text, { style: { fontSize: 10, lineHeight: 16, color: "#9CA3AF", fontFamily: INTER }, children: [
|
|
1726
|
-
"Pause (bottom): ",
|
|
1727
|
-
pauseBottom,
|
|
1728
|
-
"s"
|
|
1729
|
-
] }),
|
|
1730
|
-
/* @__PURE__ */ jsxs(reactNative.Text, { style: { fontSize: 10, lineHeight: 16, color: "#9CA3AF", fontFamily: INTER }, children: [
|
|
1731
|
-
"Concentric: ",
|
|
1732
|
-
concentric,
|
|
1733
|
-
"s"
|
|
1734
|
-
] }),
|
|
1735
|
-
/* @__PURE__ */ jsxs(reactNative.Text, { style: { fontSize: 10, lineHeight: 16, color: "#9CA3AF", fontFamily: INTER }, children: [
|
|
1736
|
-
"Pause (top): ",
|
|
1737
|
-
pauseTop,
|
|
1738
|
-
"s"
|
|
1739
|
-
] })
|
|
1740
|
-
]
|
|
1741
|
-
}
|
|
1742
|
-
),
|
|
1743
|
-
/* @__PURE__ */ jsx(
|
|
1744
|
-
reactNative.View,
|
|
1745
|
-
{
|
|
1746
|
-
style: {
|
|
1747
|
-
width: 0,
|
|
1748
|
-
height: 0,
|
|
1749
|
-
borderLeftWidth: 5,
|
|
1750
|
-
borderRightWidth: 5,
|
|
1751
|
-
borderTopWidth: 5,
|
|
1752
|
-
borderLeftColor: "transparent",
|
|
1753
|
-
borderRightColor: "transparent",
|
|
1754
|
-
borderTopColor: "#2C2C2C"
|
|
1755
|
-
}
|
|
1756
|
-
}
|
|
1757
|
-
)
|
|
1758
|
-
]
|
|
1759
|
-
}
|
|
1760
|
-
)
|
|
1761
|
-
]
|
|
1762
|
-
}
|
|
1763
|
-
);
|
|
1764
|
-
}
|
|
1765
|
-
function formatAccessibilityLabel(setNumber, reps, weight, unit) {
|
|
1766
|
-
const repsText = reps != null ? `${reps} reps` : "no reps";
|
|
1767
|
-
const weightText = weight != null ? `at ${roundWeight(weight)} ${unit}` : "";
|
|
1768
|
-
return `Set ${setNumber}: ${repsText}${weightText ? ` ${weightText}` : ""}`;
|
|
1769
|
-
}
|
|
1770
|
-
function SetRow({
|
|
1771
|
-
mode,
|
|
1772
|
-
setNumber,
|
|
1773
|
-
previous,
|
|
1774
|
-
reps,
|
|
1775
|
-
weight,
|
|
1776
|
-
rpe,
|
|
1777
|
-
unit,
|
|
1778
|
-
velocities,
|
|
1779
|
-
velocityZones,
|
|
1780
|
-
velocityLiveRepIndex,
|
|
1781
|
-
velocityExpanded,
|
|
1782
|
-
onVelocityToggle,
|
|
1783
|
-
setType,
|
|
1784
|
-
prBadges,
|
|
1785
|
-
isNextSet,
|
|
1786
|
-
targets
|
|
1787
|
-
}) {
|
|
1788
|
-
const isActive = mode === "active";
|
|
1789
|
-
const isCompleted = mode === "completed";
|
|
1790
|
-
const rowStyle = {
|
|
1791
|
-
flexDirection: "row",
|
|
1792
|
-
alignItems: "center",
|
|
1793
|
-
padding: 7,
|
|
1794
|
-
paddingHorizontal: 8,
|
|
1795
|
-
gap: 8,
|
|
1796
|
-
borderRadius: 8
|
|
1797
|
-
};
|
|
1798
|
-
if (isActive && isNextSet) {
|
|
1799
|
-
rowStyle.backgroundColor = "rgba(255,121,0,0.06)";
|
|
1800
|
-
rowStyle.borderWidth = 1;
|
|
1801
|
-
rowStyle.borderColor = "rgba(255,121,0,0.15)";
|
|
1802
|
-
}
|
|
1803
|
-
if (isCompleted && !isNextSet) {
|
|
1804
|
-
rowStyle.opacity = 0.55;
|
|
1805
|
-
}
|
|
1806
|
-
return /* @__PURE__ */ jsxs(
|
|
1807
|
-
reactNative.View,
|
|
1808
|
-
{
|
|
1809
|
-
style: rowStyle,
|
|
1810
|
-
accessibilityLabel: formatAccessibilityLabel(
|
|
1811
|
-
setNumber,
|
|
1812
|
-
reps,
|
|
1813
|
-
weight,
|
|
1814
|
-
unit
|
|
1815
|
-
),
|
|
1816
|
-
testID: "set-row",
|
|
1817
|
-
children: [
|
|
1818
|
-
/* @__PURE__ */ jsx(
|
|
1819
|
-
reactNative.View,
|
|
1820
|
-
{
|
|
1821
|
-
style: { width: 36, alignItems: "center", justifyContent: "center" },
|
|
1822
|
-
testID: "set-row-set-number",
|
|
1823
|
-
children: setType ? /* @__PURE__ */ jsx(
|
|
1824
|
-
reactNative.Text,
|
|
1825
|
-
{
|
|
1826
|
-
style: {
|
|
1827
|
-
fontSize: 10,
|
|
1828
|
-
fontWeight: "700",
|
|
1829
|
-
fontFamily: "Inter, sans-serif",
|
|
1830
|
-
color: "#ffa502",
|
|
1831
|
-
backgroundColor: "rgba(255,165,2,0.12)",
|
|
1832
|
-
paddingVertical: 1,
|
|
1833
|
-
paddingHorizontal: 5,
|
|
1834
|
-
borderRadius: 3,
|
|
1835
|
-
overflow: "hidden"
|
|
1836
|
-
},
|
|
1837
|
-
testID: "set-row-type-badge",
|
|
1838
|
-
children: setType
|
|
1839
|
-
}
|
|
1840
|
-
) : /* @__PURE__ */ jsx(
|
|
1841
|
-
reactNative.Text,
|
|
1842
|
-
{
|
|
1843
|
-
className: "text-text-secondary",
|
|
1844
|
-
style: {
|
|
1845
|
-
fontSize: 13,
|
|
1846
|
-
fontWeight: "600",
|
|
1847
|
-
fontFamily: "Inter, sans-serif"
|
|
1848
|
-
},
|
|
1849
|
-
children: setNumber
|
|
1850
|
-
}
|
|
1851
|
-
)
|
|
1852
|
-
}
|
|
1853
|
-
),
|
|
1854
|
-
/* @__PURE__ */ jsx(
|
|
1855
|
-
reactNative.View,
|
|
1856
|
-
{
|
|
1857
|
-
className: "flex-1",
|
|
1858
|
-
testID: "set-row-previous",
|
|
1859
|
-
children: /* @__PURE__ */ jsx(
|
|
1860
|
-
reactNative.Text,
|
|
1861
|
-
{
|
|
1862
|
-
className: "text-text-secondary",
|
|
1863
|
-
style: {
|
|
1864
|
-
fontSize: 12,
|
|
1865
|
-
fontFamily: "Inter, sans-serif"
|
|
1866
|
-
},
|
|
1867
|
-
children: previous ? `${previous.reps} x ${roundWeight(previous.weight)}` : "\u2014"
|
|
1868
|
-
}
|
|
1869
|
-
)
|
|
1870
|
-
}
|
|
1871
|
-
),
|
|
1872
|
-
/* @__PURE__ */ jsx(
|
|
1873
|
-
reactNative.View,
|
|
1874
|
-
{
|
|
1875
|
-
style: { width: 44, alignItems: "center", justifyContent: "center" },
|
|
1876
|
-
testID: "set-row-reps",
|
|
1877
|
-
children: isActive && reps == null && targets ? /* @__PURE__ */ jsx(
|
|
1878
|
-
reactNative.Text,
|
|
1879
|
-
{
|
|
1880
|
-
className: "text-text-tertiary",
|
|
1881
|
-
style: {
|
|
1882
|
-
fontSize: 13,
|
|
1883
|
-
fontStyle: "italic",
|
|
1884
|
-
fontFamily: "Inter, sans-serif"
|
|
1885
|
-
},
|
|
1886
|
-
testID: "set-row-target-reps",
|
|
1887
|
-
children: targets.reps
|
|
1888
|
-
}
|
|
1889
|
-
) : /* @__PURE__ */ jsx(
|
|
1890
|
-
reactNative.Text,
|
|
1891
|
-
{
|
|
1892
|
-
className: reps != null ? "text-text-primary" : "text-text-tertiary",
|
|
1893
|
-
style: {
|
|
1894
|
-
fontSize: 14,
|
|
1895
|
-
fontWeight: "600",
|
|
1896
|
-
fontFamily: "Inter, sans-serif"
|
|
1897
|
-
},
|
|
1898
|
-
children: reps != null ? reps : "\u2014"
|
|
1899
|
-
}
|
|
1900
|
-
)
|
|
1901
|
-
}
|
|
1902
|
-
),
|
|
1903
|
-
/* @__PURE__ */ jsx(
|
|
1904
|
-
reactNative.View,
|
|
1905
|
-
{
|
|
1906
|
-
style: { width: 56, alignItems: "center", justifyContent: "center" },
|
|
1907
|
-
testID: "set-row-weight",
|
|
1908
|
-
children: isActive && weight == null && targets ? /* @__PURE__ */ jsx(
|
|
1909
|
-
reactNative.Text,
|
|
1910
|
-
{
|
|
1911
|
-
className: "text-text-tertiary",
|
|
1912
|
-
style: {
|
|
1913
|
-
fontSize: 13,
|
|
1914
|
-
fontStyle: "italic",
|
|
1915
|
-
fontFamily: "Inter, sans-serif"
|
|
1916
|
-
},
|
|
1917
|
-
testID: "set-row-target-weight",
|
|
1918
|
-
children: roundWeight(targets.weight)
|
|
1919
|
-
}
|
|
1920
|
-
) : /* @__PURE__ */ jsx(
|
|
1921
|
-
reactNative.Text,
|
|
1922
|
-
{
|
|
1923
|
-
className: weight != null ? "text-text-primary" : "text-text-tertiary",
|
|
1924
|
-
style: {
|
|
1925
|
-
fontSize: 14,
|
|
1926
|
-
fontWeight: "600",
|
|
1927
|
-
fontFamily: "Inter, sans-serif"
|
|
1928
|
-
},
|
|
1929
|
-
children: weight != null ? roundWeight(weight) : "\u2014"
|
|
1930
|
-
}
|
|
1931
|
-
)
|
|
1932
|
-
}
|
|
1933
|
-
),
|
|
1934
|
-
/* @__PURE__ */ jsx(
|
|
1935
|
-
reactNative.View,
|
|
1936
|
-
{
|
|
1937
|
-
style: { width: 36, alignItems: "center", justifyContent: "center" },
|
|
1938
|
-
testID: "set-row-rpe",
|
|
1939
|
-
children: /* @__PURE__ */ jsx(
|
|
1940
|
-
reactNative.Text,
|
|
1941
|
-
{
|
|
1942
|
-
className: rpe != null ? void 0 : "text-text-tertiary",
|
|
1943
|
-
style: {
|
|
1944
|
-
fontSize: 13,
|
|
1945
|
-
fontWeight: "600",
|
|
1946
|
-
fontFamily: "Inter, sans-serif",
|
|
1947
|
-
// rpeColor returns a concrete hex (native-safe); only the tertiary
|
|
1948
|
-
// fallback needs the className token.
|
|
1949
|
-
color: rpe != null ? rpeColor(rpe) : void 0
|
|
1950
|
-
},
|
|
1951
|
-
children: rpe != null ? roundRpe(rpe) : "\u2014"
|
|
1952
|
-
}
|
|
1953
|
-
)
|
|
1954
|
-
}
|
|
1955
|
-
),
|
|
1956
|
-
prBadges && prBadges.length > 0 && /* @__PURE__ */ jsx(
|
|
1957
|
-
reactNative.View,
|
|
1958
|
-
{
|
|
1959
|
-
className: "flex-row items-center",
|
|
1960
|
-
style: { gap: 4 },
|
|
1961
|
-
testID: "set-row-pr-badges",
|
|
1962
|
-
children: prBadges.map((badge, i) => /* @__PURE__ */ jsx(
|
|
1963
|
-
PrBadge,
|
|
1964
|
-
{
|
|
1965
|
-
type: badge.type,
|
|
1966
|
-
label: badge.label,
|
|
1967
|
-
animate: false,
|
|
1968
|
-
compact: true
|
|
1969
|
-
},
|
|
1970
|
-
i
|
|
1971
|
-
))
|
|
1972
|
-
}
|
|
1973
|
-
),
|
|
1974
|
-
velocities && velocities.length > 0 && /* @__PURE__ */ jsx(
|
|
1975
|
-
reactNative.View,
|
|
1976
|
-
{
|
|
1977
|
-
style: { position: "absolute", bottom: 0, left: 8, right: 8 },
|
|
1978
|
-
testID: "set-row-velocity-strip",
|
|
1979
|
-
children: /* @__PURE__ */ jsx(
|
|
1980
|
-
VelocityStrip,
|
|
1981
|
-
{
|
|
1982
|
-
velocities,
|
|
1983
|
-
zones: velocityZones,
|
|
1984
|
-
liveRepIndex: velocityLiveRepIndex,
|
|
1985
|
-
expanded: velocityExpanded,
|
|
1986
|
-
onToggle: onVelocityToggle,
|
|
1987
|
-
variant: onVelocityToggle ? "full" : "mini"
|
|
1988
|
-
}
|
|
1989
|
-
)
|
|
2327
|
+
reactNative.View,
|
|
2328
|
+
{
|
|
2329
|
+
style: {
|
|
2330
|
+
backgroundColor: "#191919",
|
|
2331
|
+
borderRadius: 6,
|
|
2332
|
+
paddingVertical: 8,
|
|
2333
|
+
paddingHorizontal: 12,
|
|
2334
|
+
borderWidth: 1,
|
|
2335
|
+
borderColor: "#2C2C2C"
|
|
2336
|
+
},
|
|
2337
|
+
children: [
|
|
2338
|
+
/* @__PURE__ */ jsxs(reactNative.Text, { style: { fontSize: 10, lineHeight: 16, color: "#9CA3AF", fontFamily: INTER }, children: [
|
|
2339
|
+
"Eccentric: ",
|
|
2340
|
+
eccentric,
|
|
2341
|
+
"s"
|
|
2342
|
+
] }),
|
|
2343
|
+
/* @__PURE__ */ jsxs(reactNative.Text, { style: { fontSize: 10, lineHeight: 16, color: "#9CA3AF", fontFamily: INTER }, children: [
|
|
2344
|
+
"Pause (bottom): ",
|
|
2345
|
+
pauseBottom,
|
|
2346
|
+
"s"
|
|
2347
|
+
] }),
|
|
2348
|
+
/* @__PURE__ */ jsxs(reactNative.Text, { style: { fontSize: 10, lineHeight: 16, color: "#9CA3AF", fontFamily: INTER }, children: [
|
|
2349
|
+
"Concentric: ",
|
|
2350
|
+
concentric,
|
|
2351
|
+
"s"
|
|
2352
|
+
] }),
|
|
2353
|
+
/* @__PURE__ */ jsxs(reactNative.Text, { style: { fontSize: 10, lineHeight: 16, color: "#9CA3AF", fontFamily: INTER }, children: [
|
|
2354
|
+
"Pause (top): ",
|
|
2355
|
+
pauseTop,
|
|
2356
|
+
"s"
|
|
2357
|
+
] })
|
|
2358
|
+
]
|
|
2359
|
+
}
|
|
2360
|
+
),
|
|
2361
|
+
/* @__PURE__ */ jsx(
|
|
2362
|
+
reactNative.View,
|
|
2363
|
+
{
|
|
2364
|
+
style: {
|
|
2365
|
+
width: 0,
|
|
2366
|
+
height: 0,
|
|
2367
|
+
borderLeftWidth: 5,
|
|
2368
|
+
borderRightWidth: 5,
|
|
2369
|
+
borderTopWidth: 5,
|
|
2370
|
+
borderLeftColor: "transparent",
|
|
2371
|
+
borderRightColor: "transparent",
|
|
2372
|
+
borderTopColor: "#2C2C2C"
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
)
|
|
2376
|
+
]
|
|
1990
2377
|
}
|
|
1991
2378
|
)
|
|
1992
2379
|
]
|
|
1993
2380
|
}
|
|
1994
2381
|
);
|
|
1995
2382
|
}
|
|
1996
|
-
|
|
1997
|
-
|
|
2383
|
+
var t4 = getSemanticColors("dark");
|
|
2384
|
+
var INDICATOR_CONFIG = {
|
|
2385
|
+
imbalance: { Icon: ScaleIcon, color: t4["status-error"], label: "Left/right imbalance" },
|
|
2386
|
+
overshoot: { Icon: AlertTriangleIcon, color: t4["status-error"], label: "Load overshoot" },
|
|
2387
|
+
"velocity-loss": { Icon: TrendingDownIcon, color: t4["status-warning"], label: "Velocity loss" },
|
|
2388
|
+
"missed-reps": { Icon: CircleSlashIcon, color: t4["status-warning"], label: "Missed reps" },
|
|
2389
|
+
pr: { Icon: AwardIcon, color: t4["status-success"], label: "Personal record" },
|
|
2390
|
+
info: { Icon: InfoIcon, color: t4["status-info"], label: "More info" }
|
|
2391
|
+
};
|
|
2392
|
+
function ExerciseIndicator({ kind, onPress, className, ...props }) {
|
|
2393
|
+
const { Icon, color, label } = INDICATOR_CONFIG[kind];
|
|
2394
|
+
const chip = /* @__PURE__ */ jsx(
|
|
2395
|
+
reactNative.View,
|
|
2396
|
+
{
|
|
2397
|
+
className,
|
|
2398
|
+
style: {
|
|
2399
|
+
width: 16,
|
|
2400
|
+
height: 16,
|
|
2401
|
+
borderRadius: 8,
|
|
2402
|
+
borderWidth: 1,
|
|
2403
|
+
borderColor: color,
|
|
2404
|
+
alignItems: "center",
|
|
2405
|
+
justifyContent: "center"
|
|
2406
|
+
},
|
|
2407
|
+
accessibilityRole: "image",
|
|
2408
|
+
accessibilityLabel: label,
|
|
2409
|
+
testID: "exercise-indicator",
|
|
2410
|
+
...props,
|
|
2411
|
+
children: /* @__PURE__ */ jsx(Icon, { size: 11, color })
|
|
2412
|
+
}
|
|
2413
|
+
);
|
|
2414
|
+
if (onPress) {
|
|
2415
|
+
return /* @__PURE__ */ jsx(reactNative.Pressable, { onPress, accessibilityRole: "button", accessibilityLabel: label, children: chip });
|
|
2416
|
+
}
|
|
2417
|
+
return chip;
|
|
1998
2418
|
}
|
|
1999
2419
|
|
|
2000
|
-
// src/components/custom/Workout/
|
|
2001
|
-
function
|
|
2002
|
-
return
|
|
2420
|
+
// src/components/custom/Workout/ExerciseHeading.tsx
|
|
2421
|
+
function headingLabel(name, sets, reps, load, unit) {
|
|
2422
|
+
return `${name}, ${sets}\xD7${reps} @ ${roundWeight(load)} ${unit}`;
|
|
2423
|
+
}
|
|
2424
|
+
function ExerciseHeading({
|
|
2425
|
+
name,
|
|
2426
|
+
sets,
|
|
2427
|
+
reps,
|
|
2428
|
+
load,
|
|
2429
|
+
unit = "lbs",
|
|
2430
|
+
tempo,
|
|
2431
|
+
indicator,
|
|
2432
|
+
dimmed,
|
|
2433
|
+
onPress
|
|
2434
|
+
}) {
|
|
2435
|
+
return /* @__PURE__ */ jsxs(reactNative.View, { style: { opacity: dimmed ? 0.55 : 1 }, testID: "exercise-heading", children: [
|
|
2436
|
+
/* @__PURE__ */ jsxs(
|
|
2437
|
+
reactNative.Pressable,
|
|
2438
|
+
{
|
|
2439
|
+
onPress,
|
|
2440
|
+
accessibilityRole: "button",
|
|
2441
|
+
accessibilityLabel: headingLabel(name, sets, reps, load, unit),
|
|
2442
|
+
className: "flex-row items-center",
|
|
2443
|
+
style: { gap: 8 },
|
|
2444
|
+
testID: "exercise-card-header",
|
|
2445
|
+
children: [
|
|
2446
|
+
/* @__PURE__ */ jsx(
|
|
2447
|
+
reactNative.Text,
|
|
2448
|
+
{
|
|
2449
|
+
className: "text-text-primary",
|
|
2450
|
+
style: { fontSize: 14, fontFamily: '"Space Grotesk", sans-serif', fontWeight: "700" },
|
|
2451
|
+
testID: "exercise-card-name",
|
|
2452
|
+
children: name
|
|
2453
|
+
}
|
|
2454
|
+
),
|
|
2455
|
+
/* @__PURE__ */ jsx(reactNative.View, { className: "flex-1" }),
|
|
2456
|
+
indicator && /* @__PURE__ */ jsx(ExerciseIndicator, { kind: indicator })
|
|
2457
|
+
]
|
|
2458
|
+
}
|
|
2459
|
+
),
|
|
2460
|
+
/* @__PURE__ */ jsxs(
|
|
2461
|
+
reactNative.View,
|
|
2462
|
+
{
|
|
2463
|
+
className: "flex-row items-center",
|
|
2464
|
+
style: { gap: 8, marginTop: 1 },
|
|
2465
|
+
testID: "exercise-card-summary",
|
|
2466
|
+
children: [
|
|
2467
|
+
/* @__PURE__ */ jsx(SetsRepsLoad, { sets, reps, load, unit }),
|
|
2468
|
+
/* @__PURE__ */ jsx(reactNative.View, { className: "flex-1" }),
|
|
2469
|
+
tempo && /* @__PURE__ */ jsx(TempoDisplay, { tempo, size: "sm", showLabel: false, showInfo: false })
|
|
2470
|
+
]
|
|
2471
|
+
}
|
|
2472
|
+
)
|
|
2473
|
+
] });
|
|
2474
|
+
}
|
|
2475
|
+
|
|
2476
|
+
// src/components/custom/Workout/ExerciseCardHeading.tsx
|
|
2477
|
+
function ExerciseCardHeading({
|
|
2478
|
+
setStates,
|
|
2479
|
+
stripHeight = 8,
|
|
2480
|
+
dimmed,
|
|
2481
|
+
testID = "exercise-card",
|
|
2482
|
+
...heading
|
|
2483
|
+
}) {
|
|
2484
|
+
return /* @__PURE__ */ jsxs(
|
|
2485
|
+
reactNative.View,
|
|
2486
|
+
{
|
|
2487
|
+
style: { paddingVertical: 9, paddingHorizontal: 12, opacity: dimmed ? 0.55 : 1 },
|
|
2488
|
+
testID,
|
|
2489
|
+
children: [
|
|
2490
|
+
/* @__PURE__ */ jsx(ExerciseHeading, { ...heading }),
|
|
2491
|
+
setStates.length > 0 && /* @__PURE__ */ jsx(reactNative.View, { style: { marginTop: 7 }, testID: "exercise-card-strip", children: /* @__PURE__ */ jsx(SetStrip, { sets: setStates, height: stripHeight }) })
|
|
2492
|
+
]
|
|
2493
|
+
}
|
|
2494
|
+
);
|
|
2003
2495
|
}
|
|
2496
|
+
|
|
2497
|
+
// src/components/custom/Workout/ExerciseCard.tsx
|
|
2004
2498
|
function getSupersetBorderRadius(position) {
|
|
2005
2499
|
switch (position) {
|
|
2006
2500
|
case "first":
|
|
@@ -2043,7 +2537,7 @@ function formatSummary(summary) {
|
|
|
2043
2537
|
if (!summary) return "";
|
|
2044
2538
|
return `${summary.sets}\xD7${summary.reps} @ ${roundWeight(summary.weight)} ${summary.unit}`;
|
|
2045
2539
|
}
|
|
2046
|
-
function
|
|
2540
|
+
function formatAccessibilityLabel(name, summary, prescription) {
|
|
2047
2541
|
if (summary) return `${name}, ${formatSummary(summary)}`;
|
|
2048
2542
|
if (prescription) return `${name}, ${prescription}`;
|
|
2049
2543
|
return name;
|
|
@@ -2052,7 +2546,6 @@ function CollapsedCard({
|
|
|
2052
2546
|
name,
|
|
2053
2547
|
onToggle,
|
|
2054
2548
|
summary,
|
|
2055
|
-
e1rm,
|
|
2056
2549
|
isPR,
|
|
2057
2550
|
setVelocities,
|
|
2058
2551
|
velocityZones,
|
|
@@ -2071,7 +2564,7 @@ function CollapsedCard({
|
|
|
2071
2564
|
onPressIn: () => setPressed(true),
|
|
2072
2565
|
onPressOut: () => setPressed(false),
|
|
2073
2566
|
accessibilityRole: "button",
|
|
2074
|
-
accessibilityLabel:
|
|
2567
|
+
accessibilityLabel: formatAccessibilityLabel(name, summary, void 0),
|
|
2075
2568
|
testID: "exercise-card",
|
|
2076
2569
|
children: /* @__PURE__ */ jsxs(
|
|
2077
2570
|
reactNative.View,
|
|
@@ -2085,100 +2578,93 @@ function CollapsedCard({
|
|
|
2085
2578
|
...supersetMargin
|
|
2086
2579
|
},
|
|
2087
2580
|
children: [
|
|
2088
|
-
/* @__PURE__ */ jsxs(
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
{
|
|
2138
|
-
className: "flex-row",
|
|
2139
|
-
style: { marginTop: 6, gap: 4 },
|
|
2140
|
-
testID: "exercise-card-strips",
|
|
2141
|
-
children: [
|
|
2142
|
-
setVelocities?.map((velocities, i) => /* @__PURE__ */ jsx(
|
|
2143
|
-
VelocityStrip,
|
|
2144
|
-
{
|
|
2145
|
-
velocities,
|
|
2146
|
-
zones: velocityZones,
|
|
2147
|
-
variant: "mini",
|
|
2148
|
-
testID: `exercise-card-velocity-strip-${i}`
|
|
2149
|
-
},
|
|
2150
|
-
i
|
|
2151
|
-
)),
|
|
2152
|
-
Array.from({ length: remaining }, (_, i) => /* @__PURE__ */ jsx(
|
|
2153
|
-
PlaceholderStrip,
|
|
2154
|
-
{
|
|
2155
|
-
testID: `exercise-card-placeholder-${i}`
|
|
2156
|
-
},
|
|
2157
|
-
`placeholder-${i}`
|
|
2158
|
-
))
|
|
2159
|
-
]
|
|
2160
|
-
}
|
|
2161
|
-
)
|
|
2581
|
+
/* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", testID: "exercise-card-header", children: [
|
|
2582
|
+
/* @__PURE__ */ jsx(
|
|
2583
|
+
reactNative.Text,
|
|
2584
|
+
{
|
|
2585
|
+
className: "text-text-primary",
|
|
2586
|
+
style: {
|
|
2587
|
+
fontSize: 14,
|
|
2588
|
+
fontFamily: '"Space Grotesk", sans-serif',
|
|
2589
|
+
fontWeight: "700"
|
|
2590
|
+
},
|
|
2591
|
+
testID: "exercise-card-name",
|
|
2592
|
+
children: name
|
|
2593
|
+
}
|
|
2594
|
+
),
|
|
2595
|
+
/* @__PURE__ */ jsx(reactNative.View, { className: "flex-1" }),
|
|
2596
|
+
summary && /* @__PURE__ */ jsx(
|
|
2597
|
+
reactNative.Text,
|
|
2598
|
+
{
|
|
2599
|
+
className: "text-text-secondary",
|
|
2600
|
+
style: {
|
|
2601
|
+
fontSize: 12,
|
|
2602
|
+
fontFamily: "Inter, sans-serif",
|
|
2603
|
+
marginRight: 8
|
|
2604
|
+
},
|
|
2605
|
+
testID: "exercise-card-summary",
|
|
2606
|
+
children: formatSummary(summary)
|
|
2607
|
+
}
|
|
2608
|
+
),
|
|
2609
|
+
isPR && /* @__PURE__ */ jsx(reactNative.View, { style: { marginLeft: 4 }, children: /* @__PURE__ */ jsx(PrBadge, { type: "e1rm", compact: true, animate: false }) })
|
|
2610
|
+
] }),
|
|
2611
|
+
(completedSets > 0 || remaining > 0) && /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row", style: { marginTop: 6, gap: 4 }, testID: "exercise-card-strips", children: [
|
|
2612
|
+
setVelocities?.map((velocities, i) => /* @__PURE__ */ jsx(
|
|
2613
|
+
VelocityStrip,
|
|
2614
|
+
{
|
|
2615
|
+
velocities,
|
|
2616
|
+
zones: velocityZones,
|
|
2617
|
+
variant: "mini",
|
|
2618
|
+
testID: `exercise-card-velocity-strip-${i}`
|
|
2619
|
+
},
|
|
2620
|
+
i
|
|
2621
|
+
)),
|
|
2622
|
+
Array.from({ length: remaining }, (_, i) => /* @__PURE__ */ jsx(
|
|
2623
|
+
PlaceholderStrip,
|
|
2624
|
+
{
|
|
2625
|
+
testID: `exercise-card-placeholder-${i}`
|
|
2626
|
+
},
|
|
2627
|
+
`placeholder-${i}`
|
|
2628
|
+
))
|
|
2629
|
+
] })
|
|
2162
2630
|
]
|
|
2163
2631
|
}
|
|
2164
2632
|
)
|
|
2165
2633
|
}
|
|
2166
2634
|
);
|
|
2167
2635
|
}
|
|
2636
|
+
var DARK2 = getSemanticColors("dark");
|
|
2637
|
+
var BODY_DIVIDER = DARK2["border-subtle"];
|
|
2638
|
+
function deriveHeaderSetStates(sets) {
|
|
2639
|
+
return sets.map((set) => {
|
|
2640
|
+
switch (set.state) {
|
|
2641
|
+
case "live":
|
|
2642
|
+
return { status: "active", velocities: set.velocities, planned: set.target.reps };
|
|
2643
|
+
case "done":
|
|
2644
|
+
return { status: "done", velocities: set.velocities };
|
|
2645
|
+
case "todo":
|
|
2646
|
+
return { status: "todo", planned: set.planned ?? set.target.reps };
|
|
2647
|
+
}
|
|
2648
|
+
});
|
|
2649
|
+
}
|
|
2168
2650
|
function ExpandedCard({
|
|
2169
2651
|
name,
|
|
2170
2652
|
onToggle,
|
|
2171
2653
|
summary,
|
|
2172
|
-
e1rm,
|
|
2173
2654
|
isPR,
|
|
2174
2655
|
sets,
|
|
2175
2656
|
tempo,
|
|
2657
|
+
indicator,
|
|
2658
|
+
setStates,
|
|
2659
|
+
stripHeight = 8,
|
|
2660
|
+
velocityZones,
|
|
2176
2661
|
supersetPosition
|
|
2177
2662
|
}) {
|
|
2178
2663
|
const borderRadius = getSupersetBorderRadius(supersetPosition);
|
|
2179
2664
|
const supersetMargin = getSupersetMargin(supersetPosition);
|
|
2180
2665
|
const unit = summary?.unit ?? sets?.[0]?.unit ?? "lbs";
|
|
2181
|
-
const
|
|
2666
|
+
const headerStates = setStates ?? (sets ? deriveHeaderSetStates(sets) : []);
|
|
2667
|
+
const headerIndicator = indicator ?? (isPR ? "pr" : void 0);
|
|
2182
2668
|
return /* @__PURE__ */ jsxs(
|
|
2183
2669
|
reactNative.View,
|
|
2184
2670
|
{
|
|
@@ -2191,114 +2677,32 @@ function ExpandedCard({
|
|
|
2191
2677
|
testID: "exercise-card",
|
|
2192
2678
|
children: [
|
|
2193
2679
|
/* @__PURE__ */ jsx(
|
|
2194
|
-
|
|
2680
|
+
ExerciseCardHeading,
|
|
2195
2681
|
{
|
|
2682
|
+
name,
|
|
2683
|
+
sets: summary?.sets ?? sets?.length ?? 0,
|
|
2684
|
+
reps: summary?.reps ?? 0,
|
|
2685
|
+
load: summary?.weight ?? 0,
|
|
2686
|
+
unit,
|
|
2687
|
+
tempo,
|
|
2688
|
+
indicator: headerIndicator,
|
|
2689
|
+
setStates: headerStates,
|
|
2690
|
+
stripHeight,
|
|
2196
2691
|
onPress: onToggle,
|
|
2197
|
-
|
|
2198
|
-
accessibilityLabel: formatAccessibilityLabel2(name, summary, void 0),
|
|
2199
|
-
"aria-expanded": true,
|
|
2200
|
-
testID: "exercise-card-header",
|
|
2201
|
-
children: /* @__PURE__ */ jsxs(
|
|
2202
|
-
reactNative.View,
|
|
2203
|
-
{
|
|
2204
|
-
className: "flex-row items-center",
|
|
2205
|
-
style: {
|
|
2206
|
-
padding: 12,
|
|
2207
|
-
paddingHorizontal: 14,
|
|
2208
|
-
paddingBottom: 10,
|
|
2209
|
-
borderBottomWidth: 1,
|
|
2210
|
-
borderBottomColor: resolveColor("border-default")
|
|
2211
|
-
},
|
|
2212
|
-
children: [
|
|
2213
|
-
/* @__PURE__ */ jsx(
|
|
2214
|
-
reactNative.Text,
|
|
2215
|
-
{
|
|
2216
|
-
className: "text-text-primary",
|
|
2217
|
-
style: {
|
|
2218
|
-
fontSize: 14,
|
|
2219
|
-
fontFamily: '"Space Grotesk", sans-serif',
|
|
2220
|
-
fontWeight: "700"
|
|
2221
|
-
},
|
|
2222
|
-
testID: "exercise-card-name",
|
|
2223
|
-
children: name
|
|
2224
|
-
}
|
|
2225
|
-
),
|
|
2226
|
-
/* @__PURE__ */ jsx(reactNative.View, { className: "flex-1" }),
|
|
2227
|
-
summary && /* @__PURE__ */ jsx(
|
|
2228
|
-
reactNative.Text,
|
|
2229
|
-
{
|
|
2230
|
-
className: "text-text-secondary",
|
|
2231
|
-
style: {
|
|
2232
|
-
fontSize: 12,
|
|
2233
|
-
fontFamily: "Inter, sans-serif",
|
|
2234
|
-
marginRight: 8
|
|
2235
|
-
},
|
|
2236
|
-
testID: "exercise-card-summary",
|
|
2237
|
-
children: formatSummary(summary)
|
|
2238
|
-
}
|
|
2239
|
-
),
|
|
2240
|
-
e1rm && /* @__PURE__ */ jsx(
|
|
2241
|
-
WeightBadge,
|
|
2242
|
-
{
|
|
2243
|
-
value: roundWeight(e1rm.value),
|
|
2244
|
-
unit: e1rm.unit,
|
|
2245
|
-
size: "sm",
|
|
2246
|
-
showIcon: false,
|
|
2247
|
-
testID: "exercise-card-e1rm"
|
|
2248
|
-
}
|
|
2249
|
-
),
|
|
2250
|
-
isPR && /* @__PURE__ */ jsx(reactNative.View, { style: { marginLeft: 4 }, children: /* @__PURE__ */ jsx(PrBadge, { type: "e1rm", compact: true, animate: false }) })
|
|
2251
|
-
]
|
|
2252
|
-
}
|
|
2253
|
-
)
|
|
2692
|
+
testID: "exercise-card-heading"
|
|
2254
2693
|
}
|
|
2255
2694
|
),
|
|
2256
|
-
|
|
2257
|
-
/* @__PURE__ */ jsx(
|
|
2695
|
+
/* @__PURE__ */ jsxs(
|
|
2258
2696
|
reactNative.View,
|
|
2259
2697
|
{
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
testID: "exercise-card-column-headers",
|
|
2267
|
-
children: columnHeaders.map((header, i) => {
|
|
2268
|
-
const widths = [36, void 0, 44, 56, 36];
|
|
2269
|
-
const width = widths[i];
|
|
2270
|
-
const isFlex = width === void 0;
|
|
2271
|
-
return /* @__PURE__ */ jsx(
|
|
2272
|
-
reactNative.View,
|
|
2273
|
-
{
|
|
2274
|
-
style: {
|
|
2275
|
-
...isFlex ? {} : { width },
|
|
2276
|
-
alignItems: "center",
|
|
2277
|
-
justifyContent: "center",
|
|
2278
|
-
gap: 8
|
|
2279
|
-
},
|
|
2280
|
-
...isFlex ? { className: "flex-1" } : {},
|
|
2281
|
-
children: /* @__PURE__ */ jsx(
|
|
2282
|
-
reactNative.Text,
|
|
2283
|
-
{
|
|
2284
|
-
className: "text-text-tertiary",
|
|
2285
|
-
style: {
|
|
2286
|
-
fontSize: 10,
|
|
2287
|
-
fontWeight: "600",
|
|
2288
|
-
fontFamily: "Inter, sans-serif",
|
|
2289
|
-
textTransform: "uppercase",
|
|
2290
|
-
letterSpacing: 0.8
|
|
2291
|
-
},
|
|
2292
|
-
children: header
|
|
2293
|
-
}
|
|
2294
|
-
)
|
|
2295
|
-
},
|
|
2296
|
-
header
|
|
2297
|
-
);
|
|
2298
|
-
})
|
|
2698
|
+
style: { borderTopWidth: 1, borderTopColor: BODY_DIVIDER, paddingBottom: 6 },
|
|
2699
|
+
testID: "exercise-card-body",
|
|
2700
|
+
children: [
|
|
2701
|
+
/* @__PURE__ */ jsx(SetTableHeader, { unit, showPrevious: false, testID: "exercise-card-column-headers" }),
|
|
2702
|
+
sets && /* @__PURE__ */ jsx(reactNative.View, { testID: "exercise-card-sets", children: sets.map((set, i) => /* @__PURE__ */ jsx(SetRow, { ...set, velocityZones: set.velocityZones ?? velocityZones }, i)) })
|
|
2703
|
+
]
|
|
2299
2704
|
}
|
|
2300
|
-
)
|
|
2301
|
-
sets && /* @__PURE__ */ jsx(reactNative.View, { testID: "exercise-card-sets", children: sets.map((setProps, i) => /* @__PURE__ */ jsx(SetRow, { ...setProps }, i)) })
|
|
2705
|
+
)
|
|
2302
2706
|
]
|
|
2303
2707
|
}
|
|
2304
2708
|
);
|
|
@@ -2307,11 +2711,12 @@ function UpcomingCard({
|
|
|
2307
2711
|
name,
|
|
2308
2712
|
prescription,
|
|
2309
2713
|
previousBest,
|
|
2310
|
-
supersetPosition
|
|
2714
|
+
supersetPosition,
|
|
2715
|
+
onToggle
|
|
2311
2716
|
}) {
|
|
2312
2717
|
const borderRadius = getSupersetBorderRadius(supersetPosition);
|
|
2313
2718
|
const supersetMargin = getSupersetMargin(supersetPosition);
|
|
2314
|
-
return /* @__PURE__ */ jsx(
|
|
2719
|
+
return /* @__PURE__ */ jsx(reactNative.Pressable, { onPress: onToggle, accessibilityRole: "button", children: /* @__PURE__ */ jsx(
|
|
2315
2720
|
reactNative.View,
|
|
2316
2721
|
{
|
|
2317
2722
|
style: {
|
|
@@ -2321,7 +2726,7 @@ function UpcomingCard({
|
|
|
2321
2726
|
...borderRadius,
|
|
2322
2727
|
...supersetMargin
|
|
2323
2728
|
},
|
|
2324
|
-
accessibilityLabel:
|
|
2729
|
+
accessibilityLabel: formatAccessibilityLabel(name, void 0, prescription),
|
|
2325
2730
|
testID: "exercise-card",
|
|
2326
2731
|
children: /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", children: [
|
|
2327
2732
|
/* @__PURE__ */ jsx(
|
|
@@ -2329,6 +2734,7 @@ function UpcomingCard({
|
|
|
2329
2734
|
{
|
|
2330
2735
|
className: "text-text-primary",
|
|
2331
2736
|
style: {
|
|
2737
|
+
flexShrink: 0,
|
|
2332
2738
|
fontSize: 14,
|
|
2333
2739
|
fontFamily: '"Space Grotesk", sans-serif',
|
|
2334
2740
|
fontWeight: "700"
|
|
@@ -2341,7 +2747,9 @@ function UpcomingCard({
|
|
|
2341
2747
|
reactNative.Text,
|
|
2342
2748
|
{
|
|
2343
2749
|
className: "text-text-secondary",
|
|
2750
|
+
numberOfLines: 1,
|
|
2344
2751
|
style: {
|
|
2752
|
+
flexShrink: 1,
|
|
2345
2753
|
fontSize: 12,
|
|
2346
2754
|
fontFamily: "Inter, sans-serif",
|
|
2347
2755
|
marginLeft: 8
|
|
@@ -2350,12 +2758,14 @@ function UpcomingCard({
|
|
|
2350
2758
|
children: prescription
|
|
2351
2759
|
}
|
|
2352
2760
|
),
|
|
2353
|
-
/* @__PURE__ */ jsx(reactNative.View, { className: "flex-1" }),
|
|
2761
|
+
/* @__PURE__ */ jsx(reactNative.View, { className: "flex-1", style: { minWidth: 8 } }),
|
|
2354
2762
|
previousBest && /* @__PURE__ */ jsx(
|
|
2355
2763
|
reactNative.Text,
|
|
2356
2764
|
{
|
|
2357
2765
|
className: "text-text-tertiary",
|
|
2766
|
+
numberOfLines: 1,
|
|
2358
2767
|
style: {
|
|
2768
|
+
flexShrink: 1,
|
|
2359
2769
|
fontSize: 11,
|
|
2360
2770
|
fontFamily: "Inter, sans-serif"
|
|
2361
2771
|
},
|
|
@@ -2365,19 +2775,32 @@ function UpcomingCard({
|
|
|
2365
2775
|
)
|
|
2366
2776
|
] })
|
|
2367
2777
|
}
|
|
2368
|
-
);
|
|
2778
|
+
) });
|
|
2369
2779
|
}
|
|
2370
|
-
function ExerciseCard(
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2780
|
+
function ExerciseCard({
|
|
2781
|
+
upcoming,
|
|
2782
|
+
expanded,
|
|
2783
|
+
defaultExpanded,
|
|
2784
|
+
onExpandedChange,
|
|
2785
|
+
...rest
|
|
2786
|
+
}) {
|
|
2787
|
+
const [internalExpanded, setInternalExpanded] = react.useState(defaultExpanded ?? false);
|
|
2788
|
+
const isControlled = expanded !== void 0;
|
|
2789
|
+
const isExpanded = isControlled ? expanded : internalExpanded;
|
|
2790
|
+
const onToggle = () => {
|
|
2791
|
+
const next = !isExpanded;
|
|
2792
|
+
onExpandedChange?.(next);
|
|
2793
|
+
if (!isControlled) setInternalExpanded(next);
|
|
2794
|
+
};
|
|
2795
|
+
if (upcoming) return /* @__PURE__ */ jsx(UpcomingCard, { ...rest, onToggle });
|
|
2796
|
+
return isExpanded ? /* @__PURE__ */ jsx(ExpandedCard, { ...rest, onToggle }) : /* @__PURE__ */ jsx(CollapsedCard, { ...rest, onToggle });
|
|
2379
2797
|
}
|
|
2380
|
-
|
|
2798
|
+
function resolveColor(token, mode = "dark") {
|
|
2799
|
+
return reactNative.Platform.OS === "web" ? `var(--color-${token})` : getSemanticColors(mode)[token];
|
|
2800
|
+
}
|
|
2801
|
+
|
|
2802
|
+
// src/components/custom/Workout/InputBar.tsx
|
|
2803
|
+
var BRAND_PRIMARY2 = getSemanticColors("dark")["brand-primary"];
|
|
2381
2804
|
var INPUT_CLASSNAME = "bg-surface-raised border-border-strong text-text-primary";
|
|
2382
2805
|
var inputStyle = {
|
|
2383
2806
|
fontSize: 14,
|
|
@@ -2506,7 +2929,7 @@ function InputBar({
|
|
|
2506
2929
|
onPress: onRecord,
|
|
2507
2930
|
disabled: !canRecord,
|
|
2508
2931
|
style: ({ pressed }) => ({
|
|
2509
|
-
backgroundColor:
|
|
2932
|
+
backgroundColor: BRAND_PRIMARY2,
|
|
2510
2933
|
borderRadius: 8,
|
|
2511
2934
|
paddingVertical: 10,
|
|
2512
2935
|
paddingHorizontal: 16,
|
|
@@ -2533,7 +2956,46 @@ function InputBar({
|
|
|
2533
2956
|
}
|
|
2534
2957
|
);
|
|
2535
2958
|
}
|
|
2536
|
-
|
|
2959
|
+
function formatDuration(ms) {
|
|
2960
|
+
const totalSeconds = Math.max(0, Math.ceil(ms / 1e3));
|
|
2961
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
2962
|
+
const seconds = totalSeconds % 60;
|
|
2963
|
+
return `${minutes}:${String(seconds).padStart(2, "0")}`;
|
|
2964
|
+
}
|
|
2965
|
+
function useTimer(options = {}) {
|
|
2966
|
+
const {
|
|
2967
|
+
mode = "up",
|
|
2968
|
+
durationMs,
|
|
2969
|
+
elapsedMs: controlledElapsedMs,
|
|
2970
|
+
running = false,
|
|
2971
|
+
autoTick = false,
|
|
2972
|
+
tickMs = 1e3
|
|
2973
|
+
} = options;
|
|
2974
|
+
const isControlled = controlledElapsedMs != null;
|
|
2975
|
+
const [internalElapsedMs, setInternalElapsedMs] = react.useState(0);
|
|
2976
|
+
react.useEffect(() => {
|
|
2977
|
+
if (isControlled || !autoTick || !running) return;
|
|
2978
|
+
const id = setInterval(() => {
|
|
2979
|
+
setInternalElapsedMs((prev) => prev + tickMs);
|
|
2980
|
+
}, tickMs);
|
|
2981
|
+
return () => clearInterval(id);
|
|
2982
|
+
}, [isControlled, autoTick, running, tickMs]);
|
|
2983
|
+
const elapsedMs = isControlled ? controlledElapsedMs : internalElapsedMs;
|
|
2984
|
+
const hasDuration = durationMs != null && durationMs > 0;
|
|
2985
|
+
const remainingMs = durationMs != null ? Math.max(0, durationMs - elapsedMs) : 0;
|
|
2986
|
+
let progress;
|
|
2987
|
+
if (hasDuration) {
|
|
2988
|
+
progress = Math.min(1, Math.max(0, elapsedMs / durationMs));
|
|
2989
|
+
} else {
|
|
2990
|
+
progress = mode === "down" ? 1 : 0;
|
|
2991
|
+
}
|
|
2992
|
+
const label = formatDuration(mode === "down" ? remainingMs : elapsedMs);
|
|
2993
|
+
const done = durationMs != null && elapsedMs >= durationMs;
|
|
2994
|
+
return { elapsedMs, remainingMs, progress, label, done };
|
|
2995
|
+
}
|
|
2996
|
+
|
|
2997
|
+
// src/components/custom/Workout/RestTimer.tsx
|
|
2998
|
+
var BRAND_PRIMARY3 = getSemanticColors("dark")["brand-primary"];
|
|
2537
2999
|
function RestTimer({
|
|
2538
3000
|
totalSeconds,
|
|
2539
3001
|
elapsedMs,
|
|
@@ -2543,14 +3005,18 @@ function RestTimer({
|
|
|
2543
3005
|
visible,
|
|
2544
3006
|
displayOnly = false
|
|
2545
3007
|
}) {
|
|
2546
|
-
|
|
2547
|
-
|
|
3008
|
+
const {
|
|
3009
|
+
remainingMs,
|
|
3010
|
+
progress,
|
|
3011
|
+
label: timeDisplay
|
|
3012
|
+
} = useTimer({
|
|
3013
|
+
mode: "down",
|
|
3014
|
+
durationMs: totalSeconds * 1e3,
|
|
3015
|
+
elapsedMs
|
|
3016
|
+
});
|
|
2548
3017
|
const remainingSec = Math.ceil(remainingMs / 1e3);
|
|
2549
|
-
const
|
|
2550
|
-
|
|
2551
|
-
const timeDisplay = `${minutes}:${String(seconds).padStart(2, "0")}`;
|
|
2552
|
-
const totalMs = totalSeconds * 1e3;
|
|
2553
|
-
const progressPct = totalMs > 0 ? Math.min(100, elapsedMs / totalMs * 100) : 100;
|
|
3018
|
+
const progressPct = progress * 100;
|
|
3019
|
+
if (!visible) return null;
|
|
2554
3020
|
return /* @__PURE__ */ jsxs(
|
|
2555
3021
|
reactNative.View,
|
|
2556
3022
|
{
|
|
@@ -2639,7 +3105,7 @@ function RestTimer({
|
|
|
2639
3105
|
{
|
|
2640
3106
|
style: {
|
|
2641
3107
|
height: "100%",
|
|
2642
|
-
backgroundColor:
|
|
3108
|
+
backgroundColor: BRAND_PRIMARY3,
|
|
2643
3109
|
borderRadius: 2,
|
|
2644
3110
|
width: `${progressPct}%`
|
|
2645
3111
|
},
|
|
@@ -2696,7 +3162,7 @@ function RestTimer({
|
|
|
2696
3162
|
fontSize: 11,
|
|
2697
3163
|
fontFamily: "Inter, sans-serif",
|
|
2698
3164
|
fontWeight: "600",
|
|
2699
|
-
color:
|
|
3165
|
+
color: BRAND_PRIMARY3
|
|
2700
3166
|
},
|
|
2701
3167
|
children: "Skip"
|
|
2702
3168
|
}
|
|
@@ -2710,7 +3176,7 @@ function RestTimer({
|
|
|
2710
3176
|
}
|
|
2711
3177
|
var DEFAULTS = {
|
|
2712
3178
|
label: "SS",
|
|
2713
|
-
color: "
|
|
3179
|
+
color: getSemanticColors("dark")["brand-primary"],
|
|
2714
3180
|
bgBase: "#101010"
|
|
2715
3181
|
};
|
|
2716
3182
|
function SupersetWrapper({
|
|
@@ -2763,7 +3229,7 @@ function SupersetWrapper({
|
|
|
2763
3229
|
}
|
|
2764
3230
|
|
|
2765
3231
|
// src/components/custom/Workout/ActiveWorkoutPage.tsx
|
|
2766
|
-
var
|
|
3232
|
+
var BRAND_PRIMARY4 = getSemanticColors("dark")["brand-primary"];
|
|
2767
3233
|
function countCompletedSets(exercise) {
|
|
2768
3234
|
if (exercise.setVelocities != null) return exercise.setVelocities.length;
|
|
2769
3235
|
if (exercise.status === "completed") return exercise.totalPlannedSets;
|
|
@@ -2789,23 +3255,22 @@ function deriveWorkoutProgress(exercises) {
|
|
|
2789
3255
|
function findActiveExercise(exercises) {
|
|
2790
3256
|
return exercises.find((exercise) => exercise.status === "active") ?? null;
|
|
2791
3257
|
}
|
|
2792
|
-
function
|
|
2793
|
-
|
|
2794
|
-
return focused ? "expanded" : "collapsed";
|
|
3258
|
+
function isUpcomingExercise(status) {
|
|
3259
|
+
return status === "upcoming";
|
|
2795
3260
|
}
|
|
2796
3261
|
function toActiveCardProps(exercise, focused, onToggle, supersetPosition = null, supersetColor) {
|
|
2797
|
-
const
|
|
3262
|
+
const upcoming = isUpcomingExercise(exercise.status);
|
|
2798
3263
|
return {
|
|
2799
3264
|
name: exercise.name,
|
|
2800
|
-
|
|
2801
|
-
|
|
3265
|
+
upcoming,
|
|
3266
|
+
expanded: focused,
|
|
3267
|
+
onExpandedChange: onToggle,
|
|
2802
3268
|
summary: exercise.summary,
|
|
2803
|
-
e1rm: exercise.e1rm,
|
|
2804
3269
|
isPR: exercise.isPR,
|
|
2805
3270
|
tempo: exercise.tempo,
|
|
2806
3271
|
setVelocities: exercise.setVelocities,
|
|
2807
3272
|
totalPlannedSets: exercise.totalPlannedSets,
|
|
2808
|
-
sets:
|
|
3273
|
+
sets: focused ? exercise.sets : void 0,
|
|
2809
3274
|
prescription: exercise.prescription,
|
|
2810
3275
|
previousBest: exercise.previousBest,
|
|
2811
3276
|
supersetPosition,
|
|
@@ -2878,7 +3343,7 @@ function WorkoutHeader({
|
|
|
2878
3343
|
fontSize: 15,
|
|
2879
3344
|
fontFamily: '"Space Grotesk", sans-serif',
|
|
2880
3345
|
fontWeight: "700",
|
|
2881
|
-
color:
|
|
3346
|
+
color: BRAND_PRIMARY4,
|
|
2882
3347
|
fontVariant: ["tabular-nums"]
|
|
2883
3348
|
},
|
|
2884
3349
|
children: `${progress.completedExercises}/${progress.totalExercises}`
|
|
@@ -2912,7 +3377,7 @@ function WorkoutHeader({
|
|
|
2912
3377
|
style: {
|
|
2913
3378
|
height: "100%",
|
|
2914
3379
|
width: `${Math.round(progress.fraction * 100)}%`,
|
|
2915
|
-
backgroundColor:
|
|
3380
|
+
backgroundColor: BRAND_PRIMARY4,
|
|
2916
3381
|
borderRadius: 2
|
|
2917
3382
|
},
|
|
2918
3383
|
testID: "active-workout-page-progress-fill"
|
|
@@ -3494,17 +3959,18 @@ function CardContent({ children, className }) {
|
|
|
3494
3959
|
function CardFooter({ children, className }) {
|
|
3495
3960
|
return /* @__PURE__ */ jsx(reactNative.View, { className: cn("px-6 py-4 flex-row items-center gap-2", className), children });
|
|
3496
3961
|
}
|
|
3962
|
+
var t5 = getSemanticColors("dark");
|
|
3497
3963
|
var solidVariantColors = {
|
|
3498
|
-
success: "
|
|
3499
|
-
warning: "
|
|
3500
|
-
error: "
|
|
3964
|
+
success: t5["status-success"],
|
|
3965
|
+
warning: t5["status-warning"],
|
|
3966
|
+
error: t5["status-error"],
|
|
3501
3967
|
neutral: "#6B7280"
|
|
3502
3968
|
};
|
|
3503
3969
|
var ringVariantStyles = {
|
|
3504
3970
|
"on-track": {
|
|
3505
|
-
backgroundColor: "rgba(
|
|
3971
|
+
backgroundColor: "rgba(46,213,115,0.15)",
|
|
3506
3972
|
borderWidth: 1,
|
|
3507
|
-
borderColor: "rgba(
|
|
3973
|
+
borderColor: "rgba(46,213,115,0.3)"
|
|
3508
3974
|
},
|
|
3509
3975
|
deviation: {
|
|
3510
3976
|
backgroundColor: "rgba(245,158,11,0.15)",
|
|
@@ -3519,11 +3985,11 @@ var ringVariantStyles = {
|
|
|
3519
3985
|
}
|
|
3520
3986
|
};
|
|
3521
3987
|
var glowStyles = {
|
|
3522
|
-
success: { boxShadow: "0 0 4px rgba(
|
|
3988
|
+
success: { boxShadow: "0 0 4px rgba(46,213,115,0.4)" },
|
|
3523
3989
|
warning: { boxShadow: "0 0 4px rgba(245,158,11,0.4)" },
|
|
3524
3990
|
error: { boxShadow: "0 0 4px rgba(239,68,68,0.4)" },
|
|
3525
3991
|
neutral: { boxShadow: "0 0 4px rgba(107,114,128,0.4)" },
|
|
3526
|
-
"on-track": { boxShadow: "0 0 4px rgba(
|
|
3992
|
+
"on-track": { boxShadow: "0 0 4px rgba(46,213,115,0.4)" },
|
|
3527
3993
|
deviation: { boxShadow: "0 0 4px rgba(245,158,11,0.4)" },
|
|
3528
3994
|
future: { boxShadow: "0 0 4px rgba(107,114,128,0.4)" }
|
|
3529
3995
|
};
|
|
@@ -3537,8 +4003,8 @@ var iconColors = {
|
|
|
3537
4003
|
warning: "#6B4000",
|
|
3538
4004
|
error: "#5C1A1A",
|
|
3539
4005
|
neutral: "#D1D5DB",
|
|
3540
|
-
"on-track": "
|
|
3541
|
-
deviation: "
|
|
4006
|
+
"on-track": t5["status-success"],
|
|
4007
|
+
deviation: t5["status-warning"],
|
|
3542
4008
|
future: "#6B7280"
|
|
3543
4009
|
};
|
|
3544
4010
|
var sizeDimensions = {
|
|
@@ -3619,20 +4085,24 @@ function StatusDot({
|
|
|
3619
4085
|
}
|
|
3620
4086
|
return /* @__PURE__ */ jsx(reactNative.View, { className, ...props, children: dot });
|
|
3621
4087
|
}
|
|
4088
|
+
var MESO_ACCENT_GRADIENT_DARK = primitiveRamps.orange[500];
|
|
4089
|
+
var MESO_ACCENT_GRADIENT_LIGHT = primitiveRamps.orange[300];
|
|
4090
|
+
var WORKOUT_PILL_DELOAD = primitiveRamps.magenta[600];
|
|
3622
4091
|
|
|
3623
4092
|
// src/components/custom/Workout/MesoStatusCard.tsx
|
|
3624
|
-
var
|
|
3625
|
-
var
|
|
3626
|
-
var
|
|
3627
|
-
var
|
|
3628
|
-
var
|
|
3629
|
-
var
|
|
3630
|
-
var
|
|
4093
|
+
var t6 = getSemanticColors("dark");
|
|
4094
|
+
var BRAND_PRIMARY5 = t6["brand-primary"];
|
|
4095
|
+
var BRAND_PRIMARY_DARK = MESO_ACCENT_GRADIENT_DARK;
|
|
4096
|
+
var BRAND_PRIMARY_LIGHT = MESO_ACCENT_GRADIENT_LIGHT;
|
|
4097
|
+
var SUCCESS = t6["status-success"];
|
|
4098
|
+
var WARNING = t6["status-warning"];
|
|
4099
|
+
var ERROR = t6["status-error"];
|
|
4100
|
+
var ACCENT_STOPS = [BRAND_PRIMARY_DARK, BRAND_PRIMARY5, BRAND_PRIMARY_LIGHT];
|
|
3631
4101
|
var CARD_GRADIENT = `linear-gradient(135deg, ${resolveColor("surface-elevated")} 0%, ${resolveColor("surface-raised")} 100%)`;
|
|
3632
|
-
var GAUGE_GRADIENT = "linear-gradient(90deg, rgba(
|
|
4102
|
+
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%)";
|
|
3633
4103
|
var STATUS_VARIANTS = {
|
|
3634
|
-
success: { bg: "rgba(
|
|
3635
|
-
warning: { bg: "rgba(
|
|
4104
|
+
success: { bg: "rgba(46,213,115,0.15)", border: "rgba(46,213,115,0.3)", text: SUCCESS },
|
|
4105
|
+
warning: { bg: "rgba(249,180,21,0.15)", border: "rgba(249,180,21,0.3)", text: WARNING },
|
|
3636
4106
|
error: { bg: "rgba(209,67,67,0.15)", border: "rgba(209,67,67,0.25)", text: ERROR }
|
|
3637
4107
|
};
|
|
3638
4108
|
function clamp01(value) {
|
|
@@ -3698,7 +4168,7 @@ function StatusPill({ badge }) {
|
|
|
3698
4168
|
}
|
|
3699
4169
|
);
|
|
3700
4170
|
}
|
|
3701
|
-
function
|
|
4171
|
+
function MetricCell2({ metric }) {
|
|
3702
4172
|
return /* @__PURE__ */ jsxs(reactNative.View, { style: { width: "48%" }, testID: "meso-status-card-metric", children: [
|
|
3703
4173
|
/* @__PURE__ */ jsx(
|
|
3704
4174
|
reactNative.Text,
|
|
@@ -3916,7 +4386,7 @@ function MesoStatusCard({
|
|
|
3916
4386
|
className: "flex-row flex-wrap",
|
|
3917
4387
|
style: { gap: 8 },
|
|
3918
4388
|
testID: "meso-status-card-metrics",
|
|
3919
|
-
children: metrics.map((metric, index) => /* @__PURE__ */ jsx(
|
|
4389
|
+
children: metrics.map((metric, index) => /* @__PURE__ */ jsx(MetricCell2, { metric }, `${metric.label}-${index}`))
|
|
3920
4390
|
}
|
|
3921
4391
|
),
|
|
3922
4392
|
gauges.length > 0 && /* @__PURE__ */ jsx(reactNative.View, { style: { gap: 12 }, testID: "meso-status-card-gauges", children: gauges.map((gauge, index) => /* @__PURE__ */ jsx(Gauge, { gauge }, `${gauge.label}-${index}`)) }),
|
|
@@ -3924,9 +4394,9 @@ function MesoStatusCard({
|
|
|
3924
4394
|
reactNative.View,
|
|
3925
4395
|
{
|
|
3926
4396
|
style: {
|
|
3927
|
-
backgroundColor: "rgba(
|
|
4397
|
+
backgroundColor: "rgba(249,180,21,0.06)",
|
|
3928
4398
|
borderWidth: 1,
|
|
3929
|
-
borderColor: "rgba(
|
|
4399
|
+
borderColor: "rgba(249,180,21,0.15)",
|
|
3930
4400
|
borderRadius: 8,
|
|
3931
4401
|
paddingVertical: 10,
|
|
3932
4402
|
paddingHorizontal: 12
|
|
@@ -3952,9 +4422,9 @@ function MesoStatusCard({
|
|
|
3952
4422
|
className: "flex-row items-center",
|
|
3953
4423
|
style: {
|
|
3954
4424
|
gap: 8,
|
|
3955
|
-
backgroundColor: "rgba(
|
|
4425
|
+
backgroundColor: "rgba(46,213,115,0.06)",
|
|
3956
4426
|
borderWidth: 1,
|
|
3957
|
-
borderColor: "rgba(
|
|
4427
|
+
borderColor: "rgba(46,213,115,0.2)",
|
|
3958
4428
|
borderRadius: 8,
|
|
3959
4429
|
paddingVertical: 10,
|
|
3960
4430
|
paddingHorizontal: 12
|
|
@@ -3983,21 +4453,22 @@ function MesoStatusCard({
|
|
|
3983
4453
|
}
|
|
3984
4454
|
);
|
|
3985
4455
|
}
|
|
3986
|
-
var
|
|
4456
|
+
var sem = getSemanticColors("dark");
|
|
4457
|
+
var BRAND_PRIMARY6 = sem["brand-primary"];
|
|
3987
4458
|
var PROJECTION_LINE_COLOR = resolveColor("text-tertiary");
|
|
3988
|
-
var STATUS_SUCCESS = "
|
|
3989
|
-
var STATUS_ERROR2 = "
|
|
3990
|
-
var STATUS_WARNING = "
|
|
4459
|
+
var STATUS_SUCCESS = sem["status-success"];
|
|
4460
|
+
var STATUS_ERROR2 = sem["status-error"];
|
|
4461
|
+
var STATUS_WARNING = sem["status-warning"];
|
|
3991
4462
|
var GRID_LINE = "rgba(255,255,255,0.06)";
|
|
3992
|
-
var SUCCESS_PILL_BG = "rgba(
|
|
3993
|
-
var SUCCESS_PILL_BORDER = "rgba(
|
|
4463
|
+
var SUCCESS_PILL_BG = "rgba(46,213,115,0.10)";
|
|
4464
|
+
var SUCCESS_PILL_BORDER = "rgba(46,213,115,0.20)";
|
|
3994
4465
|
var ERROR_PILL_BG = "rgba(209,67,67,0.10)";
|
|
3995
4466
|
var ERROR_PILL_BORDER = "rgba(209,67,67,0.20)";
|
|
3996
4467
|
var PLOT_LEFT = 26;
|
|
3997
4468
|
var TOOLTIP_WIDTH = 124;
|
|
3998
4469
|
function timeOf(dateStr) {
|
|
3999
|
-
const
|
|
4000
|
-
return Number.isNaN(
|
|
4470
|
+
const t12 = Date.parse(dateStr);
|
|
4471
|
+
return Number.isNaN(t12) ? 0 : t12;
|
|
4001
4472
|
}
|
|
4002
4473
|
function formatValue(value) {
|
|
4003
4474
|
return `${Math.round(value)}`;
|
|
@@ -4274,7 +4745,7 @@ function StrengthTrendChart({
|
|
|
4274
4745
|
ChartLine,
|
|
4275
4746
|
{
|
|
4276
4747
|
coords: geometry.actual,
|
|
4277
|
-
color:
|
|
4748
|
+
color: BRAND_PRIMARY6,
|
|
4278
4749
|
strokeWidth: 2.5,
|
|
4279
4750
|
testID: "strength-trend-chart-actual-segment"
|
|
4280
4751
|
}
|
|
@@ -4327,7 +4798,7 @@ function StrengthTrendChart({
|
|
|
4327
4798
|
width: 8,
|
|
4328
4799
|
height: 8,
|
|
4329
4800
|
borderRadius: 1,
|
|
4330
|
-
backgroundColor:
|
|
4801
|
+
backgroundColor: BRAND_PRIMARY6
|
|
4331
4802
|
}
|
|
4332
4803
|
},
|
|
4333
4804
|
`point-${c.index}`
|
|
@@ -4457,7 +4928,7 @@ function StrengthTrendChart({
|
|
|
4457
4928
|
testID: "strength-trend-chart-legend",
|
|
4458
4929
|
children: [
|
|
4459
4930
|
/* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", style: { gap: 5 }, children: [
|
|
4460
|
-
/* @__PURE__ */ jsx(reactNative.View, { style: { width: 14, height: 2.5, borderRadius: 1.5, backgroundColor:
|
|
4931
|
+
/* @__PURE__ */ jsx(reactNative.View, { style: { width: 14, height: 2.5, borderRadius: 1.5, backgroundColor: BRAND_PRIMARY6 } }),
|
|
4461
4932
|
/* @__PURE__ */ jsx(reactNative.Text, { className: "text-text-secondary", style: { fontSize: 10, fontFamily: "Inter, sans-serif" }, children: "Actual" })
|
|
4462
4933
|
] }),
|
|
4463
4934
|
/* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", style: { gap: 5 }, children: [
|
|
@@ -4486,13 +4957,14 @@ function StrengthTrendChart({
|
|
|
4486
4957
|
}
|
|
4487
4958
|
);
|
|
4488
4959
|
}
|
|
4489
|
-
var
|
|
4490
|
-
var
|
|
4491
|
-
var
|
|
4960
|
+
var t7 = getSemanticColors("dark");
|
|
4961
|
+
var STATUS_SUCCESS2 = t7["status-success"];
|
|
4962
|
+
var STATUS_WARNING2 = t7["status-warning"];
|
|
4963
|
+
var STATUS_INFO = t7["status-info"];
|
|
4492
4964
|
var DOT_BORDER = "#F3F4F6";
|
|
4493
|
-
var BAND_FILL = "rgba(
|
|
4494
|
-
var BAND_EDGE = "rgba(
|
|
4495
|
-
var PROJECTION_FILL = "rgba(
|
|
4965
|
+
var BAND_FILL = "rgba(46,213,115,0.1)";
|
|
4966
|
+
var BAND_EDGE = "rgba(46,213,115,0.45)";
|
|
4967
|
+
var PROJECTION_FILL = "rgba(46,213,115,0.05)";
|
|
4496
4968
|
var PADDING_LEFT = 28;
|
|
4497
4969
|
var PADDING_RIGHT = 10;
|
|
4498
4970
|
var PADDING_TOP = 8;
|
|
@@ -4531,13 +5003,13 @@ function interpEdge(pixels, x, key) {
|
|
|
4531
5003
|
const a = pixels[i];
|
|
4532
5004
|
const b = pixels[i + 1];
|
|
4533
5005
|
if (x >= a.x && x <= b.x) {
|
|
4534
|
-
const
|
|
4535
|
-
return a[key] +
|
|
5006
|
+
const t12 = b.x === a.x ? 0 : (x - a.x) / (b.x - a.x);
|
|
5007
|
+
return a[key] + t12 * (b[key] - a[key]);
|
|
4536
5008
|
}
|
|
4537
5009
|
}
|
|
4538
5010
|
return pixels[pixels.length - 1][key];
|
|
4539
5011
|
}
|
|
4540
|
-
function
|
|
5012
|
+
function buildColumns2(pixels, step) {
|
|
4541
5013
|
if (pixels.length < 2) return [];
|
|
4542
5014
|
const start = pixels[0].x;
|
|
4543
5015
|
const end = pixels[pixels.length - 1].x;
|
|
@@ -4649,7 +5121,7 @@ function CapacityBandChart({
|
|
|
4649
5121
|
}
|
|
4650
5122
|
const { toX, toY } = scale;
|
|
4651
5123
|
const bandPixels = toPixels(band, toX, toY);
|
|
4652
|
-
const columns =
|
|
5124
|
+
const columns = buildColumns2(bandPixels, COLUMN_STEP);
|
|
4653
5125
|
const topEdge = buildEdges(bandPixels, "yHigh");
|
|
4654
5126
|
const bottomEdge = buildEdges(bandPixels, "yLow");
|
|
4655
5127
|
const lastBandPoint = band[band.length - 1];
|
|
@@ -4724,8 +5196,8 @@ function CapacityBandChart({
|
|
|
4724
5196
|
testID: "capacity-band-chart-reveal",
|
|
4725
5197
|
children: /* @__PURE__ */ jsxs(reactNative.View, { style: { width, height, position: "relative" }, children: [
|
|
4726
5198
|
projection && /* @__PURE__ */ jsxs(reactNative.View, { testID: "capacity-band-chart-projection", children: [
|
|
4727
|
-
renderColumns(
|
|
4728
|
-
renderColumns(
|
|
5199
|
+
renderColumns(buildColumns2(trainingPixels, COLUMN_STEP), PROJECTION_FILL, "capacity-band-chart-projection-fill"),
|
|
5200
|
+
renderColumns(buildColumns2(restPixels, COLUMN_STEP), PROJECTION_FILL, "capacity-band-chart-projection-fill"),
|
|
4729
5201
|
renderEdges(buildEdges(trainingPixels, "yHigh"), STATUS_SUCCESS2, true, "capacity-band-chart-projection-training"),
|
|
4730
5202
|
renderEdges(buildEdges(trainingPixels, "yLow"), STATUS_SUCCESS2, true, "capacity-band-chart-projection-training"),
|
|
4731
5203
|
renderEdges(buildEdges(restPixels, "yHigh"), STATUS_INFO, true, "capacity-band-chart-projection-rest"),
|
|
@@ -4864,7 +5336,7 @@ function CapacityBandChart({
|
|
|
4864
5336
|
}
|
|
4865
5337
|
|
|
4866
5338
|
// src/components/custom/Workout/ExerciseDetailPage.tsx
|
|
4867
|
-
var
|
|
5339
|
+
var BRAND_PRIMARY7 = getSemanticColors("dark")["brand-primary"];
|
|
4868
5340
|
var CHART_WIDTH = 326;
|
|
4869
5341
|
var CHART_HEIGHT = 150;
|
|
4870
5342
|
var EXERCISE_DETAIL_TABS = [
|
|
@@ -4886,10 +5358,9 @@ function deriveExerciseStats(entries) {
|
|
|
4886
5358
|
function toExerciseCardProps(entry, expanded, onToggle) {
|
|
4887
5359
|
return {
|
|
4888
5360
|
name: entry.title,
|
|
4889
|
-
|
|
4890
|
-
onToggle,
|
|
5361
|
+
expanded,
|
|
5362
|
+
onExpandedChange: onToggle,
|
|
4891
5363
|
summary: entry.summary,
|
|
4892
|
-
e1rm: entry.e1rm,
|
|
4893
5364
|
isPR: entry.isPR,
|
|
4894
5365
|
tempo: entry.tempo,
|
|
4895
5366
|
sets: expanded ? entry.sets : void 0
|
|
@@ -4928,7 +5399,7 @@ function TabBar({ active, onSelect }) {
|
|
|
4928
5399
|
alignItems: "center",
|
|
4929
5400
|
paddingVertical: 10,
|
|
4930
5401
|
borderBottomWidth: 2,
|
|
4931
|
-
borderBottomColor: isActive ?
|
|
5402
|
+
borderBottomColor: isActive ? BRAND_PRIMARY7 : "transparent"
|
|
4932
5403
|
},
|
|
4933
5404
|
testID: `exercise-detail-page-tab-${key}`,
|
|
4934
5405
|
children: /* @__PURE__ */ jsx(
|
|
@@ -5250,7 +5721,7 @@ function ExerciseDetailPage({
|
|
|
5250
5721
|
fontSize: 15,
|
|
5251
5722
|
fontFamily: '"Space Grotesk", sans-serif',
|
|
5252
5723
|
fontWeight: "700",
|
|
5253
|
-
color:
|
|
5724
|
+
color: BRAND_PRIMARY7
|
|
5254
5725
|
},
|
|
5255
5726
|
children: `${exercise.currentE1rm} ${exercise.unit}`
|
|
5256
5727
|
}
|
|
@@ -5316,9 +5787,9 @@ function ExerciseDetailPage({
|
|
|
5316
5787
|
}
|
|
5317
5788
|
);
|
|
5318
5789
|
}
|
|
5319
|
-
var
|
|
5790
|
+
var BRAND_PRIMARY8 = getSemanticColors("dark")["brand-primary"];
|
|
5320
5791
|
var segmentBgColors = {
|
|
5321
|
-
completed: "rgba(
|
|
5792
|
+
completed: "rgba(46,213,115,0.3)",
|
|
5322
5793
|
current: "rgba(255,121,0,0.5)",
|
|
5323
5794
|
upcoming: "rgba(255,255,255,0.06)"
|
|
5324
5795
|
};
|
|
@@ -5368,7 +5839,7 @@ function MesoSegment({ meso, isActive, onPress }) {
|
|
|
5368
5839
|
},
|
|
5369
5840
|
isActive ? {
|
|
5370
5841
|
borderWidth: 2,
|
|
5371
|
-
borderColor:
|
|
5842
|
+
borderColor: BRAND_PRIMARY8,
|
|
5372
5843
|
transform: [{ scale: 1.02 }, { scale: pressScale }]
|
|
5373
5844
|
} : void 0
|
|
5374
5845
|
],
|
|
@@ -5382,7 +5853,7 @@ function MesoSegment({ meso, isActive, onPress }) {
|
|
|
5382
5853
|
top: 0,
|
|
5383
5854
|
bottom: 0,
|
|
5384
5855
|
width: `${progress * 100}%`,
|
|
5385
|
-
backgroundColor:
|
|
5856
|
+
backgroundColor: BRAND_PRIMARY8
|
|
5386
5857
|
},
|
|
5387
5858
|
testID: `meso-segment-fill-${meso.id}`
|
|
5388
5859
|
}
|
|
@@ -5433,9 +5904,11 @@ var colorStyles = {
|
|
|
5433
5904
|
default: "bg-text-tertiary",
|
|
5434
5905
|
primary: "bg-brand-primary",
|
|
5435
5906
|
success: "bg-status-success",
|
|
5907
|
+
live: "bg-status-live",
|
|
5436
5908
|
error: "bg-status-error",
|
|
5437
5909
|
warning: "bg-status-warning",
|
|
5438
|
-
info: "bg-status-info"
|
|
5910
|
+
info: "bg-status-info",
|
|
5911
|
+
"error-vivid": "bg-status-error-vivid"
|
|
5439
5912
|
};
|
|
5440
5913
|
function Indicator({
|
|
5441
5914
|
size = "sm",
|
|
@@ -5443,14 +5916,40 @@ function Indicator({
|
|
|
5443
5916
|
customColor,
|
|
5444
5917
|
glow = false,
|
|
5445
5918
|
ring = false,
|
|
5919
|
+
pulse = false,
|
|
5446
5920
|
className,
|
|
5447
5921
|
style,
|
|
5448
5922
|
...props
|
|
5449
5923
|
}) {
|
|
5924
|
+
const pulseMode = pulse === true ? "opacity" : pulse || false;
|
|
5925
|
+
const colorClass = !customColor ? colorStyles[color] : void 0;
|
|
5926
|
+
const colorStyle = customColor ? { backgroundColor: customColor } : void 0;
|
|
5927
|
+
if (pulseMode === "ping") {
|
|
5928
|
+
return /* @__PURE__ */ jsxs(reactNative.View, { className: cn("relative", sizeStyles[size], className), style, ...props, children: [
|
|
5929
|
+
/* @__PURE__ */ jsx(
|
|
5930
|
+
reactNative.View,
|
|
5931
|
+
{
|
|
5932
|
+
className: cn("absolute inset-0 rounded-full animate-ping", colorClass),
|
|
5933
|
+
style: colorStyle
|
|
5934
|
+
}
|
|
5935
|
+
),
|
|
5936
|
+
/* @__PURE__ */ jsx(
|
|
5937
|
+
reactNative.View,
|
|
5938
|
+
{
|
|
5939
|
+
className: cn(
|
|
5940
|
+
"relative rounded-full",
|
|
5941
|
+
sizeStyles[size],
|
|
5942
|
+
colorClass,
|
|
5943
|
+
ring && "border-2 border-background-base"
|
|
5944
|
+
),
|
|
5945
|
+
style: colorStyle
|
|
5946
|
+
}
|
|
5947
|
+
)
|
|
5948
|
+
] });
|
|
5949
|
+
}
|
|
5450
5950
|
const dynamicStyle = {
|
|
5451
5951
|
...typeof style === "object" ? style : {},
|
|
5452
|
-
...
|
|
5453
|
-
...glow && !customColor ? {} : {},
|
|
5952
|
+
...colorStyle ?? {},
|
|
5454
5953
|
...glow && customColor ? { boxShadow: `0 0 6px ${customColor}` } : {}
|
|
5455
5954
|
};
|
|
5456
5955
|
return /* @__PURE__ */ jsx(
|
|
@@ -5459,12 +5958,14 @@ function Indicator({
|
|
|
5459
5958
|
className: cn(
|
|
5460
5959
|
"rounded-full shrink-0",
|
|
5461
5960
|
sizeStyles[size],
|
|
5462
|
-
|
|
5961
|
+
colorClass,
|
|
5962
|
+
pulseMode === "opacity" && "animate-pulse",
|
|
5463
5963
|
ring && "border-2 border-background-base",
|
|
5464
|
-
glow && !customColor && color === "success" && "shadow-[0_0_6px_rgba(
|
|
5964
|
+
glow && !customColor && (color === "success" || color === "live") && "shadow-[0_0_6px_rgba(46,213,115,0.6)]",
|
|
5465
5965
|
glow && !customColor && color === "error" && "shadow-[0_0_6px_rgba(239,68,68,0.6)]",
|
|
5466
5966
|
glow && !customColor && color === "warning" && "shadow-[0_0_6px_rgba(245,158,11,0.6)]",
|
|
5467
5967
|
glow && !customColor && color === "primary" && "shadow-[0_0_6px_rgba(255,121,0,0.6)]",
|
|
5968
|
+
glow && !customColor && color === "error-vivid" && "shadow-[0_0_6px_rgba(255,71,87,0.6)]",
|
|
5468
5969
|
className
|
|
5469
5970
|
),
|
|
5470
5971
|
style: Object.keys(dynamicStyle).length > 0 ? dynamicStyle : style,
|
|
@@ -5542,31 +6043,32 @@ function Badge({
|
|
|
5542
6043
|
}
|
|
5543
6044
|
);
|
|
5544
6045
|
}
|
|
6046
|
+
var t8 = getSemanticColors("dark");
|
|
5545
6047
|
var statusBgColors = {
|
|
5546
|
-
completed: "rgba(
|
|
6048
|
+
completed: "rgba(46,213,115,0.15)",
|
|
5547
6049
|
current: "rgba(255,121,0,0.15)",
|
|
5548
6050
|
next: "transparent",
|
|
5549
6051
|
upcoming: "#1C1C1C",
|
|
5550
6052
|
missed: "rgba(209,67,67,0.1)",
|
|
5551
|
-
deload: "rgba(
|
|
6053
|
+
deload: "rgba(186,41,150,0.15)"
|
|
5552
6054
|
};
|
|
5553
6055
|
var statusBorderStyles = {
|
|
5554
|
-
completed: { borderWidth: 1, borderColor: "rgba(
|
|
6056
|
+
completed: { borderWidth: 1, borderColor: "rgba(46,213,115,0.3)" },
|
|
5555
6057
|
current: { borderWidth: 1, borderColor: "rgba(255,121,0,0.3)" },
|
|
5556
6058
|
next: { borderWidth: 1, borderColor: "rgba(255,121,0,0.4)" },
|
|
5557
6059
|
upcoming: { borderWidth: 1, borderColor: "#1F1F1F" },
|
|
5558
6060
|
missed: { borderWidth: 1, borderColor: "rgba(209,67,67,0.25)" },
|
|
5559
|
-
deload: { borderWidth: 1, borderColor: "rgba(
|
|
6061
|
+
deload: { borderWidth: 1, borderColor: "rgba(186,41,150,0.3)" }
|
|
5560
6062
|
};
|
|
5561
6063
|
var textColors = {
|
|
5562
|
-
completed: "
|
|
5563
|
-
current: "
|
|
5564
|
-
next: "
|
|
6064
|
+
completed: t8["status-success"],
|
|
6065
|
+
current: t8["brand-primary"],
|
|
6066
|
+
next: t8["brand-primary"],
|
|
5565
6067
|
upcoming: "#6B7280",
|
|
5566
6068
|
missed: "rgba(209,67,67,0.7)",
|
|
5567
|
-
deload:
|
|
6069
|
+
deload: WORKOUT_PILL_DELOAD
|
|
5568
6070
|
};
|
|
5569
|
-
function
|
|
6071
|
+
function usePulse2(enabled) {
|
|
5570
6072
|
const [opacity] = react.useState(() => new reactNative.Animated.Value(1));
|
|
5571
6073
|
react.useEffect(() => {
|
|
5572
6074
|
if (!enabled) {
|
|
@@ -5604,7 +6106,7 @@ function WorkoutPill({
|
|
|
5604
6106
|
...props
|
|
5605
6107
|
}) {
|
|
5606
6108
|
const shouldPulse = pulse ?? status === "current";
|
|
5607
|
-
const pulseOpacity =
|
|
6109
|
+
const pulseOpacity = usePulse2(shouldPulse);
|
|
5608
6110
|
const isCompleted = status === "completed";
|
|
5609
6111
|
const isMissed = status === "missed";
|
|
5610
6112
|
const pill = /* @__PURE__ */ jsx(
|
|
@@ -5694,23 +6196,24 @@ function WorkoutPill({
|
|
|
5694
6196
|
}
|
|
5695
6197
|
return pill;
|
|
5696
6198
|
}
|
|
6199
|
+
var t9 = getSemanticColors("dark");
|
|
5697
6200
|
var TRACK_BG = "#333333";
|
|
5698
6201
|
var LABEL_COLOR = "#6B7280";
|
|
5699
6202
|
var TARGET_LINE_COLOR = "rgba(33, 150, 243, 0.5)";
|
|
5700
6203
|
var AT_TARGET_GLOW = "0 0 5px 1px rgba(33, 150, 243, 0.35), 0 0 10px 3px rgba(33, 150, 243, 0.15)";
|
|
5701
6204
|
var ZONE = {
|
|
5702
|
-
building: "
|
|
5703
|
-
//
|
|
5704
|
-
approaching: "
|
|
5705
|
-
//
|
|
5706
|
-
target: "
|
|
5707
|
-
//
|
|
5708
|
-
over1: "
|
|
5709
|
-
//
|
|
5710
|
-
over2:
|
|
5711
|
-
//
|
|
5712
|
-
over3:
|
|
5713
|
-
//
|
|
6205
|
+
building: t9["status-success"],
|
|
6206
|
+
// below target ramp-up
|
|
6207
|
+
approaching: t9["status-warning"],
|
|
6208
|
+
// nearing target
|
|
6209
|
+
target: t9["brand-primary"],
|
|
6210
|
+
// exactly at target
|
|
6211
|
+
over1: t9["status-error"],
|
|
6212
|
+
// mild over-target
|
|
6213
|
+
over2: WORKOUT_TOKENS.intensity.over2,
|
|
6214
|
+
// moderate over-target
|
|
6215
|
+
over3: WORKOUT_TOKENS.intensity.over3
|
|
6216
|
+
// severe over-target
|
|
5714
6217
|
};
|
|
5715
6218
|
var BULGE_SIZE = { 1: 8, 2: 10, 3: 11 };
|
|
5716
6219
|
function zoneForPct(pct) {
|
|
@@ -5868,7 +6371,7 @@ function IntensityBar({
|
|
|
5868
6371
|
}
|
|
5869
6372
|
|
|
5870
6373
|
// src/components/custom/Workout/WeekRow.tsx
|
|
5871
|
-
var
|
|
6374
|
+
var BRAND_PRIMARY9 = getSemanticColors("dark")["brand-primary"];
|
|
5872
6375
|
function WeekRow({
|
|
5873
6376
|
weekNumber,
|
|
5874
6377
|
totalWeeks,
|
|
@@ -5888,12 +6391,12 @@ function WeekRow({
|
|
|
5888
6391
|
gap: 12
|
|
5889
6392
|
};
|
|
5890
6393
|
if (isDeload) {
|
|
5891
|
-
rowStyle.backgroundColor = "rgba(
|
|
6394
|
+
rowStyle.backgroundColor = "rgba(186,41,150,0.06)";
|
|
5892
6395
|
}
|
|
5893
6396
|
if (isCurrent) {
|
|
5894
6397
|
rowStyle.backgroundColor = "rgba(255,121,0,0.04)";
|
|
5895
6398
|
rowStyle.borderLeftWidth = 2;
|
|
5896
|
-
rowStyle.borderLeftColor =
|
|
6399
|
+
rowStyle.borderLeftColor = BRAND_PRIMARY9;
|
|
5897
6400
|
}
|
|
5898
6401
|
return /* @__PURE__ */ jsxs(
|
|
5899
6402
|
reactNative.View,
|
|
@@ -5917,7 +6420,7 @@ function WeekRow({
|
|
|
5917
6420
|
width: 6,
|
|
5918
6421
|
height: 6,
|
|
5919
6422
|
borderRadius: 3,
|
|
5920
|
-
backgroundColor:
|
|
6423
|
+
backgroundColor: BRAND_PRIMARY9
|
|
5921
6424
|
},
|
|
5922
6425
|
accessibilityElementsHidden: true,
|
|
5923
6426
|
testID: "week-row-current-dot"
|
|
@@ -5931,7 +6434,7 @@ function WeekRow({
|
|
|
5931
6434
|
fontSize: 13,
|
|
5932
6435
|
fontWeight: "700",
|
|
5933
6436
|
fontFamily: "Inter, sans-serif",
|
|
5934
|
-
color: isCurrent ?
|
|
6437
|
+
color: isCurrent ? BRAND_PRIMARY9 : void 0
|
|
5935
6438
|
},
|
|
5936
6439
|
accessibilityElementsHidden: true,
|
|
5937
6440
|
children: `W${weekNumber}`
|
|
@@ -5972,11 +6475,11 @@ function WeekRow({
|
|
|
5972
6475
|
}
|
|
5973
6476
|
|
|
5974
6477
|
// src/components/custom/Workout/MesoCard.tsx
|
|
5975
|
-
var
|
|
5976
|
-
var BRAND_PRIMARY_DARK2 =
|
|
5977
|
-
var BRAND_PRIMARY_LIGHT2 =
|
|
6478
|
+
var BRAND_PRIMARY10 = getSemanticColors("dark")["brand-primary"];
|
|
6479
|
+
var BRAND_PRIMARY_DARK2 = MESO_ACCENT_GRADIENT_DARK;
|
|
6480
|
+
var BRAND_PRIMARY_LIGHT2 = MESO_ACCENT_GRADIENT_LIGHT;
|
|
5978
6481
|
var BORDER_DEFAULT = "#1F1F1F";
|
|
5979
|
-
var ACCENT_STOPS2 = [BRAND_PRIMARY_DARK2,
|
|
6482
|
+
var ACCENT_STOPS2 = [BRAND_PRIMARY_DARK2, BRAND_PRIMARY10, BRAND_PRIMARY_LIGHT2];
|
|
5980
6483
|
function heatmapColor(percentage) {
|
|
5981
6484
|
const clamped = Math.max(0, Math.min(100, percentage));
|
|
5982
6485
|
const opacity = 0.12 + clamped / 100 * 0.78;
|
|
@@ -6011,7 +6514,7 @@ function MesoCard({
|
|
|
6011
6514
|
}, [highlighted, highlight]);
|
|
6012
6515
|
const borderColor = highlight.interpolate({
|
|
6013
6516
|
inputRange: [0, 1],
|
|
6014
|
-
outputRange: [BORDER_DEFAULT,
|
|
6517
|
+
outputRange: [BORDER_DEFAULT, BRAND_PRIMARY10]
|
|
6015
6518
|
});
|
|
6016
6519
|
const header = /* @__PURE__ */ jsxs(reactNative.View, { style: { paddingHorizontal: 14, paddingTop: 12, paddingBottom: 10 }, testID: "meso-card-body", children: [
|
|
6017
6520
|
/* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", style: { gap: 8 }, testID: "meso-card-header", children: [
|
|
@@ -6071,7 +6574,7 @@ function MesoCard({
|
|
|
6071
6574
|
{
|
|
6072
6575
|
variant: "outline",
|
|
6073
6576
|
elevation: 2,
|
|
6074
|
-
borderColor: highlighted ?
|
|
6577
|
+
borderColor: highlighted ? BRAND_PRIMARY10 : BORDER_DEFAULT,
|
|
6075
6578
|
className,
|
|
6076
6579
|
style: [
|
|
6077
6580
|
{ borderColor },
|
|
@@ -6128,12 +6631,13 @@ function MesoCard({
|
|
|
6128
6631
|
}
|
|
6129
6632
|
) });
|
|
6130
6633
|
}
|
|
6634
|
+
var t10 = getSemanticColors("dark");
|
|
6131
6635
|
var dotColorMap = {
|
|
6132
6636
|
untrained: "#2C2C2C",
|
|
6133
|
-
behind: "
|
|
6134
|
-
ontrack: "
|
|
6135
|
-
target: "
|
|
6136
|
-
over: "
|
|
6637
|
+
behind: t10["brand-secondary"],
|
|
6638
|
+
ontrack: t10["status-success"],
|
|
6639
|
+
target: t10["brand-primary"],
|
|
6640
|
+
over: t10["status-error"]
|
|
6137
6641
|
};
|
|
6138
6642
|
function MuscleGroupChip({
|
|
6139
6643
|
name,
|
|
@@ -6207,9 +6711,10 @@ function MuscleGroupChip({
|
|
|
6207
6711
|
}
|
|
6208
6712
|
|
|
6209
6713
|
// src/components/custom/Workout/WorkoutCard.tsx
|
|
6714
|
+
var t11 = getSemanticColors("dark");
|
|
6210
6715
|
var COLORS = {
|
|
6211
|
-
statusSuccess: "
|
|
6212
|
-
brandPrimary: "
|
|
6716
|
+
statusSuccess: t11["status-success"],
|
|
6717
|
+
brandPrimary: t11["brand-primary"],
|
|
6213
6718
|
borderDefault: "#1F1F1F",
|
|
6214
6719
|
brandPrimarySubtle: "rgba(255,121,0,0.06)"
|
|
6215
6720
|
};
|
|
@@ -6353,7 +6858,7 @@ function WorkoutCard({
|
|
|
6353
6858
|
}
|
|
6354
6859
|
|
|
6355
6860
|
// src/components/custom/Workout/ProgramPlanningPage.tsx
|
|
6356
|
-
var
|
|
6861
|
+
var BRAND_PRIMARY11 = getSemanticColors("dark")["brand-primary"];
|
|
6357
6862
|
var WORKOUT_PILL_STATUS = {
|
|
6358
6863
|
completed: "completed",
|
|
6359
6864
|
today: "current",
|
|
@@ -6421,7 +6926,7 @@ function Breadcrumbs({ crumbs, onNavigate }) {
|
|
|
6421
6926
|
fontSize: 12,
|
|
6422
6927
|
fontFamily: "Inter, sans-serif",
|
|
6423
6928
|
fontWeight: isLast ? "700" : "500",
|
|
6424
|
-
color: isLast ? void 0 :
|
|
6929
|
+
color: isLast ? void 0 : BRAND_PRIMARY11
|
|
6425
6930
|
},
|
|
6426
6931
|
children: crumb.label
|
|
6427
6932
|
}
|
|
@@ -6493,8 +6998,8 @@ function WeekLevel({ week, onSelectWorkout }) {
|
|
|
6493
6998
|
function WorkoutLevel({ workout, expandedExercise, onToggleExercise }) {
|
|
6494
6999
|
const exercises = workout.exercises.map((exercise, index) => ({
|
|
6495
7000
|
...exercise,
|
|
6496
|
-
|
|
6497
|
-
|
|
7001
|
+
expanded: index === expandedExercise,
|
|
7002
|
+
onExpandedChange: () => onToggleExercise(index)
|
|
6498
7003
|
}));
|
|
6499
7004
|
return /* @__PURE__ */ jsx(reactNative.View, { testID: "program-planning-page-workout-level", children: /* @__PURE__ */ jsx(
|
|
6500
7005
|
WorkoutCard,
|
|
@@ -6637,7 +7142,7 @@ exports.findMeso = findMeso;
|
|
|
6637
7142
|
exports.findWeek = findWeek;
|
|
6638
7143
|
exports.findWorkout = findWorkout;
|
|
6639
7144
|
exports.groupExercises = groupExercises;
|
|
6640
|
-
exports.
|
|
7145
|
+
exports.isUpcomingExercise = isUpcomingExercise;
|
|
6641
7146
|
exports.summarizeVbt = summarizeVbt;
|
|
6642
7147
|
exports.toActiveCardProps = toActiveCardProps;
|
|
6643
7148
|
exports.toExerciseCardProps = toExerciseCardProps;
|