@titan-design/react-ui 0.6.0 → 0.8.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 +12 -7
- package/dist/bodymap.js.map +1 -1
- package/dist/bodymap.mjs +12 -7
- package/dist/bodymap.mjs.map +1 -1
- package/dist/index.d.mts +956 -128
- package/dist/index.d.ts +956 -128
- package/dist/index.js +2873 -981
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2826 -982
- package/dist/index.mjs.map +1 -1
- package/dist/{pages-MO0JCySL.d.mts → pages-DCFBqp79.d.mts} +289 -57
- package/dist/{pages-D7Jlssvp.d.ts → pages-_fI3-x7Z.d.ts} +289 -57
- package/dist/pages.d.mts +1 -1
- package/dist/pages.d.ts +1 -1
- package/dist/pages.js +1659 -799
- package/dist/pages.js.map +1 -1
- package/dist/pages.mjs +1660 -800
- package/dist/pages.mjs.map +1 -1
- package/dist/theme/index.d.mts +16 -82
- package/dist/theme/index.d.ts +16 -82
- package/dist/theme/index.js +13 -115
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/index.mjs +13 -115
- package/dist/theme/index.mjs.map +1 -1
- package/dist/theme/tokens-css.js +14 -6
- package/dist/theme/tokens-css.js.map +1 -1
- package/dist/theme/tokens-css.mjs +14 -6
- package/dist/theme/tokens-css.mjs.map +1 -1
- package/package.json +1 -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/CircularTimer/CircularTimer.stories.tsx +90 -0
- package/src/components/custom/CircularTimer/CircularTimer.test.tsx +62 -0
- package/src/components/custom/CircularTimer/CircularTimer.tsx +112 -0
- package/src/components/custom/CircularTimer/index.ts +1 -0
- package/src/components/custom/DateTime/DateTime.stories.tsx +1 -1
- package/src/components/custom/EmptyState/EmptyState.stories.tsx +1 -1
- package/src/components/custom/Gauge/Gauge.stories.tsx +1 -1
- package/src/components/custom/Metric/Metric.stories.tsx +1 -1
- package/src/components/custom/Scatter/Scatter.stories.tsx +1 -1
- 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/Typography/Typography.stories.tsx +1 -1
- 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 +9 -15
- 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/BodyMapDetailPanel.stories.tsx +1 -1
- package/src/components/custom/Workout/CapacityBandChart.stories.tsx +1 -1
- package/src/components/custom/Workout/DeviationBar.stories.tsx +1 -1
- 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 +4 -5
- 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 +85 -0
- package/src/components/custom/Workout/FatigueMeter.tsx +86 -0
- package/src/components/custom/Workout/InputBar.stories.tsx +1 -1
- package/src/components/custom/Workout/IntensityBar.stories.tsx +1 -1
- 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/MesoProgressBar.stories.tsx +1 -1
- package/src/components/custom/Workout/MesoStatusCard.stories.tsx +1 -1
- 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/PlaceholderStrip.stories.tsx +1 -1
- package/src/components/custom/Workout/PrBadge.stories.tsx +1 -1
- package/src/components/custom/Workout/PrHistoryModal.stories.tsx +1 -1
- package/src/components/custom/Workout/ProgramPlanningPage.stories.tsx +4 -16
- package/src/components/custom/Workout/ProgramPlanningPage.tsx +8 -6
- package/src/components/custom/Workout/README.md +193 -4
- package/src/components/custom/Workout/ReadinessCheck.stories.tsx +1 -1
- package/src/components/custom/Workout/RestTimer.stories.tsx +133 -3
- package/src/components/custom/Workout/RestTimer.test.tsx +73 -0
- package/src/components/custom/Workout/RestTimer.tsx +155 -59
- 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 +169 -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/StatusDot.stories.tsx +1 -1
- 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/SupersetWrapper.stories.tsx +1 -1
- package/src/components/custom/Workout/TempoBar.stories.tsx +70 -1
- package/src/components/custom/Workout/TempoBar.test.tsx +119 -4
- package/src/components/custom/Workout/TempoBar.tsx +107 -22
- package/src/components/custom/Workout/TempoDisplay.stories.tsx +12 -1
- package/src/components/custom/Workout/TempoDisplay.tsx +23 -33
- 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 +262 -56
- package/src/components/custom/Workout/VelocityStrip.test.tsx +440 -141
- package/src/components/custom/Workout/VelocityStrip.tsx +776 -141
- 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/WeightBadge.stories.tsx +1 -1
- 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/WorkoutPill.stories.tsx +1 -1
- package/src/components/custom/Workout/ZoneTrack.stories.tsx +139 -0
- package/src/components/custom/Workout/ZoneTrack.test.tsx +234 -0
- package/src/components/custom/Workout/ZoneTrack.tsx +373 -0
- 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 +2 -0
- package/src/components/custom/stepper/Stepper.stories.tsx +1 -1
- package/src/components/icons/icons.stories.tsx +67 -2
- package/src/components/icons/icons.test.tsx +32 -2
- package/src/components/icons/icons.tsx +108 -0
- package/src/components/shell/BrandLockup.stories.tsx +3 -3
- 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 +2 -2
- package/src/components/shell/DeviceMenu.stories.tsx +5 -5
- package/src/components/shell/DeviceRow.stories.tsx +3 -3
- 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 +30 -0
- package/src/components/shell/SessionRailSpecimen.stories.tsx +753 -0
- package/src/components/shell/SessionStatePill.stories.tsx +3 -3
- package/src/components/shell/SessionStatePill.tsx +1 -1
- 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 +5 -5
- package/src/components/shell/index.ts +5 -0
- package/src/components/ui/alert/Alert.stories.tsx +86 -3
- package/src/components/ui/alert/Alert.test.tsx +52 -0
- package/src/components/ui/alert/Alert.tsx +54 -20
- 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 +2 -2
- package/src/components/ui/indicator/Indicator.test.tsx +1 -0
- package/src/components/ui/indicator/Indicator.tsx +6 -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/progress/Progress.tsx +47 -22
- 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/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/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 +1 -1
- package/src/theme/Colors.stories.tsx +5 -8
- package/src/theme/config.ts +4 -0
- package/src/theme/elevation.stories.tsx +1 -1
- package/src/theme/global.css +5 -1
- package/src/theme/shadows.stories.tsx +1 -1
- package/src/theme/tokens/primitives.ts +11 -107
- package/src/theme/tokens/semantic.ts +8 -0
- package/src/theme/workout-tokens.ts +11 -7
- package/tailwind.config.js +5 -0
package/dist/index.mjs
CHANGED
|
@@ -76,6 +76,72 @@ function DumbbellIcon(props) {
|
|
|
76
76
|
function StarIcon(props) {
|
|
77
77
|
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" }) });
|
|
78
78
|
}
|
|
79
|
+
function ActivityIcon(props) {
|
|
80
|
+
return /* @__PURE__ */ jsx(SvgIcon, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M22 12h-4l-3 9L9 3l-3 9H2" }) });
|
|
81
|
+
}
|
|
82
|
+
function HistoryIcon(props) {
|
|
83
|
+
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
84
|
+
/* @__PURE__ */ jsx("path", { d: "M3 12a9 9 0 1 0 3-6.7L3 8" }),
|
|
85
|
+
/* @__PURE__ */ jsx("path", { d: "M3 3v5h5" }),
|
|
86
|
+
/* @__PURE__ */ jsx("path", { d: "M12 7v5l4 2" })
|
|
87
|
+
] });
|
|
88
|
+
}
|
|
89
|
+
function LayersIcon(props) {
|
|
90
|
+
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
91
|
+
/* @__PURE__ */ jsx("path", { d: "m12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83Z" }),
|
|
92
|
+
/* @__PURE__ */ jsx("path", { d: "m6.08 9.5-3.49 1.59a1 1 0 0 0 0 1.81l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9a1 1 0 0 0 0-1.83l-3.5-1.59" }),
|
|
93
|
+
/* @__PURE__ */ jsx("path", { d: "m6.08 14.5-3.49 1.59a1 1 0 0 0 0 1.81l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9a1 1 0 0 0 0-1.83l-3.5-1.59" })
|
|
94
|
+
] });
|
|
95
|
+
}
|
|
96
|
+
function PersonStandingIcon(props) {
|
|
97
|
+
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
98
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "5", r: "1" }),
|
|
99
|
+
/* @__PURE__ */ jsx("path", { d: "m9 20 3-6 3 6" }),
|
|
100
|
+
/* @__PURE__ */ jsx("path", { d: "m6 8 6 2 6-2" }),
|
|
101
|
+
/* @__PURE__ */ jsx("path", { d: "M12 10v4" })
|
|
102
|
+
] });
|
|
103
|
+
}
|
|
104
|
+
function ScaleIcon(props) {
|
|
105
|
+
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
106
|
+
/* @__PURE__ */ jsx("path", { d: "m16 16 3-8 3 8c-.87.65-1.92 1-3 1s-2.13-.35-3-1Z" }),
|
|
107
|
+
/* @__PURE__ */ jsx("path", { d: "m2 16 3-8 3 8c-.87.65-1.92 1-3 1s-2.13-.35-3-1Z" }),
|
|
108
|
+
/* @__PURE__ */ jsx("path", { d: "M7 21h10" }),
|
|
109
|
+
/* @__PURE__ */ jsx("path", { d: "M12 3v18" }),
|
|
110
|
+
/* @__PURE__ */ jsx("path", { d: "M3 7h2c2 0 5-1 7-2 2 1 5 2 7 2h2" })
|
|
111
|
+
] });
|
|
112
|
+
}
|
|
113
|
+
function AlertTriangleIcon(props) {
|
|
114
|
+
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
115
|
+
/* @__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" }),
|
|
116
|
+
/* @__PURE__ */ jsx("path", { d: "M12 9v4" }),
|
|
117
|
+
/* @__PURE__ */ jsx("path", { d: "M12 17h.01" })
|
|
118
|
+
] });
|
|
119
|
+
}
|
|
120
|
+
function TrendingDownIcon(props) {
|
|
121
|
+
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
122
|
+
/* @__PURE__ */ jsx("path", { d: "M16 17h6v-6" }),
|
|
123
|
+
/* @__PURE__ */ jsx("path", { d: "m22 17-8.5-8.5-5 5L2 7" })
|
|
124
|
+
] });
|
|
125
|
+
}
|
|
126
|
+
function CircleSlashIcon(props) {
|
|
127
|
+
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
128
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
129
|
+
/* @__PURE__ */ jsx("path", { d: "m9 15 6-6" })
|
|
130
|
+
] });
|
|
131
|
+
}
|
|
132
|
+
function AwardIcon(props) {
|
|
133
|
+
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
134
|
+
/* @__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" }),
|
|
135
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "8", r: "6" })
|
|
136
|
+
] });
|
|
137
|
+
}
|
|
138
|
+
function InfoIcon(props) {
|
|
139
|
+
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
140
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
141
|
+
/* @__PURE__ */ jsx("path", { d: "M12 16v-4" }),
|
|
142
|
+
/* @__PURE__ */ jsx("path", { d: "M12 8h.01" })
|
|
143
|
+
] });
|
|
144
|
+
}
|
|
79
145
|
function cn(...inputs) {
|
|
80
146
|
return twMerge(clsx(inputs));
|
|
81
147
|
}
|
|
@@ -86,6 +152,7 @@ var statusColors = {
|
|
|
86
152
|
subtle: "bg-status-success-subtle",
|
|
87
153
|
outline: "border-2 border-status-success bg-transparent",
|
|
88
154
|
solid: "bg-status-success",
|
|
155
|
+
border: "border-status-success",
|
|
89
156
|
icon: "text-status-success",
|
|
90
157
|
text: "text-status-success"
|
|
91
158
|
},
|
|
@@ -93,6 +160,7 @@ var statusColors = {
|
|
|
93
160
|
subtle: "bg-status-info-subtle",
|
|
94
161
|
outline: "border-2 border-status-info bg-transparent",
|
|
95
162
|
solid: "bg-status-info",
|
|
163
|
+
border: "border-status-info",
|
|
96
164
|
icon: "text-status-info",
|
|
97
165
|
text: "text-status-info"
|
|
98
166
|
},
|
|
@@ -100,6 +168,7 @@ var statusColors = {
|
|
|
100
168
|
subtle: "bg-status-warning-subtle",
|
|
101
169
|
outline: "border-2 border-status-warning bg-transparent",
|
|
102
170
|
solid: "bg-status-warning",
|
|
171
|
+
border: "border-status-warning",
|
|
103
172
|
icon: "text-status-warning",
|
|
104
173
|
text: "text-status-warning"
|
|
105
174
|
},
|
|
@@ -107,6 +176,7 @@ var statusColors = {
|
|
|
107
176
|
subtle: "bg-status-error-subtle",
|
|
108
177
|
outline: "border-2 border-status-error bg-transparent",
|
|
109
178
|
solid: "bg-status-error",
|
|
179
|
+
border: "border-status-error",
|
|
110
180
|
icon: "text-status-error",
|
|
111
181
|
text: "text-status-error"
|
|
112
182
|
}
|
|
@@ -120,6 +190,8 @@ var defaultIcons = {
|
|
|
120
190
|
function Alert({
|
|
121
191
|
status = "info",
|
|
122
192
|
variant = "subtle",
|
|
193
|
+
size = "default",
|
|
194
|
+
message,
|
|
123
195
|
icon,
|
|
124
196
|
showIcon = true,
|
|
125
197
|
onClose,
|
|
@@ -129,28 +201,43 @@ function Alert({
|
|
|
129
201
|
}) {
|
|
130
202
|
const colors = statusColors[status];
|
|
131
203
|
const isSolid = variant === "solid";
|
|
204
|
+
const isCompact = size === "compact";
|
|
132
205
|
return /* @__PURE__ */ jsxs(
|
|
133
206
|
View,
|
|
134
207
|
{
|
|
135
208
|
accessibilityRole: "alert",
|
|
136
209
|
className: cn(
|
|
137
|
-
"flex-row items-start p-4 rounded-lg",
|
|
210
|
+
isCompact ? "flex-row items-center px-3 py-2 rounded-lg" : "flex-row items-start p-4 rounded-lg",
|
|
138
211
|
colors[variant],
|
|
212
|
+
// A compact `subtle` pill gets a hairline status border so it reads as a
|
|
213
|
+
// defined cue on a dark wall (the CueFlag look); other variants carry their own.
|
|
214
|
+
isCompact && variant === "subtle" && cn("border", colors.border),
|
|
139
215
|
className
|
|
140
216
|
),
|
|
141
217
|
...props,
|
|
142
218
|
children: [
|
|
143
|
-
showIcon && /* @__PURE__ */ jsx(View, { className: "mr-3 mt-0.5", children: icon || /* @__PURE__ */ jsx(
|
|
219
|
+
showIcon && /* @__PURE__ */ jsx(View, { className: isCompact ? "mr-2" : "mr-3 mt-0.5", children: icon || /* @__PURE__ */ jsx(
|
|
144
220
|
Text,
|
|
145
221
|
{
|
|
146
222
|
className: cn(
|
|
147
|
-
"
|
|
223
|
+
"font-bold",
|
|
224
|
+
isCompact ? "text-base" : "text-lg",
|
|
148
225
|
isSolid ? "text-white" : colors.icon
|
|
149
226
|
),
|
|
150
227
|
children: defaultIcons[status]
|
|
151
228
|
}
|
|
152
229
|
) }),
|
|
153
|
-
/* @__PURE__ */
|
|
230
|
+
/* @__PURE__ */ jsxs(View, { className: "flex-1", children: [
|
|
231
|
+
message != null && /* @__PURE__ */ jsx(
|
|
232
|
+
Text,
|
|
233
|
+
{
|
|
234
|
+
className: cn("text-sm font-semibold", isSolid ? "text-white" : colors.text),
|
|
235
|
+
testID: "alert-message",
|
|
236
|
+
children: message
|
|
237
|
+
}
|
|
238
|
+
),
|
|
239
|
+
children
|
|
240
|
+
] }),
|
|
154
241
|
onClose && /* @__PURE__ */ jsx(
|
|
155
242
|
Pressable,
|
|
156
243
|
{
|
|
@@ -174,7 +261,7 @@ function AlertDescription({ children, className }) {
|
|
|
174
261
|
|
|
175
262
|
// src/theme/tokens/primitives.ts
|
|
176
263
|
var primitiveColors = {
|
|
177
|
-
// Blue scale
|
|
264
|
+
// Blue scale
|
|
178
265
|
blue: {
|
|
179
266
|
50: "#EFF6FF",
|
|
180
267
|
100: "#DBEAFE",
|
|
@@ -183,124 +270,36 @@ var primitiveColors = {
|
|
|
183
270
|
400: "#60A5FA",
|
|
184
271
|
500: "#3B82F6",
|
|
185
272
|
600: "#5048E5",
|
|
186
|
-
// Primary main
|
|
187
273
|
700: "#3832A0",
|
|
188
|
-
// Primary dark
|
|
189
274
|
800: "#1E40AF",
|
|
190
275
|
900: "#1E3A8A"
|
|
191
276
|
},
|
|
192
|
-
//
|
|
193
|
-
green: {
|
|
194
|
-
50: "#ECFDF5",
|
|
195
|
-
100: "#D1FAE5",
|
|
196
|
-
200: "#A7F3D0",
|
|
197
|
-
300: "#6EE7B7",
|
|
198
|
-
400: "#3FC79A",
|
|
199
|
-
// Secondary light
|
|
200
|
-
500: "#10B981",
|
|
201
|
-
// Secondary main
|
|
202
|
-
600: "#059669",
|
|
203
|
-
700: "#0B815A",
|
|
204
|
-
// Secondary dark
|
|
205
|
-
800: "#065F46",
|
|
206
|
-
900: "#064E3B"
|
|
207
|
-
},
|
|
208
|
-
// Teal scale (success)
|
|
209
|
-
teal: {
|
|
210
|
-
50: "#F0FDFA",
|
|
211
|
-
100: "#CCFBF1",
|
|
212
|
-
200: "#99F6E4",
|
|
213
|
-
300: "#5EEAD4",
|
|
214
|
-
400: "#43C6B7",
|
|
215
|
-
// Success light
|
|
216
|
-
500: "#14B8A6",
|
|
217
|
-
// Success main
|
|
218
|
-
600: "#0D9488",
|
|
219
|
-
700: "#0E8074",
|
|
220
|
-
// Success dark
|
|
221
|
-
800: "#115E59",
|
|
222
|
-
900: "#134E4A"
|
|
223
|
-
},
|
|
224
|
-
// Red scale (error)
|
|
277
|
+
// Red scale
|
|
225
278
|
red: {
|
|
226
279
|
50: "#FEF2F2",
|
|
227
280
|
100: "#FEE2E2",
|
|
228
281
|
200: "#FECACA",
|
|
229
282
|
300: "#FCA5A5",
|
|
230
283
|
400: "#DA6868",
|
|
231
|
-
// Error light
|
|
232
284
|
500: "#EF4444",
|
|
233
285
|
600: "#D14343",
|
|
234
|
-
// Error main
|
|
235
286
|
700: "#922E2E",
|
|
236
|
-
// Error dark
|
|
237
287
|
800: "#991B1B",
|
|
238
288
|
900: "#7F1D1D"
|
|
239
289
|
},
|
|
240
|
-
// Vivid
|
|
241
|
-
greenVivid: {
|
|
242
|
-
50: "#E9FBF0",
|
|
243
|
-
100: "#C8F7DA",
|
|
244
|
-
200: "#9FF0BF",
|
|
245
|
-
300: "#6BE79D",
|
|
246
|
-
400: "#47DE84",
|
|
247
|
-
// Success vivid light
|
|
248
|
-
500: "#2ED573",
|
|
249
|
-
// Success vivid main
|
|
250
|
-
600: "#22B85F",
|
|
251
|
-
700: "#1A9950",
|
|
252
|
-
// Success vivid dark
|
|
253
|
-
800: "#157A40",
|
|
254
|
-
900: "#105C30"
|
|
255
|
-
},
|
|
256
|
-
// Vivid red scale (alert)
|
|
290
|
+
// Vivid red scale
|
|
257
291
|
redVivid: {
|
|
258
292
|
50: "#FFECEE",
|
|
259
293
|
100: "#FFD6DB",
|
|
260
294
|
200: "#FFB3BC",
|
|
261
295
|
300: "#FF8593",
|
|
262
296
|
400: "#FF6070",
|
|
263
|
-
// Error vivid light
|
|
264
297
|
500: "#FF4757",
|
|
265
|
-
// Error vivid main
|
|
266
298
|
600: "#E63548",
|
|
267
299
|
700: "#C42539",
|
|
268
|
-
// Error vivid dark
|
|
269
300
|
800: "#9E1C2C",
|
|
270
301
|
900: "#7A1520"
|
|
271
302
|
},
|
|
272
|
-
// Amber scale (warning)
|
|
273
|
-
amber: {
|
|
274
|
-
50: "#FFFBEB",
|
|
275
|
-
100: "#FEF3C7",
|
|
276
|
-
200: "#FDE68A",
|
|
277
|
-
300: "#FCD34D",
|
|
278
|
-
400: "#FFBF4C",
|
|
279
|
-
// Warning light
|
|
280
|
-
500: "#FFB020",
|
|
281
|
-
// Warning main
|
|
282
|
-
600: "#B27B16",
|
|
283
|
-
// Warning dark
|
|
284
|
-
700: "#B45309",
|
|
285
|
-
800: "#92400E",
|
|
286
|
-
900: "#78350F"
|
|
287
|
-
},
|
|
288
|
-
// Sky/Blue scale (info)
|
|
289
|
-
sky: {
|
|
290
|
-
50: "#F0F9FF",
|
|
291
|
-
100: "#E0F2FE",
|
|
292
|
-
200: "#BAE6FD",
|
|
293
|
-
300: "#7DD3FC",
|
|
294
|
-
400: "#64B6F7",
|
|
295
|
-
// Info light
|
|
296
|
-
500: "#2196F3",
|
|
297
|
-
// Info main
|
|
298
|
-
600: "#0284C7",
|
|
299
|
-
700: "#0B79D0",
|
|
300
|
-
// Info dark
|
|
301
|
-
800: "#075985",
|
|
302
|
-
900: "#0C4A6E"
|
|
303
|
-
},
|
|
304
303
|
// Neutral/Gray scale
|
|
305
304
|
neutral: {
|
|
306
305
|
50: "#FAFAFA",
|
|
@@ -315,18 +314,6 @@ var primitiveColors = {
|
|
|
315
314
|
900: "#111827",
|
|
316
315
|
950: "#030712"
|
|
317
316
|
},
|
|
318
|
-
// Orange scale (accent/brand color)
|
|
319
|
-
accent: {
|
|
320
|
-
100: "#FFA860",
|
|
321
|
-
200: "#FF9630",
|
|
322
|
-
300: "#FF8500",
|
|
323
|
-
400: "#FF7900",
|
|
324
|
-
500: "#F56C00",
|
|
325
|
-
600: "#E06D10",
|
|
326
|
-
700: "#D0620C",
|
|
327
|
-
800: "#B75500",
|
|
328
|
-
900: "#A34900"
|
|
329
|
-
},
|
|
330
317
|
// Charcoal scale (dark backgrounds)
|
|
331
318
|
charcoal: {
|
|
332
319
|
0: "#6E6E6E",
|
|
@@ -341,18 +328,6 @@ var primitiveColors = {
|
|
|
341
328
|
800: "#131313",
|
|
342
329
|
900: "#101010"
|
|
343
330
|
},
|
|
344
|
-
// Steel scale (cool accent)
|
|
345
|
-
steel: {
|
|
346
|
-
100: "#8AA4B8",
|
|
347
|
-
200: "#7894A8",
|
|
348
|
-
300: "#678498",
|
|
349
|
-
400: "#557488",
|
|
350
|
-
500: "#406D87",
|
|
351
|
-
600: "#39617A",
|
|
352
|
-
700: "#32556D",
|
|
353
|
-
800: "#243D53",
|
|
354
|
-
900: "#1D3146"
|
|
355
|
-
},
|
|
356
331
|
// Pure colors
|
|
357
332
|
white: "#FFFFFF",
|
|
358
333
|
black: "#000000",
|
|
@@ -743,6 +718,9 @@ var semanticColorsLight = {
|
|
|
743
718
|
"status-success-light": primitiveRamps.green[200],
|
|
744
719
|
"status-success-dark": primitiveRamps.green[600],
|
|
745
720
|
"status-success-subtle": primitiveRamps.green[50],
|
|
721
|
+
// Live-session accent — its OWN role, decoupled from success so the two can diverge
|
|
722
|
+
"status-live": primitiveRamps.green[300],
|
|
723
|
+
"status-live-muted": primitiveRamps.green[500],
|
|
746
724
|
"status-error": primitiveRamps.red[600],
|
|
747
725
|
"status-error-light": primitiveRamps.red[500],
|
|
748
726
|
"status-error-dark": primitiveRamps.red[700],
|
|
@@ -876,6 +854,9 @@ var semanticColorsDark = {
|
|
|
876
854
|
"status-success-light": primitiveRamps.green[200],
|
|
877
855
|
"status-success-dark": primitiveRamps.green[600],
|
|
878
856
|
"status-success-subtle": "rgba(46, 213, 115, 0.12)",
|
|
857
|
+
// Live-session accent — its OWN role, decoupled from success so the two can diverge
|
|
858
|
+
"status-live": primitiveRamps.green[300],
|
|
859
|
+
"status-live-muted": primitiveRamps.green[500],
|
|
879
860
|
"status-error": primitiveRamps.red[600],
|
|
880
861
|
"status-error-light": primitiveRamps.red[500],
|
|
881
862
|
"status-error-dark": primitiveRamps.red[700],
|
|
@@ -1470,6 +1451,8 @@ var lightThemeCSSVars = {
|
|
|
1470
1451
|
"--color-on-brand-secondary": semanticColorsLight["on-brand-secondary"],
|
|
1471
1452
|
"--color-status-success": semanticColorsLight["status-success"],
|
|
1472
1453
|
"--color-status-success-subtle": semanticColorsLight["status-success-subtle"],
|
|
1454
|
+
"--color-status-live": semanticColorsLight["status-live"],
|
|
1455
|
+
"--color-status-live-muted": semanticColorsLight["status-live-muted"],
|
|
1473
1456
|
"--color-status-error": semanticColorsLight["status-error"],
|
|
1474
1457
|
"--color-status-error-subtle": semanticColorsLight["status-error-subtle"],
|
|
1475
1458
|
"--color-status-warning": semanticColorsLight["status-warning"],
|
|
@@ -1566,6 +1549,8 @@ var darkThemeCSSVars = {
|
|
|
1566
1549
|
"--color-on-brand-secondary": semanticColorsDark["on-brand-secondary"],
|
|
1567
1550
|
"--color-status-success": semanticColorsDark["status-success"],
|
|
1568
1551
|
"--color-status-success-subtle": semanticColorsDark["status-success-subtle"],
|
|
1552
|
+
"--color-status-live": semanticColorsDark["status-live"],
|
|
1553
|
+
"--color-status-live-muted": semanticColorsDark["status-live-muted"],
|
|
1569
1554
|
"--color-status-error": semanticColorsDark["status-error"],
|
|
1570
1555
|
"--color-status-error-subtle": semanticColorsDark["status-error-subtle"],
|
|
1571
1556
|
"--color-status-warning": semanticColorsDark["status-warning"],
|
|
@@ -2783,6 +2768,7 @@ var colorStyles = {
|
|
|
2783
2768
|
default: "bg-text-tertiary",
|
|
2784
2769
|
primary: "bg-brand-primary",
|
|
2785
2770
|
success: "bg-status-success",
|
|
2771
|
+
live: "bg-status-live",
|
|
2786
2772
|
error: "bg-status-error",
|
|
2787
2773
|
warning: "bg-status-warning",
|
|
2788
2774
|
info: "bg-status-info",
|
|
@@ -2839,7 +2825,7 @@ function Indicator({
|
|
|
2839
2825
|
colorClass,
|
|
2840
2826
|
pulseMode === "opacity" && "animate-pulse",
|
|
2841
2827
|
ring && "border-2 border-background-base",
|
|
2842
|
-
glow && !customColor && color === "success" && "shadow-[0_0_6px_rgba(46,213,115,0.6)]",
|
|
2828
|
+
glow && !customColor && (color === "success" || color === "live") && "shadow-[0_0_6px_rgba(46,213,115,0.6)]",
|
|
2843
2829
|
glow && !customColor && color === "error" && "shadow-[0_0_6px_rgba(239,68,68,0.6)]",
|
|
2844
2830
|
glow && !customColor && color === "warning" && "shadow-[0_0_6px_rgba(245,158,11,0.6)]",
|
|
2845
2831
|
glow && !customColor && color === "primary" && "shadow-[0_0_6px_rgba(255,121,0,0.6)]",
|
|
@@ -5101,6 +5087,8 @@ function CircularProgress({
|
|
|
5101
5087
|
color = "primary",
|
|
5102
5088
|
showValue = false,
|
|
5103
5089
|
formatValue: formatValue3 = (v, m) => `${Math.round(v / m * 100)}%`,
|
|
5090
|
+
children,
|
|
5091
|
+
fill = false,
|
|
5104
5092
|
className,
|
|
5105
5093
|
...props
|
|
5106
5094
|
}) {
|
|
@@ -5109,11 +5097,12 @@ function CircularProgress({
|
|
|
5109
5097
|
const circumference = 2 * Math.PI * radius;
|
|
5110
5098
|
const strokeDashoffset = circumference - percentage / 100 * circumference;
|
|
5111
5099
|
const center = size / 2;
|
|
5100
|
+
const boxStyle = fill ? { width: "100%", aspectRatio: 1 } : { width: size, height: size };
|
|
5112
5101
|
return /* @__PURE__ */ jsxs(
|
|
5113
5102
|
View,
|
|
5114
5103
|
{
|
|
5115
5104
|
className: cn("items-center justify-center", className),
|
|
5116
|
-
style:
|
|
5105
|
+
style: boxStyle,
|
|
5117
5106
|
accessibilityRole: "progressbar",
|
|
5118
5107
|
accessibilityValue: {
|
|
5119
5108
|
min: 0,
|
|
@@ -5122,52 +5111,56 @@ function CircularProgress({
|
|
|
5122
5111
|
},
|
|
5123
5112
|
...props,
|
|
5124
5113
|
children: [
|
|
5125
|
-
/* @__PURE__ */ jsx(
|
|
5114
|
+
/* @__PURE__ */ jsx(View, { className: cn(isIndeterminate && "animate-spin"), style: boxStyle, children: /* @__PURE__ */ jsxs(
|
|
5115
|
+
"svg",
|
|
5116
|
+
{
|
|
5117
|
+
width: "100%",
|
|
5118
|
+
height: "100%",
|
|
5119
|
+
viewBox: `0 0 ${size} ${size}`,
|
|
5120
|
+
style: { position: "absolute" },
|
|
5121
|
+
children: [
|
|
5122
|
+
/* @__PURE__ */ jsx(
|
|
5123
|
+
"circle",
|
|
5124
|
+
{
|
|
5125
|
+
cx: center,
|
|
5126
|
+
cy: center,
|
|
5127
|
+
r: radius,
|
|
5128
|
+
fill: "none",
|
|
5129
|
+
stroke: "var(--color-border-default)",
|
|
5130
|
+
strokeWidth
|
|
5131
|
+
}
|
|
5132
|
+
),
|
|
5133
|
+
/* @__PURE__ */ jsx(
|
|
5134
|
+
"circle",
|
|
5135
|
+
{
|
|
5136
|
+
cx: center,
|
|
5137
|
+
cy: center,
|
|
5138
|
+
r: radius,
|
|
5139
|
+
fill: "none",
|
|
5140
|
+
stroke: colorVarMap[color],
|
|
5141
|
+
strokeWidth,
|
|
5142
|
+
strokeLinecap: "round",
|
|
5143
|
+
strokeDasharray: circumference,
|
|
5144
|
+
strokeDashoffset: isIndeterminate ? circumference * 0.75 : strokeDashoffset,
|
|
5145
|
+
transform: `rotate(-90 ${center} ${center})`,
|
|
5146
|
+
style: { transition: "stroke-dashoffset 300ms cubic-bezier(0.22, 1, 0.36, 1)" }
|
|
5147
|
+
}
|
|
5148
|
+
)
|
|
5149
|
+
]
|
|
5150
|
+
}
|
|
5151
|
+
) }),
|
|
5152
|
+
children != null ? /* @__PURE__ */ jsx(
|
|
5126
5153
|
View,
|
|
5127
5154
|
{
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
"
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
viewBox: `0 0 ${size} ${size}`,
|
|
5136
|
-
style: { position: "absolute" },
|
|
5137
|
-
children: [
|
|
5138
|
-
/* @__PURE__ */ jsx(
|
|
5139
|
-
"circle",
|
|
5140
|
-
{
|
|
5141
|
-
cx: center,
|
|
5142
|
-
cy: center,
|
|
5143
|
-
r: radius,
|
|
5144
|
-
fill: "none",
|
|
5145
|
-
stroke: "var(--color-border-default)",
|
|
5146
|
-
strokeWidth
|
|
5147
|
-
}
|
|
5148
|
-
),
|
|
5149
|
-
/* @__PURE__ */ jsx(
|
|
5150
|
-
"circle",
|
|
5151
|
-
{
|
|
5152
|
-
cx: center,
|
|
5153
|
-
cy: center,
|
|
5154
|
-
r: radius,
|
|
5155
|
-
fill: "none",
|
|
5156
|
-
stroke: colorVarMap[color],
|
|
5157
|
-
strokeWidth,
|
|
5158
|
-
strokeLinecap: "round",
|
|
5159
|
-
strokeDasharray: circumference,
|
|
5160
|
-
strokeDashoffset: isIndeterminate ? circumference * 0.75 : strokeDashoffset,
|
|
5161
|
-
transform: `rotate(-90 ${center} ${center})`,
|
|
5162
|
-
style: { transition: "stroke-dashoffset 300ms cubic-bezier(0.22, 1, 0.36, 1)" }
|
|
5163
|
-
}
|
|
5164
|
-
)
|
|
5165
|
-
]
|
|
5166
|
-
}
|
|
5167
|
-
)
|
|
5155
|
+
style: {
|
|
5156
|
+
position: "absolute",
|
|
5157
|
+
alignItems: "center",
|
|
5158
|
+
justifyContent: "center",
|
|
5159
|
+
pointerEvents: "none"
|
|
5160
|
+
},
|
|
5161
|
+
children
|
|
5168
5162
|
}
|
|
5169
|
-
)
|
|
5170
|
-
showValue && !isIndeterminate && /* @__PURE__ */ jsx(
|
|
5163
|
+
) : showValue && !isIndeterminate && /* @__PURE__ */ jsx(
|
|
5171
5164
|
Text,
|
|
5172
5165
|
{
|
|
5173
5166
|
className: "text-xs font-semibold text-text-primary absolute",
|
|
@@ -5263,7 +5256,7 @@ function ToastProvider({
|
|
|
5263
5256
|
return id;
|
|
5264
5257
|
}, [defaultDuration, maxToasts]);
|
|
5265
5258
|
const removeToast = useCallback((id) => {
|
|
5266
|
-
setToasts((prev) => prev.filter((
|
|
5259
|
+
setToasts((prev) => prev.filter((t18) => t18.id !== id));
|
|
5267
5260
|
}, []);
|
|
5268
5261
|
const removeAllToasts = useCallback(() => {
|
|
5269
5262
|
setToasts([]);
|
|
@@ -6132,6 +6125,50 @@ function Pill({
|
|
|
6132
6125
|
}
|
|
6133
6126
|
return /* @__PURE__ */ jsx(View, { className: containerClasses, ...props, children: content });
|
|
6134
6127
|
}
|
|
6128
|
+
function Tile({
|
|
6129
|
+
label,
|
|
6130
|
+
value,
|
|
6131
|
+
valueColor,
|
|
6132
|
+
align = "center",
|
|
6133
|
+
className,
|
|
6134
|
+
...props
|
|
6135
|
+
}) {
|
|
6136
|
+
const isCenter = align === "center";
|
|
6137
|
+
return /* @__PURE__ */ jsxs(
|
|
6138
|
+
View,
|
|
6139
|
+
{
|
|
6140
|
+
className: cn(
|
|
6141
|
+
"flex-1 rounded-md bg-surface-raised px-1.5 py-2",
|
|
6142
|
+
isCenter ? "items-center" : "items-start",
|
|
6143
|
+
className
|
|
6144
|
+
),
|
|
6145
|
+
...props,
|
|
6146
|
+
children: [
|
|
6147
|
+
/* @__PURE__ */ jsx(
|
|
6148
|
+
Text,
|
|
6149
|
+
{
|
|
6150
|
+
className: cn(
|
|
6151
|
+
"text-[10px] font-bold uppercase tracking-wider text-text-tertiary",
|
|
6152
|
+
isCenter ? "text-center" : "text-left"
|
|
6153
|
+
),
|
|
6154
|
+
children: label
|
|
6155
|
+
}
|
|
6156
|
+
),
|
|
6157
|
+
/* @__PURE__ */ jsx(
|
|
6158
|
+
Text,
|
|
6159
|
+
{
|
|
6160
|
+
className: cn(
|
|
6161
|
+
"mt-0.5 font-mono text-sm font-bold text-text-primary",
|
|
6162
|
+
isCenter ? "text-center" : "text-left"
|
|
6163
|
+
),
|
|
6164
|
+
style: valueColor ? { color: valueColor } : void 0,
|
|
6165
|
+
children: value
|
|
6166
|
+
}
|
|
6167
|
+
)
|
|
6168
|
+
]
|
|
6169
|
+
}
|
|
6170
|
+
);
|
|
6171
|
+
}
|
|
6135
6172
|
var variantStyles4 = {
|
|
6136
6173
|
h1: "font-heading text-5xl font-bold leading-tight",
|
|
6137
6174
|
h2: "font-heading text-4xl font-bold leading-tight",
|
|
@@ -6991,6 +7028,143 @@ function formatDateTime(value, format = "datetime", isUTC = false, fallback = "-
|
|
|
6991
7028
|
}
|
|
6992
7029
|
return formatDate(value, format, isUTC);
|
|
6993
7030
|
}
|
|
7031
|
+
function formatDuration(ms) {
|
|
7032
|
+
const totalSeconds = Math.max(0, Math.ceil(ms / 1e3));
|
|
7033
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
7034
|
+
const seconds = totalSeconds % 60;
|
|
7035
|
+
return `${minutes}:${String(seconds).padStart(2, "0")}`;
|
|
7036
|
+
}
|
|
7037
|
+
function useTimer(options = {}) {
|
|
7038
|
+
const {
|
|
7039
|
+
mode = "up",
|
|
7040
|
+
durationMs,
|
|
7041
|
+
elapsedMs: controlledElapsedMs,
|
|
7042
|
+
running = false,
|
|
7043
|
+
autoTick = false,
|
|
7044
|
+
tickMs = 1e3
|
|
7045
|
+
} = options;
|
|
7046
|
+
const isControlled = controlledElapsedMs != null;
|
|
7047
|
+
const [internalElapsedMs, setInternalElapsedMs] = useState(0);
|
|
7048
|
+
useEffect(() => {
|
|
7049
|
+
if (isControlled || !autoTick || !running) return;
|
|
7050
|
+
const id = setInterval(() => {
|
|
7051
|
+
setInternalElapsedMs((prev) => prev + tickMs);
|
|
7052
|
+
}, tickMs);
|
|
7053
|
+
return () => clearInterval(id);
|
|
7054
|
+
}, [isControlled, autoTick, running, tickMs]);
|
|
7055
|
+
const elapsedMs = isControlled ? controlledElapsedMs : internalElapsedMs;
|
|
7056
|
+
const hasDuration = durationMs != null && durationMs > 0;
|
|
7057
|
+
const remainingMs = durationMs != null ? Math.max(0, durationMs - elapsedMs) : 0;
|
|
7058
|
+
let progress;
|
|
7059
|
+
if (hasDuration) {
|
|
7060
|
+
progress = Math.min(1, Math.max(0, elapsedMs / durationMs));
|
|
7061
|
+
} else {
|
|
7062
|
+
progress = mode === "down" ? 1 : 0;
|
|
7063
|
+
}
|
|
7064
|
+
const label = formatDuration(mode === "down" ? remainingMs : elapsedMs);
|
|
7065
|
+
const done = durationMs != null && elapsedMs >= durationMs;
|
|
7066
|
+
return { elapsedMs, remainingMs, progress, label, done };
|
|
7067
|
+
}
|
|
7068
|
+
|
|
7069
|
+
// src/components/custom/TimerReadout/TimerReadout.tsx
|
|
7070
|
+
var semantic = getSemanticColors("dark");
|
|
7071
|
+
var LIVE_GREEN = primitiveRamps.green[500];
|
|
7072
|
+
var SECONDARY = semantic["text-secondary"];
|
|
7073
|
+
var TERTIARY = semantic["text-tertiary"];
|
|
7074
|
+
var DEFAULT_GLYPH = "\u23F1";
|
|
7075
|
+
function TimerReadout({
|
|
7076
|
+
mode = "up",
|
|
7077
|
+
elapsedMs,
|
|
7078
|
+
durationMs,
|
|
7079
|
+
running = false,
|
|
7080
|
+
autoTick = false,
|
|
7081
|
+
showTotal = false,
|
|
7082
|
+
glyph = DEFAULT_GLYPH,
|
|
7083
|
+
className,
|
|
7084
|
+
...rest
|
|
7085
|
+
}) {
|
|
7086
|
+
const { label } = useTimer({ mode, durationMs, elapsedMs, running, autoTick });
|
|
7087
|
+
const currentColor = running ? LIVE_GREEN : SECONDARY;
|
|
7088
|
+
const total = showTotal && durationMs != null ? formatDuration(durationMs) : null;
|
|
7089
|
+
return /* @__PURE__ */ jsx(
|
|
7090
|
+
View,
|
|
7091
|
+
{
|
|
7092
|
+
accessibilityRole: "timer",
|
|
7093
|
+
accessibilityLabel: total != null ? `${label} of ${total}` : label,
|
|
7094
|
+
className: cn("flex-row items-baseline justify-end", className),
|
|
7095
|
+
...rest,
|
|
7096
|
+
children: /* @__PURE__ */ jsxs(Typography, { variant: "mono", style: { fontSize: 11, textAlign: "right" }, children: [
|
|
7097
|
+
/* @__PURE__ */ jsx(Text, { testID: "timer-readout-glyph", style: { color: currentColor, marginRight: 3 }, children: glyph }),
|
|
7098
|
+
/* @__PURE__ */ jsx(Text, { testID: "timer-readout-current", style: { color: currentColor }, children: label }),
|
|
7099
|
+
total != null ? /* @__PURE__ */ jsx(Text, { testID: "timer-readout-total", style: { color: TERTIARY }, children: ` / ${total}` }) : null
|
|
7100
|
+
] })
|
|
7101
|
+
}
|
|
7102
|
+
);
|
|
7103
|
+
}
|
|
7104
|
+
function CircularTimer({
|
|
7105
|
+
durationMs,
|
|
7106
|
+
elapsedMs,
|
|
7107
|
+
mode = "down",
|
|
7108
|
+
size = 160,
|
|
7109
|
+
strokeWidth = 8,
|
|
7110
|
+
fill = false,
|
|
7111
|
+
color = "primary",
|
|
7112
|
+
doneLabel,
|
|
7113
|
+
doneColor = "success",
|
|
7114
|
+
controls,
|
|
7115
|
+
accessibilityLabel: accessibilityLabel2,
|
|
7116
|
+
testID
|
|
7117
|
+
}) {
|
|
7118
|
+
const { remainingMs, progress, label, done } = useTimer({ mode, durationMs, elapsedMs });
|
|
7119
|
+
const isDone = done && mode === "down";
|
|
7120
|
+
const showDone = isDone && doneLabel != null;
|
|
7121
|
+
const remainingFrac = durationMs > 0 ? Math.max(0, Math.min(1, remainingMs / durationMs)) : 0;
|
|
7122
|
+
const arc = mode === "down" ? showDone ? 1 : remainingFrac : progress;
|
|
7123
|
+
const ringColor = showDone ? doneColor : color;
|
|
7124
|
+
const remainingSec = Math.ceil(Math.max(0, remainingMs) / 1e3);
|
|
7125
|
+
const a11y = accessibilityLabel2 ?? (isDone ? "Timer complete" : `${remainingSec} seconds remaining`);
|
|
7126
|
+
return /* @__PURE__ */ jsxs(
|
|
7127
|
+
View,
|
|
7128
|
+
{
|
|
7129
|
+
style: { alignItems: "center", gap: 16 },
|
|
7130
|
+
accessibilityRole: "timer",
|
|
7131
|
+
accessibilityLabel: a11y,
|
|
7132
|
+
testID: testID ?? "circular-timer",
|
|
7133
|
+
children: [
|
|
7134
|
+
/* @__PURE__ */ jsx(
|
|
7135
|
+
CircularProgress,
|
|
7136
|
+
{
|
|
7137
|
+
value: arc,
|
|
7138
|
+
max: 1,
|
|
7139
|
+
size,
|
|
7140
|
+
strokeWidth,
|
|
7141
|
+
fill,
|
|
7142
|
+
color: ringColor,
|
|
7143
|
+
accessibilityLabel: "Timer ring",
|
|
7144
|
+
testID: "circular-timer-ring",
|
|
7145
|
+
children: /* @__PURE__ */ jsx(
|
|
7146
|
+
Text,
|
|
7147
|
+
{
|
|
7148
|
+
className: showDone ? void 0 : "text-text-primary",
|
|
7149
|
+
style: {
|
|
7150
|
+
fontSize: Math.round(size * (showDone ? 0.28 : 0.24)),
|
|
7151
|
+
fontFamily: '"Space Grotesk", sans-serif',
|
|
7152
|
+
fontWeight: "800",
|
|
7153
|
+
fontVariant: ["tabular-nums"],
|
|
7154
|
+
letterSpacing: showDone ? 1 : -1,
|
|
7155
|
+
...showDone ? { color: colorVarMap[doneColor] } : null
|
|
7156
|
+
},
|
|
7157
|
+
testID: "circular-timer-label",
|
|
7158
|
+
children: showDone ? doneLabel : label
|
|
7159
|
+
}
|
|
7160
|
+
)
|
|
7161
|
+
}
|
|
7162
|
+
),
|
|
7163
|
+
controls
|
|
7164
|
+
]
|
|
7165
|
+
}
|
|
7166
|
+
);
|
|
7167
|
+
}
|
|
6994
7168
|
var sizeConfig2 = {
|
|
6995
7169
|
sm: { value: "text-lg font-bold", label: "text-xs", unit: "text-xs" },
|
|
6996
7170
|
md: { value: "text-2xl font-bold", label: "text-xs", unit: "text-sm" },
|
|
@@ -7420,15 +7594,22 @@ var WORKOUT_TOKENS = {
|
|
|
7420
7594
|
// Canonical 4-band performance scale — the single source for BOTH the
|
|
7421
7595
|
// VelocityStrip zone bars and the SetRow RPE color (TD-03.43). The direction
|
|
7422
7596
|
// is intentionally inverted between the two consumers: for velocity, green =
|
|
7423
|
-
// fastest/best; for RPE, green = easiest. This is the [0,
|
|
7424
|
-
// the canonical `sequentialEffort` primitive
|
|
7425
|
-
//
|
|
7597
|
+
// fastest/best; for RPE, green = easiest. This is the [0,2,3,4] subsample of
|
|
7598
|
+
// the canonical `sequentialEffort` primitive: an EVEN hue walk across the ramp
|
|
7599
|
+
// (green → gold → orange → red). The earlier [0,1,2,4] spent two of its four
|
|
7600
|
+
// bands on adjacent yellows (amber-200 + amber-300) and skipped orange, reading
|
|
7601
|
+
// yellow-heavy with an abrupt jump to red; sampling amber-300 + orange-400
|
|
7602
|
+
// instead gives four cleanly separable bands that hold at 3px strip scale.
|
|
7603
|
+
// Consumed inline (RN).
|
|
7426
7604
|
scale: {
|
|
7427
7605
|
green: sequentialEffort[0],
|
|
7428
|
-
|
|
7429
|
-
|
|
7430
|
-
// gold
|
|
7606
|
+
// green-300
|
|
7607
|
+
yellow: sequentialEffort[2],
|
|
7608
|
+
// amber-300 (gold)
|
|
7609
|
+
orange: sequentialEffort[3],
|
|
7610
|
+
// orange-400 (true orange)
|
|
7431
7611
|
red: sequentialEffort[4]
|
|
7612
|
+
// red-600
|
|
7432
7613
|
},
|
|
7433
7614
|
// BodyMap volume heatmap — the canonical `divergingScale` (under → optimal →
|
|
7434
7615
|
// over): a true diverging shape with a light green center, cool-blue under-
|
|
@@ -7553,8 +7734,8 @@ function roundTempo(tempo) {
|
|
|
7553
7734
|
return tempo.map((v) => Math.round(v * 10) / 10);
|
|
7554
7735
|
}
|
|
7555
7736
|
function formatSignedPct(ratio) {
|
|
7556
|
-
const
|
|
7557
|
-
return `${
|
|
7737
|
+
const pct2 = Math.round(ratio * 100);
|
|
7738
|
+
return `${pct2 > 0 ? "+" : ""}${pct2}%`;
|
|
7558
7739
|
}
|
|
7559
7740
|
function formatPrescription(p) {
|
|
7560
7741
|
if (p == null) return null;
|
|
@@ -7634,6 +7815,11 @@ var TEMPO_PACING = {
|
|
|
7634
7815
|
behindThresholdPct: 0.15,
|
|
7635
7816
|
minPhaseDurationMs: 500
|
|
7636
7817
|
};
|
|
7818
|
+
function formatTempoDelta(remainingMs) {
|
|
7819
|
+
const s = remainingMs / 1e3;
|
|
7820
|
+
const rounded = Math.abs(s) < 0.05 ? 0 : s;
|
|
7821
|
+
return rounded.toFixed(1);
|
|
7822
|
+
}
|
|
7637
7823
|
function getTempoPacingState(elapsedMs, targetMs) {
|
|
7638
7824
|
if (!targetMs || targetMs < TEMPO_PACING.minPhaseDurationMs) return "none";
|
|
7639
7825
|
const ratio = elapsedMs / targetMs;
|
|
@@ -7646,24 +7832,33 @@ function getTempoFillPct(elapsedMs, targetMs) {
|
|
|
7646
7832
|
}
|
|
7647
7833
|
var PHASE_ORDER = ["concentric", "hold", "eccentric"];
|
|
7648
7834
|
var PHASE_CONFIG = {
|
|
7649
|
-
concentric: { label: "Con", color: t2["status-success"], flex: 2 },
|
|
7650
|
-
hold: { label: "Hold", color: t2["brand-primary"], flex: 1 },
|
|
7651
|
-
eccentric: { label: "Ecc", color: t2["status-warning"], flex: 3 }
|
|
7835
|
+
concentric: { label: "Con", wallLabel: "Concentric", color: t2["status-success"], flex: 2 },
|
|
7836
|
+
hold: { label: "Hold", wallLabel: "Hold", color: t2["brand-primary"], flex: 1 },
|
|
7837
|
+
eccentric: { label: "Ecc", wallLabel: "Eccentric", color: t2["status-warning"], flex: 3 }
|
|
7838
|
+
};
|
|
7839
|
+
var TEMPO_SIZES = {
|
|
7840
|
+
default: { labelMargin: 4, labelFont: 10, barGap: 2, barHeight: 20, radius: 4, segFont: 12 },
|
|
7841
|
+
wall: { labelMargin: 8, labelFont: 15, barGap: 4, barHeight: 40, radius: 6, segFont: 22 }
|
|
7652
7842
|
};
|
|
7653
7843
|
function TempoBar({
|
|
7654
7844
|
activePhase,
|
|
7655
7845
|
phaseElapsedMs,
|
|
7656
7846
|
completed,
|
|
7657
7847
|
target,
|
|
7848
|
+
size = "default",
|
|
7849
|
+
activeDisplay = "time",
|
|
7658
7850
|
className,
|
|
7659
7851
|
...props
|
|
7660
7852
|
}) {
|
|
7853
|
+
const s = TEMPO_SIZES[size];
|
|
7854
|
+
const [display, setDisplay] = useState(activeDisplay);
|
|
7855
|
+
const toggleDisplay = () => setDisplay((d) => d === "time" ? "delta" : "time");
|
|
7661
7856
|
return /* @__PURE__ */ jsxs(View, { className, testID: "tempo-bar", ...props, children: [
|
|
7662
|
-
/* @__PURE__ */ jsx(View, { style: { flexDirection: "row", marginBottom:
|
|
7857
|
+
/* @__PURE__ */ jsx(View, { style: { flexDirection: "row", marginBottom: s.labelMargin }, children: PHASE_ORDER.map((phase) => {
|
|
7663
7858
|
const config = PHASE_CONFIG[phase];
|
|
7664
|
-
return /* @__PURE__ */ jsx(View, { style: { flex: config.flex, alignItems: "center" }, children: /* @__PURE__ */ jsx(Text, { style: { fontSize:
|
|
7859
|
+
return /* @__PURE__ */ jsx(View, { style: { flex: config.flex, alignItems: "center" }, children: /* @__PURE__ */ jsx(Text, { numberOfLines: 1, style: { fontSize: s.labelFont, color: t2["text-disabled"] }, children: size === "wall" ? config.wallLabel : config.label }) }, phase);
|
|
7665
7860
|
}) }),
|
|
7666
|
-
/* @__PURE__ */ jsx(View, { style: { flexDirection: "row", gap:
|
|
7861
|
+
/* @__PURE__ */ jsx(View, { style: { flexDirection: "row", gap: s.barGap, height: s.barHeight }, children: PHASE_ORDER.map((phase) => {
|
|
7667
7862
|
const config = PHASE_CONFIG[phase];
|
|
7668
7863
|
const isActive = activePhase === phase;
|
|
7669
7864
|
const completedMs = completed?.[phase];
|
|
@@ -7675,7 +7870,7 @@ function TempoBar({
|
|
|
7675
7870
|
style: {
|
|
7676
7871
|
flex: config.flex,
|
|
7677
7872
|
backgroundColor: alpha("#ffffff", 0.06),
|
|
7678
|
-
borderRadius:
|
|
7873
|
+
borderRadius: s.radius,
|
|
7679
7874
|
overflow: "hidden"
|
|
7680
7875
|
},
|
|
7681
7876
|
children: isActive ? /* @__PURE__ */ jsx(
|
|
@@ -7683,9 +7878,21 @@ function TempoBar({
|
|
|
7683
7878
|
{
|
|
7684
7879
|
config,
|
|
7685
7880
|
phaseElapsedMs,
|
|
7686
|
-
targetMs
|
|
7881
|
+
targetMs,
|
|
7882
|
+
radius: s.radius,
|
|
7883
|
+
font: s.segFont,
|
|
7884
|
+
display,
|
|
7885
|
+
onToggleDisplay: toggleDisplay
|
|
7886
|
+
}
|
|
7887
|
+
) : completedMs != null ? /* @__PURE__ */ jsx(
|
|
7888
|
+
CompletedSegment,
|
|
7889
|
+
{
|
|
7890
|
+
config,
|
|
7891
|
+
completedMs,
|
|
7892
|
+
targetMs,
|
|
7893
|
+
font: s.segFont
|
|
7687
7894
|
}
|
|
7688
|
-
) :
|
|
7895
|
+
) : null
|
|
7689
7896
|
},
|
|
7690
7897
|
phase
|
|
7691
7898
|
);
|
|
@@ -7695,49 +7902,65 @@ function TempoBar({
|
|
|
7695
7902
|
function ActiveSegment({
|
|
7696
7903
|
config,
|
|
7697
7904
|
phaseElapsedMs,
|
|
7698
|
-
targetMs
|
|
7905
|
+
targetMs,
|
|
7906
|
+
radius,
|
|
7907
|
+
font,
|
|
7908
|
+
display,
|
|
7909
|
+
onToggleDisplay
|
|
7699
7910
|
}) {
|
|
7700
7911
|
const pacing = getTempoPacingState(phaseElapsedMs, targetMs);
|
|
7701
7912
|
const barColor = pacing === "behind" ? t2["status-error"] : config.color;
|
|
7702
7913
|
const fillPct = getTempoFillPct(phaseElapsedMs, targetMs);
|
|
7703
|
-
const label = targetMs ? `${
|
|
7704
|
-
return /* @__PURE__ */ jsxs(
|
|
7705
|
-
|
|
7706
|
-
|
|
7707
|
-
|
|
7708
|
-
|
|
7709
|
-
|
|
7710
|
-
|
|
7711
|
-
|
|
7712
|
-
|
|
7713
|
-
|
|
7714
|
-
|
|
7715
|
-
|
|
7716
|
-
|
|
7717
|
-
|
|
7718
|
-
|
|
7719
|
-
|
|
7720
|
-
|
|
7721
|
-
|
|
7722
|
-
|
|
7723
|
-
|
|
7724
|
-
|
|
7725
|
-
|
|
7726
|
-
|
|
7727
|
-
|
|
7728
|
-
|
|
7729
|
-
|
|
7730
|
-
|
|
7731
|
-
|
|
7914
|
+
const label = display === "delta" && targetMs != null ? formatTempoDelta(targetMs - phaseElapsedMs) : targetMs != null ? `${formatDuration2(phaseElapsedMs)} / ${formatDuration2(targetMs)}` : formatDuration2(phaseElapsedMs);
|
|
7915
|
+
return /* @__PURE__ */ jsxs(
|
|
7916
|
+
Pressable,
|
|
7917
|
+
{
|
|
7918
|
+
onPress: onToggleDisplay,
|
|
7919
|
+
style: { height: "100%", position: "relative" },
|
|
7920
|
+
accessibilityRole: "button",
|
|
7921
|
+
accessibilityLabel: `Tempo readout: ${display === "delta" ? "delta" : "time"} \u2014 tap to switch`,
|
|
7922
|
+
testID: `tempo-segment-active-${config.label}`,
|
|
7923
|
+
children: [
|
|
7924
|
+
/* @__PURE__ */ jsx(
|
|
7925
|
+
View,
|
|
7926
|
+
{
|
|
7927
|
+
style: {
|
|
7928
|
+
position: "absolute",
|
|
7929
|
+
left: 0,
|
|
7930
|
+
top: 0,
|
|
7931
|
+
bottom: 0,
|
|
7932
|
+
width: `${fillPct}%`,
|
|
7933
|
+
backgroundColor: alpha(barColor, 0.3),
|
|
7934
|
+
borderRadius: radius
|
|
7935
|
+
}
|
|
7936
|
+
}
|
|
7937
|
+
),
|
|
7938
|
+
/* @__PURE__ */ jsx(
|
|
7939
|
+
View,
|
|
7940
|
+
{
|
|
7941
|
+
style: {
|
|
7942
|
+
height: "100%",
|
|
7943
|
+
flexDirection: "row",
|
|
7944
|
+
alignItems: "center",
|
|
7945
|
+
justifyContent: "center"
|
|
7946
|
+
},
|
|
7947
|
+
children: /* @__PURE__ */ jsx(Text, { style: { fontSize: font, fontWeight: "700", color: barColor }, children: label })
|
|
7948
|
+
}
|
|
7949
|
+
)
|
|
7950
|
+
]
|
|
7951
|
+
}
|
|
7952
|
+
);
|
|
7732
7953
|
}
|
|
7733
7954
|
function CompletedSegment({
|
|
7734
7955
|
config,
|
|
7735
7956
|
completedMs,
|
|
7736
|
-
targetMs
|
|
7957
|
+
targetMs,
|
|
7958
|
+
font
|
|
7737
7959
|
}) {
|
|
7738
7960
|
const pacing = getTempoPacingState(completedMs, targetMs);
|
|
7739
7961
|
const hitTarget = pacing !== "behind";
|
|
7740
7962
|
const indicator = targetMs && targetMs >= TEMPO_PACING.minPhaseDurationMs ? hitTarget ? " \u2713" : " \u2717" : "";
|
|
7963
|
+
const cueColor = hitTarget ? config.color : t2["status-error"];
|
|
7741
7964
|
return /* @__PURE__ */ jsx(
|
|
7742
7965
|
View,
|
|
7743
7966
|
{
|
|
@@ -7746,20 +7969,46 @@ function CompletedSegment({
|
|
|
7746
7969
|
flexDirection: "row",
|
|
7747
7970
|
alignItems: "center",
|
|
7748
7971
|
justifyContent: "center",
|
|
7749
|
-
backgroundColor: alpha(
|
|
7972
|
+
backgroundColor: alpha(cueColor, 0.15)
|
|
7750
7973
|
},
|
|
7751
7974
|
testID: `tempo-segment-completed-${config.label}`,
|
|
7752
|
-
children: /* @__PURE__ */ jsxs(
|
|
7753
|
-
|
|
7754
|
-
|
|
7755
|
-
|
|
7975
|
+
children: /* @__PURE__ */ jsxs(
|
|
7976
|
+
Text,
|
|
7977
|
+
{
|
|
7978
|
+
style: {
|
|
7979
|
+
fontSize: font,
|
|
7980
|
+
fontWeight: "500",
|
|
7981
|
+
color: hitTarget ? alpha(config.color, 0.7) : cueColor
|
|
7982
|
+
},
|
|
7983
|
+
children: [
|
|
7984
|
+
formatDuration2(completedMs),
|
|
7985
|
+
indicator
|
|
7986
|
+
]
|
|
7987
|
+
}
|
|
7988
|
+
)
|
|
7756
7989
|
}
|
|
7757
7990
|
);
|
|
7758
7991
|
}
|
|
7759
|
-
function
|
|
7992
|
+
function formatDuration2(ms) {
|
|
7760
7993
|
const s = ms / 1e3;
|
|
7761
7994
|
return s < 10 ? s.toFixed(1) : Math.round(s).toString();
|
|
7762
7995
|
}
|
|
7996
|
+
var METRIC_FONT = "Inter, sans-serif";
|
|
7997
|
+
function MetricCell({ children, color, fontSize = 11 }) {
|
|
7998
|
+
return /* @__PURE__ */ jsx(
|
|
7999
|
+
Text,
|
|
8000
|
+
{
|
|
8001
|
+
style: {
|
|
8002
|
+
fontFamily: METRIC_FONT,
|
|
8003
|
+
fontSize,
|
|
8004
|
+
color,
|
|
8005
|
+
fontWeight: "600",
|
|
8006
|
+
letterSpacing: 1
|
|
8007
|
+
},
|
|
8008
|
+
children
|
|
8009
|
+
}
|
|
8010
|
+
);
|
|
8011
|
+
}
|
|
7763
8012
|
|
|
7764
8013
|
// src/components/custom/Workout/TempoDisplay.tsx
|
|
7765
8014
|
var t3 = getSemanticColors("dark");
|
|
@@ -7778,34 +8027,10 @@ function TempoValue({
|
|
|
7778
8027
|
color,
|
|
7779
8028
|
fontSize
|
|
7780
8029
|
}) {
|
|
7781
|
-
return /* @__PURE__ */ jsx(
|
|
7782
|
-
Text,
|
|
7783
|
-
{
|
|
7784
|
-
style: {
|
|
7785
|
-
fontFamily: INTER,
|
|
7786
|
-
fontSize,
|
|
7787
|
-
color,
|
|
7788
|
-
fontWeight: "600",
|
|
7789
|
-
letterSpacing: 1
|
|
7790
|
-
},
|
|
7791
|
-
children: value
|
|
7792
|
-
}
|
|
7793
|
-
);
|
|
8030
|
+
return /* @__PURE__ */ jsx(MetricCell, { color, fontSize, children: value });
|
|
7794
8031
|
}
|
|
7795
8032
|
function TempoSeparator({ color, fontSize }) {
|
|
7796
|
-
return /* @__PURE__ */ jsx(
|
|
7797
|
-
Text,
|
|
7798
|
-
{
|
|
7799
|
-
style: {
|
|
7800
|
-
fontFamily: INTER,
|
|
7801
|
-
fontSize,
|
|
7802
|
-
color,
|
|
7803
|
-
fontWeight: "600",
|
|
7804
|
-
letterSpacing: 1
|
|
7805
|
-
},
|
|
7806
|
-
children: "-"
|
|
7807
|
-
}
|
|
7808
|
-
);
|
|
8033
|
+
return /* @__PURE__ */ jsx(MetricCell, { color, fontSize, children: "-" });
|
|
7809
8034
|
}
|
|
7810
8035
|
var LIVE_PHASES = [
|
|
7811
8036
|
{ key: "eccentric", color: phaseColors.eccentric },
|
|
@@ -7867,6 +8092,7 @@ function TempoDisplay({
|
|
|
7867
8092
|
tempo,
|
|
7868
8093
|
size = "md",
|
|
7869
8094
|
colored = true,
|
|
8095
|
+
showLabel = true,
|
|
7870
8096
|
showInfo = true,
|
|
7871
8097
|
live,
|
|
7872
8098
|
onPress,
|
|
@@ -7900,7 +8126,7 @@ function TempoDisplay({
|
|
|
7900
8126
|
},
|
|
7901
8127
|
...props,
|
|
7902
8128
|
children: [
|
|
7903
|
-
/* @__PURE__ */ jsx(
|
|
8129
|
+
showLabel && /* @__PURE__ */ jsx(
|
|
7904
8130
|
Text,
|
|
7905
8131
|
{
|
|
7906
8132
|
style: {
|
|
@@ -8128,12 +8354,12 @@ var ZONE = {
|
|
|
8128
8354
|
// severe over-target
|
|
8129
8355
|
};
|
|
8130
8356
|
var BULGE_SIZE = { 1: 8, 2: 10, 3: 11 };
|
|
8131
|
-
function zoneForPct(
|
|
8132
|
-
if (
|
|
8133
|
-
if (
|
|
8134
|
-
if (
|
|
8135
|
-
if (
|
|
8136
|
-
if (
|
|
8357
|
+
function zoneForPct(pct2) {
|
|
8358
|
+
if (pct2 >= 125) return { color: ZONE.over3, over: 3 };
|
|
8359
|
+
if (pct2 >= 115) return { color: ZONE.over2, over: 2 };
|
|
8360
|
+
if (pct2 > 100) return { color: ZONE.over1, over: 1 };
|
|
8361
|
+
if (pct2 === 100) return { color: ZONE.target, over: 0 };
|
|
8362
|
+
if (pct2 >= 75) return { color: ZONE.approaching, over: 0 };
|
|
8137
8363
|
return { color: ZONE.building, over: 0 };
|
|
8138
8364
|
}
|
|
8139
8365
|
function clampFill(value) {
|
|
@@ -8141,9 +8367,9 @@ function clampFill(value) {
|
|
|
8141
8367
|
if (value > 1) return 1;
|
|
8142
8368
|
return value;
|
|
8143
8369
|
}
|
|
8144
|
-
function isAtTarget(
|
|
8370
|
+
function isAtTarget(pct2, threshold) {
|
|
8145
8371
|
if (threshold == null) return false;
|
|
8146
|
-
return Math.abs(
|
|
8372
|
+
return Math.abs(pct2 - Math.round(threshold * 100)) <= 5;
|
|
8147
8373
|
}
|
|
8148
8374
|
function IntensityBar({
|
|
8149
8375
|
level,
|
|
@@ -8157,9 +8383,9 @@ function IntensityBar({
|
|
|
8157
8383
|
}) {
|
|
8158
8384
|
const isVertical = orientation === "vertical";
|
|
8159
8385
|
const fillLevel = clampFill(level);
|
|
8160
|
-
const
|
|
8161
|
-
const zone = zoneForPct(
|
|
8162
|
-
const atTarget = isAtTarget(
|
|
8386
|
+
const pct2 = Math.round(Math.max(0, level) * 100);
|
|
8387
|
+
const zone = zoneForPct(pct2);
|
|
8388
|
+
const atTarget = isAtTarget(pct2, threshold);
|
|
8163
8389
|
const [fillAnim] = useState(() => new Animated.Value(fillLevel));
|
|
8164
8390
|
useEffect(() => {
|
|
8165
8391
|
const animation = Animated.timing(fillAnim, {
|
|
@@ -8210,8 +8436,8 @@ function IntensityBar({
|
|
|
8210
8436
|
className,
|
|
8211
8437
|
style: { alignItems: "center" },
|
|
8212
8438
|
accessibilityRole: "progressbar",
|
|
8213
|
-
accessibilityValue: { min: 0, max: 100, now:
|
|
8214
|
-
accessibilityLabel: `Intensity level: ${
|
|
8439
|
+
accessibilityValue: { min: 0, max: 100, now: pct2 },
|
|
8440
|
+
accessibilityLabel: `Intensity level: ${pct2}%`,
|
|
8215
8441
|
testID: "intensity-bar",
|
|
8216
8442
|
...props,
|
|
8217
8443
|
children: [
|
|
@@ -8257,7 +8483,7 @@ function IntensityBar({
|
|
|
8257
8483
|
accessibilityElementsHidden: true,
|
|
8258
8484
|
testID: "intensity-label",
|
|
8259
8485
|
children: [
|
|
8260
|
-
|
|
8486
|
+
pct2,
|
|
8261
8487
|
"%"
|
|
8262
8488
|
]
|
|
8263
8489
|
}
|
|
@@ -8442,13 +8668,257 @@ function WorkoutPill({
|
|
|
8442
8668
|
}
|
|
8443
8669
|
return pill;
|
|
8444
8670
|
}
|
|
8671
|
+
var PULSE_HALF_MS = 950;
|
|
8672
|
+
var PULSE_MIN_OPACITY = 0.45;
|
|
8673
|
+
var SEGMENTED_BAR_GAP = 5;
|
|
8674
|
+
function usePulse2(active) {
|
|
8675
|
+
const [value] = useState(() => new Animated.Value(0));
|
|
8676
|
+
useEffect(() => {
|
|
8677
|
+
if (!active) return;
|
|
8678
|
+
const loop = Animated.loop(
|
|
8679
|
+
Animated.sequence([
|
|
8680
|
+
Animated.timing(value, {
|
|
8681
|
+
toValue: 1,
|
|
8682
|
+
duration: PULSE_HALF_MS,
|
|
8683
|
+
easing: Easing.inOut(Easing.ease),
|
|
8684
|
+
useNativeDriver: false
|
|
8685
|
+
}),
|
|
8686
|
+
Animated.timing(value, {
|
|
8687
|
+
toValue: 0,
|
|
8688
|
+
duration: PULSE_HALF_MS,
|
|
8689
|
+
easing: Easing.inOut(Easing.ease),
|
|
8690
|
+
useNativeDriver: false
|
|
8691
|
+
})
|
|
8692
|
+
])
|
|
8693
|
+
);
|
|
8694
|
+
loop.start();
|
|
8695
|
+
return () => loop.stop();
|
|
8696
|
+
}, [active, value]);
|
|
8697
|
+
return value;
|
|
8698
|
+
}
|
|
8699
|
+
function SegmentedBar({
|
|
8700
|
+
segments,
|
|
8701
|
+
height = 8,
|
|
8702
|
+
gap = SEGMENTED_BAR_GAP,
|
|
8703
|
+
radius = 2,
|
|
8704
|
+
marker = null,
|
|
8705
|
+
segmentTestID,
|
|
8706
|
+
style,
|
|
8707
|
+
...props
|
|
8708
|
+
}) {
|
|
8709
|
+
const pulse = usePulse2(segments.some((s) => s.pulse));
|
|
8710
|
+
return /* @__PURE__ */ jsxs(View, { style: [{ flexDirection: "row", height, gap, position: "relative" }, style], ...props, children: [
|
|
8711
|
+
segments.map((seg, i) => {
|
|
8712
|
+
const fillStyle = {
|
|
8713
|
+
width: `${(seg.fill ?? 1) * 100}%`,
|
|
8714
|
+
height: "100%",
|
|
8715
|
+
backgroundColor: seg.color,
|
|
8716
|
+
opacity: seg.opacity
|
|
8717
|
+
};
|
|
8718
|
+
const testID = segmentTestID?.(seg, i) ?? "segmented-bar-segment";
|
|
8719
|
+
return /* @__PURE__ */ jsx(
|
|
8720
|
+
View,
|
|
8721
|
+
{
|
|
8722
|
+
style: {
|
|
8723
|
+
flex: seg.weight ?? 1,
|
|
8724
|
+
minWidth: 0,
|
|
8725
|
+
height: "100%",
|
|
8726
|
+
marginLeft: seg.leadingGap,
|
|
8727
|
+
borderRadius: radius,
|
|
8728
|
+
overflow: "hidden"
|
|
8729
|
+
},
|
|
8730
|
+
children: seg.pulse ? /* @__PURE__ */ jsx(
|
|
8731
|
+
Animated.View,
|
|
8732
|
+
{
|
|
8733
|
+
style: {
|
|
8734
|
+
...fillStyle,
|
|
8735
|
+
...seg.pulseColor ? {
|
|
8736
|
+
backgroundColor: pulse.interpolate({
|
|
8737
|
+
inputRange: [0, 1],
|
|
8738
|
+
outputRange: seg.pulseColor
|
|
8739
|
+
})
|
|
8740
|
+
} : {
|
|
8741
|
+
opacity: pulse.interpolate({
|
|
8742
|
+
inputRange: [0, 1],
|
|
8743
|
+
outputRange: [PULSE_MIN_OPACITY, 1]
|
|
8744
|
+
})
|
|
8745
|
+
}
|
|
8746
|
+
},
|
|
8747
|
+
accessibilityElementsHidden: true,
|
|
8748
|
+
testID
|
|
8749
|
+
}
|
|
8750
|
+
) : /* @__PURE__ */ jsx(View, { style: fillStyle, accessibilityElementsHidden: true, testID })
|
|
8751
|
+
},
|
|
8752
|
+
i
|
|
8753
|
+
);
|
|
8754
|
+
}),
|
|
8755
|
+
marker ? /* @__PURE__ */ jsx(
|
|
8756
|
+
View,
|
|
8757
|
+
{
|
|
8758
|
+
style: {
|
|
8759
|
+
position: "absolute",
|
|
8760
|
+
left: `${marker.position * 100}%`,
|
|
8761
|
+
top: 0,
|
|
8762
|
+
bottom: 0,
|
|
8763
|
+
width: 2,
|
|
8764
|
+
backgroundColor: marker.color
|
|
8765
|
+
},
|
|
8766
|
+
accessibilityElementsHidden: true,
|
|
8767
|
+
testID: "segmented-bar-marker"
|
|
8768
|
+
}
|
|
8769
|
+
) : null
|
|
8770
|
+
] });
|
|
8771
|
+
}
|
|
8772
|
+
|
|
8773
|
+
// src/components/custom/Workout/SetBar.tsx
|
|
8774
|
+
var SET_STRIP_ZONES = {
|
|
8775
|
+
slow: primitiveRamps.red[600],
|
|
8776
|
+
moderate: primitiveRamps.orange[400],
|
|
8777
|
+
fast: primitiveRamps.amber[300],
|
|
8778
|
+
fastest: primitiveRamps.green[300]
|
|
8779
|
+
};
|
|
8780
|
+
var TODO_COLOR = primitiveColors.charcoal[300];
|
|
8781
|
+
var SET_STRIP_VARIABLE_COLOR = primitiveRamps.cyan[900];
|
|
8782
|
+
var NOTCH_GAP = 2;
|
|
8783
|
+
var CLUSTER_GAP = 3;
|
|
8784
|
+
var MYO_UPCOMING_CLUSTERS = 3;
|
|
8785
|
+
var MYO_UPCOMING_CLUSTER_LEN = 5;
|
|
8786
|
+
var MYO_UPCOMING_FADE = 0.6;
|
|
8787
|
+
var PULSE_RANGE = {
|
|
8788
|
+
[SET_STRIP_ZONES.slow]: [primitiveRamps.red[500], primitiveRamps.red[700]],
|
|
8789
|
+
[SET_STRIP_ZONES.moderate]: [primitiveRamps.orange[300], primitiveRamps.orange[500]],
|
|
8790
|
+
[SET_STRIP_ZONES.fast]: [primitiveRamps.amber[200], primitiveRamps.amber[400]],
|
|
8791
|
+
[SET_STRIP_ZONES.fastest]: [primitiveRamps.green[200], primitiveRamps.green[400]]
|
|
8792
|
+
};
|
|
8793
|
+
function velocityZoneColor(v) {
|
|
8794
|
+
if (v < 0.5) return SET_STRIP_ZONES.slow;
|
|
8795
|
+
if (v < 0.75) return SET_STRIP_ZONES.moderate;
|
|
8796
|
+
if (v < 1) return SET_STRIP_ZONES.fast;
|
|
8797
|
+
return SET_STRIP_ZONES.fastest;
|
|
8798
|
+
}
|
|
8799
|
+
function chunkedSegments(chunks, gap) {
|
|
8800
|
+
return chunks.flatMap(
|
|
8801
|
+
(vels, ci) => vels.map((v, ri) => ({
|
|
8802
|
+
color: velocityZoneColor(v),
|
|
8803
|
+
...ci > 0 && ri === 0 ? { leadingGap: gap } : {}
|
|
8804
|
+
}))
|
|
8805
|
+
);
|
|
8806
|
+
}
|
|
8807
|
+
function rangeSegments(floor, max, doneVels) {
|
|
8808
|
+
return Array.from({ length: max }, (_, i) => {
|
|
8809
|
+
if (i < doneVels.length) return { color: velocityZoneColor(doneVels[i]) };
|
|
8810
|
+
return { color: i < floor ? TODO_COLOR : SET_STRIP_VARIABLE_COLOR };
|
|
8811
|
+
});
|
|
8812
|
+
}
|
|
8813
|
+
function myoUpcomingSegments(activationLen, clusterCount) {
|
|
8814
|
+
const activation = Array.from({ length: activationLen }, () => ({ color: TODO_COLOR }));
|
|
8815
|
+
const trail = Array.from(
|
|
8816
|
+
{ length: clusterCount },
|
|
8817
|
+
(_, ci) => Array.from({ length: MYO_UPCOMING_CLUSTER_LEN }, (_2, ri) => ({
|
|
8818
|
+
color: SET_STRIP_VARIABLE_COLOR,
|
|
8819
|
+
opacity: MYO_UPCOMING_FADE ** ci,
|
|
8820
|
+
...ri === 0 ? { leadingGap: CLUSTER_GAP } : {}
|
|
8821
|
+
}))
|
|
8822
|
+
).flat();
|
|
8823
|
+
return [...activation, ...trail];
|
|
8824
|
+
}
|
|
8825
|
+
function setSegments(set) {
|
|
8826
|
+
if (set.status === "todo") {
|
|
8827
|
+
return [{ color: TODO_COLOR }];
|
|
8828
|
+
}
|
|
8829
|
+
if (set.status === "done") {
|
|
8830
|
+
return set.velocities.map((v) => ({ color: velocityZoneColor(v) }));
|
|
8831
|
+
}
|
|
8832
|
+
if (set.status === "range") {
|
|
8833
|
+
return rangeSegments(set.floor, set.max, set.doneVels);
|
|
8834
|
+
}
|
|
8835
|
+
if (set.status === "drop") {
|
|
8836
|
+
return chunkedSegments(set.subloads, NOTCH_GAP);
|
|
8837
|
+
}
|
|
8838
|
+
if (set.status === "myo") {
|
|
8839
|
+
return chunkedSegments([set.activation, ...set.clusters], CLUSTER_GAP);
|
|
8840
|
+
}
|
|
8841
|
+
if (set.status === "myo-upcoming") {
|
|
8842
|
+
return myoUpcomingSegments(set.activationLen, set.clusterCount ?? MYO_UPCOMING_CLUSTERS);
|
|
8843
|
+
}
|
|
8844
|
+
const performed = set.velocities.map((v) => {
|
|
8845
|
+
const color = velocityZoneColor(v);
|
|
8846
|
+
return { color, pulse: true, pulseColor: PULSE_RANGE[color] };
|
|
8847
|
+
});
|
|
8848
|
+
const remaining = Math.max(0, set.planned - set.velocities.length);
|
|
8849
|
+
return [...performed, ...Array.from({ length: remaining }, () => ({ color: TODO_COLOR }))];
|
|
8850
|
+
}
|
|
8851
|
+
function setBarSegmentTestID(seg) {
|
|
8852
|
+
if (seg.pulse) return "set-strip-pulse";
|
|
8853
|
+
if (seg.color === SET_STRIP_VARIABLE_COLOR) return "set-strip-variable";
|
|
8854
|
+
return seg.color === TODO_COLOR ? "set-strip-empty" : "set-strip-fill";
|
|
8855
|
+
}
|
|
8856
|
+
function SetBar({ set, height = 8 }) {
|
|
8857
|
+
return /* @__PURE__ */ jsx(
|
|
8858
|
+
SegmentedBar,
|
|
8859
|
+
{
|
|
8860
|
+
segments: setSegments(set),
|
|
8861
|
+
height,
|
|
8862
|
+
gap: 0,
|
|
8863
|
+
radius: 0,
|
|
8864
|
+
segmentTestID: setBarSegmentTestID,
|
|
8865
|
+
style: { flex: 1, minWidth: 0, borderRadius: 2, overflow: "hidden" },
|
|
8866
|
+
testID: "set-strip-set"
|
|
8867
|
+
}
|
|
8868
|
+
);
|
|
8869
|
+
}
|
|
8870
|
+
|
|
8871
|
+
// src/components/custom/Workout/SetStrip.tsx
|
|
8872
|
+
var SET_STRIP_GAP = 5;
|
|
8873
|
+
function setCategory(set) {
|
|
8874
|
+
switch (set.status) {
|
|
8875
|
+
case "done":
|
|
8876
|
+
case "drop":
|
|
8877
|
+
case "myo":
|
|
8878
|
+
return "done";
|
|
8879
|
+
case "active":
|
|
8880
|
+
return "active";
|
|
8881
|
+
case "range":
|
|
8882
|
+
return set.doneVels.length > 0 ? "active" : "upcoming";
|
|
8883
|
+
case "todo":
|
|
8884
|
+
case "myo-upcoming":
|
|
8885
|
+
return "upcoming";
|
|
8886
|
+
}
|
|
8887
|
+
}
|
|
8888
|
+
function describeSets(sets) {
|
|
8889
|
+
const done = sets.filter((s) => setCategory(s) === "done").length;
|
|
8890
|
+
const active = sets.filter((s) => setCategory(s) === "active").length;
|
|
8891
|
+
const upcoming = sets.filter((s) => setCategory(s) === "upcoming").length;
|
|
8892
|
+
return `Set progress: ${done} done, ${active} in progress, ${upcoming} upcoming`;
|
|
8893
|
+
}
|
|
8894
|
+
function SetStrip({ sets, height = 8, className, ...props }) {
|
|
8895
|
+
return /* @__PURE__ */ jsx(
|
|
8896
|
+
View,
|
|
8897
|
+
{
|
|
8898
|
+
className,
|
|
8899
|
+
style: { flexDirection: "row", width: "100%", height, gap: SET_STRIP_GAP },
|
|
8900
|
+
accessibilityRole: "image",
|
|
8901
|
+
accessibilityLabel: describeSets(sets),
|
|
8902
|
+
testID: "set-strip",
|
|
8903
|
+
...props,
|
|
8904
|
+
children: sets.map((set, i) => /* @__PURE__ */ jsx(SetBar, { set, height }, i))
|
|
8905
|
+
}
|
|
8906
|
+
);
|
|
8907
|
+
}
|
|
8908
|
+
|
|
8909
|
+
// src/components/custom/Workout/VelocityStrip.tsx
|
|
8445
8910
|
var VEL_COLORS = WORKOUT_TOKENS.scale;
|
|
8446
|
-
var
|
|
8447
|
-
speed:
|
|
8448
|
-
|
|
8449
|
-
|
|
8450
|
-
|
|
8451
|
-
|
|
8911
|
+
var bandIdToEffortColor = {
|
|
8912
|
+
speed: sequentialEffort[0],
|
|
8913
|
+
// green-300
|
|
8914
|
+
power: sequentialEffort[2],
|
|
8915
|
+
// amber-300 (gold)
|
|
8916
|
+
strengthSpeed: sequentialEffort[3],
|
|
8917
|
+
// orange-400
|
|
8918
|
+
maximalStrength: sequentialEffort[4],
|
|
8919
|
+
// red-600
|
|
8920
|
+
grinding: sequentialEffort[5]
|
|
8921
|
+
// red-700 — the distinct 5th band
|
|
8452
8922
|
};
|
|
8453
8923
|
function getVelocityZoneColor(velocity) {
|
|
8454
8924
|
if (velocity >= 1) return "vel-green";
|
|
@@ -8487,14 +8957,140 @@ function classifyBand(velocity, bands) {
|
|
|
8487
8957
|
return bands[bands.length - 1];
|
|
8488
8958
|
}
|
|
8489
8959
|
function bandColor(band) {
|
|
8490
|
-
|
|
8491
|
-
return token ? VEL_COLORS[token] : VEL_COLORS.green;
|
|
8960
|
+
return bandIdToEffortColor[band.id] ?? VEL_COLORS.green;
|
|
8492
8961
|
}
|
|
8493
8962
|
function getLossStyle(loss) {
|
|
8494
8963
|
if (loss > 25) return { color: VEL_COLORS.red };
|
|
8495
8964
|
if (loss > 20) return { color: VEL_COLORS.orange };
|
|
8496
8965
|
return null;
|
|
8497
8966
|
}
|
|
8967
|
+
var REP_GAP = 2;
|
|
8968
|
+
var WIDE_GAP = 8;
|
|
8969
|
+
var TODO_COLOR2 = primitiveColors.charcoal[300];
|
|
8970
|
+
var CONTINUE_OUTLINE = primitiveRamps.cyan[800];
|
|
8971
|
+
function deriveDoneVelocities(set) {
|
|
8972
|
+
switch (set.type) {
|
|
8973
|
+
case "drop":
|
|
8974
|
+
return set.subloads.flat();
|
|
8975
|
+
case "myo":
|
|
8976
|
+
return [...set.activation, ...set.clusters.flat()];
|
|
8977
|
+
default:
|
|
8978
|
+
return set.velocities;
|
|
8979
|
+
}
|
|
8980
|
+
}
|
|
8981
|
+
function chunkedRepSlots(chunks) {
|
|
8982
|
+
const slots = [];
|
|
8983
|
+
chunks.forEach((chunk) => {
|
|
8984
|
+
chunk.forEach((velocity, ri) => {
|
|
8985
|
+
const first = slots.length === 0;
|
|
8986
|
+
slots.push({ kind: "rep", velocity, leadingGap: first ? 0 : ri === 0 ? WIDE_GAP : REP_GAP });
|
|
8987
|
+
});
|
|
8988
|
+
});
|
|
8989
|
+
return slots;
|
|
8990
|
+
}
|
|
8991
|
+
function buildSlots(set) {
|
|
8992
|
+
switch (set.type) {
|
|
8993
|
+
case "straight": {
|
|
8994
|
+
const total = Math.max(set.velocities.length, set.planned ?? set.velocities.length);
|
|
8995
|
+
return Array.from({ length: total }, (_, i) => {
|
|
8996
|
+
const done = i < set.velocities.length;
|
|
8997
|
+
return {
|
|
8998
|
+
kind: done ? "rep" : "todo",
|
|
8999
|
+
velocity: done ? set.velocities[i] : void 0,
|
|
9000
|
+
leadingGap: i === 0 ? 0 : REP_GAP
|
|
9001
|
+
};
|
|
9002
|
+
});
|
|
9003
|
+
}
|
|
9004
|
+
case "range": {
|
|
9005
|
+
const total = Math.max(set.max, set.velocities.length);
|
|
9006
|
+
return Array.from({ length: total }, (_, i) => {
|
|
9007
|
+
const kind = i < set.velocities.length ? "rep" : i < set.floor ? "todo" : "variable";
|
|
9008
|
+
return {
|
|
9009
|
+
kind,
|
|
9010
|
+
velocity: kind === "rep" ? set.velocities[i] : void 0,
|
|
9011
|
+
leadingGap: i === 0 ? 0 : REP_GAP
|
|
9012
|
+
};
|
|
9013
|
+
});
|
|
9014
|
+
}
|
|
9015
|
+
case "amrap": {
|
|
9016
|
+
const reps = set.velocities.map((velocity, i) => ({
|
|
9017
|
+
kind: "rep",
|
|
9018
|
+
velocity,
|
|
9019
|
+
leadingGap: i === 0 ? 0 : REP_GAP
|
|
9020
|
+
}));
|
|
9021
|
+
reps.push({ kind: "continue", leadingGap: reps.length === 0 ? 0 : REP_GAP });
|
|
9022
|
+
return reps;
|
|
9023
|
+
}
|
|
9024
|
+
case "drop":
|
|
9025
|
+
return chunkedRepSlots(set.subloads);
|
|
9026
|
+
case "myo": {
|
|
9027
|
+
const slots = chunkedRepSlots([set.activation, ...set.clusters]);
|
|
9028
|
+
if (set.open) slots.push({ kind: "continue", leadingGap: slots.length === 0 ? 0 : REP_GAP });
|
|
9029
|
+
return slots;
|
|
9030
|
+
}
|
|
9031
|
+
case "cluster": {
|
|
9032
|
+
const total = Math.max(set.velocities.length, set.planned ?? set.velocities.length);
|
|
9033
|
+
return Array.from({ length: total }, (_, i) => {
|
|
9034
|
+
const done = i < set.velocities.length;
|
|
9035
|
+
const boundary = i > 0 && i % set.groupSize === 0;
|
|
9036
|
+
return {
|
|
9037
|
+
kind: done ? "rep" : "todo",
|
|
9038
|
+
velocity: done ? set.velocities[i] : void 0,
|
|
9039
|
+
leadingGap: i === 0 ? 0 : boundary ? WIDE_GAP : REP_GAP
|
|
9040
|
+
};
|
|
9041
|
+
});
|
|
9042
|
+
}
|
|
9043
|
+
}
|
|
9044
|
+
}
|
|
9045
|
+
function setAccessibilityLabel(set, repCount) {
|
|
9046
|
+
switch (set.type) {
|
|
9047
|
+
case "straight":
|
|
9048
|
+
return `Velocity strip, straight set, ${repCount} reps`;
|
|
9049
|
+
case "range":
|
|
9050
|
+
return `Velocity strip, rep-range set, floor ${set.floor} to ${set.max}, ${repCount} reps done`;
|
|
9051
|
+
case "amrap":
|
|
9052
|
+
return `Velocity strip, AMRAP set, ${repCount} reps and counting`;
|
|
9053
|
+
case "drop":
|
|
9054
|
+
return `Velocity strip, drop set, ${set.subloads.length} loads, ${repCount} reps`;
|
|
9055
|
+
case "myo":
|
|
9056
|
+
return `Velocity strip, myo-reps set, ${set.clusters.length} clusters${set.open ? ", open" : ""}, ${repCount} reps`;
|
|
9057
|
+
case "cluster":
|
|
9058
|
+
return `Velocity strip, cluster set, groups of ${set.groupSize}, ${repCount} reps`;
|
|
9059
|
+
}
|
|
9060
|
+
}
|
|
9061
|
+
function slotAccessibilityLabel(slot, index) {
|
|
9062
|
+
switch (slot.kind) {
|
|
9063
|
+
case "rep":
|
|
9064
|
+
return `Rep ${index + 1}: ${formatVelocity(slot.velocity ?? 0)} meters per second`;
|
|
9065
|
+
case "todo":
|
|
9066
|
+
return `Rep ${index + 1}: planned`;
|
|
9067
|
+
case "variable":
|
|
9068
|
+
return `Rep ${index + 1}: variable`;
|
|
9069
|
+
case "continue":
|
|
9070
|
+
return "Keep going";
|
|
9071
|
+
}
|
|
9072
|
+
}
|
|
9073
|
+
var EXPANDED_TODO_STUB_PCT = 16;
|
|
9074
|
+
var EXPANDED_ENCODED_PCT = 45;
|
|
9075
|
+
var EXPANDED_HEIGHT = 60;
|
|
9076
|
+
var FIXED_MAX_VELOCITY = 1.15;
|
|
9077
|
+
var BARE_STUB_HEIGHT = 3;
|
|
9078
|
+
var HERO_HEIGHT = 220;
|
|
9079
|
+
var HERO_LABEL_HEADROOM = 20;
|
|
9080
|
+
var HERO_BAR_GAP = 8;
|
|
9081
|
+
var HERO_BAR_MAX_WIDTH = 52;
|
|
9082
|
+
var HERO_BAR_RADIUS = 5;
|
|
9083
|
+
var HERO_MIN_BAR_HEIGHT = 4;
|
|
9084
|
+
var HERO_PENDING_COLOR = primitiveColors.charcoal[100];
|
|
9085
|
+
var HERO_REFERENCE_COLOR = primitiveColors.charcoal[0];
|
|
9086
|
+
function scaleDenominator(scale, maxVelocity) {
|
|
9087
|
+
return scale === "fixed" ? FIXED_MAX_VELOCITY : maxVelocity * 1.15;
|
|
9088
|
+
}
|
|
9089
|
+
function bareSlotHeight(slot, height, denom) {
|
|
9090
|
+
if (slot.kind !== "rep" || denom <= 0) return BARE_STUB_HEIGHT;
|
|
9091
|
+
const ratio = Math.min(1, (slot.velocity ?? 0) / denom);
|
|
9092
|
+
return Math.max(BARE_STUB_HEIGHT, ratio * height);
|
|
9093
|
+
}
|
|
8498
9094
|
function getReducedMotionPreference() {
|
|
8499
9095
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
|
|
8500
9096
|
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
@@ -8514,33 +9110,11 @@ function usePrefersReducedMotion() {
|
|
|
8514
9110
|
var ANIMATION_DURATION = 400;
|
|
8515
9111
|
var ANIMATION_EASING = Easing.bezier(0.22, 1, 0.36, 1);
|
|
8516
9112
|
var POP_EASING = Easing.bezier(0.34, 1.56, 0.64, 1);
|
|
8517
|
-
function
|
|
8518
|
-
velocities,
|
|
8519
|
-
zones,
|
|
8520
|
-
liveRepIndex,
|
|
8521
|
-
expanded = false,
|
|
8522
|
-
onToggle,
|
|
8523
|
-
onRepPress,
|
|
8524
|
-
variant = "full",
|
|
8525
|
-
showInfo = true,
|
|
8526
|
-
className,
|
|
8527
|
-
...props
|
|
8528
|
-
}) {
|
|
8529
|
-
const maxVelocity = Math.max(...velocities, 0);
|
|
8530
|
-
const meanVelocity = calculateMeanVelocity(velocities);
|
|
8531
|
-
const loss = calculateVelocityLoss(velocities);
|
|
8532
|
-
const hasZones = zones != null && zones.length > 0;
|
|
8533
|
-
const barColorFor = (v) => hasZones ? bandColor(classifyBand(v, zones)) : zoneHexMap[getVelocityZoneColor(v)];
|
|
8534
|
-
const meanZone = hasZones ? classifyBand(meanVelocity, zones)?.label ?? "" : getVelocityZoneName(meanVelocity);
|
|
9113
|
+
function useLiveRepPop(active, liveRepIndex, liveVelocity, isNewPeak) {
|
|
8535
9114
|
const prefersReducedMotion = usePrefersReducedMotion();
|
|
8536
|
-
const [heightAnim] = useState(() => new Animated.Value(expanded ? 60 : 3));
|
|
8537
|
-
const [labelOpacity] = useState(() => new Animated.Value(expanded ? 1 : 0));
|
|
8538
|
-
const [infoOpacity] = useState(() => new Animated.Value(expanded ? 1 : 0));
|
|
8539
9115
|
const [liveScale] = useState(() => new Animated.Value(1));
|
|
8540
|
-
const liveVelocity = liveRepIndex != null ? velocities[liveRepIndex] : void 0;
|
|
8541
|
-
const isNewPeak = liveVelocity != null && maxVelocity > 0 && liveVelocity === maxVelocity;
|
|
8542
9116
|
useEffect(() => {
|
|
8543
|
-
if (
|
|
9117
|
+
if (!active || liveRepIndex == null || liveVelocity == null) return;
|
|
8544
9118
|
if (prefersReducedMotion) {
|
|
8545
9119
|
liveScale.setValue(1);
|
|
8546
9120
|
return;
|
|
@@ -8570,12 +9144,201 @@ function VelocityStrip({
|
|
|
8570
9144
|
useNativeDriver: true
|
|
8571
9145
|
}).start();
|
|
8572
9146
|
}
|
|
8573
|
-
}, [
|
|
9147
|
+
}, [active, liveRepIndex, liveVelocity, isNewPeak, prefersReducedMotion, liveScale]);
|
|
9148
|
+
return liveScale;
|
|
9149
|
+
}
|
|
9150
|
+
function HeroVelocityChart({
|
|
9151
|
+
doneVelocities,
|
|
9152
|
+
barColorFor,
|
|
9153
|
+
scaleDenom,
|
|
9154
|
+
referenceVelocity,
|
|
9155
|
+
liveRepIndex,
|
|
9156
|
+
isNewPeak,
|
|
9157
|
+
targetReps,
|
|
9158
|
+
height,
|
|
9159
|
+
className,
|
|
9160
|
+
viewProps
|
|
9161
|
+
}) {
|
|
9162
|
+
const liveVelocity = liveRepIndex != null ? doneVelocities[liveRepIndex] : void 0;
|
|
9163
|
+
const liveScale = useLiveRepPop(true, liveRepIndex, liveVelocity, isNewPeak);
|
|
9164
|
+
const plotHeight = Math.max(0, height - HERO_LABEL_HEADROOM);
|
|
9165
|
+
const barHeight = (velocity) => scaleDenom > 0 ? Math.max(HERO_MIN_BAR_HEIGHT, Math.min(1, velocity / scaleDenom) * plotHeight) : HERO_MIN_BAR_HEIGHT;
|
|
9166
|
+
const pendingCount = Math.max(0, (targetReps ?? 0) - doneVelocities.length);
|
|
9167
|
+
const referencePx = referenceVelocity > 0 && scaleDenom > 0 ? Math.min(plotHeight, referenceVelocity / scaleDenom * plotHeight) : 0;
|
|
9168
|
+
const repCount = doneVelocities.length;
|
|
9169
|
+
const total = Math.max(repCount, targetReps ?? repCount);
|
|
9170
|
+
const label = referenceVelocity > 0 ? `Velocity chart, ${repCount} of ${total} reps, best ${formatVelocity(referenceVelocity)} meters per second` : `Velocity chart, ${repCount} of ${total} reps`;
|
|
9171
|
+
const { style: externalStyle, ...restProps } = viewProps;
|
|
9172
|
+
return /* @__PURE__ */ jsx(
|
|
9173
|
+
View,
|
|
9174
|
+
{
|
|
9175
|
+
className,
|
|
9176
|
+
style: [{ height }, externalStyle],
|
|
9177
|
+
accessibilityRole: "image",
|
|
9178
|
+
accessibilityLabel: label,
|
|
9179
|
+
testID: "velocity-strip-hero",
|
|
9180
|
+
...restProps,
|
|
9181
|
+
children: /* @__PURE__ */ jsxs(
|
|
9182
|
+
View,
|
|
9183
|
+
{
|
|
9184
|
+
style: {
|
|
9185
|
+
flex: 1,
|
|
9186
|
+
flexDirection: "row",
|
|
9187
|
+
alignItems: "flex-end",
|
|
9188
|
+
gap: HERO_BAR_GAP,
|
|
9189
|
+
position: "relative",
|
|
9190
|
+
borderBottomWidth: 2,
|
|
9191
|
+
borderBottomColor: HERO_PENDING_COLOR
|
|
9192
|
+
},
|
|
9193
|
+
children: [
|
|
9194
|
+
referencePx > 0 && /* @__PURE__ */ jsx(
|
|
9195
|
+
View,
|
|
9196
|
+
{
|
|
9197
|
+
accessibilityElementsHidden: true,
|
|
9198
|
+
style: {
|
|
9199
|
+
position: "absolute",
|
|
9200
|
+
left: 0,
|
|
9201
|
+
right: 0,
|
|
9202
|
+
bottom: referencePx,
|
|
9203
|
+
borderTopWidth: 1,
|
|
9204
|
+
borderStyle: "dashed",
|
|
9205
|
+
borderColor: HERO_REFERENCE_COLOR,
|
|
9206
|
+
pointerEvents: "none"
|
|
9207
|
+
},
|
|
9208
|
+
testID: "velocity-hero-reference"
|
|
9209
|
+
}
|
|
9210
|
+
),
|
|
9211
|
+
doneVelocities.map((velocity, i) => {
|
|
9212
|
+
const isLive = liveRepIndex === i;
|
|
9213
|
+
return /* @__PURE__ */ jsxs(
|
|
9214
|
+
View,
|
|
9215
|
+
{
|
|
9216
|
+
accessibilityElementsHidden: true,
|
|
9217
|
+
style: {
|
|
9218
|
+
flex: 1,
|
|
9219
|
+
maxWidth: HERO_BAR_MAX_WIDTH,
|
|
9220
|
+
height: "100%",
|
|
9221
|
+
alignItems: "center",
|
|
9222
|
+
justifyContent: "flex-end"
|
|
9223
|
+
},
|
|
9224
|
+
children: [
|
|
9225
|
+
/* @__PURE__ */ jsx(
|
|
9226
|
+
Text,
|
|
9227
|
+
{
|
|
9228
|
+
className: "text-text-primary",
|
|
9229
|
+
style: { fontSize: 12, fontWeight: "800", marginBottom: 4 },
|
|
9230
|
+
testID: `velocity-label-${i}`,
|
|
9231
|
+
children: formatVelocity(velocity)
|
|
9232
|
+
}
|
|
9233
|
+
),
|
|
9234
|
+
/* @__PURE__ */ jsx(
|
|
9235
|
+
Animated.View,
|
|
9236
|
+
{
|
|
9237
|
+
style: [
|
|
9238
|
+
{
|
|
9239
|
+
width: "100%",
|
|
9240
|
+
height: barHeight(velocity),
|
|
9241
|
+
borderTopLeftRadius: HERO_BAR_RADIUS,
|
|
9242
|
+
borderTopRightRadius: HERO_BAR_RADIUS,
|
|
9243
|
+
backgroundColor: barColorFor(velocity)
|
|
9244
|
+
},
|
|
9245
|
+
isLive ? { transform: [{ scale: liveScale }] } : null
|
|
9246
|
+
],
|
|
9247
|
+
testID: `velocity-bar-${i}`
|
|
9248
|
+
}
|
|
9249
|
+
)
|
|
9250
|
+
]
|
|
9251
|
+
},
|
|
9252
|
+
i
|
|
9253
|
+
);
|
|
9254
|
+
}),
|
|
9255
|
+
Array.from({ length: pendingCount }, (_, i) => /* @__PURE__ */ jsx(
|
|
9256
|
+
View,
|
|
9257
|
+
{
|
|
9258
|
+
accessibilityElementsHidden: true,
|
|
9259
|
+
style: {
|
|
9260
|
+
flex: 1,
|
|
9261
|
+
maxWidth: HERO_BAR_MAX_WIDTH,
|
|
9262
|
+
height: "100%",
|
|
9263
|
+
alignItems: "center",
|
|
9264
|
+
justifyContent: "flex-end"
|
|
9265
|
+
},
|
|
9266
|
+
children: /* @__PURE__ */ jsx(
|
|
9267
|
+
View,
|
|
9268
|
+
{
|
|
9269
|
+
style: {
|
|
9270
|
+
width: "100%",
|
|
9271
|
+
height: HERO_MIN_BAR_HEIGHT * 3,
|
|
9272
|
+
borderWidth: 1,
|
|
9273
|
+
borderStyle: "dashed",
|
|
9274
|
+
borderColor: HERO_PENDING_COLOR,
|
|
9275
|
+
borderTopLeftRadius: HERO_BAR_RADIUS,
|
|
9276
|
+
borderTopRightRadius: HERO_BAR_RADIUS
|
|
9277
|
+
},
|
|
9278
|
+
testID: "velocity-slot-todo"
|
|
9279
|
+
}
|
|
9280
|
+
)
|
|
9281
|
+
},
|
|
9282
|
+
`pending-${i}`
|
|
9283
|
+
))
|
|
9284
|
+
]
|
|
9285
|
+
}
|
|
9286
|
+
)
|
|
9287
|
+
}
|
|
9288
|
+
);
|
|
9289
|
+
}
|
|
9290
|
+
function VelocityStrip({
|
|
9291
|
+
velocities,
|
|
9292
|
+
set,
|
|
9293
|
+
zones,
|
|
9294
|
+
liveRepIndex,
|
|
9295
|
+
expanded = true,
|
|
9296
|
+
onToggle,
|
|
9297
|
+
onRepPress,
|
|
9298
|
+
variant = "expanded",
|
|
9299
|
+
height = EXPANDED_HEIGHT,
|
|
9300
|
+
targetReps,
|
|
9301
|
+
scale = "peak",
|
|
9302
|
+
showNumbers = true,
|
|
9303
|
+
showInfo = true,
|
|
9304
|
+
className,
|
|
9305
|
+
...props
|
|
9306
|
+
}) {
|
|
9307
|
+
const doneVelocities = set ? deriveDoneVelocities(set) : velocities ?? [];
|
|
9308
|
+
const slots = set ? buildSlots(set) : doneVelocities.map((v, i) => ({
|
|
9309
|
+
kind: "rep",
|
|
9310
|
+
velocity: v,
|
|
9311
|
+
leadingGap: i === 0 ? 0 : REP_GAP
|
|
9312
|
+
}));
|
|
9313
|
+
const maxVelocity = Math.max(...doneVelocities, 0);
|
|
9314
|
+
const meanVelocity = calculateMeanVelocity(doneVelocities);
|
|
9315
|
+
const loss = calculateVelocityLoss(doneVelocities);
|
|
9316
|
+
const framed = showNumbers || showInfo;
|
|
9317
|
+
const scaleDenom = scaleDenominator(scale, maxVelocity);
|
|
9318
|
+
const hasZones = zones != null && zones.length > 0;
|
|
9319
|
+
const barColorFor = (v) => hasZones ? bandColor(classifyBand(v, zones)) : zoneHexMap[getVelocityZoneColor(v)];
|
|
9320
|
+
const slotColor = (slot) => {
|
|
9321
|
+
if (slot.kind === "rep") return barColorFor(slot.velocity ?? 0);
|
|
9322
|
+
if (slot.kind === "todo") return TODO_COLOR2;
|
|
9323
|
+
return SET_STRIP_VARIABLE_COLOR;
|
|
9324
|
+
};
|
|
9325
|
+
const meanZone = hasZones ? classifyBand(meanVelocity, zones)?.label ?? "" : getVelocityZoneName(meanVelocity);
|
|
9326
|
+
const [heightAnim] = useState(() => new Animated.Value(expanded ? height : 3));
|
|
9327
|
+
const [labelOpacity] = useState(() => new Animated.Value(expanded ? 1 : 0));
|
|
9328
|
+
const [infoOpacity] = useState(() => new Animated.Value(expanded ? 1 : 0));
|
|
9329
|
+
const liveVelocity = liveRepIndex != null ? doneVelocities[liveRepIndex] : void 0;
|
|
9330
|
+
const isNewPeak = liveVelocity != null && maxVelocity > 0 && liveVelocity === maxVelocity;
|
|
9331
|
+
const liveScale = useLiveRepPop(
|
|
9332
|
+
variant === "expanded" && framed,
|
|
9333
|
+
liveRepIndex,
|
|
9334
|
+
liveVelocity,
|
|
9335
|
+
isNewPeak
|
|
9336
|
+
);
|
|
8574
9337
|
useEffect(() => {
|
|
8575
|
-
if (variant
|
|
9338
|
+
if (variant !== "expanded" || !framed) return;
|
|
8576
9339
|
Animated.parallel([
|
|
8577
9340
|
Animated.timing(heightAnim, {
|
|
8578
|
-
toValue: expanded ?
|
|
9341
|
+
toValue: expanded ? height : 3,
|
|
8579
9342
|
duration: ANIMATION_DURATION,
|
|
8580
9343
|
easing: ANIMATION_EASING,
|
|
8581
9344
|
useNativeDriver: false
|
|
@@ -8593,101 +9356,219 @@ function VelocityStrip({
|
|
|
8593
9356
|
useNativeDriver: false
|
|
8594
9357
|
})
|
|
8595
9358
|
]).start();
|
|
8596
|
-
}, [expanded, variant, heightAnim, labelOpacity, infoOpacity]);
|
|
9359
|
+
}, [expanded, variant, framed, height, heightAnim, labelOpacity, infoOpacity]);
|
|
9360
|
+
if (set == null && velocities == null) return null;
|
|
9361
|
+
const repCount = doneVelocities.length;
|
|
9362
|
+
const miniLabel = set ? setAccessibilityLabel(set, repCount) : `Velocity strip, ${repCount} reps`;
|
|
9363
|
+
if (variant === "hero") {
|
|
9364
|
+
const heroHeight = height === EXPANDED_HEIGHT ? HERO_HEIGHT : height;
|
|
9365
|
+
return /* @__PURE__ */ jsx(
|
|
9366
|
+
HeroVelocityChart,
|
|
9367
|
+
{
|
|
9368
|
+
doneVelocities,
|
|
9369
|
+
barColorFor,
|
|
9370
|
+
scaleDenom,
|
|
9371
|
+
referenceVelocity: maxVelocity,
|
|
9372
|
+
liveRepIndex,
|
|
9373
|
+
isNewPeak,
|
|
9374
|
+
targetReps,
|
|
9375
|
+
height: heroHeight,
|
|
9376
|
+
className,
|
|
9377
|
+
viewProps: props
|
|
9378
|
+
}
|
|
9379
|
+
);
|
|
9380
|
+
}
|
|
8597
9381
|
if (variant === "mini") {
|
|
8598
9382
|
const { style: externalStyle, ...restProps } = props;
|
|
8599
9383
|
return /* @__PURE__ */ jsx(
|
|
8600
9384
|
View,
|
|
8601
9385
|
{
|
|
8602
9386
|
className,
|
|
8603
|
-
style: [
|
|
9387
|
+
style: [
|
|
9388
|
+
{ flexDirection: "row", height: 3, gap: REP_GAP, borderRadius: 2, overflow: "hidden" },
|
|
9389
|
+
externalStyle
|
|
9390
|
+
],
|
|
8604
9391
|
accessibilityRole: "image",
|
|
8605
|
-
accessibilityLabel:
|
|
9392
|
+
accessibilityLabel: miniLabel,
|
|
8606
9393
|
testID: "velocity-strip-mini",
|
|
8607
9394
|
...restProps,
|
|
8608
|
-
children:
|
|
9395
|
+
children: slots.map((slot, i) => /* @__PURE__ */ jsx(
|
|
8609
9396
|
View,
|
|
8610
9397
|
{
|
|
8611
9398
|
style: {
|
|
8612
9399
|
flex: 1,
|
|
8613
|
-
backgroundColor:
|
|
9400
|
+
backgroundColor: slotColor(slot),
|
|
8614
9401
|
borderRadius: 1,
|
|
8615
9402
|
minWidth: 4,
|
|
8616
|
-
height: "100%"
|
|
9403
|
+
height: "100%",
|
|
9404
|
+
// The container's uniform 2px gap covers rep spacing; a wide slot adds
|
|
9405
|
+
// only the EXTRA (WIDE_GAP − REP_GAP) so the notch totals WIDE_GAP.
|
|
9406
|
+
marginLeft: Math.max(0, slot.leadingGap - REP_GAP),
|
|
9407
|
+
...slot.kind === "continue" ? { borderWidth: 1, borderColor: CONTINUE_OUTLINE } : {}
|
|
8617
9408
|
},
|
|
8618
9409
|
accessibilityElementsHidden: true,
|
|
8619
|
-
testID: `velocity-bar-${i}`
|
|
9410
|
+
testID: slot.kind === "rep" ? `velocity-bar-${i}` : `velocity-slot-${slot.kind}`
|
|
8620
9411
|
},
|
|
8621
9412
|
i
|
|
8622
9413
|
))
|
|
8623
9414
|
}
|
|
8624
9415
|
);
|
|
8625
9416
|
}
|
|
8626
|
-
|
|
8627
|
-
|
|
8628
|
-
|
|
8629
|
-
|
|
8630
|
-
|
|
8631
|
-
|
|
8632
|
-
|
|
8633
|
-
|
|
8634
|
-
|
|
8635
|
-
|
|
8636
|
-
|
|
8637
|
-
|
|
8638
|
-
|
|
8639
|
-
|
|
8640
|
-
|
|
8641
|
-
paddingHorizontal: expanded ? 6 : 0,
|
|
8642
|
-
paddingVertical: expanded ? void 0 : 8,
|
|
8643
|
-
overflow: expanded ? "visible" : "hidden"
|
|
8644
|
-
}
|
|
8645
|
-
],
|
|
8646
|
-
accessibilityRole: hasInteractiveContainer || hasInteractiveReps ? "none" : "button",
|
|
8647
|
-
accessibilityLabel: hasInteractiveContainer || hasInteractiveReps ? void 0 : stripLabel,
|
|
8648
|
-
testID: "velocity-strip",
|
|
8649
|
-
...props,
|
|
8650
|
-
children: [
|
|
8651
|
-
/* @__PURE__ */ jsx(
|
|
9417
|
+
if (!framed) {
|
|
9418
|
+
const { style: externalStyle, ...restProps } = props;
|
|
9419
|
+
return /* @__PURE__ */ jsx(
|
|
9420
|
+
View,
|
|
9421
|
+
{
|
|
9422
|
+
className,
|
|
9423
|
+
style: [
|
|
9424
|
+
{ flexDirection: "row", height, gap: REP_GAP, alignItems: "flex-end" },
|
|
9425
|
+
externalStyle
|
|
9426
|
+
],
|
|
9427
|
+
accessibilityRole: "image",
|
|
9428
|
+
accessibilityLabel: miniLabel,
|
|
9429
|
+
testID: "velocity-strip-compact",
|
|
9430
|
+
...restProps,
|
|
9431
|
+
children: slots.map((slot, i) => /* @__PURE__ */ jsx(
|
|
8652
9432
|
View,
|
|
8653
9433
|
{
|
|
8654
|
-
style: {
|
|
8655
|
-
|
|
8656
|
-
|
|
8657
|
-
|
|
8658
|
-
|
|
8659
|
-
|
|
8660
|
-
|
|
8661
|
-
|
|
8662
|
-
|
|
8663
|
-
|
|
8664
|
-
|
|
8665
|
-
|
|
8666
|
-
|
|
8667
|
-
|
|
8668
|
-
|
|
8669
|
-
|
|
8670
|
-
|
|
8671
|
-
|
|
8672
|
-
|
|
8673
|
-
|
|
8674
|
-
|
|
8675
|
-
|
|
8676
|
-
|
|
8677
|
-
|
|
8678
|
-
|
|
8679
|
-
|
|
8680
|
-
|
|
8681
|
-
|
|
8682
|
-
|
|
8683
|
-
|
|
8684
|
-
|
|
8685
|
-
|
|
8686
|
-
|
|
8687
|
-
|
|
8688
|
-
|
|
8689
|
-
|
|
8690
|
-
|
|
9434
|
+
style: {
|
|
9435
|
+
flex: 1,
|
|
9436
|
+
minWidth: 4,
|
|
9437
|
+
height: bareSlotHeight(slot, height, scaleDenom),
|
|
9438
|
+
// Top-rounded to match the framed chart's bars (the "rounded tops from
|
|
9439
|
+
// the numbers one"); square bottoms since bars sit on the baseline.
|
|
9440
|
+
borderTopLeftRadius: 2,
|
|
9441
|
+
borderTopRightRadius: 2,
|
|
9442
|
+
backgroundColor: slotColor(slot),
|
|
9443
|
+
marginLeft: Math.max(0, slot.leadingGap - REP_GAP),
|
|
9444
|
+
...slot.kind === "continue" ? { borderWidth: 1, borderColor: CONTINUE_OUTLINE } : {}
|
|
9445
|
+
},
|
|
9446
|
+
accessibilityElementsHidden: true,
|
|
9447
|
+
testID: slot.kind === "rep" ? `velocity-bar-${i}` : `velocity-slot-${slot.kind}`
|
|
9448
|
+
},
|
|
9449
|
+
i
|
|
9450
|
+
))
|
|
9451
|
+
}
|
|
9452
|
+
);
|
|
9453
|
+
}
|
|
9454
|
+
const stripLabel = set ? `${setAccessibilityLabel(set, repCount)}, tap to ${expanded ? "collapse" : "expand"}` : `Velocity chart for set, ${repCount} reps, tap to ${expanded ? "collapse" : "expand"}`;
|
|
9455
|
+
const hasInteractiveContainer = onToggle != null;
|
|
9456
|
+
const hasInteractiveReps = onRepPress != null && expanded;
|
|
9457
|
+
const setBars = set != null && slots.map((slot, i) => {
|
|
9458
|
+
const isStraightRep = set.type === "straight" && slot.kind === "rep";
|
|
9459
|
+
const heightPct = isStraightRep ? scaleDenom > 0 ? Math.round((slot.velocity ?? 0) / scaleDenom * 100) : 0 : set.type === "straight" ? EXPANDED_TODO_STUB_PCT : EXPANDED_ENCODED_PCT;
|
|
9460
|
+
return /* @__PURE__ */ jsx(
|
|
9461
|
+
View,
|
|
9462
|
+
{
|
|
9463
|
+
style: {
|
|
9464
|
+
flex: 1,
|
|
9465
|
+
height: "100%",
|
|
9466
|
+
justifyContent: "flex-end",
|
|
9467
|
+
marginLeft: slot.leadingGap
|
|
9468
|
+
},
|
|
9469
|
+
children: /* @__PURE__ */ jsx(
|
|
9470
|
+
View,
|
|
9471
|
+
{
|
|
9472
|
+
style: {
|
|
9473
|
+
height: `${heightPct}%`,
|
|
9474
|
+
minHeight: 2,
|
|
9475
|
+
borderTopLeftRadius: 2,
|
|
9476
|
+
borderTopRightRadius: 2,
|
|
9477
|
+
backgroundColor: slotColor(slot),
|
|
9478
|
+
...slot.kind === "continue" ? { borderWidth: 1, borderColor: CONTINUE_OUTLINE } : {}
|
|
9479
|
+
},
|
|
9480
|
+
testID: slot.kind === "rep" ? `velocity-bar-${i}` : `velocity-slot-${slot.kind}`,
|
|
9481
|
+
accessibilityRole: "image",
|
|
9482
|
+
accessibilityLabel: slotAccessibilityLabel(slot, i)
|
|
9483
|
+
}
|
|
9484
|
+
)
|
|
9485
|
+
},
|
|
9486
|
+
i
|
|
9487
|
+
);
|
|
9488
|
+
});
|
|
9489
|
+
const stripContent = /* @__PURE__ */ jsxs(
|
|
9490
|
+
Animated.View,
|
|
9491
|
+
{
|
|
9492
|
+
className: [className, expanded ? "bg-surface-raised" : "bg-transparent"].filter(Boolean).join(" "),
|
|
9493
|
+
style: [
|
|
9494
|
+
{
|
|
9495
|
+
height: heightAnim,
|
|
9496
|
+
width: "100%",
|
|
9497
|
+
gap: 2,
|
|
9498
|
+
borderRadius: expanded ? 6 : 2,
|
|
9499
|
+
paddingTop: expanded ? 16 : 0,
|
|
9500
|
+
paddingBottom: expanded ? 24 : 0,
|
|
9501
|
+
// No horizontal inset — the framed chart's bars span full width, matching
|
|
9502
|
+
// the bare spotlight and mini. Numbers/info sit in the vertical padding.
|
|
9503
|
+
paddingHorizontal: 0,
|
|
9504
|
+
paddingVertical: expanded ? void 0 : 8,
|
|
9505
|
+
overflow: expanded ? "visible" : "hidden"
|
|
9506
|
+
}
|
|
9507
|
+
],
|
|
9508
|
+
accessibilityRole: hasInteractiveContainer || hasInteractiveReps ? "none" : "button",
|
|
9509
|
+
accessibilityLabel: hasInteractiveContainer || hasInteractiveReps ? void 0 : stripLabel,
|
|
9510
|
+
testID: "velocity-strip",
|
|
9511
|
+
...props,
|
|
9512
|
+
children: [
|
|
9513
|
+
/* @__PURE__ */ jsx(View, { style: { flexDirection: "row", flex: 1, gap: set ? 0 : 2, alignItems: "flex-end" }, children: set ? setBars : doneVelocities.map((v, i) => {
|
|
9514
|
+
const barBackground = barColorFor(v);
|
|
9515
|
+
const barHeightPct = scaleDenom > 0 ? Math.round(v / scaleDenom * 100) : 0;
|
|
9516
|
+
const isLive = liveRepIndex === i;
|
|
9517
|
+
const liveLabelSuffix = isLive ? isNewPeak ? ", latest rep, new set peak" : ", latest rep" : "";
|
|
9518
|
+
const barStyle = expanded ? {
|
|
9519
|
+
height: `${barHeightPct}%`,
|
|
9520
|
+
minHeight: 2,
|
|
9521
|
+
borderTopLeftRadius: 2,
|
|
9522
|
+
borderTopRightRadius: 2,
|
|
9523
|
+
backgroundColor: barBackground
|
|
9524
|
+
} : {
|
|
9525
|
+
minHeight: "100%",
|
|
9526
|
+
borderTopLeftRadius: 2,
|
|
9527
|
+
borderTopRightRadius: 2,
|
|
9528
|
+
borderBottomLeftRadius: 0,
|
|
9529
|
+
borderBottomRightRadius: 0,
|
|
9530
|
+
backgroundColor: barBackground
|
|
9531
|
+
};
|
|
9532
|
+
const barInner = isLive ? /* @__PURE__ */ jsx(
|
|
9533
|
+
Animated.View,
|
|
9534
|
+
{
|
|
9535
|
+
style: [barStyle, { transform: [{ scale: liveScale }] }],
|
|
9536
|
+
testID: `velocity-bar-${i}`,
|
|
9537
|
+
accessibilityRole: "image",
|
|
9538
|
+
accessibilityLabel: `Rep ${i + 1}: ${formatVelocity(v)} meters per second${liveLabelSuffix}`
|
|
9539
|
+
}
|
|
9540
|
+
) : /* @__PURE__ */ jsx(
|
|
9541
|
+
View,
|
|
9542
|
+
{
|
|
9543
|
+
style: barStyle,
|
|
9544
|
+
testID: `velocity-bar-${i}`,
|
|
9545
|
+
accessibilityRole: "image",
|
|
9546
|
+
accessibilityLabel: `Rep ${i + 1}: ${formatVelocity(v)} meters per second`
|
|
9547
|
+
}
|
|
9548
|
+
);
|
|
9549
|
+
const bar = /* @__PURE__ */ jsxs(
|
|
9550
|
+
View,
|
|
9551
|
+
{
|
|
9552
|
+
style: {
|
|
9553
|
+
flex: 1,
|
|
9554
|
+
height: "100%",
|
|
9555
|
+
justifyContent: "flex-end",
|
|
9556
|
+
position: "relative"
|
|
9557
|
+
},
|
|
9558
|
+
children: [
|
|
9559
|
+
expanded && showNumbers && /* @__PURE__ */ jsx(
|
|
9560
|
+
Animated.View,
|
|
9561
|
+
{
|
|
9562
|
+
style: {
|
|
9563
|
+
opacity: labelOpacity,
|
|
9564
|
+
alignItems: "center",
|
|
9565
|
+
position: "absolute",
|
|
9566
|
+
top: -13,
|
|
9567
|
+
left: 0,
|
|
9568
|
+
right: 0
|
|
9569
|
+
},
|
|
9570
|
+
accessibilityElementsHidden: true,
|
|
9571
|
+
children: /* @__PURE__ */ jsx(
|
|
8691
9572
|
Text,
|
|
8692
9573
|
{
|
|
8693
9574
|
className: "text-text-secondary",
|
|
@@ -8695,30 +9576,30 @@ function VelocityStrip({
|
|
|
8695
9576
|
testID: `velocity-label-${i}`,
|
|
8696
9577
|
children: formatVelocity(v)
|
|
8697
9578
|
}
|
|
8698
|
-
)
|
|
8699
|
-
|
|
8700
|
-
|
|
8701
|
-
|
|
8702
|
-
|
|
8703
|
-
|
|
8704
|
-
|
|
8705
|
-
|
|
8706
|
-
|
|
8707
|
-
|
|
8708
|
-
|
|
8709
|
-
|
|
8710
|
-
|
|
8711
|
-
|
|
8712
|
-
|
|
8713
|
-
|
|
8714
|
-
|
|
8715
|
-
|
|
8716
|
-
|
|
8717
|
-
|
|
8718
|
-
|
|
8719
|
-
})
|
|
9579
|
+
)
|
|
9580
|
+
}
|
|
9581
|
+
),
|
|
9582
|
+
barInner
|
|
9583
|
+
]
|
|
9584
|
+
},
|
|
9585
|
+
i
|
|
9586
|
+
);
|
|
9587
|
+
if (onRepPress && expanded) {
|
|
9588
|
+
return /* @__PURE__ */ jsx(
|
|
9589
|
+
Pressable,
|
|
9590
|
+
{
|
|
9591
|
+
style: { flex: 1, height: "100%" },
|
|
9592
|
+
onPress: () => onRepPress(i, v),
|
|
9593
|
+
accessibilityRole: "button",
|
|
9594
|
+
accessibilityLabel: `Rep ${i + 1}: ${formatVelocity(v)} meters per second, tap for details`,
|
|
9595
|
+
testID: `velocity-bar-pressable-${i}`,
|
|
9596
|
+
children: bar
|
|
9597
|
+
},
|
|
9598
|
+
i
|
|
9599
|
+
);
|
|
8720
9600
|
}
|
|
8721
|
-
|
|
9601
|
+
return bar;
|
|
9602
|
+
}) }),
|
|
8722
9603
|
expanded && showInfo && /* @__PURE__ */ jsxs(
|
|
8723
9604
|
Animated.View,
|
|
8724
9605
|
{
|
|
@@ -9016,233 +9897,90 @@ function Sparkline({
|
|
|
9016
9897
|
}
|
|
9017
9898
|
);
|
|
9018
9899
|
}
|
|
9019
|
-
|
|
9020
|
-
|
|
9021
|
-
|
|
9022
|
-
|
|
9900
|
+
var DARK = getSemanticColors("dark");
|
|
9901
|
+
var TEXT_ACTIVE = DARK["text-primary"];
|
|
9902
|
+
var TEXT_MUTED = DARK["text-secondary"];
|
|
9903
|
+
var COL = { set: 36, reps: 44, load: 56, rpe: 36 };
|
|
9904
|
+
var cellText = { fontFamily: "Inter, sans-serif", fontSize: 13, fontWeight: "600" };
|
|
9905
|
+
var typeBadge = {
|
|
9906
|
+
fontSize: 10,
|
|
9907
|
+
fontWeight: "700",
|
|
9908
|
+
fontFamily: "Inter, sans-serif",
|
|
9909
|
+
color: WORKOUT_TOKENS.scale.orange,
|
|
9910
|
+
backgroundColor: "rgba(255,165,2,0.12)",
|
|
9911
|
+
paddingVertical: 1,
|
|
9912
|
+
paddingHorizontal: 5,
|
|
9913
|
+
borderRadius: 3,
|
|
9914
|
+
overflow: "hidden"
|
|
9915
|
+
};
|
|
9916
|
+
function displayReps(set) {
|
|
9917
|
+
return set.state === "done" ? set.reps : set.target.reps;
|
|
9918
|
+
}
|
|
9919
|
+
function displayWeight(set) {
|
|
9920
|
+
return set.state === "done" ? set.weight : set.target.weight;
|
|
9921
|
+
}
|
|
9922
|
+
function plannedReps(set) {
|
|
9923
|
+
if (set.state === "done") return set.velocities.length;
|
|
9924
|
+
if (set.state === "live") return set.target.reps;
|
|
9925
|
+
return set.planned ?? set.target.reps;
|
|
9926
|
+
}
|
|
9927
|
+
function accessibilityLabel(set) {
|
|
9928
|
+
const base = `Set ${set.setNumber}: ${displayReps(set)} reps at ${roundWeight(displayWeight(set))} ${set.unit}`;
|
|
9929
|
+
if (set.state === "live") return `${base}, in progress`;
|
|
9930
|
+
if (set.state === "todo") return `${base}, upcoming`;
|
|
9931
|
+
return base;
|
|
9932
|
+
}
|
|
9933
|
+
function Cell({
|
|
9934
|
+
width,
|
|
9935
|
+
children,
|
|
9936
|
+
testID
|
|
9937
|
+
}) {
|
|
9938
|
+
return /* @__PURE__ */ jsx(View, { style: { width, alignItems: "center", justifyContent: "center" }, testID, children });
|
|
9023
9939
|
}
|
|
9024
|
-
function
|
|
9025
|
-
|
|
9026
|
-
|
|
9027
|
-
|
|
9028
|
-
|
|
9029
|
-
|
|
9030
|
-
|
|
9031
|
-
|
|
9032
|
-
|
|
9033
|
-
|
|
9034
|
-
|
|
9035
|
-
|
|
9036
|
-
|
|
9037
|
-
|
|
9038
|
-
|
|
9039
|
-
isNextSet,
|
|
9040
|
-
targets
|
|
9041
|
-
}) {
|
|
9042
|
-
const isActive = mode === "active";
|
|
9043
|
-
const isCompleted = mode === "completed";
|
|
9044
|
-
const rowStyle = {
|
|
9045
|
-
flexDirection: "row",
|
|
9046
|
-
alignItems: "center",
|
|
9047
|
-
padding: 7,
|
|
9048
|
-
paddingHorizontal: 8,
|
|
9049
|
-
gap: 8,
|
|
9050
|
-
borderRadius: 8
|
|
9051
|
-
};
|
|
9052
|
-
if (isActive && isNextSet) {
|
|
9053
|
-
rowStyle.backgroundColor = "rgba(255,121,0,0.06)";
|
|
9054
|
-
rowStyle.borderWidth = 1;
|
|
9055
|
-
rowStyle.borderColor = "rgba(255,121,0,0.15)";
|
|
9056
|
-
}
|
|
9057
|
-
if (isCompleted && !isNextSet) {
|
|
9058
|
-
rowStyle.opacity = 0.55;
|
|
9940
|
+
function RowStrip({ set }) {
|
|
9941
|
+
const zones = set.velocityZones;
|
|
9942
|
+
if (set.state === "live") {
|
|
9943
|
+
return /* @__PURE__ */ jsx(
|
|
9944
|
+
VelocityStrip,
|
|
9945
|
+
{
|
|
9946
|
+
variant: "expanded",
|
|
9947
|
+
showNumbers: false,
|
|
9948
|
+
showInfo: false,
|
|
9949
|
+
height: 24,
|
|
9950
|
+
scale: "fixed",
|
|
9951
|
+
set: { type: "straight", velocities: set.velocities, planned: set.target.reps },
|
|
9952
|
+
zones
|
|
9953
|
+
}
|
|
9954
|
+
);
|
|
9059
9955
|
}
|
|
9956
|
+
const velocities = set.state === "done" ? set.velocities : [];
|
|
9957
|
+
return /* @__PURE__ */ jsx(
|
|
9958
|
+
VelocityStrip,
|
|
9959
|
+
{
|
|
9960
|
+
variant: "mini",
|
|
9961
|
+
set: { type: "straight", velocities, planned: plannedReps(set) },
|
|
9962
|
+
zones
|
|
9963
|
+
}
|
|
9964
|
+
);
|
|
9965
|
+
}
|
|
9966
|
+
function SetRow(set) {
|
|
9967
|
+
const live = set.state === "live";
|
|
9968
|
+
const valueColor = live ? TEXT_ACTIVE : TEXT_MUTED;
|
|
9969
|
+
const rpe = set.state === "todo" ? null : set.rpe;
|
|
9060
9970
|
return /* @__PURE__ */ jsxs(
|
|
9061
9971
|
View,
|
|
9062
9972
|
{
|
|
9063
|
-
style:
|
|
9064
|
-
accessibilityLabel:
|
|
9065
|
-
setNumber,
|
|
9066
|
-
reps,
|
|
9067
|
-
weight,
|
|
9068
|
-
unit
|
|
9069
|
-
),
|
|
9973
|
+
style: { paddingVertical: 6, paddingHorizontal: 8 },
|
|
9974
|
+
accessibilityLabel: accessibilityLabel(set),
|
|
9070
9975
|
testID: "set-row",
|
|
9071
9976
|
children: [
|
|
9072
|
-
/* @__PURE__ */
|
|
9073
|
-
|
|
9074
|
-
{
|
|
9075
|
-
|
|
9076
|
-
|
|
9077
|
-
|
|
9078
|
-
|
|
9079
|
-
{
|
|
9080
|
-
style: {
|
|
9081
|
-
fontSize: 10,
|
|
9082
|
-
fontWeight: "700",
|
|
9083
|
-
fontFamily: "Inter, sans-serif",
|
|
9084
|
-
color: WORKOUT_TOKENS.scale.orange,
|
|
9085
|
-
backgroundColor: "rgba(255,165,2,0.12)",
|
|
9086
|
-
paddingVertical: 1,
|
|
9087
|
-
paddingHorizontal: 5,
|
|
9088
|
-
borderRadius: 3,
|
|
9089
|
-
overflow: "hidden"
|
|
9090
|
-
},
|
|
9091
|
-
testID: "set-row-type-badge",
|
|
9092
|
-
children: setType
|
|
9093
|
-
}
|
|
9094
|
-
) : /* @__PURE__ */ jsx(
|
|
9095
|
-
Text,
|
|
9096
|
-
{
|
|
9097
|
-
className: "text-text-secondary",
|
|
9098
|
-
style: {
|
|
9099
|
-
fontSize: 13,
|
|
9100
|
-
fontWeight: "600",
|
|
9101
|
-
fontFamily: "Inter, sans-serif"
|
|
9102
|
-
},
|
|
9103
|
-
children: setNumber
|
|
9104
|
-
}
|
|
9105
|
-
)
|
|
9106
|
-
}
|
|
9107
|
-
),
|
|
9108
|
-
/* @__PURE__ */ jsx(
|
|
9109
|
-
View,
|
|
9110
|
-
{
|
|
9111
|
-
className: "flex-1",
|
|
9112
|
-
testID: "set-row-previous",
|
|
9113
|
-
children: /* @__PURE__ */ jsx(
|
|
9114
|
-
Text,
|
|
9115
|
-
{
|
|
9116
|
-
className: "text-text-secondary",
|
|
9117
|
-
style: {
|
|
9118
|
-
fontSize: 12,
|
|
9119
|
-
fontFamily: "Inter, sans-serif"
|
|
9120
|
-
},
|
|
9121
|
-
children: previous ? `${previous.reps} x ${roundWeight(previous.weight)}` : "\u2014"
|
|
9122
|
-
}
|
|
9123
|
-
)
|
|
9124
|
-
}
|
|
9125
|
-
),
|
|
9126
|
-
/* @__PURE__ */ jsx(
|
|
9127
|
-
View,
|
|
9128
|
-
{
|
|
9129
|
-
style: { width: 44, alignItems: "center", justifyContent: "center" },
|
|
9130
|
-
testID: "set-row-reps",
|
|
9131
|
-
children: isActive && reps == null && targets ? /* @__PURE__ */ jsx(
|
|
9132
|
-
Text,
|
|
9133
|
-
{
|
|
9134
|
-
className: "text-text-tertiary",
|
|
9135
|
-
style: {
|
|
9136
|
-
fontSize: 13,
|
|
9137
|
-
fontStyle: "italic",
|
|
9138
|
-
fontFamily: "Inter, sans-serif"
|
|
9139
|
-
},
|
|
9140
|
-
testID: "set-row-target-reps",
|
|
9141
|
-
children: targets.reps
|
|
9142
|
-
}
|
|
9143
|
-
) : /* @__PURE__ */ jsx(
|
|
9144
|
-
Text,
|
|
9145
|
-
{
|
|
9146
|
-
className: reps != null ? "text-text-primary" : "text-text-tertiary",
|
|
9147
|
-
style: {
|
|
9148
|
-
fontSize: 14,
|
|
9149
|
-
fontWeight: "600",
|
|
9150
|
-
fontFamily: "Inter, sans-serif"
|
|
9151
|
-
},
|
|
9152
|
-
children: reps != null ? reps : "\u2014"
|
|
9153
|
-
}
|
|
9154
|
-
)
|
|
9155
|
-
}
|
|
9156
|
-
),
|
|
9157
|
-
/* @__PURE__ */ jsx(
|
|
9158
|
-
View,
|
|
9159
|
-
{
|
|
9160
|
-
style: { width: 56, alignItems: "center", justifyContent: "center" },
|
|
9161
|
-
testID: "set-row-weight",
|
|
9162
|
-
children: isActive && weight == null && targets ? /* @__PURE__ */ jsx(
|
|
9163
|
-
Text,
|
|
9164
|
-
{
|
|
9165
|
-
className: "text-text-tertiary",
|
|
9166
|
-
style: {
|
|
9167
|
-
fontSize: 13,
|
|
9168
|
-
fontStyle: "italic",
|
|
9169
|
-
fontFamily: "Inter, sans-serif"
|
|
9170
|
-
},
|
|
9171
|
-
testID: "set-row-target-weight",
|
|
9172
|
-
children: roundWeight(targets.weight)
|
|
9173
|
-
}
|
|
9174
|
-
) : /* @__PURE__ */ jsx(
|
|
9175
|
-
Text,
|
|
9176
|
-
{
|
|
9177
|
-
className: weight != null ? "text-text-primary" : "text-text-tertiary",
|
|
9178
|
-
style: {
|
|
9179
|
-
fontSize: 14,
|
|
9180
|
-
fontWeight: "600",
|
|
9181
|
-
fontFamily: "Inter, sans-serif"
|
|
9182
|
-
},
|
|
9183
|
-
children: weight != null ? roundWeight(weight) : "\u2014"
|
|
9184
|
-
}
|
|
9185
|
-
)
|
|
9186
|
-
}
|
|
9187
|
-
),
|
|
9188
|
-
/* @__PURE__ */ jsx(
|
|
9189
|
-
View,
|
|
9190
|
-
{
|
|
9191
|
-
style: { width: 36, alignItems: "center", justifyContent: "center" },
|
|
9192
|
-
testID: "set-row-rpe",
|
|
9193
|
-
children: /* @__PURE__ */ jsx(
|
|
9194
|
-
Text,
|
|
9195
|
-
{
|
|
9196
|
-
className: rpe != null ? void 0 : "text-text-tertiary",
|
|
9197
|
-
style: {
|
|
9198
|
-
fontSize: 13,
|
|
9199
|
-
fontWeight: "600",
|
|
9200
|
-
fontFamily: "Inter, sans-serif",
|
|
9201
|
-
// rpeColor returns a concrete hex (native-safe); only the tertiary
|
|
9202
|
-
// fallback needs the className token.
|
|
9203
|
-
color: rpe != null ? rpeColor(rpe) : void 0
|
|
9204
|
-
},
|
|
9205
|
-
children: rpe != null ? roundRpe(rpe) : "\u2014"
|
|
9206
|
-
}
|
|
9207
|
-
)
|
|
9208
|
-
}
|
|
9209
|
-
),
|
|
9210
|
-
prBadges && prBadges.length > 0 && /* @__PURE__ */ jsx(
|
|
9211
|
-
View,
|
|
9212
|
-
{
|
|
9213
|
-
className: "flex-row items-center",
|
|
9214
|
-
style: { gap: 4 },
|
|
9215
|
-
testID: "set-row-pr-badges",
|
|
9216
|
-
children: prBadges.map((badge, i) => /* @__PURE__ */ jsx(
|
|
9217
|
-
PrBadge,
|
|
9218
|
-
{
|
|
9219
|
-
type: badge.type,
|
|
9220
|
-
label: badge.label,
|
|
9221
|
-
animate: false,
|
|
9222
|
-
compact: true
|
|
9223
|
-
},
|
|
9224
|
-
i
|
|
9225
|
-
))
|
|
9226
|
-
}
|
|
9227
|
-
),
|
|
9228
|
-
velocities && velocities.length > 0 && /* @__PURE__ */ jsx(
|
|
9229
|
-
View,
|
|
9230
|
-
{
|
|
9231
|
-
style: { position: "absolute", bottom: 0, left: 8, right: 8 },
|
|
9232
|
-
testID: "set-row-velocity-strip",
|
|
9233
|
-
children: /* @__PURE__ */ jsx(
|
|
9234
|
-
VelocityStrip,
|
|
9235
|
-
{
|
|
9236
|
-
velocities,
|
|
9237
|
-
zones: velocityZones,
|
|
9238
|
-
liveRepIndex: velocityLiveRepIndex,
|
|
9239
|
-
expanded: velocityExpanded,
|
|
9240
|
-
onToggle: onVelocityToggle,
|
|
9241
|
-
variant: onVelocityToggle ? "full" : "mini"
|
|
9242
|
-
}
|
|
9243
|
-
)
|
|
9244
|
-
}
|
|
9245
|
-
)
|
|
9977
|
+
/* @__PURE__ */ jsxs(View, { className: "flex-row items-center", style: { justifyContent: "space-between" }, children: [
|
|
9978
|
+
/* @__PURE__ */ jsx(Cell, { width: COL.set, testID: "set-row-set-number", children: set.setType ? /* @__PURE__ */ jsx(Text, { style: typeBadge, testID: "set-row-type-badge", children: set.setType }) : /* @__PURE__ */ jsx(Text, { style: { ...cellText, color: valueColor, fontWeight: live ? "700" : "600" }, children: set.setNumber }) }),
|
|
9979
|
+
/* @__PURE__ */ jsx(Cell, { width: COL.reps, testID: "set-row-reps", children: /* @__PURE__ */ jsx(Text, { style: { ...cellText, color: valueColor }, children: displayReps(set) }) }),
|
|
9980
|
+
/* @__PURE__ */ jsx(Cell, { width: COL.load, testID: "set-row-weight", children: /* @__PURE__ */ jsx(Text, { style: { ...cellText, color: valueColor }, children: roundWeight(displayWeight(set)) }) }),
|
|
9981
|
+
/* @__PURE__ */ jsx(Cell, { width: COL.rpe, testID: "set-row-rpe", children: /* @__PURE__ */ jsx(Text, { style: { ...cellText, color: TEXT_MUTED }, children: rpe != null ? roundRpe(rpe) : "\u2014" }) })
|
|
9982
|
+
] }),
|
|
9983
|
+
/* @__PURE__ */ jsx(View, { style: { marginTop: live ? 6 : 4 }, testID: "set-row-strip", children: /* @__PURE__ */ jsx(RowStrip, { set }) })
|
|
9246
9984
|
]
|
|
9247
9985
|
}
|
|
9248
9986
|
);
|
|
@@ -9404,23 +10142,139 @@ function InputBar({
|
|
|
9404
10142
|
);
|
|
9405
10143
|
}
|
|
9406
10144
|
var BRAND_PRIMARY4 = getSemanticColors("dark")["brand-primary"];
|
|
9407
|
-
|
|
9408
|
-
|
|
9409
|
-
|
|
10145
|
+
var RING_DEFAULT_SIZE = 180;
|
|
10146
|
+
function RestActions({ onAddTime, onSkip }) {
|
|
10147
|
+
return /* @__PURE__ */ jsxs(View, { style: { flexDirection: "row", gap: 8 }, children: [
|
|
10148
|
+
/* @__PURE__ */ jsx(
|
|
10149
|
+
Pressable,
|
|
10150
|
+
{
|
|
10151
|
+
onPress: onAddTime,
|
|
10152
|
+
style: {
|
|
10153
|
+
backgroundColor: "rgba(255,255,255,0.06)",
|
|
10154
|
+
paddingVertical: 8,
|
|
10155
|
+
paddingHorizontal: 20,
|
|
10156
|
+
borderRadius: 8
|
|
10157
|
+
},
|
|
10158
|
+
accessibilityRole: "button",
|
|
10159
|
+
accessibilityLabel: "Add 30 seconds",
|
|
10160
|
+
testID: "rest-timer-add-time",
|
|
10161
|
+
children: /* @__PURE__ */ jsx(
|
|
10162
|
+
Text,
|
|
10163
|
+
{
|
|
10164
|
+
className: "text-text-secondary",
|
|
10165
|
+
style: { fontSize: 11, fontFamily: "Inter, sans-serif", fontWeight: "600" },
|
|
10166
|
+
children: "+30s"
|
|
10167
|
+
}
|
|
10168
|
+
)
|
|
10169
|
+
}
|
|
10170
|
+
),
|
|
10171
|
+
/* @__PURE__ */ jsx(
|
|
10172
|
+
Pressable,
|
|
10173
|
+
{
|
|
10174
|
+
onPress: onSkip,
|
|
10175
|
+
style: {
|
|
10176
|
+
backgroundColor: "rgba(255,121,0,0.12)",
|
|
10177
|
+
paddingVertical: 8,
|
|
10178
|
+
paddingHorizontal: 20,
|
|
10179
|
+
borderRadius: 8
|
|
10180
|
+
},
|
|
10181
|
+
accessibilityRole: "button",
|
|
10182
|
+
accessibilityLabel: "Skip rest",
|
|
10183
|
+
testID: "rest-timer-skip",
|
|
10184
|
+
children: /* @__PURE__ */ jsx(
|
|
10185
|
+
Text,
|
|
10186
|
+
{
|
|
10187
|
+
style: {
|
|
10188
|
+
fontSize: 11,
|
|
10189
|
+
fontFamily: "Inter, sans-serif",
|
|
10190
|
+
fontWeight: "600",
|
|
10191
|
+
color: BRAND_PRIMARY4
|
|
10192
|
+
},
|
|
10193
|
+
children: "Skip"
|
|
10194
|
+
}
|
|
10195
|
+
)
|
|
10196
|
+
}
|
|
10197
|
+
)
|
|
10198
|
+
] });
|
|
10199
|
+
}
|
|
10200
|
+
function RestTimerRing({
|
|
10201
|
+
totalSeconds,
|
|
10202
|
+
elapsedMs,
|
|
10203
|
+
remainingSec,
|
|
10204
|
+
done,
|
|
10205
|
+
size,
|
|
10206
|
+
nextSetInfo,
|
|
10207
|
+
displayOnly,
|
|
10208
|
+
onSkip,
|
|
10209
|
+
onAddTime
|
|
10210
|
+
}) {
|
|
10211
|
+
const a11yLabel = done ? "Rest complete, next set ready" : `Rest timer, ${Math.max(0, remainingSec)} seconds remaining`;
|
|
10212
|
+
return /* @__PURE__ */ jsxs(View, { style: { alignItems: "center", gap: 16 }, testID: "rest-timer", children: [
|
|
10213
|
+
/* @__PURE__ */ jsx(
|
|
10214
|
+
CircularTimer,
|
|
10215
|
+
{
|
|
10216
|
+
durationMs: totalSeconds * 1e3,
|
|
10217
|
+
elapsedMs,
|
|
10218
|
+
mode: "down",
|
|
10219
|
+
size,
|
|
10220
|
+
doneLabel: "GO",
|
|
10221
|
+
doneColor: "success",
|
|
10222
|
+
accessibilityLabel: a11yLabel,
|
|
10223
|
+
controls: !displayOnly ? /* @__PURE__ */ jsx(RestActions, { onAddTime, onSkip }) : void 0,
|
|
10224
|
+
testID: "rest-timer-ring"
|
|
10225
|
+
}
|
|
10226
|
+
),
|
|
10227
|
+
nextSetInfo != null && /* @__PURE__ */ jsx(
|
|
10228
|
+
Text,
|
|
10229
|
+
{
|
|
10230
|
+
className: "text-text-tertiary",
|
|
10231
|
+
style: { fontSize: 13, fontFamily: "Inter, sans-serif" },
|
|
10232
|
+
testID: "rest-timer-next-set",
|
|
10233
|
+
children: nextSetInfo
|
|
10234
|
+
}
|
|
10235
|
+
)
|
|
10236
|
+
] });
|
|
10237
|
+
}
|
|
10238
|
+
function RestTimer({
|
|
10239
|
+
totalSeconds,
|
|
10240
|
+
elapsedMs,
|
|
9410
10241
|
onSkip,
|
|
9411
10242
|
onAddTime,
|
|
9412
10243
|
nextSetInfo,
|
|
9413
10244
|
visible,
|
|
9414
|
-
displayOnly = false
|
|
10245
|
+
displayOnly = false,
|
|
10246
|
+
variant = "bar",
|
|
10247
|
+
size = RING_DEFAULT_SIZE
|
|
9415
10248
|
}) {
|
|
9416
|
-
|
|
9417
|
-
|
|
10249
|
+
const {
|
|
10250
|
+
remainingMs,
|
|
10251
|
+
progress,
|
|
10252
|
+
label: timeDisplay,
|
|
10253
|
+
done
|
|
10254
|
+
} = useTimer({
|
|
10255
|
+
mode: "down",
|
|
10256
|
+
durationMs: totalSeconds * 1e3,
|
|
10257
|
+
elapsedMs
|
|
10258
|
+
});
|
|
9418
10259
|
const remainingSec = Math.ceil(remainingMs / 1e3);
|
|
9419
|
-
const
|
|
9420
|
-
|
|
9421
|
-
|
|
9422
|
-
|
|
9423
|
-
|
|
10260
|
+
const progressPct = progress * 100;
|
|
10261
|
+
if (!visible) return null;
|
|
10262
|
+
if (variant === "ring") {
|
|
10263
|
+
return /* @__PURE__ */ jsx(
|
|
10264
|
+
RestTimerRing,
|
|
10265
|
+
{
|
|
10266
|
+
totalSeconds,
|
|
10267
|
+
elapsedMs,
|
|
10268
|
+
remainingSec,
|
|
10269
|
+
done,
|
|
10270
|
+
size,
|
|
10271
|
+
nextSetInfo,
|
|
10272
|
+
displayOnly,
|
|
10273
|
+
onSkip,
|
|
10274
|
+
onAddTime
|
|
10275
|
+
}
|
|
10276
|
+
);
|
|
10277
|
+
}
|
|
9424
10278
|
return /* @__PURE__ */ jsxs(
|
|
9425
10279
|
View,
|
|
9426
10280
|
{
|
|
@@ -9518,69 +10372,318 @@ function RestTimer({
|
|
|
9518
10372
|
)
|
|
9519
10373
|
}
|
|
9520
10374
|
),
|
|
9521
|
-
!displayOnly && /* @__PURE__ */
|
|
10375
|
+
!displayOnly && /* @__PURE__ */ jsx(RestActions, { onAddTime, onSkip })
|
|
10376
|
+
]
|
|
10377
|
+
}
|
|
10378
|
+
);
|
|
10379
|
+
}
|
|
10380
|
+
var t8 = getSemanticColors("dark");
|
|
10381
|
+
var TIMES = "\xD7";
|
|
10382
|
+
var AT = "@";
|
|
10383
|
+
function SetsRepsLoad({
|
|
10384
|
+
sets,
|
|
10385
|
+
reps,
|
|
10386
|
+
load,
|
|
10387
|
+
unit = "lb",
|
|
10388
|
+
className,
|
|
10389
|
+
...props
|
|
10390
|
+
}) {
|
|
10391
|
+
const value = t8["text-primary"];
|
|
10392
|
+
const sep = t8["text-tertiary"];
|
|
10393
|
+
return /* @__PURE__ */ jsxs(
|
|
10394
|
+
View,
|
|
10395
|
+
{
|
|
10396
|
+
className,
|
|
10397
|
+
style: { flexDirection: "row", alignItems: "baseline" },
|
|
10398
|
+
accessibilityLabel: `${sets} sets of ${reps} reps at ${load} ${unit}`,
|
|
10399
|
+
testID: "sets-reps-load",
|
|
10400
|
+
...props,
|
|
10401
|
+
children: [
|
|
10402
|
+
/* @__PURE__ */ jsx(MetricCell, { color: value, children: sets }),
|
|
10403
|
+
/* @__PURE__ */ jsx(MetricCell, { color: sep, children: ` ${TIMES} ` }),
|
|
10404
|
+
/* @__PURE__ */ jsx(MetricCell, { color: value, children: reps }),
|
|
10405
|
+
/* @__PURE__ */ jsx(MetricCell, { color: sep, children: ` ${AT} ` }),
|
|
10406
|
+
/* @__PURE__ */ jsx(MetricCell, { color: value, children: load }),
|
|
10407
|
+
/* @__PURE__ */ jsx(MetricCell, { color: sep, children: ` ${unit}` })
|
|
10408
|
+
]
|
|
10409
|
+
}
|
|
10410
|
+
);
|
|
10411
|
+
}
|
|
10412
|
+
|
|
10413
|
+
// src/components/custom/Workout/paceTone.ts
|
|
10414
|
+
function paceTone(progress, target) {
|
|
10415
|
+
if (target === void 0) return "neutral";
|
|
10416
|
+
return progress >= target ? "ahead" : "behind";
|
|
10417
|
+
}
|
|
10418
|
+
var PACE_TONE_COLORS = {
|
|
10419
|
+
ahead: getSemanticColors("dark")["status-success"],
|
|
10420
|
+
behind: getSemanticColors("dark")["status-warning"],
|
|
10421
|
+
neutral: primitiveRamps.cyan[400]
|
|
10422
|
+
};
|
|
10423
|
+
function paceToneColor(tone) {
|
|
10424
|
+
return PACE_TONE_COLORS[tone];
|
|
10425
|
+
}
|
|
10426
|
+
|
|
10427
|
+
// src/components/custom/Workout/SegmentedProgressBar.tsx
|
|
10428
|
+
var DEFAULT_MARKER_COLOR = primitiveRamps.green[500];
|
|
10429
|
+
function SegmentedProgressBar({
|
|
10430
|
+
segments,
|
|
10431
|
+
value,
|
|
10432
|
+
target,
|
|
10433
|
+
markerColor = DEFAULT_MARKER_COLOR,
|
|
10434
|
+
color,
|
|
10435
|
+
height,
|
|
10436
|
+
gap,
|
|
10437
|
+
...props
|
|
10438
|
+
}) {
|
|
10439
|
+
const total = segments.reduce((sum, s) => sum + s.weight, 0);
|
|
10440
|
+
const fillColor = color ?? paceToneColor(paceTone(total > 0 ? value / total : 0, target));
|
|
10441
|
+
const barSegments = segments.map((seg, i) => {
|
|
10442
|
+
const cumulativeBefore = segments.slice(0, i).reduce((sum, s) => sum + s.weight, 0);
|
|
10443
|
+
const fill = Math.max(0, Math.min(1, (value - cumulativeBefore) / seg.weight));
|
|
10444
|
+
return { weight: seg.weight, fill, color: fillColor };
|
|
10445
|
+
});
|
|
10446
|
+
return /* @__PURE__ */ jsx(
|
|
10447
|
+
SegmentedBar,
|
|
10448
|
+
{
|
|
10449
|
+
segments: barSegments,
|
|
10450
|
+
marker: target != null ? { position: target, color: markerColor } : null,
|
|
10451
|
+
height,
|
|
10452
|
+
gap,
|
|
10453
|
+
...props
|
|
10454
|
+
}
|
|
10455
|
+
);
|
|
10456
|
+
}
|
|
10457
|
+
|
|
10458
|
+
// src/components/custom/Workout/MetricTiles.tsx
|
|
10459
|
+
function MetricTiles({ metrics, gap = 1, ...props }) {
|
|
10460
|
+
return /* @__PURE__ */ jsx(HStack, { gap, align: "stretch", ...props, children: metrics.map((metric) => /* @__PURE__ */ jsx(
|
|
10461
|
+
Tile,
|
|
10462
|
+
{
|
|
10463
|
+
label: metric.label,
|
|
10464
|
+
value: metric.value,
|
|
10465
|
+
valueColor: metric.valueColor
|
|
10466
|
+
},
|
|
10467
|
+
metric.label
|
|
10468
|
+
)) });
|
|
10469
|
+
}
|
|
10470
|
+
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
10471
|
+
var SOON_ACCENT = primitiveRamps.orange[400];
|
|
10472
|
+
function compactUntil(ms) {
|
|
10473
|
+
if (ms <= 0) return "now";
|
|
10474
|
+
const min = Math.round(ms / 6e4);
|
|
10475
|
+
if (min < 60) return `${min}m`;
|
|
10476
|
+
const hr = Math.round(min / 60);
|
|
10477
|
+
if (hr < 24) return `${hr}h`;
|
|
10478
|
+
const d = Math.round(hr / 24);
|
|
10479
|
+
if (d < 7) return `${d}d`;
|
|
10480
|
+
return `${Math.round(d / 7)}w`;
|
|
10481
|
+
}
|
|
10482
|
+
function ScheduleTiles({ when, now, gap = 1, ...props }) {
|
|
10483
|
+
const [mountNow] = useState(() => Date.now());
|
|
10484
|
+
const reference = now ?? mountNow;
|
|
10485
|
+
const whenMs = when instanceof Date ? when.getTime() : when;
|
|
10486
|
+
const soon = whenMs - reference < DAY_MS;
|
|
10487
|
+
const time = new Date(whenMs).toLocaleTimeString(void 0, {
|
|
10488
|
+
hour: "numeric",
|
|
10489
|
+
minute: "2-digit",
|
|
10490
|
+
hour12: true
|
|
10491
|
+
});
|
|
10492
|
+
return /* @__PURE__ */ jsxs(HStack, { gap, ...props, children: [
|
|
10493
|
+
/* @__PURE__ */ jsx(Tile, { label: "Date", value: formatDateTime(when, "short") }),
|
|
10494
|
+
/* @__PURE__ */ jsx(Tile, { label: "Time", value: time }),
|
|
10495
|
+
/* @__PURE__ */ jsx(
|
|
10496
|
+
Tile,
|
|
10497
|
+
{
|
|
10498
|
+
label: "Until",
|
|
10499
|
+
value: compactUntil(whenMs - reference),
|
|
10500
|
+
valueColor: soon ? SOON_ACCENT : void 0
|
|
10501
|
+
}
|
|
10502
|
+
)
|
|
10503
|
+
] });
|
|
10504
|
+
}
|
|
10505
|
+
var t9 = getSemanticColors("dark");
|
|
10506
|
+
var INDICATOR_CONFIG = {
|
|
10507
|
+
imbalance: { Icon: ScaleIcon, color: t9["status-error"], label: "Left/right imbalance" },
|
|
10508
|
+
overshoot: { Icon: AlertTriangleIcon, color: t9["status-error"], label: "Load overshoot" },
|
|
10509
|
+
"velocity-loss": { Icon: TrendingDownIcon, color: t9["status-warning"], label: "Velocity loss" },
|
|
10510
|
+
"missed-reps": { Icon: CircleSlashIcon, color: t9["status-warning"], label: "Missed reps" },
|
|
10511
|
+
pr: { Icon: AwardIcon, color: t9["status-success"], label: "Personal record" },
|
|
10512
|
+
info: { Icon: InfoIcon, color: t9["status-info"], label: "More info" }
|
|
10513
|
+
};
|
|
10514
|
+
var INDICATOR_PRECEDENCE = [
|
|
10515
|
+
"imbalance",
|
|
10516
|
+
"overshoot",
|
|
10517
|
+
"velocity-loss",
|
|
10518
|
+
"missed-reps",
|
|
10519
|
+
"pr",
|
|
10520
|
+
"info"
|
|
10521
|
+
];
|
|
10522
|
+
function resolveIndicator(candidates) {
|
|
10523
|
+
return INDICATOR_PRECEDENCE.find((kind) => candidates.includes(kind));
|
|
10524
|
+
}
|
|
10525
|
+
function ExerciseIndicator({ kind, onPress, className, ...props }) {
|
|
10526
|
+
const { Icon, color, label } = INDICATOR_CONFIG[kind];
|
|
10527
|
+
const chip = /* @__PURE__ */ jsx(
|
|
10528
|
+
View,
|
|
10529
|
+
{
|
|
10530
|
+
className,
|
|
10531
|
+
style: {
|
|
10532
|
+
width: 16,
|
|
10533
|
+
height: 16,
|
|
10534
|
+
borderRadius: 8,
|
|
10535
|
+
borderWidth: 1,
|
|
10536
|
+
borderColor: color,
|
|
10537
|
+
alignItems: "center",
|
|
10538
|
+
justifyContent: "center"
|
|
10539
|
+
},
|
|
10540
|
+
accessibilityRole: "image",
|
|
10541
|
+
accessibilityLabel: label,
|
|
10542
|
+
testID: "exercise-indicator",
|
|
10543
|
+
...props,
|
|
10544
|
+
children: /* @__PURE__ */ jsx(Icon, { size: 11, color })
|
|
10545
|
+
}
|
|
10546
|
+
);
|
|
10547
|
+
if (onPress) {
|
|
10548
|
+
return /* @__PURE__ */ jsx(Pressable, { onPress, accessibilityRole: "button", accessibilityLabel: label, children: chip });
|
|
10549
|
+
}
|
|
10550
|
+
return chip;
|
|
10551
|
+
}
|
|
10552
|
+
function headingLabel(name, sets, reps, load, unit) {
|
|
10553
|
+
return `${name}, ${sets}\xD7${reps} @ ${roundWeight(load)} ${unit}`;
|
|
10554
|
+
}
|
|
10555
|
+
function ExerciseHeading({
|
|
10556
|
+
name,
|
|
10557
|
+
sets,
|
|
10558
|
+
reps,
|
|
10559
|
+
load,
|
|
10560
|
+
unit = "lbs",
|
|
10561
|
+
tempo,
|
|
10562
|
+
indicator,
|
|
10563
|
+
dimmed,
|
|
10564
|
+
onPress
|
|
10565
|
+
}) {
|
|
10566
|
+
return /* @__PURE__ */ jsxs(View, { style: { opacity: dimmed ? 0.55 : 1 }, testID: "exercise-heading", children: [
|
|
10567
|
+
/* @__PURE__ */ jsxs(
|
|
10568
|
+
Pressable,
|
|
10569
|
+
{
|
|
10570
|
+
onPress,
|
|
10571
|
+
accessibilityRole: "button",
|
|
10572
|
+
accessibilityLabel: headingLabel(name, sets, reps, load, unit),
|
|
10573
|
+
className: "flex-row items-center",
|
|
10574
|
+
style: { gap: 8 },
|
|
10575
|
+
testID: "exercise-card-header",
|
|
10576
|
+
children: [
|
|
9522
10577
|
/* @__PURE__ */ jsx(
|
|
9523
|
-
|
|
10578
|
+
Text,
|
|
9524
10579
|
{
|
|
9525
|
-
|
|
9526
|
-
style: {
|
|
9527
|
-
|
|
9528
|
-
|
|
9529
|
-
paddingHorizontal: 20,
|
|
9530
|
-
borderRadius: 8
|
|
9531
|
-
},
|
|
9532
|
-
accessibilityRole: "button",
|
|
9533
|
-
accessibilityLabel: "Add 30 seconds",
|
|
9534
|
-
testID: "rest-timer-add-time",
|
|
9535
|
-
children: /* @__PURE__ */ jsx(
|
|
9536
|
-
Text,
|
|
9537
|
-
{
|
|
9538
|
-
className: "text-text-secondary",
|
|
9539
|
-
style: {
|
|
9540
|
-
fontSize: 11,
|
|
9541
|
-
fontFamily: "Inter, sans-serif",
|
|
9542
|
-
fontWeight: "600"
|
|
9543
|
-
},
|
|
9544
|
-
children: "+30s"
|
|
9545
|
-
}
|
|
9546
|
-
)
|
|
10580
|
+
className: "text-text-primary",
|
|
10581
|
+
style: { fontSize: 14, fontFamily: '"Space Grotesk", sans-serif', fontWeight: "700" },
|
|
10582
|
+
testID: "exercise-card-name",
|
|
10583
|
+
children: name
|
|
9547
10584
|
}
|
|
9548
10585
|
),
|
|
9549
|
-
/* @__PURE__ */ jsx(
|
|
9550
|
-
|
|
9551
|
-
|
|
9552
|
-
|
|
9553
|
-
|
|
9554
|
-
|
|
9555
|
-
|
|
9556
|
-
|
|
9557
|
-
|
|
9558
|
-
|
|
9559
|
-
|
|
9560
|
-
|
|
9561
|
-
|
|
9562
|
-
|
|
9563
|
-
|
|
9564
|
-
|
|
9565
|
-
|
|
9566
|
-
|
|
9567
|
-
|
|
9568
|
-
|
|
9569
|
-
|
|
9570
|
-
|
|
9571
|
-
|
|
9572
|
-
|
|
9573
|
-
|
|
9574
|
-
|
|
9575
|
-
|
|
9576
|
-
|
|
10586
|
+
/* @__PURE__ */ jsx(View, { className: "flex-1" }),
|
|
10587
|
+
indicator && /* @__PURE__ */ jsx(ExerciseIndicator, { kind: indicator })
|
|
10588
|
+
]
|
|
10589
|
+
}
|
|
10590
|
+
),
|
|
10591
|
+
/* @__PURE__ */ jsxs(
|
|
10592
|
+
View,
|
|
10593
|
+
{
|
|
10594
|
+
className: "flex-row items-center",
|
|
10595
|
+
style: { gap: 8, marginTop: 1 },
|
|
10596
|
+
testID: "exercise-card-summary",
|
|
10597
|
+
children: [
|
|
10598
|
+
/* @__PURE__ */ jsx(SetsRepsLoad, { sets, reps, load, unit }),
|
|
10599
|
+
/* @__PURE__ */ jsx(View, { className: "flex-1" }),
|
|
10600
|
+
tempo && /* @__PURE__ */ jsx(TempoDisplay, { tempo, size: "sm", showLabel: false, showInfo: false })
|
|
10601
|
+
]
|
|
10602
|
+
}
|
|
10603
|
+
)
|
|
10604
|
+
] });
|
|
10605
|
+
}
|
|
10606
|
+
function ExerciseCardHeading({
|
|
10607
|
+
setStates,
|
|
10608
|
+
stripHeight = 8,
|
|
10609
|
+
dimmed,
|
|
10610
|
+
testID = "exercise-card",
|
|
10611
|
+
...heading
|
|
10612
|
+
}) {
|
|
10613
|
+
return /* @__PURE__ */ jsxs(
|
|
10614
|
+
View,
|
|
10615
|
+
{
|
|
10616
|
+
style: { paddingVertical: 9, paddingHorizontal: 12, opacity: dimmed ? 0.55 : 1 },
|
|
10617
|
+
testID,
|
|
10618
|
+
children: [
|
|
10619
|
+
/* @__PURE__ */ jsx(ExerciseHeading, { ...heading }),
|
|
10620
|
+
setStates.length > 0 && /* @__PURE__ */ jsx(View, { style: { marginTop: 7 }, testID: "exercise-card-strip", children: /* @__PURE__ */ jsx(SetStrip, { sets: setStates, height: stripHeight }) })
|
|
9577
10621
|
]
|
|
9578
10622
|
}
|
|
9579
10623
|
);
|
|
9580
10624
|
}
|
|
9581
|
-
|
|
9582
|
-
|
|
10625
|
+
var PREV_COLUMN = { label: "PREV", width: void 0 };
|
|
10626
|
+
function buildColumns(unit, showPrevious) {
|
|
10627
|
+
return [
|
|
10628
|
+
{ label: "SET", width: 36 },
|
|
10629
|
+
...showPrevious ? [PREV_COLUMN] : [],
|
|
10630
|
+
{ label: "REPS", width: 44 },
|
|
10631
|
+
{ label: unit.toUpperCase(), width: 56 },
|
|
10632
|
+
{ label: "RPE", width: 36 }
|
|
10633
|
+
];
|
|
9583
10634
|
}
|
|
10635
|
+
function SetTableHeader({
|
|
10636
|
+
unit = "lbs",
|
|
10637
|
+
showPrevious = true,
|
|
10638
|
+
testID = "table-header"
|
|
10639
|
+
}) {
|
|
10640
|
+
const columns = buildColumns(unit, showPrevious);
|
|
10641
|
+
return /* @__PURE__ */ jsx(
|
|
10642
|
+
View,
|
|
10643
|
+
{
|
|
10644
|
+
className: "flex-row",
|
|
10645
|
+
style: {
|
|
10646
|
+
paddingVertical: 8,
|
|
10647
|
+
paddingHorizontal: 8,
|
|
10648
|
+
paddingBottom: 4,
|
|
10649
|
+
...showPrevious ? {} : { justifyContent: "space-between" }
|
|
10650
|
+
},
|
|
10651
|
+
testID,
|
|
10652
|
+
children: columns.map(({ label, width }) => {
|
|
10653
|
+
const isFlex = width === void 0;
|
|
10654
|
+
return /* @__PURE__ */ jsx(
|
|
10655
|
+
View,
|
|
10656
|
+
{
|
|
10657
|
+
style: {
|
|
10658
|
+
...isFlex ? { minWidth: 44 } : { width, flexShrink: 1 },
|
|
10659
|
+
alignItems: "center",
|
|
10660
|
+
justifyContent: "center",
|
|
10661
|
+
gap: 8
|
|
10662
|
+
},
|
|
10663
|
+
...isFlex ? { className: "flex-1" } : {},
|
|
10664
|
+
children: /* @__PURE__ */ jsx(
|
|
10665
|
+
Text,
|
|
10666
|
+
{
|
|
10667
|
+
className: "text-text-tertiary",
|
|
10668
|
+
style: {
|
|
10669
|
+
fontSize: 10,
|
|
10670
|
+
fontWeight: "600",
|
|
10671
|
+
fontFamily: "Inter, sans-serif",
|
|
10672
|
+
textTransform: "uppercase",
|
|
10673
|
+
letterSpacing: 0.8
|
|
10674
|
+
},
|
|
10675
|
+
children: label
|
|
10676
|
+
}
|
|
10677
|
+
)
|
|
10678
|
+
},
|
|
10679
|
+
label
|
|
10680
|
+
);
|
|
10681
|
+
})
|
|
10682
|
+
}
|
|
10683
|
+
);
|
|
10684
|
+
}
|
|
10685
|
+
|
|
10686
|
+
// src/components/custom/Workout/ExerciseCard.tsx
|
|
9584
10687
|
function getSupersetBorderRadius(position) {
|
|
9585
10688
|
switch (position) {
|
|
9586
10689
|
case "first":
|
|
@@ -9623,7 +10726,7 @@ function formatSummary(summary) {
|
|
|
9623
10726
|
if (!summary) return "";
|
|
9624
10727
|
return `${summary.sets}\xD7${summary.reps} @ ${roundWeight(summary.weight)} ${summary.unit}`;
|
|
9625
10728
|
}
|
|
9626
|
-
function
|
|
10729
|
+
function formatAccessibilityLabel(name, summary, prescription) {
|
|
9627
10730
|
if (summary) return `${name}, ${formatSummary(summary)}`;
|
|
9628
10731
|
if (prescription) return `${name}, ${prescription}`;
|
|
9629
10732
|
return name;
|
|
@@ -9632,7 +10735,6 @@ function CollapsedCard({
|
|
|
9632
10735
|
name,
|
|
9633
10736
|
onToggle,
|
|
9634
10737
|
summary,
|
|
9635
|
-
e1rm,
|
|
9636
10738
|
isPR,
|
|
9637
10739
|
setVelocities,
|
|
9638
10740
|
velocityZones,
|
|
@@ -9651,7 +10753,7 @@ function CollapsedCard({
|
|
|
9651
10753
|
onPressIn: () => setPressed(true),
|
|
9652
10754
|
onPressOut: () => setPressed(false),
|
|
9653
10755
|
accessibilityRole: "button",
|
|
9654
|
-
accessibilityLabel:
|
|
10756
|
+
accessibilityLabel: formatAccessibilityLabel(name, summary, void 0),
|
|
9655
10757
|
testID: "exercise-card",
|
|
9656
10758
|
children: /* @__PURE__ */ jsxs(
|
|
9657
10759
|
View,
|
|
@@ -9665,220 +10767,131 @@ function CollapsedCard({
|
|
|
9665
10767
|
...supersetMargin
|
|
9666
10768
|
},
|
|
9667
10769
|
children: [
|
|
9668
|
-
/* @__PURE__ */ jsxs(
|
|
9669
|
-
|
|
9670
|
-
|
|
9671
|
-
|
|
9672
|
-
|
|
9673
|
-
|
|
9674
|
-
|
|
9675
|
-
|
|
9676
|
-
|
|
9677
|
-
|
|
9678
|
-
|
|
9679
|
-
|
|
9680
|
-
|
|
9681
|
-
|
|
9682
|
-
|
|
9683
|
-
|
|
9684
|
-
|
|
9685
|
-
|
|
9686
|
-
|
|
9687
|
-
|
|
9688
|
-
|
|
9689
|
-
|
|
9690
|
-
|
|
9691
|
-
|
|
9692
|
-
|
|
9693
|
-
|
|
9694
|
-
|
|
9695
|
-
|
|
9696
|
-
|
|
9697
|
-
|
|
9698
|
-
|
|
9699
|
-
|
|
9700
|
-
|
|
9701
|
-
|
|
9702
|
-
|
|
9703
|
-
|
|
9704
|
-
|
|
9705
|
-
|
|
9706
|
-
|
|
9707
|
-
|
|
9708
|
-
|
|
9709
|
-
|
|
9710
|
-
|
|
9711
|
-
|
|
9712
|
-
|
|
9713
|
-
|
|
9714
|
-
|
|
9715
|
-
|
|
9716
|
-
|
|
9717
|
-
{
|
|
9718
|
-
className: "flex-row",
|
|
9719
|
-
style: { marginTop: 6, gap: 4 },
|
|
9720
|
-
testID: "exercise-card-strips",
|
|
9721
|
-
children: [
|
|
9722
|
-
setVelocities?.map((velocities, i) => /* @__PURE__ */ jsx(
|
|
9723
|
-
VelocityStrip,
|
|
9724
|
-
{
|
|
9725
|
-
velocities,
|
|
9726
|
-
zones: velocityZones,
|
|
9727
|
-
variant: "mini",
|
|
9728
|
-
testID: `exercise-card-velocity-strip-${i}`
|
|
9729
|
-
},
|
|
9730
|
-
i
|
|
9731
|
-
)),
|
|
9732
|
-
Array.from({ length: remaining }, (_, i) => /* @__PURE__ */ jsx(
|
|
9733
|
-
PlaceholderStrip,
|
|
9734
|
-
{
|
|
9735
|
-
testID: `exercise-card-placeholder-${i}`
|
|
9736
|
-
},
|
|
9737
|
-
`placeholder-${i}`
|
|
9738
|
-
))
|
|
9739
|
-
]
|
|
9740
|
-
}
|
|
9741
|
-
)
|
|
10770
|
+
/* @__PURE__ */ jsxs(View, { className: "flex-row items-center", testID: "exercise-card-header", children: [
|
|
10771
|
+
/* @__PURE__ */ jsx(
|
|
10772
|
+
Text,
|
|
10773
|
+
{
|
|
10774
|
+
className: "text-text-primary",
|
|
10775
|
+
style: {
|
|
10776
|
+
fontSize: 14,
|
|
10777
|
+
fontFamily: '"Space Grotesk", sans-serif',
|
|
10778
|
+
fontWeight: "700"
|
|
10779
|
+
},
|
|
10780
|
+
testID: "exercise-card-name",
|
|
10781
|
+
children: name
|
|
10782
|
+
}
|
|
10783
|
+
),
|
|
10784
|
+
/* @__PURE__ */ jsx(View, { className: "flex-1" }),
|
|
10785
|
+
summary && /* @__PURE__ */ jsx(
|
|
10786
|
+
Text,
|
|
10787
|
+
{
|
|
10788
|
+
className: "text-text-secondary",
|
|
10789
|
+
style: {
|
|
10790
|
+
fontSize: 12,
|
|
10791
|
+
fontFamily: "Inter, sans-serif",
|
|
10792
|
+
marginRight: 8
|
|
10793
|
+
},
|
|
10794
|
+
testID: "exercise-card-summary",
|
|
10795
|
+
children: formatSummary(summary)
|
|
10796
|
+
}
|
|
10797
|
+
),
|
|
10798
|
+
isPR && /* @__PURE__ */ jsx(View, { style: { marginLeft: 4 }, children: /* @__PURE__ */ jsx(PrBadge, { type: "e1rm", compact: true, animate: false }) })
|
|
10799
|
+
] }),
|
|
10800
|
+
(completedSets > 0 || remaining > 0) && /* @__PURE__ */ jsxs(View, { className: "flex-row", style: { marginTop: 6, gap: 4 }, testID: "exercise-card-strips", children: [
|
|
10801
|
+
setVelocities?.map((velocities, i) => /* @__PURE__ */ jsx(
|
|
10802
|
+
VelocityStrip,
|
|
10803
|
+
{
|
|
10804
|
+
velocities,
|
|
10805
|
+
zones: velocityZones,
|
|
10806
|
+
variant: "mini",
|
|
10807
|
+
testID: `exercise-card-velocity-strip-${i}`
|
|
10808
|
+
},
|
|
10809
|
+
i
|
|
10810
|
+
)),
|
|
10811
|
+
Array.from({ length: remaining }, (_, i) => /* @__PURE__ */ jsx(
|
|
10812
|
+
PlaceholderStrip,
|
|
10813
|
+
{
|
|
10814
|
+
testID: `exercise-card-placeholder-${i}`
|
|
10815
|
+
},
|
|
10816
|
+
`placeholder-${i}`
|
|
10817
|
+
))
|
|
10818
|
+
] })
|
|
9742
10819
|
]
|
|
9743
10820
|
}
|
|
9744
10821
|
)
|
|
9745
10822
|
}
|
|
9746
10823
|
);
|
|
9747
10824
|
}
|
|
10825
|
+
var DARK2 = getSemanticColors("dark");
|
|
10826
|
+
var BODY_DIVIDER = DARK2["border-subtle"];
|
|
10827
|
+
function deriveHeaderSetStates(sets) {
|
|
10828
|
+
return sets.map((set) => {
|
|
10829
|
+
switch (set.state) {
|
|
10830
|
+
case "live":
|
|
10831
|
+
return { status: "active", velocities: set.velocities, planned: set.target.reps };
|
|
10832
|
+
case "done":
|
|
10833
|
+
return { status: "done", velocities: set.velocities };
|
|
10834
|
+
case "todo":
|
|
10835
|
+
return { status: "todo", planned: set.planned ?? set.target.reps };
|
|
10836
|
+
}
|
|
10837
|
+
});
|
|
10838
|
+
}
|
|
9748
10839
|
function ExpandedCard({
|
|
9749
10840
|
name,
|
|
9750
10841
|
onToggle,
|
|
9751
10842
|
summary,
|
|
9752
|
-
e1rm,
|
|
9753
10843
|
isPR,
|
|
9754
10844
|
sets,
|
|
9755
10845
|
tempo,
|
|
10846
|
+
indicator,
|
|
10847
|
+
setStates,
|
|
10848
|
+
stripHeight = 8,
|
|
10849
|
+
velocityZones,
|
|
9756
10850
|
supersetPosition
|
|
9757
10851
|
}) {
|
|
9758
10852
|
const borderRadius = getSupersetBorderRadius(supersetPosition);
|
|
9759
10853
|
const supersetMargin = getSupersetMargin(supersetPosition);
|
|
9760
10854
|
const unit = summary?.unit ?? sets?.[0]?.unit ?? "lbs";
|
|
9761
|
-
const
|
|
10855
|
+
const headerStates = setStates ?? (sets ? deriveHeaderSetStates(sets) : []);
|
|
10856
|
+
const headerIndicator = indicator ?? (isPR ? "pr" : void 0);
|
|
9762
10857
|
return /* @__PURE__ */ jsxs(
|
|
9763
|
-
View,
|
|
9764
|
-
{
|
|
9765
|
-
className: "bg-surface-elevated border-border",
|
|
9766
|
-
style: {
|
|
9767
|
-
borderWidth: 1,
|
|
9768
|
-
...borderRadius,
|
|
9769
|
-
...supersetMargin
|
|
9770
|
-
},
|
|
9771
|
-
testID: "exercise-card",
|
|
9772
|
-
children: [
|
|
9773
|
-
/* @__PURE__ */ jsx(
|
|
9774
|
-
|
|
9775
|
-
{
|
|
9776
|
-
|
|
9777
|
-
|
|
9778
|
-
|
|
9779
|
-
|
|
9780
|
-
|
|
9781
|
-
|
|
9782
|
-
|
|
9783
|
-
|
|
9784
|
-
|
|
9785
|
-
|
|
9786
|
-
|
|
9787
|
-
paddingHorizontal: 14,
|
|
9788
|
-
paddingBottom: 10,
|
|
9789
|
-
borderBottomWidth: 1,
|
|
9790
|
-
borderBottomColor: resolveColor("border-default")
|
|
9791
|
-
},
|
|
9792
|
-
children: [
|
|
9793
|
-
/* @__PURE__ */ jsx(
|
|
9794
|
-
Text,
|
|
9795
|
-
{
|
|
9796
|
-
className: "text-text-primary",
|
|
9797
|
-
style: {
|
|
9798
|
-
fontSize: 14,
|
|
9799
|
-
fontFamily: '"Space Grotesk", sans-serif',
|
|
9800
|
-
fontWeight: "700"
|
|
9801
|
-
},
|
|
9802
|
-
testID: "exercise-card-name",
|
|
9803
|
-
children: name
|
|
9804
|
-
}
|
|
9805
|
-
),
|
|
9806
|
-
/* @__PURE__ */ jsx(View, { className: "flex-1" }),
|
|
9807
|
-
summary && /* @__PURE__ */ jsx(
|
|
9808
|
-
Text,
|
|
9809
|
-
{
|
|
9810
|
-
className: "text-text-secondary",
|
|
9811
|
-
style: {
|
|
9812
|
-
fontSize: 12,
|
|
9813
|
-
fontFamily: "Inter, sans-serif",
|
|
9814
|
-
marginRight: 8
|
|
9815
|
-
},
|
|
9816
|
-
testID: "exercise-card-summary",
|
|
9817
|
-
children: formatSummary(summary)
|
|
9818
|
-
}
|
|
9819
|
-
),
|
|
9820
|
-
e1rm && /* @__PURE__ */ jsx(
|
|
9821
|
-
WeightBadge,
|
|
9822
|
-
{
|
|
9823
|
-
value: roundWeight(e1rm.value),
|
|
9824
|
-
unit: e1rm.unit,
|
|
9825
|
-
size: "sm",
|
|
9826
|
-
showIcon: false,
|
|
9827
|
-
testID: "exercise-card-e1rm"
|
|
9828
|
-
}
|
|
9829
|
-
),
|
|
9830
|
-
isPR && /* @__PURE__ */ jsx(View, { style: { marginLeft: 4 }, children: /* @__PURE__ */ jsx(PrBadge, { type: "e1rm", compact: true, animate: false }) })
|
|
9831
|
-
]
|
|
9832
|
-
}
|
|
9833
|
-
)
|
|
10858
|
+
View,
|
|
10859
|
+
{
|
|
10860
|
+
className: "bg-surface-elevated border-border",
|
|
10861
|
+
style: {
|
|
10862
|
+
borderWidth: 1,
|
|
10863
|
+
...borderRadius,
|
|
10864
|
+
...supersetMargin
|
|
10865
|
+
},
|
|
10866
|
+
testID: "exercise-card",
|
|
10867
|
+
children: [
|
|
10868
|
+
/* @__PURE__ */ jsx(
|
|
10869
|
+
ExerciseCardHeading,
|
|
10870
|
+
{
|
|
10871
|
+
name,
|
|
10872
|
+
sets: summary?.sets ?? sets?.length ?? 0,
|
|
10873
|
+
reps: summary?.reps ?? 0,
|
|
10874
|
+
load: summary?.weight ?? 0,
|
|
10875
|
+
unit,
|
|
10876
|
+
tempo,
|
|
10877
|
+
indicator: headerIndicator,
|
|
10878
|
+
setStates: headerStates,
|
|
10879
|
+
stripHeight,
|
|
10880
|
+
onPress: onToggle,
|
|
10881
|
+
testID: "exercise-card-heading"
|
|
9834
10882
|
}
|
|
9835
10883
|
),
|
|
9836
|
-
|
|
9837
|
-
/* @__PURE__ */ jsx(
|
|
10884
|
+
/* @__PURE__ */ jsxs(
|
|
9838
10885
|
View,
|
|
9839
10886
|
{
|
|
9840
|
-
|
|
9841
|
-
|
|
9842
|
-
|
|
9843
|
-
|
|
9844
|
-
|
|
9845
|
-
|
|
9846
|
-
testID: "exercise-card-column-headers",
|
|
9847
|
-
children: columnHeaders.map((header, i) => {
|
|
9848
|
-
const widths = [36, void 0, 44, 56, 36];
|
|
9849
|
-
const width = widths[i];
|
|
9850
|
-
const isFlex = width === void 0;
|
|
9851
|
-
return /* @__PURE__ */ jsx(
|
|
9852
|
-
View,
|
|
9853
|
-
{
|
|
9854
|
-
style: {
|
|
9855
|
-
...isFlex ? {} : { width },
|
|
9856
|
-
alignItems: "center",
|
|
9857
|
-
justifyContent: "center",
|
|
9858
|
-
gap: 8
|
|
9859
|
-
},
|
|
9860
|
-
...isFlex ? { className: "flex-1" } : {},
|
|
9861
|
-
children: /* @__PURE__ */ jsx(
|
|
9862
|
-
Text,
|
|
9863
|
-
{
|
|
9864
|
-
className: "text-text-tertiary",
|
|
9865
|
-
style: {
|
|
9866
|
-
fontSize: 10,
|
|
9867
|
-
fontWeight: "600",
|
|
9868
|
-
fontFamily: "Inter, sans-serif",
|
|
9869
|
-
textTransform: "uppercase",
|
|
9870
|
-
letterSpacing: 0.8
|
|
9871
|
-
},
|
|
9872
|
-
children: header
|
|
9873
|
-
}
|
|
9874
|
-
)
|
|
9875
|
-
},
|
|
9876
|
-
header
|
|
9877
|
-
);
|
|
9878
|
-
})
|
|
10887
|
+
style: { borderTopWidth: 1, borderTopColor: BODY_DIVIDER, paddingBottom: 6 },
|
|
10888
|
+
testID: "exercise-card-body",
|
|
10889
|
+
children: [
|
|
10890
|
+
/* @__PURE__ */ jsx(SetTableHeader, { unit, showPrevious: false, testID: "exercise-card-column-headers" }),
|
|
10891
|
+
sets && /* @__PURE__ */ jsx(View, { testID: "exercise-card-sets", children: sets.map((set, i) => /* @__PURE__ */ jsx(SetRow, { ...set, velocityZones: set.velocityZones ?? velocityZones }, i)) })
|
|
10892
|
+
]
|
|
9879
10893
|
}
|
|
9880
|
-
)
|
|
9881
|
-
sets && /* @__PURE__ */ jsx(View, { testID: "exercise-card-sets", children: sets.map((setProps, i) => /* @__PURE__ */ jsx(SetRow, { ...setProps }, i)) })
|
|
10894
|
+
)
|
|
9882
10895
|
]
|
|
9883
10896
|
}
|
|
9884
10897
|
);
|
|
@@ -9887,11 +10900,12 @@ function UpcomingCard({
|
|
|
9887
10900
|
name,
|
|
9888
10901
|
prescription,
|
|
9889
10902
|
previousBest,
|
|
9890
|
-
supersetPosition
|
|
10903
|
+
supersetPosition,
|
|
10904
|
+
onToggle
|
|
9891
10905
|
}) {
|
|
9892
10906
|
const borderRadius = getSupersetBorderRadius(supersetPosition);
|
|
9893
10907
|
const supersetMargin = getSupersetMargin(supersetPosition);
|
|
9894
|
-
return /* @__PURE__ */ jsx(
|
|
10908
|
+
return /* @__PURE__ */ jsx(Pressable, { onPress: onToggle, accessibilityRole: "button", children: /* @__PURE__ */ jsx(
|
|
9895
10909
|
View,
|
|
9896
10910
|
{
|
|
9897
10911
|
style: {
|
|
@@ -9901,7 +10915,7 @@ function UpcomingCard({
|
|
|
9901
10915
|
...borderRadius,
|
|
9902
10916
|
...supersetMargin
|
|
9903
10917
|
},
|
|
9904
|
-
accessibilityLabel:
|
|
10918
|
+
accessibilityLabel: formatAccessibilityLabel(name, void 0, prescription),
|
|
9905
10919
|
testID: "exercise-card",
|
|
9906
10920
|
children: /* @__PURE__ */ jsxs(View, { className: "flex-row items-center", children: [
|
|
9907
10921
|
/* @__PURE__ */ jsx(
|
|
@@ -9909,6 +10923,7 @@ function UpcomingCard({
|
|
|
9909
10923
|
{
|
|
9910
10924
|
className: "text-text-primary",
|
|
9911
10925
|
style: {
|
|
10926
|
+
flexShrink: 0,
|
|
9912
10927
|
fontSize: 14,
|
|
9913
10928
|
fontFamily: '"Space Grotesk", sans-serif',
|
|
9914
10929
|
fontWeight: "700"
|
|
@@ -9921,7 +10936,9 @@ function UpcomingCard({
|
|
|
9921
10936
|
Text,
|
|
9922
10937
|
{
|
|
9923
10938
|
className: "text-text-secondary",
|
|
10939
|
+
numberOfLines: 1,
|
|
9924
10940
|
style: {
|
|
10941
|
+
flexShrink: 1,
|
|
9925
10942
|
fontSize: 12,
|
|
9926
10943
|
fontFamily: "Inter, sans-serif",
|
|
9927
10944
|
marginLeft: 8
|
|
@@ -9930,12 +10947,14 @@ function UpcomingCard({
|
|
|
9930
10947
|
children: prescription
|
|
9931
10948
|
}
|
|
9932
10949
|
),
|
|
9933
|
-
/* @__PURE__ */ jsx(View, { className: "flex-1" }),
|
|
10950
|
+
/* @__PURE__ */ jsx(View, { className: "flex-1", style: { minWidth: 8 } }),
|
|
9934
10951
|
previousBest && /* @__PURE__ */ jsx(
|
|
9935
10952
|
Text,
|
|
9936
10953
|
{
|
|
9937
10954
|
className: "text-text-tertiary",
|
|
10955
|
+
numberOfLines: 1,
|
|
9938
10956
|
style: {
|
|
10957
|
+
flexShrink: 1,
|
|
9939
10958
|
fontSize: 11,
|
|
9940
10959
|
fontFamily: "Inter, sans-serif"
|
|
9941
10960
|
},
|
|
@@ -9945,17 +10964,208 @@ function UpcomingCard({
|
|
|
9945
10964
|
)
|
|
9946
10965
|
] })
|
|
9947
10966
|
}
|
|
10967
|
+
) });
|
|
10968
|
+
}
|
|
10969
|
+
function ExerciseCard({
|
|
10970
|
+
upcoming,
|
|
10971
|
+
expanded,
|
|
10972
|
+
defaultExpanded,
|
|
10973
|
+
onExpandedChange,
|
|
10974
|
+
...rest
|
|
10975
|
+
}) {
|
|
10976
|
+
const [internalExpanded, setInternalExpanded] = useState(defaultExpanded ?? false);
|
|
10977
|
+
const isControlled = expanded !== void 0;
|
|
10978
|
+
const isExpanded = isControlled ? expanded : internalExpanded;
|
|
10979
|
+
const onToggle = () => {
|
|
10980
|
+
const next = !isExpanded;
|
|
10981
|
+
onExpandedChange?.(next);
|
|
10982
|
+
if (!isControlled) setInternalExpanded(next);
|
|
10983
|
+
};
|
|
10984
|
+
if (upcoming) return /* @__PURE__ */ jsx(UpcomingCard, { ...rest, onToggle });
|
|
10985
|
+
return isExpanded ? /* @__PURE__ */ jsx(ExpandedCard, { ...rest, onToggle }) : /* @__PURE__ */ jsx(CollapsedCard, { ...rest, onToggle });
|
|
10986
|
+
}
|
|
10987
|
+
var t10 = getSemanticColors("dark");
|
|
10988
|
+
var RAISED = primitiveColors.charcoal[400];
|
|
10989
|
+
var BAR_HEIGHT = 9;
|
|
10990
|
+
var BAR_GAP = 3;
|
|
10991
|
+
function SessionHeader({
|
|
10992
|
+
title,
|
|
10993
|
+
plan,
|
|
10994
|
+
setsDone = 0,
|
|
10995
|
+
elapsedMs,
|
|
10996
|
+
budgetMs,
|
|
10997
|
+
running = true,
|
|
10998
|
+
metrics = [],
|
|
10999
|
+
next,
|
|
11000
|
+
className,
|
|
11001
|
+
style,
|
|
11002
|
+
...props
|
|
11003
|
+
}) {
|
|
11004
|
+
const upcoming = next != null;
|
|
11005
|
+
const totalSets = plan.reduce((sum, e) => sum + e.sets, 0);
|
|
11006
|
+
const hasPace = !upcoming && budgetMs != null && elapsedMs != null;
|
|
11007
|
+
const target = hasPace ? elapsedMs / budgetMs : void 0;
|
|
11008
|
+
const setsLabel = upcoming ? `${totalSets} sets` : `${Math.floor(setsDone)}/${totalSets} sets`;
|
|
11009
|
+
const setsLabelColor = upcoming ? t10["text-secondary"] : paceToneColor(paceTone(totalSets > 0 ? setsDone / totalSets : 0, target));
|
|
11010
|
+
return /* @__PURE__ */ jsxs(
|
|
11011
|
+
View,
|
|
11012
|
+
{
|
|
11013
|
+
className,
|
|
11014
|
+
style: [
|
|
11015
|
+
{
|
|
11016
|
+
backgroundColor: RAISED,
|
|
11017
|
+
paddingTop: 11,
|
|
11018
|
+
paddingRight: 12,
|
|
11019
|
+
paddingBottom: 12,
|
|
11020
|
+
paddingLeft: 12,
|
|
11021
|
+
zIndex: 2
|
|
11022
|
+
},
|
|
11023
|
+
style
|
|
11024
|
+
],
|
|
11025
|
+
testID: "session-rail-header",
|
|
11026
|
+
...props,
|
|
11027
|
+
children: [
|
|
11028
|
+
/* @__PURE__ */ jsx(
|
|
11029
|
+
Text,
|
|
11030
|
+
{
|
|
11031
|
+
accessibilityRole: "header",
|
|
11032
|
+
style: {
|
|
11033
|
+
fontSize: 16,
|
|
11034
|
+
lineHeight: 18,
|
|
11035
|
+
fontWeight: "700",
|
|
11036
|
+
fontFamily: '"Space Grotesk", sans-serif',
|
|
11037
|
+
color: t10["text-primary"],
|
|
11038
|
+
marginBottom: 10
|
|
11039
|
+
},
|
|
11040
|
+
testID: "session-rail-title",
|
|
11041
|
+
children: title
|
|
11042
|
+
}
|
|
11043
|
+
),
|
|
11044
|
+
upcoming ? /* @__PURE__ */ jsx(ScheduleTiles, { when: next }) : /* @__PURE__ */ jsx(MetricTiles, { metrics }),
|
|
11045
|
+
/* @__PURE__ */ jsxs(View, { style: { marginTop: 10 }, children: [
|
|
11046
|
+
/* @__PURE__ */ jsx(
|
|
11047
|
+
SegmentedProgressBar,
|
|
11048
|
+
{
|
|
11049
|
+
segments: plan.map((e) => ({ weight: e.sets })),
|
|
11050
|
+
value: upcoming ? 0 : setsDone,
|
|
11051
|
+
target,
|
|
11052
|
+
height: BAR_HEIGHT,
|
|
11053
|
+
gap: BAR_GAP
|
|
11054
|
+
}
|
|
11055
|
+
),
|
|
11056
|
+
/* @__PURE__ */ jsxs(
|
|
11057
|
+
View,
|
|
11058
|
+
{
|
|
11059
|
+
style: {
|
|
11060
|
+
flexDirection: "row",
|
|
11061
|
+
justifyContent: "space-between",
|
|
11062
|
+
alignItems: "baseline",
|
|
11063
|
+
marginTop: 5
|
|
11064
|
+
},
|
|
11065
|
+
children: [
|
|
11066
|
+
/* @__PURE__ */ jsx(
|
|
11067
|
+
Typography,
|
|
11068
|
+
{
|
|
11069
|
+
variant: "mono",
|
|
11070
|
+
style: { fontSize: 10, color: setsLabelColor },
|
|
11071
|
+
testID: "session-rail-sets",
|
|
11072
|
+
children: setsLabel
|
|
11073
|
+
}
|
|
11074
|
+
),
|
|
11075
|
+
/* @__PURE__ */ jsx(
|
|
11076
|
+
TimerReadout,
|
|
11077
|
+
{
|
|
11078
|
+
mode: "up",
|
|
11079
|
+
elapsedMs: upcoming ? budgetMs : elapsedMs,
|
|
11080
|
+
durationMs: budgetMs,
|
|
11081
|
+
running: running && !upcoming,
|
|
11082
|
+
showTotal: budgetMs != null && !upcoming
|
|
11083
|
+
}
|
|
11084
|
+
)
|
|
11085
|
+
]
|
|
11086
|
+
}
|
|
11087
|
+
)
|
|
11088
|
+
] })
|
|
11089
|
+
]
|
|
11090
|
+
}
|
|
9948
11091
|
);
|
|
9949
11092
|
}
|
|
9950
|
-
|
|
9951
|
-
|
|
9952
|
-
|
|
9953
|
-
|
|
9954
|
-
|
|
9955
|
-
|
|
9956
|
-
|
|
9957
|
-
|
|
9958
|
-
|
|
11093
|
+
var INSET = primitiveColors.charcoal[800];
|
|
11094
|
+
var DIVIDER = primitiveColors.charcoal[500];
|
|
11095
|
+
var DEFAULT_WIDTH = 246;
|
|
11096
|
+
function SessionRail({
|
|
11097
|
+
title,
|
|
11098
|
+
exercises,
|
|
11099
|
+
setsDone,
|
|
11100
|
+
elapsedMs,
|
|
11101
|
+
budgetMs,
|
|
11102
|
+
running,
|
|
11103
|
+
metrics,
|
|
11104
|
+
next,
|
|
11105
|
+
stripHeight = 8,
|
|
11106
|
+
width = DEFAULT_WIDTH,
|
|
11107
|
+
onExercisePress,
|
|
11108
|
+
className,
|
|
11109
|
+
style,
|
|
11110
|
+
...props
|
|
11111
|
+
}) {
|
|
11112
|
+
return /* @__PURE__ */ jsxs(
|
|
11113
|
+
View,
|
|
11114
|
+
{
|
|
11115
|
+
className,
|
|
11116
|
+
style: [{ width, flexDirection: "column", backgroundColor: INSET }, style],
|
|
11117
|
+
testID: "session-rail",
|
|
11118
|
+
...props,
|
|
11119
|
+
children: [
|
|
11120
|
+
/* @__PURE__ */ jsx(
|
|
11121
|
+
SessionHeader,
|
|
11122
|
+
{
|
|
11123
|
+
title,
|
|
11124
|
+
plan: exercises.map((ex) => ({ name: ex.name, sets: ex.summary.sets })),
|
|
11125
|
+
setsDone,
|
|
11126
|
+
elapsedMs,
|
|
11127
|
+
budgetMs,
|
|
11128
|
+
running,
|
|
11129
|
+
metrics,
|
|
11130
|
+
next
|
|
11131
|
+
}
|
|
11132
|
+
),
|
|
11133
|
+
/* @__PURE__ */ jsx(
|
|
11134
|
+
View,
|
|
11135
|
+
{
|
|
11136
|
+
style: [{ flex: 1, backgroundColor: INSET }, neumorphicShadows.charcoal.pressed.subtle],
|
|
11137
|
+
testID: "session-rail-list",
|
|
11138
|
+
children: exercises.map((ex, i) => /* @__PURE__ */ jsx(
|
|
11139
|
+
View,
|
|
11140
|
+
{
|
|
11141
|
+
style: {
|
|
11142
|
+
borderBottomWidth: i < exercises.length - 1 ? 1 : 0,
|
|
11143
|
+
borderBottomColor: DIVIDER
|
|
11144
|
+
},
|
|
11145
|
+
children: /* @__PURE__ */ jsx(
|
|
11146
|
+
ExerciseCardHeading,
|
|
11147
|
+
{
|
|
11148
|
+
name: ex.name,
|
|
11149
|
+
sets: ex.summary.sets,
|
|
11150
|
+
reps: ex.summary.reps,
|
|
11151
|
+
load: ex.summary.weight,
|
|
11152
|
+
unit: ex.summary.unit,
|
|
11153
|
+
tempo: ex.tempo,
|
|
11154
|
+
indicator: ex.indicator,
|
|
11155
|
+
setStates: ex.setStates,
|
|
11156
|
+
stripHeight,
|
|
11157
|
+
dimmed: ex.upcoming,
|
|
11158
|
+
onPress: () => onExercisePress?.(ex, i)
|
|
11159
|
+
}
|
|
11160
|
+
)
|
|
11161
|
+
},
|
|
11162
|
+
ex.id ?? i
|
|
11163
|
+
))
|
|
11164
|
+
}
|
|
11165
|
+
)
|
|
11166
|
+
]
|
|
11167
|
+
}
|
|
11168
|
+
);
|
|
9959
11169
|
}
|
|
9960
11170
|
var DEFAULTS = {
|
|
9961
11171
|
label: "SS",
|
|
@@ -10219,10 +11429,10 @@ function WeekRow({
|
|
|
10219
11429
|
}
|
|
10220
11430
|
);
|
|
10221
11431
|
}
|
|
10222
|
-
var
|
|
11432
|
+
var t11 = getSemanticColors("dark");
|
|
10223
11433
|
var COLORS = {
|
|
10224
|
-
statusSuccess:
|
|
10225
|
-
brandPrimary:
|
|
11434
|
+
statusSuccess: t11["status-success"],
|
|
11435
|
+
brandPrimary: t11["brand-primary"],
|
|
10226
11436
|
borderDefault: "#1F1F1F",
|
|
10227
11437
|
brandPrimarySubtle: "rgba(255,121,0,0.06)"
|
|
10228
11438
|
};
|
|
@@ -10706,12 +11916,12 @@ function PrHistoryModal({
|
|
|
10706
11916
|
}
|
|
10707
11917
|
);
|
|
10708
11918
|
}
|
|
10709
|
-
var
|
|
10710
|
-
var BRAND_PRIMARY9 =
|
|
11919
|
+
var t12 = getSemanticColors("dark");
|
|
11920
|
+
var BRAND_PRIMARY9 = t12["brand-primary"];
|
|
10711
11921
|
var BRAND_PRIMARY_SUBTLE = "rgba(255,121,0,0.12)";
|
|
10712
|
-
var STATUS_SUCCESS =
|
|
10713
|
-
var STATUS_WARNING =
|
|
10714
|
-
var STATUS_ERROR2 =
|
|
11922
|
+
var STATUS_SUCCESS = t12["status-success"];
|
|
11923
|
+
var STATUS_WARNING = t12["status-warning"];
|
|
11924
|
+
var STATUS_ERROR2 = t12["status-error"];
|
|
10715
11925
|
var EMOJI_SETS = {
|
|
10716
11926
|
sleep: ["\u{1F634}", "\u{1F610}", "\u{1F642}", "\u{1F60A}", "\u{1F929}"],
|
|
10717
11927
|
soreness: ["\u{1F635}", "\u{1F623}", "\u{1F610}", "\u{1F642}", "\u{1F4AA}"],
|
|
@@ -10901,13 +12111,13 @@ function ReadinessCheck({
|
|
|
10901
12111
|
)
|
|
10902
12112
|
] }) });
|
|
10903
12113
|
}
|
|
10904
|
-
var
|
|
10905
|
-
var BRAND_PRIMARY10 =
|
|
12114
|
+
var t13 = getSemanticColors("dark");
|
|
12115
|
+
var BRAND_PRIMARY10 = t13["brand-primary"];
|
|
10906
12116
|
var BRAND_PRIMARY_DARK2 = MESO_ACCENT_GRADIENT_DARK;
|
|
10907
12117
|
var BRAND_PRIMARY_LIGHT2 = MESO_ACCENT_GRADIENT_LIGHT;
|
|
10908
|
-
var SUCCESS =
|
|
10909
|
-
var WARNING =
|
|
10910
|
-
var ERROR =
|
|
12118
|
+
var SUCCESS = t13["status-success"];
|
|
12119
|
+
var WARNING = t13["status-warning"];
|
|
12120
|
+
var ERROR = t13["status-error"];
|
|
10911
12121
|
var ACCENT_STOPS2 = [BRAND_PRIMARY_DARK2, BRAND_PRIMARY10, BRAND_PRIMARY_LIGHT2];
|
|
10912
12122
|
var CARD_GRADIENT = `linear-gradient(135deg, ${resolveColor("surface-elevated")} 0%, ${resolveColor("surface-raised")} 100%)`;
|
|
10913
12123
|
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%)";
|
|
@@ -10979,7 +12189,7 @@ function StatusPill({ badge }) {
|
|
|
10979
12189
|
}
|
|
10980
12190
|
);
|
|
10981
12191
|
}
|
|
10982
|
-
function
|
|
12192
|
+
function MetricCell2({ metric }) {
|
|
10983
12193
|
return /* @__PURE__ */ jsxs(View, { style: { width: "48%" }, testID: "meso-status-card-metric", children: [
|
|
10984
12194
|
/* @__PURE__ */ jsx(
|
|
10985
12195
|
Text,
|
|
@@ -11197,7 +12407,7 @@ function MesoStatusCard({
|
|
|
11197
12407
|
className: "flex-row flex-wrap",
|
|
11198
12408
|
style: { gap: 8 },
|
|
11199
12409
|
testID: "meso-status-card-metrics",
|
|
11200
|
-
children: metrics.map((metric, index) => /* @__PURE__ */ jsx(
|
|
12410
|
+
children: metrics.map((metric, index) => /* @__PURE__ */ jsx(MetricCell2, { metric }, `${metric.label}-${index}`))
|
|
11201
12411
|
}
|
|
11202
12412
|
),
|
|
11203
12413
|
gauges.length > 0 && /* @__PURE__ */ jsx(View, { style: { gap: 12 }, testID: "meso-status-card-gauges", children: gauges.map((gauge, index) => /* @__PURE__ */ jsx(Gauge, { gauge }, `${gauge.label}-${index}`)) }),
|
|
@@ -11278,8 +12488,8 @@ var ERROR_PILL_BORDER = "rgba(209,67,67,0.20)";
|
|
|
11278
12488
|
var PLOT_LEFT = 26;
|
|
11279
12489
|
var TOOLTIP_WIDTH = 124;
|
|
11280
12490
|
function timeOf(dateStr) {
|
|
11281
|
-
const
|
|
11282
|
-
return Number.isNaN(
|
|
12491
|
+
const t18 = Date.parse(dateStr);
|
|
12492
|
+
return Number.isNaN(t18) ? 0 : t18;
|
|
11283
12493
|
}
|
|
11284
12494
|
function formatValue(value) {
|
|
11285
12495
|
return `${Math.round(value)}`;
|
|
@@ -11768,10 +12978,10 @@ function StrengthTrendChart({
|
|
|
11768
12978
|
}
|
|
11769
12979
|
);
|
|
11770
12980
|
}
|
|
11771
|
-
var
|
|
11772
|
-
var STATUS_SUCCESS3 =
|
|
11773
|
-
var STATUS_WARNING3 =
|
|
11774
|
-
var STATUS_INFO =
|
|
12981
|
+
var t14 = getSemanticColors("dark");
|
|
12982
|
+
var STATUS_SUCCESS3 = t14["status-success"];
|
|
12983
|
+
var STATUS_WARNING3 = t14["status-warning"];
|
|
12984
|
+
var STATUS_INFO = t14["status-info"];
|
|
11775
12985
|
var DOT_BORDER = "#F3F4F6";
|
|
11776
12986
|
var BAND_FILL = "rgba(46,213,115,0.1)";
|
|
11777
12987
|
var BAND_EDGE = "rgba(46,213,115,0.45)";
|
|
@@ -11814,13 +13024,13 @@ function interpEdge(pixels, x, key) {
|
|
|
11814
13024
|
const a = pixels[i];
|
|
11815
13025
|
const b = pixels[i + 1];
|
|
11816
13026
|
if (x >= a.x && x <= b.x) {
|
|
11817
|
-
const
|
|
11818
|
-
return a[key] +
|
|
13027
|
+
const t18 = b.x === a.x ? 0 : (x - a.x) / (b.x - a.x);
|
|
13028
|
+
return a[key] + t18 * (b[key] - a[key]);
|
|
11819
13029
|
}
|
|
11820
13030
|
}
|
|
11821
13031
|
return pixels[pixels.length - 1][key];
|
|
11822
13032
|
}
|
|
11823
|
-
function
|
|
13033
|
+
function buildColumns2(pixels, step) {
|
|
11824
13034
|
if (pixels.length < 2) return [];
|
|
11825
13035
|
const start = pixels[0].x;
|
|
11826
13036
|
const end = pixels[pixels.length - 1].x;
|
|
@@ -11932,7 +13142,7 @@ function CapacityBandChart({
|
|
|
11932
13142
|
}
|
|
11933
13143
|
const { toX, toY } = scale;
|
|
11934
13144
|
const bandPixels = toPixels(band, toX, toY);
|
|
11935
|
-
const columns =
|
|
13145
|
+
const columns = buildColumns2(bandPixels, COLUMN_STEP);
|
|
11936
13146
|
const topEdge = buildEdges(bandPixels, "yHigh");
|
|
11937
13147
|
const bottomEdge = buildEdges(bandPixels, "yLow");
|
|
11938
13148
|
const lastBandPoint = band[band.length - 1];
|
|
@@ -12007,8 +13217,8 @@ function CapacityBandChart({
|
|
|
12007
13217
|
testID: "capacity-band-chart-reveal",
|
|
12008
13218
|
children: /* @__PURE__ */ jsxs(View, { style: { width, height, position: "relative" }, children: [
|
|
12009
13219
|
projection && /* @__PURE__ */ jsxs(View, { testID: "capacity-band-chart-projection", children: [
|
|
12010
|
-
renderColumns(
|
|
12011
|
-
renderColumns(
|
|
13220
|
+
renderColumns(buildColumns2(trainingPixels, COLUMN_STEP), PROJECTION_FILL, "capacity-band-chart-projection-fill"),
|
|
13221
|
+
renderColumns(buildColumns2(restPixels, COLUMN_STEP), PROJECTION_FILL, "capacity-band-chart-projection-fill"),
|
|
12012
13222
|
renderEdges(buildEdges(trainingPixels, "yHigh"), STATUS_SUCCESS3, true, "capacity-band-chart-projection-training"),
|
|
12013
13223
|
renderEdges(buildEdges(trainingPixels, "yLow"), STATUS_SUCCESS3, true, "capacity-band-chart-projection-training"),
|
|
12014
13224
|
renderEdges(buildEdges(restPixels, "yHigh"), STATUS_INFO, true, "capacity-band-chart-projection-rest"),
|
|
@@ -12075,72 +13285,585 @@ function CapacityBandChart({
|
|
|
12075
13285
|
return /* @__PURE__ */ jsx(
|
|
12076
13286
|
Text,
|
|
12077
13287
|
{
|
|
12078
|
-
className: "text-text-tertiary",
|
|
13288
|
+
className: "text-text-tertiary",
|
|
13289
|
+
style: {
|
|
13290
|
+
position: "absolute",
|
|
13291
|
+
left: toX(point.date) - 14,
|
|
13292
|
+
top: height - PADDING_BOTTOM + 2,
|
|
13293
|
+
width: 28,
|
|
13294
|
+
textAlign: "center",
|
|
13295
|
+
fontSize: 10,
|
|
13296
|
+
fontFamily: "Inter, sans-serif"
|
|
13297
|
+
},
|
|
13298
|
+
accessibilityElementsHidden: true,
|
|
13299
|
+
importantForAccessibility: "no-hide-descendants",
|
|
13300
|
+
testID: "capacity-band-chart-x-label",
|
|
13301
|
+
children: formatDate2(point.date)
|
|
13302
|
+
},
|
|
13303
|
+
`x-${point.date}`
|
|
13304
|
+
);
|
|
13305
|
+
})
|
|
13306
|
+
]
|
|
13307
|
+
}
|
|
13308
|
+
),
|
|
13309
|
+
workouts.map((workout, i) => {
|
|
13310
|
+
const cx = toX(workout.date);
|
|
13311
|
+
const cy = toY(workout.load);
|
|
13312
|
+
const color = DOT_COLORS[workout.status];
|
|
13313
|
+
const dotStyle = {
|
|
13314
|
+
width: DOT_SIZE,
|
|
13315
|
+
height: DOT_SIZE,
|
|
13316
|
+
borderRadius: DOT_SIZE / 2,
|
|
13317
|
+
backgroundColor: color,
|
|
13318
|
+
borderWidth: 2,
|
|
13319
|
+
borderColor: DOT_BORDER
|
|
13320
|
+
};
|
|
13321
|
+
const label = `Workout on ${formatDate2(workout.date)}, load ${workout.load}, ${STATUS_PHRASES[workout.status]}`;
|
|
13322
|
+
return /* @__PURE__ */ jsx(
|
|
13323
|
+
Animated.View,
|
|
13324
|
+
{
|
|
13325
|
+
style: {
|
|
13326
|
+
position: "absolute",
|
|
13327
|
+
left: cx - DOT_SIZE / 2,
|
|
13328
|
+
top: cy - DOT_SIZE / 2,
|
|
13329
|
+
transform: [{ scale: dotAnims[i] ?? 1 }]
|
|
13330
|
+
},
|
|
13331
|
+
testID: "capacity-band-chart-dot-wrapper",
|
|
13332
|
+
children: onWorkoutPress ? /* @__PURE__ */ jsx(
|
|
13333
|
+
Pressable,
|
|
13334
|
+
{
|
|
13335
|
+
onPress: () => onWorkoutPress(workout),
|
|
13336
|
+
accessibilityRole: "button",
|
|
13337
|
+
accessibilityLabel: label,
|
|
13338
|
+
style: dotStyle,
|
|
13339
|
+
testID: "capacity-band-chart-dot"
|
|
13340
|
+
}
|
|
13341
|
+
) : /* @__PURE__ */ jsx(
|
|
13342
|
+
View,
|
|
13343
|
+
{
|
|
13344
|
+
accessibilityElementsHidden: true,
|
|
13345
|
+
importantForAccessibility: "no-hide-descendants",
|
|
13346
|
+
style: dotStyle,
|
|
13347
|
+
testID: "capacity-band-chart-dot"
|
|
13348
|
+
}
|
|
13349
|
+
)
|
|
13350
|
+
},
|
|
13351
|
+
`dot-${workout.date}-${i}`
|
|
13352
|
+
);
|
|
13353
|
+
})
|
|
13354
|
+
]
|
|
13355
|
+
}
|
|
13356
|
+
);
|
|
13357
|
+
}
|
|
13358
|
+
var t15 = getSemanticColors("dark");
|
|
13359
|
+
function glowShadow(color) {
|
|
13360
|
+
return `0 0 5px 1px ${alpha(color, 0.3)}, 0 0 10px 3px ${alpha(color, 0.12)}`;
|
|
13361
|
+
}
|
|
13362
|
+
var DEFAULT_TRACK_COLOR = primitiveColors.charcoal[200];
|
|
13363
|
+
var DEFAULT_MARKER_COLOR2 = primitiveColors.white;
|
|
13364
|
+
var TICK_COLOR = t15["text-tertiary"];
|
|
13365
|
+
var ZONE_SIZES = {
|
|
13366
|
+
default: {
|
|
13367
|
+
trackHeight: 14,
|
|
13368
|
+
needleOverhang: 6,
|
|
13369
|
+
needleWidth: 4,
|
|
13370
|
+
tickLineNormal: 1.5,
|
|
13371
|
+
tickLineEmphasized: 2,
|
|
13372
|
+
tickLineHeightPad: 4,
|
|
13373
|
+
tickLineTopPad: 2,
|
|
13374
|
+
labelRowHeight: 16,
|
|
13375
|
+
labelMarginTop: 5,
|
|
13376
|
+
tickFont: 9,
|
|
13377
|
+
tickLetterSpacing: 0.5,
|
|
13378
|
+
tickCellWidth: 28
|
|
13379
|
+
},
|
|
13380
|
+
wall: {
|
|
13381
|
+
trackHeight: 24,
|
|
13382
|
+
needleOverhang: 9,
|
|
13383
|
+
needleWidth: 7,
|
|
13384
|
+
tickLineNormal: 2.5,
|
|
13385
|
+
tickLineEmphasized: 3.5,
|
|
13386
|
+
tickLineHeightPad: 6,
|
|
13387
|
+
tickLineTopPad: 3,
|
|
13388
|
+
labelRowHeight: 24,
|
|
13389
|
+
labelMarginTop: 8,
|
|
13390
|
+
tickFont: 14,
|
|
13391
|
+
tickLetterSpacing: 0.5,
|
|
13392
|
+
tickCellWidth: 48
|
|
13393
|
+
}
|
|
13394
|
+
};
|
|
13395
|
+
function fraction(value, min, max) {
|
|
13396
|
+
if (max <= min) return 0;
|
|
13397
|
+
return Math.max(0, Math.min(1, (value - min) / (max - min)));
|
|
13398
|
+
}
|
|
13399
|
+
function pct(frac) {
|
|
13400
|
+
return `${frac * 100}%`;
|
|
13401
|
+
}
|
|
13402
|
+
function ZoneTrack({
|
|
13403
|
+
zones,
|
|
13404
|
+
max,
|
|
13405
|
+
min = 0,
|
|
13406
|
+
marker = null,
|
|
13407
|
+
ticks,
|
|
13408
|
+
band = null,
|
|
13409
|
+
size = "default",
|
|
13410
|
+
trackHeight: trackHeightProp,
|
|
13411
|
+
needleOverhang: needleOverhangProp,
|
|
13412
|
+
trackColor = DEFAULT_TRACK_COLOR,
|
|
13413
|
+
className,
|
|
13414
|
+
style,
|
|
13415
|
+
accessibilityLabel: accessibilityLabel2,
|
|
13416
|
+
...props
|
|
13417
|
+
}) {
|
|
13418
|
+
const s = ZONE_SIZES[size];
|
|
13419
|
+
const trackHeight = trackHeightProp ?? s.trackHeight;
|
|
13420
|
+
const needleOverhang = needleOverhangProp ?? s.needleOverhang;
|
|
13421
|
+
const isNeedle = marker?.type === "needle";
|
|
13422
|
+
const markerHeight = isNeedle ? trackHeight + needleOverhang * 2 : trackHeight;
|
|
13423
|
+
const markerFrac = marker != null ? fraction(marker.value, min, max) : 0;
|
|
13424
|
+
const bands = zones.map((zone, i) => {
|
|
13425
|
+
const prev = i === 0 ? min : zones[i - 1].upTo;
|
|
13426
|
+
const start = Math.max(min, Math.min(max, prev));
|
|
13427
|
+
const end = Math.max(min, Math.min(max, zone.upTo));
|
|
13428
|
+
return { color: zone.color, weight: Math.max(0, end - start) };
|
|
13429
|
+
});
|
|
13430
|
+
return /* @__PURE__ */ jsxs(
|
|
13431
|
+
View,
|
|
13432
|
+
{
|
|
13433
|
+
className,
|
|
13434
|
+
style: [{ width: "100%" }, style],
|
|
13435
|
+
accessibilityRole: "progressbar",
|
|
13436
|
+
accessibilityValue: marker != null ? { min, max, now: marker.value } : { min, max, now: min },
|
|
13437
|
+
accessibilityLabel: accessibilityLabel2 ?? `Zone track: ${marker?.value ?? min}`,
|
|
13438
|
+
testID: "zone-track",
|
|
13439
|
+
...props,
|
|
13440
|
+
children: [
|
|
13441
|
+
/* @__PURE__ */ jsxs(View, { style: { position: "relative", height: markerHeight }, children: [
|
|
13442
|
+
/* @__PURE__ */ jsxs(
|
|
13443
|
+
View,
|
|
13444
|
+
{
|
|
13445
|
+
testID: "zone-track-track",
|
|
13446
|
+
accessibilityElementsHidden: true,
|
|
13447
|
+
style: {
|
|
13448
|
+
position: "absolute",
|
|
13449
|
+
top: (markerHeight - trackHeight) / 2,
|
|
13450
|
+
left: 0,
|
|
13451
|
+
right: 0,
|
|
13452
|
+
height: trackHeight,
|
|
13453
|
+
borderRadius: trackHeight / 2,
|
|
13454
|
+
backgroundColor: trackColor,
|
|
13455
|
+
overflow: "hidden",
|
|
13456
|
+
flexDirection: "row",
|
|
13457
|
+
// The pill's own box-shadow renders outside its overflow:hidden, so
|
|
13458
|
+
// `glow` haloes the whole track in the marker colour.
|
|
13459
|
+
...marker?.glow ? { boxShadow: glowShadow(marker.color ?? DEFAULT_MARKER_COLOR2) } : null
|
|
13460
|
+
},
|
|
13461
|
+
children: [
|
|
13462
|
+
bands.map((b, i) => /* @__PURE__ */ jsx(
|
|
13463
|
+
View,
|
|
13464
|
+
{
|
|
13465
|
+
testID: "zone-track-band",
|
|
13466
|
+
style: {
|
|
13467
|
+
flexGrow: b.weight,
|
|
13468
|
+
flexShrink: 1,
|
|
13469
|
+
flexBasis: 0,
|
|
13470
|
+
minWidth: 0,
|
|
13471
|
+
height: "100%",
|
|
13472
|
+
backgroundColor: b.color
|
|
13473
|
+
}
|
|
13474
|
+
},
|
|
13475
|
+
i
|
|
13476
|
+
)),
|
|
13477
|
+
band != null && /* @__PURE__ */ jsx(
|
|
13478
|
+
View,
|
|
13479
|
+
{
|
|
13480
|
+
testID: "zone-track-band-highlight",
|
|
13481
|
+
style: {
|
|
13482
|
+
position: "absolute",
|
|
13483
|
+
top: 0,
|
|
13484
|
+
bottom: 0,
|
|
13485
|
+
left: pct(fraction(band.from, min, max)),
|
|
13486
|
+
width: pct(fraction(band.to, min, max) - fraction(band.from, min, max)),
|
|
13487
|
+
backgroundColor: band.color
|
|
13488
|
+
}
|
|
13489
|
+
}
|
|
13490
|
+
),
|
|
13491
|
+
marker?.type === "fill" && /* @__PURE__ */ jsx(
|
|
13492
|
+
View,
|
|
13493
|
+
{
|
|
13494
|
+
testID: "zone-track-unfilled",
|
|
13495
|
+
style: {
|
|
13496
|
+
position: "absolute",
|
|
13497
|
+
top: 0,
|
|
13498
|
+
bottom: 0,
|
|
13499
|
+
left: pct(markerFrac),
|
|
13500
|
+
right: 0,
|
|
13501
|
+
backgroundColor: trackColor
|
|
13502
|
+
}
|
|
13503
|
+
}
|
|
13504
|
+
),
|
|
13505
|
+
marker?.type === "fill" && marker.color != null && /* @__PURE__ */ jsx(
|
|
13506
|
+
View,
|
|
13507
|
+
{
|
|
13508
|
+
testID: "zone-track-fill",
|
|
12079
13509
|
style: {
|
|
12080
13510
|
position: "absolute",
|
|
12081
|
-
|
|
12082
|
-
|
|
12083
|
-
|
|
12084
|
-
|
|
12085
|
-
|
|
12086
|
-
|
|
12087
|
-
|
|
12088
|
-
|
|
12089
|
-
|
|
12090
|
-
|
|
12091
|
-
|
|
12092
|
-
|
|
12093
|
-
|
|
12094
|
-
);
|
|
12095
|
-
})
|
|
12096
|
-
]
|
|
12097
|
-
}
|
|
12098
|
-
),
|
|
12099
|
-
workouts.map((workout, i) => {
|
|
12100
|
-
const cx = toX(workout.date);
|
|
12101
|
-
const cy = toY(workout.load);
|
|
12102
|
-
const color = DOT_COLORS[workout.status];
|
|
12103
|
-
const dotStyle = {
|
|
12104
|
-
width: DOT_SIZE,
|
|
12105
|
-
height: DOT_SIZE,
|
|
12106
|
-
borderRadius: DOT_SIZE / 2,
|
|
12107
|
-
backgroundColor: color,
|
|
12108
|
-
borderWidth: 2,
|
|
12109
|
-
borderColor: DOT_BORDER
|
|
12110
|
-
};
|
|
12111
|
-
const label = `Workout on ${formatDate2(workout.date)}, load ${workout.load}, ${STATUS_PHRASES[workout.status]}`;
|
|
12112
|
-
return /* @__PURE__ */ jsx(
|
|
12113
|
-
Animated.View,
|
|
13511
|
+
top: 0,
|
|
13512
|
+
bottom: 0,
|
|
13513
|
+
left: 0,
|
|
13514
|
+
width: pct(markerFrac),
|
|
13515
|
+
backgroundColor: marker.color
|
|
13516
|
+
}
|
|
13517
|
+
}
|
|
13518
|
+
)
|
|
13519
|
+
]
|
|
13520
|
+
}
|
|
13521
|
+
),
|
|
13522
|
+
isNeedle && /* @__PURE__ */ jsx(
|
|
13523
|
+
View,
|
|
12114
13524
|
{
|
|
13525
|
+
testID: "zone-track-needle",
|
|
12115
13526
|
style: {
|
|
12116
13527
|
position: "absolute",
|
|
12117
|
-
|
|
12118
|
-
|
|
12119
|
-
|
|
13528
|
+
top: 0,
|
|
13529
|
+
left: pct(markerFrac),
|
|
13530
|
+
width: s.needleWidth,
|
|
13531
|
+
height: markerHeight,
|
|
13532
|
+
borderRadius: s.needleWidth / 2,
|
|
13533
|
+
backgroundColor: marker.color ?? DEFAULT_MARKER_COLOR2,
|
|
13534
|
+
transform: [{ translateX: -s.needleWidth / 2 }]
|
|
13535
|
+
}
|
|
13536
|
+
}
|
|
13537
|
+
),
|
|
13538
|
+
ticks?.map((tick, i) => {
|
|
13539
|
+
const emphasized = tick.emphasized === true;
|
|
13540
|
+
const lineColor = tick.color ?? (emphasized ? t15["brand-primary"] : TICK_COLOR);
|
|
13541
|
+
const lineWidth = emphasized ? s.tickLineEmphasized : s.tickLineNormal;
|
|
13542
|
+
return /* @__PURE__ */ jsx(
|
|
13543
|
+
View,
|
|
13544
|
+
{
|
|
13545
|
+
testID: "zone-track-tick-line",
|
|
13546
|
+
accessibilityElementsHidden: true,
|
|
13547
|
+
style: {
|
|
13548
|
+
position: "absolute",
|
|
13549
|
+
top: (markerHeight - trackHeight) / 2 - s.tickLineTopPad,
|
|
13550
|
+
left: pct(fraction(tick.value, min, max)),
|
|
13551
|
+
width: lineWidth,
|
|
13552
|
+
height: trackHeight + s.tickLineHeightPad,
|
|
13553
|
+
borderRadius: lineWidth / 2,
|
|
13554
|
+
backgroundColor: lineColor,
|
|
13555
|
+
transform: [{ translateX: -lineWidth / 2 }],
|
|
13556
|
+
zIndex: 3
|
|
13557
|
+
}
|
|
12120
13558
|
},
|
|
12121
|
-
|
|
12122
|
-
|
|
12123
|
-
|
|
13559
|
+
`line-${i}`
|
|
13560
|
+
);
|
|
13561
|
+
})
|
|
13562
|
+
] }),
|
|
13563
|
+
ticks != null && ticks.length > 0 && /* @__PURE__ */ jsx(
|
|
13564
|
+
View,
|
|
13565
|
+
{
|
|
13566
|
+
style: { position: "relative", height: s.labelRowHeight, marginTop: s.labelMarginTop },
|
|
13567
|
+
children: ticks.map((tick, i) => {
|
|
13568
|
+
if (tick.label == null) return null;
|
|
13569
|
+
const emphasized = tick.emphasized === true;
|
|
13570
|
+
const labelColor = tick.color ?? (emphasized ? t15["brand-primary"] : TICK_COLOR);
|
|
13571
|
+
const labelNode = /* @__PURE__ */ jsx(
|
|
13572
|
+
Text,
|
|
12124
13573
|
{
|
|
12125
|
-
|
|
12126
|
-
|
|
12127
|
-
|
|
12128
|
-
|
|
12129
|
-
|
|
13574
|
+
testID: "zone-track-tick-label",
|
|
13575
|
+
style: {
|
|
13576
|
+
fontSize: s.tickFont,
|
|
13577
|
+
letterSpacing: s.tickLetterSpacing,
|
|
13578
|
+
color: labelColor,
|
|
13579
|
+
fontFamily: "monospace",
|
|
13580
|
+
fontWeight: emphasized ? "700" : "400"
|
|
13581
|
+
},
|
|
13582
|
+
children: tick.label
|
|
12130
13583
|
}
|
|
12131
|
-
)
|
|
13584
|
+
);
|
|
13585
|
+
return /* @__PURE__ */ jsx(
|
|
12132
13586
|
View,
|
|
12133
13587
|
{
|
|
12134
|
-
|
|
12135
|
-
|
|
12136
|
-
|
|
12137
|
-
|
|
12138
|
-
|
|
12139
|
-
|
|
13588
|
+
testID: "zone-track-tick",
|
|
13589
|
+
style: {
|
|
13590
|
+
position: "absolute",
|
|
13591
|
+
left: pct(fraction(tick.value, min, max)),
|
|
13592
|
+
transform: [{ translateX: -s.tickCellWidth / 2 }],
|
|
13593
|
+
width: s.tickCellWidth,
|
|
13594
|
+
alignItems: "center"
|
|
13595
|
+
},
|
|
13596
|
+
children: tick.tooltip != null ? /* @__PURE__ */ jsx(Tooltip, { label: tick.tooltip, placement: "top", children: labelNode }) : labelNode
|
|
13597
|
+
},
|
|
13598
|
+
`label-${i}`
|
|
13599
|
+
);
|
|
13600
|
+
})
|
|
13601
|
+
}
|
|
13602
|
+
)
|
|
13603
|
+
]
|
|
13604
|
+
}
|
|
13605
|
+
);
|
|
13606
|
+
}
|
|
13607
|
+
|
|
13608
|
+
// src/components/custom/Workout/FatigueMeter.tsx
|
|
13609
|
+
var { green, yellow, orange, red } = WORKOUT_TOKENS.scale;
|
|
13610
|
+
var DEFAULT_ZONE_COLORS = [green, yellow, orange, red];
|
|
13611
|
+
var DEFAULT_THRESHOLDS = [10, 20, 30];
|
|
13612
|
+
var DEFAULT_LABELS = ["fresh", "VL10", "VL20", "VL30", "stop"];
|
|
13613
|
+
var DEFAULT_MAX = 40;
|
|
13614
|
+
function FatigueMeter({
|
|
13615
|
+
value,
|
|
13616
|
+
max = DEFAULT_MAX,
|
|
13617
|
+
thresholds = DEFAULT_THRESHOLDS,
|
|
13618
|
+
zoneColors = DEFAULT_ZONE_COLORS,
|
|
13619
|
+
labels = DEFAULT_LABELS,
|
|
13620
|
+
size = "default",
|
|
13621
|
+
trackHeight,
|
|
13622
|
+
needleColor,
|
|
13623
|
+
className,
|
|
13624
|
+
...props
|
|
13625
|
+
}) {
|
|
13626
|
+
const [t1, t22, t32] = thresholds;
|
|
13627
|
+
const zones = [
|
|
13628
|
+
{ upTo: t1, color: zoneColors[0] },
|
|
13629
|
+
{ upTo: t22, color: zoneColors[1] },
|
|
13630
|
+
{ upTo: t32, color: zoneColors[2] },
|
|
13631
|
+
{ upTo: max, color: zoneColors[3] }
|
|
13632
|
+
];
|
|
13633
|
+
const tickValues = [0, t1, t22, t32, max];
|
|
13634
|
+
const ticks = tickValues.map((v, i) => ({ value: v, label: labels[i] }));
|
|
13635
|
+
return /* @__PURE__ */ jsx(
|
|
13636
|
+
ZoneTrack,
|
|
13637
|
+
{
|
|
13638
|
+
className,
|
|
13639
|
+
zones,
|
|
13640
|
+
min: 0,
|
|
13641
|
+
max,
|
|
13642
|
+
size,
|
|
13643
|
+
trackHeight,
|
|
13644
|
+
ticks,
|
|
13645
|
+
marker: { type: "needle", value, color: needleColor },
|
|
13646
|
+
accessibilityLabel: `Fatigue: ${value}% velocity loss`,
|
|
13647
|
+
testID: "fatigue-meter",
|
|
13648
|
+
...props
|
|
13649
|
+
}
|
|
13650
|
+
);
|
|
13651
|
+
}
|
|
13652
|
+
var HEAT = WORKOUT_TOKENS.heatmap;
|
|
13653
|
+
var NEUTRAL_TRACK = primitiveColors.charcoal[200];
|
|
13654
|
+
var MONO = "monospace";
|
|
13655
|
+
var HEAT_BY_ZONE = {
|
|
13656
|
+
under: HEAT.under,
|
|
13657
|
+
maintenance: HEAT.maintenance,
|
|
13658
|
+
productive: HEAT.productive,
|
|
13659
|
+
approaching: HEAT.approaching,
|
|
13660
|
+
over: HEAT.over
|
|
13661
|
+
};
|
|
13662
|
+
var ZONE_DESCRIPTION = {
|
|
13663
|
+
under: "below MEV",
|
|
13664
|
+
maintenance: "building toward MAV",
|
|
13665
|
+
productive: "in the productive zone",
|
|
13666
|
+
approaching: "approaching MRV",
|
|
13667
|
+
over: "over MRV"
|
|
13668
|
+
};
|
|
13669
|
+
var LANDMARK_NAME = {
|
|
13670
|
+
MEV: "Minimum Effective Volume",
|
|
13671
|
+
MAV: "Maximum Adaptive Volume",
|
|
13672
|
+
MRV: "Maximum Recoverable Volume"
|
|
13673
|
+
};
|
|
13674
|
+
function zoneForSets(sets, { mev, mav, mrv }) {
|
|
13675
|
+
if (sets < mev) return "under";
|
|
13676
|
+
if (sets < mav) return "maintenance";
|
|
13677
|
+
if (sets >= mrv) return "over";
|
|
13678
|
+
const midpoint = (mav + mrv) / 2;
|
|
13679
|
+
return sets < midpoint ? "productive" : "approaching";
|
|
13680
|
+
}
|
|
13681
|
+
function VolumeLandmarkBar({
|
|
13682
|
+
muscle,
|
|
13683
|
+
currentSets,
|
|
13684
|
+
landmarks,
|
|
13685
|
+
width = 220,
|
|
13686
|
+
trackHeight = 10,
|
|
13687
|
+
scaleMax,
|
|
13688
|
+
className,
|
|
13689
|
+
style,
|
|
13690
|
+
...props
|
|
13691
|
+
}) {
|
|
13692
|
+
const { mev, mav, mrv } = landmarks;
|
|
13693
|
+
const max = scaleMax ?? mrv * 1.2;
|
|
13694
|
+
const zone = zoneForSets(currentSets, landmarks);
|
|
13695
|
+
const fillColor = HEAT_BY_ZONE[zone];
|
|
13696
|
+
const pct2 = mav > 0 ? Math.round(currentSets / mav * 100) : 0;
|
|
13697
|
+
return /* @__PURE__ */ jsxs(
|
|
13698
|
+
View,
|
|
13699
|
+
{
|
|
13700
|
+
className,
|
|
13701
|
+
style: [{ width, gap: 3 }, style],
|
|
13702
|
+
testID: "volume-landmark-bar",
|
|
13703
|
+
...props,
|
|
13704
|
+
children: [
|
|
13705
|
+
/* @__PURE__ */ jsx(
|
|
13706
|
+
DataRow,
|
|
13707
|
+
{
|
|
13708
|
+
label: muscle,
|
|
13709
|
+
value: /* @__PURE__ */ jsxs(
|
|
13710
|
+
Text,
|
|
13711
|
+
{
|
|
13712
|
+
testID: "volume-landmark-pct",
|
|
13713
|
+
style: { fontSize: 14, fontWeight: "700", fontFamily: MONO, color: fillColor },
|
|
13714
|
+
children: [
|
|
13715
|
+
pct2,
|
|
13716
|
+
"%"
|
|
13717
|
+
]
|
|
13718
|
+
}
|
|
13719
|
+
),
|
|
13720
|
+
className: "py-0",
|
|
13721
|
+
testID: "volume-landmark-header"
|
|
13722
|
+
}
|
|
13723
|
+
),
|
|
13724
|
+
/* @__PURE__ */ jsx(
|
|
13725
|
+
ZoneTrack,
|
|
13726
|
+
{
|
|
13727
|
+
zones: [{ upTo: max, color: NEUTRAL_TRACK }],
|
|
13728
|
+
max,
|
|
13729
|
+
marker: {
|
|
13730
|
+
type: "fill",
|
|
13731
|
+
value: currentSets,
|
|
13732
|
+
color: fillColor,
|
|
13733
|
+
// Glow when in the optimal productive band — the "sweet spot" cue.
|
|
13734
|
+
glow: zone === "productive"
|
|
12140
13735
|
},
|
|
12141
|
-
|
|
12142
|
-
|
|
12143
|
-
|
|
13736
|
+
trackColor: NEUTRAL_TRACK,
|
|
13737
|
+
trackHeight,
|
|
13738
|
+
ticks: [
|
|
13739
|
+
{ value: mev, label: "MEV", tooltip: `${LANDMARK_NAME.MEV} \xB7 ${mev} sets/wk` },
|
|
13740
|
+
{
|
|
13741
|
+
value: mav,
|
|
13742
|
+
label: "MAV",
|
|
13743
|
+
emphasized: true,
|
|
13744
|
+
tooltip: `${LANDMARK_NAME.MAV} (target) \xB7 ${mav} sets/wk`
|
|
13745
|
+
},
|
|
13746
|
+
{ value: mrv, label: "MRV", tooltip: `${LANDMARK_NAME.MRV} \xB7 ${mrv} sets/wk` }
|
|
13747
|
+
],
|
|
13748
|
+
accessibilityLabel: `${muscle} weekly volume: ${currentSets} sets, ${pct2}% of MAV target, ${ZONE_DESCRIPTION[zone]}`,
|
|
13749
|
+
testID: "volume-landmark-track"
|
|
13750
|
+
}
|
|
13751
|
+
)
|
|
13752
|
+
]
|
|
13753
|
+
}
|
|
13754
|
+
);
|
|
13755
|
+
}
|
|
13756
|
+
var t16 = getSemanticColors("dark");
|
|
13757
|
+
var statusToken = {
|
|
13758
|
+
productive: "status-success",
|
|
13759
|
+
threshold: "status-warning",
|
|
13760
|
+
stop: "status-error"
|
|
13761
|
+
};
|
|
13762
|
+
var statusDotVariant = {
|
|
13763
|
+
productive: "success",
|
|
13764
|
+
threshold: "warning",
|
|
13765
|
+
stop: "error"
|
|
13766
|
+
};
|
|
13767
|
+
var defaultLabel = {
|
|
13768
|
+
productive: "Productive",
|
|
13769
|
+
threshold: "Threshold",
|
|
13770
|
+
stop: "Stop"
|
|
13771
|
+
};
|
|
13772
|
+
function statusPillColor(status) {
|
|
13773
|
+
return t16[statusToken[status]];
|
|
13774
|
+
}
|
|
13775
|
+
function StatusPill2({ status, label, className, style, ...props }) {
|
|
13776
|
+
const color = statusPillColor(status);
|
|
13777
|
+
const text = label ?? defaultLabel[status];
|
|
13778
|
+
return /* @__PURE__ */ jsxs(
|
|
13779
|
+
View,
|
|
13780
|
+
{
|
|
13781
|
+
testID: "status-pill",
|
|
13782
|
+
className,
|
|
13783
|
+
style: [
|
|
13784
|
+
{
|
|
13785
|
+
flexDirection: "row",
|
|
13786
|
+
alignItems: "center",
|
|
13787
|
+
gap: 7,
|
|
13788
|
+
alignSelf: "flex-start",
|
|
13789
|
+
paddingVertical: 7,
|
|
13790
|
+
paddingHorizontal: 13,
|
|
13791
|
+
borderRadius: 9,
|
|
13792
|
+
backgroundColor: alpha(color, 0.14),
|
|
13793
|
+
borderWidth: 1,
|
|
13794
|
+
borderColor: alpha(color, 0.4)
|
|
13795
|
+
},
|
|
13796
|
+
style
|
|
13797
|
+
],
|
|
13798
|
+
...props,
|
|
13799
|
+
children: [
|
|
13800
|
+
/* @__PURE__ */ jsx(View, { accessibilityElementsHidden: true, children: /* @__PURE__ */ jsx(StatusDot, { variant: statusDotVariant[status], glow: true }) }),
|
|
13801
|
+
/* @__PURE__ */ jsx(Text, { testID: "status-pill-label", style: { fontSize: 13, fontWeight: "800", color }, children: text })
|
|
13802
|
+
]
|
|
13803
|
+
}
|
|
13804
|
+
);
|
|
13805
|
+
}
|
|
13806
|
+
var t17 = getSemanticColors("dark");
|
|
13807
|
+
var categoryToken = {
|
|
13808
|
+
productive: null,
|
|
13809
|
+
threshold: "status-warning",
|
|
13810
|
+
stop: "status-error"
|
|
13811
|
+
};
|
|
13812
|
+
var floodOpacity = {
|
|
13813
|
+
productive: 0,
|
|
13814
|
+
threshold: 0.12,
|
|
13815
|
+
stop: 0.18
|
|
13816
|
+
};
|
|
13817
|
+
function liveAuraColor(category) {
|
|
13818
|
+
const token = categoryToken[category];
|
|
13819
|
+
return token ? t17[token] : null;
|
|
13820
|
+
}
|
|
13821
|
+
function LiveAuraFrame({
|
|
13822
|
+
category,
|
|
13823
|
+
pulse = true,
|
|
13824
|
+
className,
|
|
13825
|
+
children,
|
|
13826
|
+
style,
|
|
13827
|
+
...props
|
|
13828
|
+
}) {
|
|
13829
|
+
const color = liveAuraColor(category);
|
|
13830
|
+
const tint = color ? alpha(color, floodOpacity[category]) : "transparent";
|
|
13831
|
+
const floodStyle = {
|
|
13832
|
+
...StyleSheet.absoluteFillObject,
|
|
13833
|
+
...Platform.OS === "web" ? (
|
|
13834
|
+
// backgroundImage is a runtime RNW style, not in RN ViewStyle types.
|
|
13835
|
+
{ backgroundImage: `radial-gradient(130% 95% at 50% 0%, ${tint}, transparent 62%)` }
|
|
13836
|
+
) : { backgroundColor: tint }
|
|
13837
|
+
};
|
|
13838
|
+
return /* @__PURE__ */ jsxs(
|
|
13839
|
+
View,
|
|
13840
|
+
{
|
|
13841
|
+
testID: "live-aura-frame",
|
|
13842
|
+
className,
|
|
13843
|
+
style: [
|
|
13844
|
+
{
|
|
13845
|
+
position: "relative",
|
|
13846
|
+
overflow: "hidden",
|
|
13847
|
+
borderRadius: 10,
|
|
13848
|
+
backgroundColor: t17["background-base"],
|
|
13849
|
+
borderWidth: 1,
|
|
13850
|
+
borderColor: t17["border-default"]
|
|
13851
|
+
},
|
|
13852
|
+
style
|
|
13853
|
+
],
|
|
13854
|
+
...props,
|
|
13855
|
+
children: [
|
|
13856
|
+
color && /* @__PURE__ */ jsx(
|
|
13857
|
+
View,
|
|
13858
|
+
{
|
|
13859
|
+
testID: "live-aura-flood",
|
|
13860
|
+
accessibilityElementsHidden: true,
|
|
13861
|
+
pointerEvents: "none",
|
|
13862
|
+
className: category === "stop" && pulse ? "animate-pulse" : void 0,
|
|
13863
|
+
style: floodStyle
|
|
13864
|
+
}
|
|
13865
|
+
),
|
|
13866
|
+
children
|
|
12144
13867
|
]
|
|
12145
13868
|
}
|
|
12146
13869
|
);
|
|
@@ -12351,28 +14074,28 @@ function Scatter({
|
|
|
12351
14074
|
testID: "scatter-canvas",
|
|
12352
14075
|
style: { position: "absolute", top: 0, left: 0, width, height, overflow: "hidden" },
|
|
12353
14076
|
children: [
|
|
12354
|
-
ticksOf(yd, TICK_COUNT).map((
|
|
12355
|
-
const y = toY(
|
|
14077
|
+
ticksOf(yd, TICK_COUNT).map((t18, i) => {
|
|
14078
|
+
const y = toY(t18);
|
|
12356
14079
|
return /* @__PURE__ */ jsx(
|
|
12357
14080
|
View,
|
|
12358
14081
|
{
|
|
12359
14082
|
accessibilityElementsHidden: true,
|
|
12360
14083
|
testID: "scatter-gridline-y",
|
|
12361
14084
|
style: { position: "absolute", left: PLOT_LEFT2, width: innerW, top: y, height: 1, backgroundColor: GRID_LINE2 },
|
|
12362
|
-
children: /* @__PURE__ */ jsx(Text, { className: "text-[9px] text-text-tertiary", style: { position: "absolute", left: -PLOT_LEFT2, top: -6, width: PLOT_LEFT2 - 6, textAlign: "right" }, children: formatTick(
|
|
14085
|
+
children: /* @__PURE__ */ jsx(Text, { className: "text-[9px] text-text-tertiary", style: { position: "absolute", left: -PLOT_LEFT2, top: -6, width: PLOT_LEFT2 - 6, textAlign: "right" }, children: formatTick(t18) })
|
|
12363
14086
|
},
|
|
12364
14087
|
`y-${i}`
|
|
12365
14088
|
);
|
|
12366
14089
|
}),
|
|
12367
|
-
ticksOf(xd, TICK_COUNT).map((
|
|
12368
|
-
const x = toX(
|
|
14090
|
+
ticksOf(xd, TICK_COUNT).map((t18, i) => {
|
|
14091
|
+
const x = toX(t18);
|
|
12369
14092
|
return /* @__PURE__ */ jsx(
|
|
12370
14093
|
View,
|
|
12371
14094
|
{
|
|
12372
14095
|
accessibilityElementsHidden: true,
|
|
12373
14096
|
testID: "scatter-gridline-x",
|
|
12374
14097
|
style: { position: "absolute", top: PLOT_TOP, height: innerH, left: x, width: 1, backgroundColor: GRID_LINE2 },
|
|
12375
|
-
children: /* @__PURE__ */ jsx(Text, { className: "text-[9px] text-text-tertiary", style: { position: "absolute", top: innerH + 4, left: -16, width: 32, textAlign: "center" }, children: formatTick(
|
|
14098
|
+
children: /* @__PURE__ */ jsx(Text, { className: "text-[9px] text-text-tertiary", style: { position: "absolute", top: innerH + 4, left: -16, width: 32, textAlign: "center" }, children: formatTick(t18) })
|
|
12376
14099
|
},
|
|
12377
14100
|
`x-${i}`
|
|
12378
14101
|
);
|
|
@@ -12437,7 +14160,7 @@ var STATUS_SUCCESS4 = sem2["status-success"];
|
|
|
12437
14160
|
var STATUS_WARNING4 = sem2["status-warning"];
|
|
12438
14161
|
var STATUS_ERROR4 = sem2["status-error"];
|
|
12439
14162
|
var TRACK = "rgba(255,255,255,0.08)";
|
|
12440
|
-
var
|
|
14163
|
+
var DEFAULT_THRESHOLDS2 = [
|
|
12441
14164
|
{ value: 0, color: STATUS_ERROR4 },
|
|
12442
14165
|
{ value: 60, color: STATUS_WARNING4 },
|
|
12443
14166
|
{ value: 80, color: STATUS_SUCCESS4 }
|
|
@@ -12452,8 +14175,8 @@ function clamp012(n) {
|
|
|
12452
14175
|
function formatValue2(v) {
|
|
12453
14176
|
return Number.isInteger(v) ? `${v}` : v.toFixed(1);
|
|
12454
14177
|
}
|
|
12455
|
-
function bandColor2(
|
|
12456
|
-
const value = min +
|
|
14178
|
+
function bandColor2(fraction2, bands, min, max) {
|
|
14179
|
+
const value = min + fraction2 * (max - min);
|
|
12457
14180
|
const sorted = [...bands].sort((a, b) => a.value - b.value);
|
|
12458
14181
|
let color = sorted[0]?.color ?? STATUS_SUCCESS4;
|
|
12459
14182
|
for (const band of sorted) {
|
|
@@ -12465,15 +14188,15 @@ function buildTicks(fill, size, activeColor) {
|
|
|
12465
14188
|
const center = size / 2;
|
|
12466
14189
|
const radius = center - size * 0.08;
|
|
12467
14190
|
return Array.from({ length: SEGMENTS }, (_, i) => {
|
|
12468
|
-
const
|
|
12469
|
-
const deg = ARC_START +
|
|
14191
|
+
const fraction2 = (i + 0.5) / SEGMENTS;
|
|
14192
|
+
const deg = ARC_START + fraction2 * ARC_SWEEP;
|
|
12470
14193
|
const rad = deg * Math.PI / 180;
|
|
12471
14194
|
return {
|
|
12472
14195
|
key: i,
|
|
12473
14196
|
left: center + radius * Math.cos(rad),
|
|
12474
14197
|
top: center + radius * Math.sin(rad),
|
|
12475
14198
|
rotate: `${deg - 90}deg`,
|
|
12476
|
-
color:
|
|
14199
|
+
color: fraction2 <= fill ? activeColor(fraction2) : TRACK
|
|
12477
14200
|
};
|
|
12478
14201
|
});
|
|
12479
14202
|
}
|
|
@@ -12484,7 +14207,7 @@ function Gauge2({
|
|
|
12484
14207
|
size = 160,
|
|
12485
14208
|
label,
|
|
12486
14209
|
unit,
|
|
12487
|
-
thresholds =
|
|
14210
|
+
thresholds = DEFAULT_THRESHOLDS2,
|
|
12488
14211
|
color,
|
|
12489
14212
|
className,
|
|
12490
14213
|
...props
|
|
@@ -12507,23 +14230,23 @@ function Gauge2({
|
|
|
12507
14230
|
testID: "gauge",
|
|
12508
14231
|
...props,
|
|
12509
14232
|
children: [
|
|
12510
|
-
ticks.map((
|
|
14233
|
+
ticks.map((t18) => /* @__PURE__ */ jsx(
|
|
12511
14234
|
View,
|
|
12512
14235
|
{
|
|
12513
14236
|
accessibilityElementsHidden: true,
|
|
12514
14237
|
testID: "gauge-segment",
|
|
12515
14238
|
style: {
|
|
12516
14239
|
position: "absolute",
|
|
12517
|
-
left:
|
|
12518
|
-
top:
|
|
14240
|
+
left: t18.left - tickThickness / 2,
|
|
14241
|
+
top: t18.top - tickLength / 2,
|
|
12519
14242
|
width: tickThickness,
|
|
12520
14243
|
height: tickLength,
|
|
12521
14244
|
borderRadius: tickThickness / 2,
|
|
12522
|
-
backgroundColor:
|
|
12523
|
-
transform: [{ rotate:
|
|
14245
|
+
backgroundColor: t18.color,
|
|
14246
|
+
transform: [{ rotate: t18.rotate }]
|
|
12524
14247
|
}
|
|
12525
14248
|
},
|
|
12526
|
-
|
|
14249
|
+
t18.key
|
|
12527
14250
|
)),
|
|
12528
14251
|
/* @__PURE__ */ jsxs(View, { style: { position: "absolute", top: 0, left: 0, width: size, height: size }, className: "items-center justify-center", children: [
|
|
12529
14252
|
/* @__PURE__ */ jsxs(View, { className: "flex-row items-baseline gap-0.5", children: [
|
|
@@ -12569,7 +14292,7 @@ function BrandLockup({
|
|
|
12569
14292
|
}
|
|
12570
14293
|
var stateConfig = {
|
|
12571
14294
|
// live = vivid green with an expanding ring; rest = solid amber (no pulse — operator); idle is dim.
|
|
12572
|
-
live: { label: "LIVE", color: "
|
|
14295
|
+
live: { label: "LIVE", color: "live", pulse: "ping", textColor: "primary" },
|
|
12573
14296
|
rest: { label: "REST", color: "warning", pulse: false, textColor: "primary" },
|
|
12574
14297
|
idle: { label: "IDLE", color: "default", pulse: false, textColor: "secondary" }
|
|
12575
14298
|
};
|
|
@@ -12733,6 +14456,127 @@ function TopBar({
|
|
|
12733
14456
|
}
|
|
12734
14457
|
);
|
|
12735
14458
|
}
|
|
14459
|
+
function NavItem({
|
|
14460
|
+
icon,
|
|
14461
|
+
label,
|
|
14462
|
+
active = false,
|
|
14463
|
+
live = false,
|
|
14464
|
+
onPress,
|
|
14465
|
+
className
|
|
14466
|
+
}) {
|
|
14467
|
+
const glyphColor = active ? "text-brand-primary" : "text-text-tertiary";
|
|
14468
|
+
const labelColor = active ? "text-brand-primary" : live ? "text-status-live-muted" : "text-text-tertiary";
|
|
14469
|
+
return /* @__PURE__ */ jsxs(
|
|
14470
|
+
Pressable,
|
|
14471
|
+
{
|
|
14472
|
+
accessibilityRole: "tab",
|
|
14473
|
+
accessibilityState: { selected: active },
|
|
14474
|
+
accessibilityLabel: label,
|
|
14475
|
+
onPress,
|
|
14476
|
+
className: cn("relative h-[46px] w-[60px] items-center justify-center", className),
|
|
14477
|
+
children: [
|
|
14478
|
+
active ? /* @__PURE__ */ jsx(
|
|
14479
|
+
View,
|
|
14480
|
+
{
|
|
14481
|
+
testID: "nav-item-accent",
|
|
14482
|
+
className: "absolute left-0 top-[13px] bottom-[13px] w-[3px] rounded-r-[3px] bg-brand-primary"
|
|
14483
|
+
}
|
|
14484
|
+
) : null,
|
|
14485
|
+
/* @__PURE__ */ jsxs(
|
|
14486
|
+
View,
|
|
14487
|
+
{
|
|
14488
|
+
className: cn(
|
|
14489
|
+
"h-[46px] w-[46px] items-center justify-center gap-[3px] rounded-[11px]",
|
|
14490
|
+
glyphColor
|
|
14491
|
+
),
|
|
14492
|
+
children: [
|
|
14493
|
+
icon,
|
|
14494
|
+
/* @__PURE__ */ jsx(
|
|
14495
|
+
Typography,
|
|
14496
|
+
{
|
|
14497
|
+
variant: "button",
|
|
14498
|
+
color: "inherit",
|
|
14499
|
+
className: cn("text-[8.5px] font-bold uppercase tracking-[0.4px]", labelColor),
|
|
14500
|
+
children: label
|
|
14501
|
+
}
|
|
14502
|
+
)
|
|
14503
|
+
]
|
|
14504
|
+
}
|
|
14505
|
+
)
|
|
14506
|
+
]
|
|
14507
|
+
}
|
|
14508
|
+
);
|
|
14509
|
+
}
|
|
14510
|
+
var defaultNavItems = [
|
|
14511
|
+
{ key: "live", label: "Live", icon: /* @__PURE__ */ jsx(ActivityIcon, { size: 20, color: "currentColor" }) },
|
|
14512
|
+
{ key: "review", label: "Review", icon: /* @__PURE__ */ jsx(HistoryIcon, { size: 20, color: "currentColor" }) },
|
|
14513
|
+
{ key: "program", label: "Plan", icon: /* @__PURE__ */ jsx(LayersIcon, { size: 20, color: "currentColor" }) },
|
|
14514
|
+
{ key: "body", label: "Body", icon: /* @__PURE__ */ jsx(PersonStandingIcon, { size: 20, color: "currentColor" }) }
|
|
14515
|
+
];
|
|
14516
|
+
function SideNav({
|
|
14517
|
+
items = defaultNavItems,
|
|
14518
|
+
activeKey,
|
|
14519
|
+
onNavigate,
|
|
14520
|
+
liveKey = null,
|
|
14521
|
+
className
|
|
14522
|
+
}) {
|
|
14523
|
+
return /* @__PURE__ */ jsx(
|
|
14524
|
+
View,
|
|
14525
|
+
{
|
|
14526
|
+
accessibilityRole: "tablist",
|
|
14527
|
+
className: cn(
|
|
14528
|
+
"w-[60px] items-center gap-[6px] border-r border-border bg-background-base py-3",
|
|
14529
|
+
className
|
|
14530
|
+
),
|
|
14531
|
+
children: items.map((item) => /* @__PURE__ */ jsx(
|
|
14532
|
+
NavItem,
|
|
14533
|
+
{
|
|
14534
|
+
icon: item.icon,
|
|
14535
|
+
label: item.label,
|
|
14536
|
+
active: item.key === activeKey,
|
|
14537
|
+
live: item.key === liveKey && item.key !== activeKey,
|
|
14538
|
+
onPress: () => onNavigate?.(item.key)
|
|
14539
|
+
},
|
|
14540
|
+
item.key
|
|
14541
|
+
))
|
|
14542
|
+
}
|
|
14543
|
+
);
|
|
14544
|
+
}
|
|
14545
|
+
var DEMO_DEVICES = [
|
|
14546
|
+
{ id: "Voltra-A3F2", nickname: "Left Cable", slot: "L", state: "connected" },
|
|
14547
|
+
{ id: "Voltra-9B1C", nickname: "Right Cable", slot: "R", state: "connected" }
|
|
14548
|
+
];
|
|
14549
|
+
function ContentPlaceholder() {
|
|
14550
|
+
return /* @__PURE__ */ jsx(View, { className: "flex-1 items-center justify-center", children: /* @__PURE__ */ jsx(Text, { className: "font-heading text-sm text-text-tertiary", children: "main content region" }) });
|
|
14551
|
+
}
|
|
14552
|
+
function DashboardShell({
|
|
14553
|
+
activeKey = "live",
|
|
14554
|
+
navItems,
|
|
14555
|
+
liveKey = null,
|
|
14556
|
+
state = "live",
|
|
14557
|
+
devices = DEMO_DEVICES,
|
|
14558
|
+
subtitle = "wall dashboard",
|
|
14559
|
+
onNavigate,
|
|
14560
|
+
onSelectDevice,
|
|
14561
|
+
children,
|
|
14562
|
+
className
|
|
14563
|
+
}) {
|
|
14564
|
+
return /* @__PURE__ */ jsxs(View, { className: cn("flex-1 flex-row bg-surface-base", className), children: [
|
|
14565
|
+
/* @__PURE__ */ jsx(SideNav, { activeKey, items: navItems, liveKey, onNavigate }),
|
|
14566
|
+
/* @__PURE__ */ jsxs(View, { className: "flex-1", children: [
|
|
14567
|
+
/* @__PURE__ */ jsx(
|
|
14568
|
+
TopBar,
|
|
14569
|
+
{
|
|
14570
|
+
state,
|
|
14571
|
+
devices,
|
|
14572
|
+
subtitle,
|
|
14573
|
+
onSelectDevice
|
|
14574
|
+
}
|
|
14575
|
+
),
|
|
14576
|
+
/* @__PURE__ */ jsx(View, { className: "flex-1", children: children ?? /* @__PURE__ */ jsx(ContentPlaceholder, {}) })
|
|
14577
|
+
] })
|
|
14578
|
+
] });
|
|
14579
|
+
}
|
|
12736
14580
|
|
|
12737
14581
|
// src/utils/form.ts
|
|
12738
14582
|
function getFieldValidationProps(state) {
|
|
@@ -12822,6 +14666,6 @@ function composeValidators(...validators) {
|
|
|
12822
14666
|
};
|
|
12823
14667
|
}
|
|
12824
14668
|
|
|
12825
|
-
export { Accordion, AccordionButton, AccordionItem, AccordionPanel, Alert, AlertDescription, AlertTitle, Autocomplete, Avatar, AvatarBadge, AvatarGroup, Badge, BadgeText, BaseBadge, BluetoothIcon, BrandLockup, BreadcrumbItem, Breadcrumbs, Button, ButtonIcon, ButtonSpinner, ButtonText, CATEGORICAL_CVD_SAFE_MAX, CapacityBandChart, Caption, Card, CardContent, CardDescription, CardFooter, CardHeader, CardSkeleton, CardTitle, Checkbox, CheckboxGroup, Chip, CircularProgress, Collapse, CollapseButton, CollapseContent, DataRow, DateTime, DeviationBar, DeviceIndicator, DeviceMenu, DeviceRow, Divider, Drawer, DrawerBody, DrawerFooter, DrawerHeader, DumbbellIcon, EmptyState, ExerciseCard, FormActions, FormField, FormRow, FormSection, Gauge2 as Gauge, HStack, Heading, HelpTip, IconBox, Indicator, Input, InputBar, InputGroup, IntensityBar, Label, LabelWithHelp, Link, ListItem, ListItemContent, ListItemDivider, ListItemIcon, ListItemTrailing, Menu, MenuDivider, MenuGroup, MenuItem, MenuList, MenuTrigger, MesoCard, MesoProgressBar, MesoStatusCard, Metric, MetricGroup, Modal, ModalBody, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalTitle, MuscleGroupChip, Overline, Paragraph, PasswordInput, Pill, PlaceholderStrip, Popover, PopoverCloseButton, PopoverContent, PopoverTrigger, PrBadge, PrHistoryModal, Progress, ProgressSteps, Radio, RadioGroup, ReadinessCheck, RestTimer, Scatter, Section, SectionContent, SectionHeader, Select, SessionStatePill, SetRow, Sidebar, SidebarContent, SidebarDivider, SidebarFooter, SidebarHeader, SidebarItem, SidebarSection, Skeleton, SkeletonCard, SkeletonCircle, SkeletonListItem, SkeletonText, Sparkline, Spinner, Stack, StarIcon, StatusDot, StepContent, StepIndicator, StepLabel, Stepper, Step as StepperStep, StrengthTrendChart, SupersetWrapper, Surface, SvgIcon, Switch, TEMPO_PACING, Tab, TabList, TabPanel, TabPanels, Table, TableBody, TableCell, TableHeader, TableHeaderCell, TablePagination, TableRow, Tabs, TempoBar, TempoDisplay, Toast, ToastProvider, ToolbarButton, ToolbarButtonGroup, Tooltip, TopBar, Treemap, Typography, VStack, VelocityStrip, VoltrasMark, WeekRow, WeightBadge, WorkoutCard, WorkoutPill, alpha, applyThemePreset, audiobookPreset, bestTextColor, buttonSizes, calculateMeanVelocity, calculateVelocityLoss, categoricalPalette, cn, componentElevationRanges, composeValidators, createFieldId, createFlatShadow, createPressedHoverShadow, createPressedShadow, createRaisedHoverShadow, createRaisedShadow, darkThemeCSSVars, darken, defaultPreset, discreteRainbow, divergingScale, elevationSystem, formatDateTime, formatPrescription, formatSignedPct, formatVelocity, getBaseSurfaceColor, getCategoricalColor, getContrastText, getDiscreteRainbowColor, getElevationConfig, getElevationShadow, getElevationSurface, getFieldAriaProps, getFieldValidationProps, getGlowShadow, getHoverColors, getLuminance, getResultColor, getSemanticColors, getStatusColor, getTempoFillPct, getTempoPacingState, getThemeCSSVars, getValidatedElevation, getVelocityZoneColor, getVelocityZoneName, gluestackConfig, hasMaxLength, hasMinLength, hexToRgb, hsvToRgb, isCssPropertyManifest, isDark, isEmpty, isValidEmail, lightThemeCSSVars, lighten, linearGradient, neumorphicShadows, primitiveBorderRadius, primitiveBreakpoints, primitiveColors, primitiveRamps, primitiveShadows, primitiveSpacing, primitiveTypography, primitiveZIndex, resolveColor, rgbToHex, rgbToHsv, roundRpe, roundTempo, roundWeight, rpeColor, semanticColorsDark, semanticColorsLight, semanticTypography, sequentialEffort, shadowColors, surfaceGradient, useTable, useToast, useToolbarButton, validateCssPropertyManifest, validationRules };
|
|
14669
|
+
export { Accordion, AccordionButton, AccordionItem, AccordionPanel, ActivityIcon, Alert, AlertDescription, AlertTitle, AlertTriangleIcon, Autocomplete, Avatar, AvatarBadge, AvatarGroup, AwardIcon, Badge, BadgeText, BaseBadge, BluetoothIcon, BrandLockup, BreadcrumbItem, Breadcrumbs, Button, ButtonIcon, ButtonSpinner, ButtonText, CATEGORICAL_CVD_SAFE_MAX, CapacityBandChart, Caption, Card, CardContent, CardDescription, CardFooter, CardHeader, CardSkeleton, CardTitle, Checkbox, CheckboxGroup, Chip, CircleSlashIcon, CircularProgress, CircularTimer, Collapse, CollapseButton, CollapseContent, DashboardShell, DataRow, DateTime, DeviationBar, DeviceIndicator, DeviceMenu, DeviceRow, Divider, Drawer, DrawerBody, DrawerFooter, DrawerHeader, DumbbellIcon, EmptyState, ExerciseCard, ExerciseCardHeading, ExerciseHeading, ExerciseIndicator, FatigueMeter, FormActions, FormField, FormRow, FormSection, Gauge2 as Gauge, HStack, Heading, HelpTip, HistoryIcon, INDICATOR_PRECEDENCE, IconBox, Indicator, InfoIcon, Input, InputBar, InputGroup, IntensityBar, Label, LabelWithHelp, LayersIcon, Link, ListItem, ListItemContent, ListItemDivider, ListItemIcon, ListItemTrailing, LiveAuraFrame, METRIC_FONT, Menu, MenuDivider, MenuGroup, MenuItem, MenuList, MenuTrigger, MesoCard, MesoProgressBar, MesoStatusCard, Metric, MetricCell, MetricGroup, MetricTiles, Modal, ModalBody, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalTitle, MuscleGroupChip, NavItem, Overline, Paragraph, PasswordInput, PersonStandingIcon, Pill, PlaceholderStrip, Popover, PopoverCloseButton, PopoverContent, PopoverTrigger, PrBadge, PrHistoryModal, Progress, ProgressSteps, Radio, RadioGroup, ReadinessCheck, RestTimer, SET_STRIP_VARIABLE_COLOR, SET_STRIP_ZONES, ScaleIcon, Scatter, ScheduleTiles, Section, SectionContent, SectionHeader, SegmentedBar, SegmentedProgressBar, Select, SessionHeader, SessionRail, SessionStatePill, SetBar, SetRow, SetStrip, SetTableHeader, SetsRepsLoad, SideNav, Sidebar, SidebarContent, SidebarDivider, SidebarFooter, SidebarHeader, SidebarItem, SidebarSection, Skeleton, SkeletonCard, SkeletonCircle, SkeletonListItem, SkeletonText, Sparkline, Spinner, Stack, StarIcon, StatusDot, StatusPill2 as StatusPill, StepContent, StepIndicator, StepLabel, Stepper, Step as StepperStep, StrengthTrendChart, SupersetWrapper, Surface, SvgIcon, Switch, TEMPO_PACING, Tab, TabList, TabPanel, TabPanels, Table, TableBody, TableCell, TableHeader, TableHeaderCell, TablePagination, TableRow, Tabs, TempoBar, TempoDisplay, Tile, TimerReadout, Toast, ToastProvider, ToolbarButton, ToolbarButtonGroup, Tooltip, TopBar, Treemap, TrendingDownIcon, Typography, VStack, VelocityStrip, VoltrasMark, VolumeLandmarkBar, WeekRow, WeightBadge, WorkoutCard, WorkoutPill, ZoneTrack, alpha, applyThemePreset, audiobookPreset, bestTextColor, buttonSizes, calculateMeanVelocity, calculateVelocityLoss, categoricalPalette, cn, componentElevationRanges, composeValidators, createFieldId, createFlatShadow, createPressedHoverShadow, createPressedShadow, createRaisedHoverShadow, createRaisedShadow, darkThemeCSSVars, darken, defaultNavItems, defaultPreset, discreteRainbow, divergingScale, elevationSystem, formatDateTime, formatDuration, formatPrescription, formatSignedPct, formatVelocity, getBaseSurfaceColor, getCategoricalColor, getContrastText, getDiscreteRainbowColor, getElevationConfig, getElevationShadow, getElevationSurface, getFieldAriaProps, getFieldValidationProps, getGlowShadow, getHoverColors, getLuminance, getResultColor, getSemanticColors, getStatusColor, getTempoFillPct, getTempoPacingState, getThemeCSSVars, getValidatedElevation, getVelocityZoneColor, getVelocityZoneName, gluestackConfig, hasMaxLength, hasMinLength, hexToRgb, hsvToRgb, isCssPropertyManifest, isDark, isEmpty, isValidEmail, lightThemeCSSVars, lighten, linearGradient, liveAuraColor, neumorphicShadows, paceTone, paceToneColor, primitiveBorderRadius, primitiveBreakpoints, primitiveColors, primitiveRamps, primitiveShadows, primitiveSpacing, primitiveTypography, primitiveZIndex, resolveColor, resolveIndicator, rgbToHex, rgbToHsv, roundRpe, roundTempo, roundWeight, rpeColor, semanticColorsDark, semanticColorsLight, semanticTypography, sequentialEffort, shadowColors, statusPillColor, surfaceGradient, useTable, useTimer, useToast, useToolbarButton, validateCssPropertyManifest, validationRules, velocityZoneColor };
|
|
12826
14670
|
//# sourceMappingURL=index.mjs.map
|
|
12827
14671
|
//# sourceMappingURL=index.mjs.map
|