@titan-design/react-ui 0.7.0 → 0.9.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/index.d.mts +112 -55
- package/dist/index.d.ts +112 -55
- package/dist/index.js +795 -501
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +795 -498
- package/dist/index.mjs.map +1 -1
- package/dist/{pages-8u_4WbL-.d.mts → pages-D7hOD4Vj.d.mts} +17 -8
- package/dist/{pages-DaWiBOGa.d.ts → pages-DyEx-lBf.d.ts} +17 -8
- package/dist/pages.d.mts +1 -1
- package/dist/pages.d.ts +1 -1
- package/dist/pages.js +691 -250
- package/dist/pages.js.map +1 -1
- package/dist/pages.mjs +692 -251
- package/dist/pages.mjs.map +1 -1
- package/package.json +1 -1
- 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/Workout/ExerciseIndicator.tsx +1 -1
- package/src/components/custom/Workout/FatigueMeter.stories.tsx +2 -2
- package/src/components/custom/Workout/FatigueMeter.test.tsx +12 -0
- package/src/components/custom/Workout/FatigueMeter.tsx +7 -3
- package/src/components/custom/Workout/README.md +70 -3
- package/src/components/custom/Workout/RestTimer.stories.tsx +132 -2
- package/src/components/custom/Workout/RestTimer.test.tsx +73 -0
- package/src/components/custom/Workout/RestTimer.tsx +141 -50
- package/src/components/custom/Workout/SetsRepsLoad.test.tsx +6 -0
- package/src/components/custom/Workout/SetsRepsLoad.tsx +15 -6
- package/src/components/custom/Workout/TempoDisplay.stories.tsx +240 -65
- package/src/components/custom/Workout/TempoDisplay.test.tsx +61 -16
- package/src/components/custom/Workout/TempoDisplay.tsx +173 -60
- package/src/components/custom/Workout/VelocityStrip.stories.tsx +152 -9
- package/src/components/custom/Workout/VelocityStrip.test.tsx +67 -3
- package/src/components/custom/Workout/VelocityStrip.tsx +323 -42
- package/src/components/custom/Workout/ZoneTrack.stories.tsx +2 -3
- package/src/components/custom/Workout/ZoneTrack.test.tsx +34 -0
- package/src/components/custom/Workout/ZoneTrack.tsx +91 -19
- package/src/components/custom/Workout/index.ts +1 -9
- package/src/components/custom/index.ts +1 -0
- package/src/components/ui/alert/Alert.stories.tsx +85 -2
- package/src/components/ui/alert/Alert.test.tsx +52 -0
- package/src/components/ui/alert/Alert.tsx +54 -20
- package/src/components/ui/progress/Progress.tsx +47 -22
- package/src/lab/north-star/LivePage.tsx +101 -0
- package/src/lab/north-star/LiveView.tsx +409 -0
- package/src/lab/north-star/LiveWallDashboard.stories.tsx +129 -0
- package/src/lab/north-star/RestView.tsx +140 -0
- package/src/lab/north-star/fixtures.ts +224 -0
- package/src/components/custom/Workout/TempoBar.stories.tsx +0 -95
- package/src/components/custom/Workout/TempoBar.test.tsx +0 -103
- package/src/components/custom/Workout/TempoBar.tsx +0 -215
package/dist/pages.js
CHANGED
|
@@ -35,6 +35,8 @@ var primitiveColors = {
|
|
|
35
35
|
900: "#111827"},
|
|
36
36
|
// Charcoal scale (dark backgrounds)
|
|
37
37
|
charcoal: {
|
|
38
|
+
0: "#6E6E6E",
|
|
39
|
+
100: "#4C4C4C",
|
|
38
40
|
200: "#3C3C3C",
|
|
39
41
|
300: "#2C2C2C",
|
|
40
42
|
400: "#1F1F1F",
|
|
@@ -76,6 +78,7 @@ var primitiveRamps = {
|
|
|
76
78
|
500: "#22A444",
|
|
77
79
|
600: "#298732"},
|
|
78
80
|
cyan: {
|
|
81
|
+
300: "#22D3EE",
|
|
79
82
|
// pin
|
|
80
83
|
400: "#01B5D1",
|
|
81
84
|
500: "#2697B7",
|
|
@@ -90,6 +93,7 @@ var primitiveRamps = {
|
|
|
90
93
|
// pin
|
|
91
94
|
600: "#1072CB"},
|
|
92
95
|
magenta: {
|
|
96
|
+
400: "#ED69C3",
|
|
93
97
|
600: "#BA2996"}
|
|
94
98
|
};
|
|
95
99
|
var sequentialEffort = [
|
|
@@ -606,8 +610,18 @@ var EXPANDED_ENCODED_PCT = 45;
|
|
|
606
610
|
var EXPANDED_HEIGHT = 60;
|
|
607
611
|
var FIXED_MAX_VELOCITY = 1.15;
|
|
608
612
|
var BARE_STUB_HEIGHT = 3;
|
|
613
|
+
var HERO_HEIGHT = 220;
|
|
614
|
+
var HERO_LABEL_HEADROOM = 20;
|
|
615
|
+
var HERO_BAR_GAP = 8;
|
|
616
|
+
var HERO_BAR_MAX_WIDTH = 120;
|
|
617
|
+
var HERO_LABEL_MIN_BAR_WIDTH = 30;
|
|
618
|
+
var HERO_BAR_RADIUS = 5;
|
|
619
|
+
var HERO_MIN_BAR_HEIGHT = 4;
|
|
620
|
+
var HERO_PENDING_COLOR = primitiveColors.charcoal[100];
|
|
621
|
+
var HERO_REFERENCE_COLOR = primitiveColors.charcoal[0];
|
|
622
|
+
var PEAK_HEADROOM = 1.06;
|
|
609
623
|
function scaleDenominator(scale, maxVelocity) {
|
|
610
|
-
return scale === "fixed" ? FIXED_MAX_VELOCITY : maxVelocity *
|
|
624
|
+
return scale === "fixed" ? FIXED_MAX_VELOCITY : maxVelocity * PEAK_HEADROOM;
|
|
611
625
|
}
|
|
612
626
|
function bareSlotHeight(slot, height, denom) {
|
|
613
627
|
if (slot.kind !== "rep" || denom <= 0) return BARE_STUB_HEIGHT;
|
|
@@ -633,6 +647,195 @@ function usePrefersReducedMotion() {
|
|
|
633
647
|
var ANIMATION_DURATION = 400;
|
|
634
648
|
var ANIMATION_EASING = reactNative.Easing.bezier(0.22, 1, 0.36, 1);
|
|
635
649
|
var POP_EASING = reactNative.Easing.bezier(0.34, 1.56, 0.64, 1);
|
|
650
|
+
function useLiveRepPop(active, liveRepIndex, liveVelocity, isNewPeak) {
|
|
651
|
+
const prefersReducedMotion = usePrefersReducedMotion();
|
|
652
|
+
const [liveScale] = react.useState(() => new reactNative.Animated.Value(1));
|
|
653
|
+
react.useEffect(() => {
|
|
654
|
+
if (!active || liveRepIndex == null || liveVelocity == null) return;
|
|
655
|
+
if (prefersReducedMotion) {
|
|
656
|
+
liveScale.setValue(1);
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
if (isNewPeak) {
|
|
660
|
+
liveScale.setValue(1);
|
|
661
|
+
reactNative.Animated.sequence([
|
|
662
|
+
reactNative.Animated.timing(liveScale, {
|
|
663
|
+
toValue: 1.25,
|
|
664
|
+
duration: 150,
|
|
665
|
+
easing: reactNative.Easing.out(reactNative.Easing.quad),
|
|
666
|
+
useNativeDriver: true
|
|
667
|
+
}),
|
|
668
|
+
reactNative.Animated.spring(liveScale, {
|
|
669
|
+
toValue: 1,
|
|
670
|
+
friction: 3,
|
|
671
|
+
tension: 140,
|
|
672
|
+
useNativeDriver: true
|
|
673
|
+
})
|
|
674
|
+
]).start();
|
|
675
|
+
} else {
|
|
676
|
+
liveScale.setValue(0.8);
|
|
677
|
+
reactNative.Animated.timing(liveScale, {
|
|
678
|
+
toValue: 1,
|
|
679
|
+
duration: 300,
|
|
680
|
+
easing: POP_EASING,
|
|
681
|
+
useNativeDriver: true
|
|
682
|
+
}).start();
|
|
683
|
+
}
|
|
684
|
+
}, [active, liveRepIndex, liveVelocity, isNewPeak, prefersReducedMotion, liveScale]);
|
|
685
|
+
return liveScale;
|
|
686
|
+
}
|
|
687
|
+
function HeroVelocityChart({
|
|
688
|
+
doneVelocities,
|
|
689
|
+
barColorFor,
|
|
690
|
+
scaleDenom,
|
|
691
|
+
referenceVelocity,
|
|
692
|
+
liveRepIndex,
|
|
693
|
+
isNewPeak,
|
|
694
|
+
targetReps,
|
|
695
|
+
height,
|
|
696
|
+
className,
|
|
697
|
+
viewProps
|
|
698
|
+
}) {
|
|
699
|
+
const liveVelocity = liveRepIndex != null ? doneVelocities[liveRepIndex] : void 0;
|
|
700
|
+
const liveScale = useLiveRepPop(true, liveRepIndex, liveVelocity, isNewPeak);
|
|
701
|
+
const [plotW, setPlotW] = react.useState(0);
|
|
702
|
+
const onPlotLayout = (e) => setPlotW(e.nativeEvent.layout.width);
|
|
703
|
+
const plotHeight = Math.max(0, height - HERO_LABEL_HEADROOM);
|
|
704
|
+
const barHeight = (velocity) => scaleDenom > 0 ? Math.max(HERO_MIN_BAR_HEIGHT, Math.min(1, velocity / scaleDenom) * plotHeight) : HERO_MIN_BAR_HEIGHT;
|
|
705
|
+
const pendingCount = Math.max(0, (targetReps ?? 0) - doneVelocities.length);
|
|
706
|
+
const referencePx = referenceVelocity > 0 && scaleDenom > 0 ? Math.min(plotHeight, referenceVelocity / scaleDenom * plotHeight) : 0;
|
|
707
|
+
const totalSlots = doneVelocities.length + pendingCount;
|
|
708
|
+
const barWidth = plotW > 0 && totalSlots > 0 ? Math.min(HERO_BAR_MAX_WIDTH, (plotW - HERO_BAR_GAP * (totalSlots - 1)) / totalSlots) : HERO_BAR_MAX_WIDTH;
|
|
709
|
+
const labelsCrowded = plotW > 0 && barWidth < HERO_LABEL_MIN_BAR_WIDTH;
|
|
710
|
+
const heroGap = plotW === 0 ? HERO_BAR_GAP : barWidth < 16 ? 2 : barWidth < 28 ? 4 : HERO_BAR_GAP;
|
|
711
|
+
const peakIndex = doneVelocities.reduce(
|
|
712
|
+
(best, v, i) => v > doneVelocities[best] ? i : best,
|
|
713
|
+
0
|
|
714
|
+
);
|
|
715
|
+
const showBarLabel = (i) => !labelsCrowded || i === peakIndex || i === liveRepIndex;
|
|
716
|
+
const repCount = doneVelocities.length;
|
|
717
|
+
const total = Math.max(repCount, targetReps ?? repCount);
|
|
718
|
+
const label = referenceVelocity > 0 ? `Velocity chart, ${repCount} of ${total} reps, best ${formatVelocity(referenceVelocity)} meters per second` : `Velocity chart, ${repCount} of ${total} reps`;
|
|
719
|
+
const { style: externalStyle, ...restProps } = viewProps;
|
|
720
|
+
return /* @__PURE__ */ jsx(
|
|
721
|
+
reactNative.View,
|
|
722
|
+
{
|
|
723
|
+
className,
|
|
724
|
+
style: [{ height }, externalStyle],
|
|
725
|
+
accessibilityRole: "image",
|
|
726
|
+
accessibilityLabel: label,
|
|
727
|
+
testID: "velocity-strip-hero",
|
|
728
|
+
...restProps,
|
|
729
|
+
children: /* @__PURE__ */ jsxs(
|
|
730
|
+
reactNative.View,
|
|
731
|
+
{
|
|
732
|
+
onLayout: onPlotLayout,
|
|
733
|
+
style: {
|
|
734
|
+
flex: 1,
|
|
735
|
+
flexDirection: "row",
|
|
736
|
+
alignItems: "flex-end",
|
|
737
|
+
gap: heroGap,
|
|
738
|
+
position: "relative",
|
|
739
|
+
borderBottomWidth: 2,
|
|
740
|
+
borderBottomColor: HERO_PENDING_COLOR
|
|
741
|
+
},
|
|
742
|
+
children: [
|
|
743
|
+
referencePx > 0 && /* @__PURE__ */ jsx(
|
|
744
|
+
reactNative.View,
|
|
745
|
+
{
|
|
746
|
+
accessibilityElementsHidden: true,
|
|
747
|
+
style: {
|
|
748
|
+
position: "absolute",
|
|
749
|
+
left: 0,
|
|
750
|
+
right: 0,
|
|
751
|
+
bottom: referencePx,
|
|
752
|
+
borderTopWidth: 1,
|
|
753
|
+
borderStyle: "dashed",
|
|
754
|
+
borderColor: HERO_REFERENCE_COLOR,
|
|
755
|
+
pointerEvents: "none"
|
|
756
|
+
},
|
|
757
|
+
testID: "velocity-hero-reference"
|
|
758
|
+
}
|
|
759
|
+
),
|
|
760
|
+
doneVelocities.map((velocity, i) => {
|
|
761
|
+
const isLive = liveRepIndex === i;
|
|
762
|
+
return /* @__PURE__ */ jsxs(
|
|
763
|
+
reactNative.View,
|
|
764
|
+
{
|
|
765
|
+
accessibilityElementsHidden: true,
|
|
766
|
+
style: {
|
|
767
|
+
flex: 1,
|
|
768
|
+
maxWidth: HERO_BAR_MAX_WIDTH,
|
|
769
|
+
height: "100%",
|
|
770
|
+
alignItems: "center",
|
|
771
|
+
justifyContent: "flex-end"
|
|
772
|
+
},
|
|
773
|
+
children: [
|
|
774
|
+
showBarLabel(i) && /* @__PURE__ */ jsx(
|
|
775
|
+
reactNative.Text,
|
|
776
|
+
{
|
|
777
|
+
className: "text-text-primary",
|
|
778
|
+
style: { fontSize: 12, fontWeight: "800", marginBottom: 4 },
|
|
779
|
+
testID: `velocity-label-${i}`,
|
|
780
|
+
children: formatVelocity(velocity)
|
|
781
|
+
}
|
|
782
|
+
),
|
|
783
|
+
/* @__PURE__ */ jsx(
|
|
784
|
+
reactNative.Animated.View,
|
|
785
|
+
{
|
|
786
|
+
style: [
|
|
787
|
+
{
|
|
788
|
+
width: "100%",
|
|
789
|
+
height: barHeight(velocity),
|
|
790
|
+
borderTopLeftRadius: HERO_BAR_RADIUS,
|
|
791
|
+
borderTopRightRadius: HERO_BAR_RADIUS,
|
|
792
|
+
backgroundColor: barColorFor(velocity)
|
|
793
|
+
},
|
|
794
|
+
isLive ? { transform: [{ scale: liveScale }] } : null
|
|
795
|
+
],
|
|
796
|
+
testID: `velocity-bar-${i}`
|
|
797
|
+
}
|
|
798
|
+
)
|
|
799
|
+
]
|
|
800
|
+
},
|
|
801
|
+
i
|
|
802
|
+
);
|
|
803
|
+
}),
|
|
804
|
+
Array.from({ length: pendingCount }, (_, i) => /* @__PURE__ */ jsx(
|
|
805
|
+
reactNative.View,
|
|
806
|
+
{
|
|
807
|
+
accessibilityElementsHidden: true,
|
|
808
|
+
style: {
|
|
809
|
+
flex: 1,
|
|
810
|
+
maxWidth: HERO_BAR_MAX_WIDTH,
|
|
811
|
+
height: "100%",
|
|
812
|
+
alignItems: "center",
|
|
813
|
+
justifyContent: "flex-end"
|
|
814
|
+
},
|
|
815
|
+
children: /* @__PURE__ */ jsx(
|
|
816
|
+
reactNative.View,
|
|
817
|
+
{
|
|
818
|
+
style: {
|
|
819
|
+
width: "100%",
|
|
820
|
+
height: HERO_MIN_BAR_HEIGHT * 3,
|
|
821
|
+
borderWidth: 1,
|
|
822
|
+
borderStyle: "dashed",
|
|
823
|
+
borderColor: HERO_PENDING_COLOR,
|
|
824
|
+
borderTopLeftRadius: HERO_BAR_RADIUS,
|
|
825
|
+
borderTopRightRadius: HERO_BAR_RADIUS
|
|
826
|
+
},
|
|
827
|
+
testID: "velocity-slot-todo"
|
|
828
|
+
}
|
|
829
|
+
)
|
|
830
|
+
},
|
|
831
|
+
`pending-${i}`
|
|
832
|
+
))
|
|
833
|
+
]
|
|
834
|
+
}
|
|
835
|
+
)
|
|
836
|
+
}
|
|
837
|
+
);
|
|
838
|
+
}
|
|
636
839
|
function VelocityStrip({
|
|
637
840
|
velocities,
|
|
638
841
|
set,
|
|
@@ -643,6 +846,7 @@ function VelocityStrip({
|
|
|
643
846
|
onRepPress,
|
|
644
847
|
variant = "expanded",
|
|
645
848
|
height = EXPANDED_HEIGHT,
|
|
849
|
+
targetReps,
|
|
646
850
|
scale = "peak",
|
|
647
851
|
showNumbers = true,
|
|
648
852
|
showInfo = true,
|
|
@@ -668,45 +872,17 @@ function VelocityStrip({
|
|
|
668
872
|
return SET_STRIP_VARIABLE_COLOR;
|
|
669
873
|
};
|
|
670
874
|
const meanZone = hasZones ? classifyBand(meanVelocity, zones)?.label ?? "" : getVelocityZoneName(meanVelocity);
|
|
671
|
-
const prefersReducedMotion = usePrefersReducedMotion();
|
|
672
875
|
const [heightAnim] = react.useState(() => new reactNative.Animated.Value(expanded ? height : 3));
|
|
673
876
|
const [labelOpacity] = react.useState(() => new reactNative.Animated.Value(expanded ? 1 : 0));
|
|
674
877
|
const [infoOpacity] = react.useState(() => new reactNative.Animated.Value(expanded ? 1 : 0));
|
|
675
|
-
const [liveScale] = react.useState(() => new reactNative.Animated.Value(1));
|
|
676
878
|
const liveVelocity = liveRepIndex != null ? doneVelocities[liveRepIndex] : void 0;
|
|
677
879
|
const isNewPeak = liveVelocity != null && maxVelocity > 0 && liveVelocity === maxVelocity;
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
if (isNewPeak) {
|
|
685
|
-
liveScale.setValue(1);
|
|
686
|
-
reactNative.Animated.sequence([
|
|
687
|
-
reactNative.Animated.timing(liveScale, {
|
|
688
|
-
toValue: 1.25,
|
|
689
|
-
duration: 150,
|
|
690
|
-
easing: reactNative.Easing.out(reactNative.Easing.quad),
|
|
691
|
-
useNativeDriver: true
|
|
692
|
-
}),
|
|
693
|
-
reactNative.Animated.spring(liveScale, {
|
|
694
|
-
toValue: 1,
|
|
695
|
-
friction: 3,
|
|
696
|
-
tension: 140,
|
|
697
|
-
useNativeDriver: true
|
|
698
|
-
})
|
|
699
|
-
]).start();
|
|
700
|
-
} else {
|
|
701
|
-
liveScale.setValue(0.8);
|
|
702
|
-
reactNative.Animated.timing(liveScale, {
|
|
703
|
-
toValue: 1,
|
|
704
|
-
duration: 300,
|
|
705
|
-
easing: POP_EASING,
|
|
706
|
-
useNativeDriver: true
|
|
707
|
-
}).start();
|
|
708
|
-
}
|
|
709
|
-
}, [variant, framed, liveRepIndex, liveVelocity, isNewPeak, prefersReducedMotion, liveScale]);
|
|
880
|
+
const liveScale = useLiveRepPop(
|
|
881
|
+
variant === "expanded" && framed,
|
|
882
|
+
liveRepIndex,
|
|
883
|
+
liveVelocity,
|
|
884
|
+
isNewPeak
|
|
885
|
+
);
|
|
710
886
|
react.useEffect(() => {
|
|
711
887
|
if (variant !== "expanded" || !framed) return;
|
|
712
888
|
reactNative.Animated.parallel([
|
|
@@ -733,6 +909,24 @@ function VelocityStrip({
|
|
|
733
909
|
if (set == null && velocities == null) return null;
|
|
734
910
|
const repCount = doneVelocities.length;
|
|
735
911
|
const miniLabel = set ? setAccessibilityLabel(set, repCount) : `Velocity strip, ${repCount} reps`;
|
|
912
|
+
if (variant === "hero") {
|
|
913
|
+
const heroHeight = height === EXPANDED_HEIGHT ? HERO_HEIGHT : height;
|
|
914
|
+
return /* @__PURE__ */ jsx(
|
|
915
|
+
HeroVelocityChart,
|
|
916
|
+
{
|
|
917
|
+
doneVelocities,
|
|
918
|
+
barColorFor,
|
|
919
|
+
scaleDenom,
|
|
920
|
+
referenceVelocity: maxVelocity,
|
|
921
|
+
liveRepIndex,
|
|
922
|
+
isNewPeak,
|
|
923
|
+
targetReps,
|
|
924
|
+
height: heroHeight,
|
|
925
|
+
className,
|
|
926
|
+
viewProps: props
|
|
927
|
+
}
|
|
928
|
+
);
|
|
929
|
+
}
|
|
736
930
|
if (variant === "mini") {
|
|
737
931
|
const { style: externalStyle, ...restProps } = props;
|
|
738
932
|
return /* @__PURE__ */ jsx(
|
|
@@ -1776,6 +1970,7 @@ function SetsRepsLoad({
|
|
|
1776
1970
|
reps,
|
|
1777
1971
|
load,
|
|
1778
1972
|
unit = "lb",
|
|
1973
|
+
fontSize,
|
|
1779
1974
|
className,
|
|
1780
1975
|
...props
|
|
1781
1976
|
}) {
|
|
@@ -1790,12 +1985,12 @@ function SetsRepsLoad({
|
|
|
1790
1985
|
testID: "sets-reps-load",
|
|
1791
1986
|
...props,
|
|
1792
1987
|
children: [
|
|
1793
|
-
/* @__PURE__ */ jsx(MetricCell, { color: value, children: sets }),
|
|
1794
|
-
/* @__PURE__ */ jsx(MetricCell, { color: sep, children: ` ${TIMES} ` }),
|
|
1795
|
-
/* @__PURE__ */ jsx(MetricCell, { color: value, children: reps }),
|
|
1796
|
-
/* @__PURE__ */ jsx(MetricCell, { color: sep, children: ` ${AT} ` }),
|
|
1797
|
-
/* @__PURE__ */ jsx(MetricCell, { color: value, children: load }),
|
|
1798
|
-
/* @__PURE__ */ jsx(MetricCell, { color: sep, children: ` ${unit}` })
|
|
1988
|
+
/* @__PURE__ */ jsx(MetricCell, { color: value, fontSize, children: sets }),
|
|
1989
|
+
/* @__PURE__ */ jsx(MetricCell, { color: sep, fontSize, children: ` ${TIMES} ` }),
|
|
1990
|
+
/* @__PURE__ */ jsx(MetricCell, { color: value, fontSize, children: reps }),
|
|
1991
|
+
/* @__PURE__ */ jsx(MetricCell, { color: sep, fontSize, children: ` ${AT} ` }),
|
|
1992
|
+
/* @__PURE__ */ jsx(MetricCell, { color: value, fontSize, children: load }),
|
|
1993
|
+
/* @__PURE__ */ jsx(MetricCell, { color: sep, fontSize, children: ` ${unit}` })
|
|
1799
1994
|
]
|
|
1800
1995
|
}
|
|
1801
1996
|
);
|
|
@@ -2109,36 +2304,34 @@ function alpha(color, opacity) {
|
|
|
2109
2304
|
}
|
|
2110
2305
|
return color;
|
|
2111
2306
|
}
|
|
2307
|
+
|
|
2308
|
+
// src/components/custom/Workout/TempoDisplay.tsx
|
|
2112
2309
|
var t2 = getSemanticColors("dark");
|
|
2113
|
-
var
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
const ratio = elapsedMs / targetMs;
|
|
2120
|
-
if (ratio > 1 + TEMPO_PACING.behindThresholdPct) return "behind";
|
|
2121
|
-
return "on-pace";
|
|
2122
|
-
}
|
|
2310
|
+
var INTER = "Inter, sans-serif";
|
|
2311
|
+
var TEXT_TERTIARY = "#6B7280";
|
|
2312
|
+
var STATUS_ERROR = t2["status-error"];
|
|
2313
|
+
var STATUS_SUCCESS = t2["status-success"];
|
|
2314
|
+
var STATUS_WARNING = t2["status-warning"];
|
|
2315
|
+
var ON_TARGET_MS = 100;
|
|
2123
2316
|
function getTempoFillPct(elapsedMs, targetMs) {
|
|
2124
2317
|
if (!targetMs) return 100;
|
|
2125
2318
|
return Math.min(100, elapsedMs / targetMs * 100);
|
|
2126
2319
|
}
|
|
2127
|
-
({
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2320
|
+
function activeNumberTone(elapsedMs, targetMs) {
|
|
2321
|
+
if (targetMs == null) return t2["text-primary"];
|
|
2322
|
+
const remainingMs = targetMs - elapsedMs;
|
|
2323
|
+
if (remainingMs > ON_TARGET_MS) return STATUS_WARNING;
|
|
2324
|
+
if (remainingMs >= -ON_TARGET_MS) return STATUS_SUCCESS;
|
|
2325
|
+
return STATUS_ERROR;
|
|
2326
|
+
}
|
|
2327
|
+
function liveReadoutText(elapsedMs, targetMs, readout) {
|
|
2328
|
+
const seconds = readout === "countup" ? elapsedMs / 1e3 : (targetMs - elapsedMs) / 1e3;
|
|
2329
|
+
return seconds.toFixed(1);
|
|
2330
|
+
}
|
|
2138
2331
|
var phaseColors = {
|
|
2139
|
-
eccentric:
|
|
2332
|
+
eccentric: primitiveRamps.magenta[400],
|
|
2140
2333
|
pauseBottom: TEXT_TERTIARY,
|
|
2141
|
-
concentric:
|
|
2334
|
+
concentric: primitiveRamps.cyan[300],
|
|
2142
2335
|
pauseTop: TEXT_TERTIARY,
|
|
2143
2336
|
dash: TEXT_TERTIARY
|
|
2144
2337
|
};
|
|
@@ -2158,63 +2351,98 @@ var LIVE_PHASES = [
|
|
|
2158
2351
|
{ key: "concentric", color: phaseColors.concentric },
|
|
2159
2352
|
{ key: "pauseTop", color: phaseColors.pauseTop }
|
|
2160
2353
|
];
|
|
2354
|
+
function CellFill({ color, pct }) {
|
|
2355
|
+
return /* @__PURE__ */ jsx(
|
|
2356
|
+
reactNative.View,
|
|
2357
|
+
{
|
|
2358
|
+
style: {
|
|
2359
|
+
position: "absolute",
|
|
2360
|
+
left: 2,
|
|
2361
|
+
right: 2,
|
|
2362
|
+
bottom: 0,
|
|
2363
|
+
height: `${pct}%`,
|
|
2364
|
+
backgroundColor: alpha(color, 0.28),
|
|
2365
|
+
borderRadius: 3
|
|
2366
|
+
}
|
|
2367
|
+
}
|
|
2368
|
+
);
|
|
2369
|
+
}
|
|
2370
|
+
var MONO = "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace";
|
|
2371
|
+
var READOUT_MAX_CHARS = 5;
|
|
2161
2372
|
function LiveTempoCell({
|
|
2162
2373
|
value,
|
|
2163
2374
|
color,
|
|
2164
|
-
|
|
2375
|
+
status,
|
|
2165
2376
|
phaseElapsedMs,
|
|
2166
|
-
|
|
2377
|
+
completedMs,
|
|
2378
|
+
fontSize,
|
|
2379
|
+
readout
|
|
2167
2380
|
}) {
|
|
2168
|
-
if (!isActive) {
|
|
2169
|
-
return /* @__PURE__ */ jsx(TempoValue, { value, color: alpha(color, 0.35), fontSize });
|
|
2170
|
-
}
|
|
2171
2381
|
const targetMs = value > 0 ? value * 1e3 : null;
|
|
2172
|
-
const
|
|
2382
|
+
const cellW = Math.ceil(fontSize * 0.62 * READOUT_MAX_CHARS);
|
|
2383
|
+
const wrap = {
|
|
2384
|
+
position: "relative",
|
|
2385
|
+
width: cellW,
|
|
2386
|
+
minHeight: Math.round(fontSize * 1.25),
|
|
2387
|
+
alignItems: "center",
|
|
2388
|
+
justifyContent: "center"
|
|
2389
|
+
};
|
|
2390
|
+
const num = (c, text) => /* @__PURE__ */ jsx(reactNative.Text, { style: { fontFamily: MONO, fontSize, color: c, fontWeight: "700" }, children: text });
|
|
2391
|
+
if (status === "upcoming") {
|
|
2392
|
+
const targetText = targetMs != null ? (targetMs / 1e3).toFixed(1) : String(value);
|
|
2393
|
+
return /* @__PURE__ */ jsx(reactNative.View, { style: wrap, children: num(color, targetText) });
|
|
2394
|
+
}
|
|
2395
|
+
if (status === "done") {
|
|
2396
|
+
const finalMs = completedMs ?? targetMs ?? 0;
|
|
2397
|
+
const finalText = targetMs != null ? liveReadoutText(finalMs, targetMs, readout) : String(value);
|
|
2398
|
+
const finalTone = targetMs != null ? activeNumberTone(finalMs, targetMs) : color;
|
|
2399
|
+
return /* @__PURE__ */ jsxs(reactNative.View, { style: wrap, testID: "tempo-live-done", children: [
|
|
2400
|
+
/* @__PURE__ */ jsx(CellFill, { color, pct: 100 }),
|
|
2401
|
+
num(finalTone, finalText)
|
|
2402
|
+
] });
|
|
2403
|
+
}
|
|
2404
|
+
const numberTone = activeNumberTone(phaseElapsedMs, targetMs);
|
|
2173
2405
|
const fillPct = getTempoFillPct(phaseElapsedMs, targetMs);
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
style: {
|
|
2179
|
-
position: "absolute",
|
|
2180
|
-
left: 0,
|
|
2181
|
-
top: 0,
|
|
2182
|
-
bottom: 0,
|
|
2183
|
-
width: `${fillPct}%`,
|
|
2184
|
-
backgroundColor: alpha(barColor, 0.3),
|
|
2185
|
-
borderRadius: 2
|
|
2186
|
-
}
|
|
2187
|
-
}
|
|
2188
|
-
),
|
|
2189
|
-
/* @__PURE__ */ jsx(TempoValue, { value, color: barColor, fontSize })
|
|
2406
|
+
const activeText = targetMs != null ? liveReadoutText(phaseElapsedMs, targetMs, readout) : String(value);
|
|
2407
|
+
return /* @__PURE__ */ jsxs(reactNative.View, { style: wrap, testID: "tempo-live-active", children: [
|
|
2408
|
+
/* @__PURE__ */ jsx(CellFill, { color, pct: fillPct }),
|
|
2409
|
+
num(numberTone, activeText)
|
|
2190
2410
|
] });
|
|
2191
2411
|
}
|
|
2192
2412
|
function LiveTempoRow({
|
|
2193
2413
|
values,
|
|
2194
2414
|
live,
|
|
2195
|
-
fontSize
|
|
2415
|
+
fontSize,
|
|
2416
|
+
readout
|
|
2196
2417
|
}) {
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
{
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2418
|
+
const activeIndex = live.activePhase ? LIVE_PHASES.findIndex((p) => p.key === live.activePhase) : -1;
|
|
2419
|
+
return /* @__PURE__ */ jsx(jsxRuntime.Fragment, { children: LIVE_PHASES.map((phase, i) => {
|
|
2420
|
+
const status = activeIndex < 0 || i > activeIndex ? "upcoming" : i < activeIndex ? "done" : "active";
|
|
2421
|
+
return /* @__PURE__ */ jsxs(reactNative.View, { style: { flexDirection: "row", alignItems: "center" }, children: [
|
|
2422
|
+
i > 0 && /* @__PURE__ */ jsx(TempoSeparator, { color: phaseColors.dash, fontSize }),
|
|
2423
|
+
/* @__PURE__ */ jsx(
|
|
2424
|
+
LiveTempoCell,
|
|
2425
|
+
{
|
|
2426
|
+
value: values[i],
|
|
2427
|
+
color: phase.color,
|
|
2428
|
+
status,
|
|
2429
|
+
phaseElapsedMs: live.phaseElapsedMs,
|
|
2430
|
+
completedMs: live.completed?.[phase.key],
|
|
2431
|
+
fontSize,
|
|
2432
|
+
readout
|
|
2433
|
+
}
|
|
2434
|
+
)
|
|
2435
|
+
] }, phase.key);
|
|
2436
|
+
}) });
|
|
2210
2437
|
}
|
|
2211
2438
|
function TempoDisplay({
|
|
2212
2439
|
tempo,
|
|
2213
2440
|
size = "md",
|
|
2214
|
-
|
|
2441
|
+
fontSize: fontSizeProp,
|
|
2215
2442
|
showLabel = true,
|
|
2216
2443
|
showInfo = true,
|
|
2217
2444
|
live,
|
|
2445
|
+
liveReadout = "countdown",
|
|
2218
2446
|
onPress,
|
|
2219
2447
|
className,
|
|
2220
2448
|
...props
|
|
@@ -2222,8 +2450,11 @@ function TempoDisplay({
|
|
|
2222
2450
|
const [showTooltip, setShowTooltip] = react.useState(false);
|
|
2223
2451
|
const [eccentric, pauseBottom, concentric, pauseTop] = roundTempo(tempo);
|
|
2224
2452
|
const isSm = size === "sm";
|
|
2225
|
-
const fontSize = isSm ? 9 : 11;
|
|
2226
|
-
const
|
|
2453
|
+
const fontSize = fontSizeProp ?? (isSm ? 9 : 11);
|
|
2454
|
+
const chromePadX = Math.round(fontSize * 0.6);
|
|
2455
|
+
const chromePadY = Math.round(fontSize * 0.3);
|
|
2456
|
+
const chromeRadius = Math.round(fontSize * 0.4);
|
|
2457
|
+
const labelFont = Math.max(9, Math.round(fontSize * 0.5));
|
|
2227
2458
|
const handlePress = react.useCallback(() => {
|
|
2228
2459
|
if (onPress) {
|
|
2229
2460
|
onPress();
|
|
@@ -2240,9 +2471,9 @@ function TempoDisplay({
|
|
|
2240
2471
|
flexDirection: "row",
|
|
2241
2472
|
alignItems: "center",
|
|
2242
2473
|
backgroundColor: "#1C1C1C",
|
|
2243
|
-
paddingHorizontal:
|
|
2244
|
-
paddingVertical:
|
|
2245
|
-
borderRadius:
|
|
2474
|
+
paddingHorizontal: chromePadX,
|
|
2475
|
+
paddingVertical: chromePadY,
|
|
2476
|
+
borderRadius: chromeRadius
|
|
2246
2477
|
},
|
|
2247
2478
|
...props,
|
|
2248
2479
|
children: [
|
|
@@ -2251,12 +2482,13 @@ function TempoDisplay({
|
|
|
2251
2482
|
{
|
|
2252
2483
|
style: {
|
|
2253
2484
|
fontFamily: INTER,
|
|
2254
|
-
fontSize:
|
|
2485
|
+
fontSize: labelFont,
|
|
2255
2486
|
fontWeight: "500",
|
|
2256
|
-
|
|
2487
|
+
// Live-muted green while a rep is running, tertiary at rest.
|
|
2488
|
+
color: live ? t2["status-live-muted"] : TEXT_TERTIARY,
|
|
2257
2489
|
letterSpacing: 0.5,
|
|
2258
2490
|
textTransform: "uppercase",
|
|
2259
|
-
marginRight:
|
|
2491
|
+
marginRight: Math.round(fontSize * 0.5)
|
|
2260
2492
|
},
|
|
2261
2493
|
children: "TEMPO"
|
|
2262
2494
|
}
|
|
@@ -2266,36 +2498,20 @@ function TempoDisplay({
|
|
|
2266
2498
|
{
|
|
2267
2499
|
values: [eccentric, pauseBottom, concentric, pauseTop],
|
|
2268
2500
|
live,
|
|
2269
|
-
fontSize
|
|
2270
|
-
|
|
2271
|
-
) : colored ? /* @__PURE__ */ jsxs(jsxRuntime.Fragment, { children: [
|
|
2272
|
-
/* @__PURE__ */ jsx(TempoValue, { value: eccentric, color: phaseColors.eccentric, fontSize }),
|
|
2273
|
-
/* @__PURE__ */ jsx(TempoSeparator, { color: phaseColors.dash, fontSize }),
|
|
2274
|
-
/* @__PURE__ */ jsx(TempoValue, { value: pauseBottom, color: phaseColors.pauseBottom, fontSize }),
|
|
2275
|
-
/* @__PURE__ */ jsx(TempoSeparator, { color: phaseColors.dash, fontSize }),
|
|
2276
|
-
/* @__PURE__ */ jsx(TempoValue, { value: concentric, color: phaseColors.concentric, fontSize }),
|
|
2277
|
-
/* @__PURE__ */ jsx(TempoSeparator, { color: phaseColors.dash, fontSize }),
|
|
2278
|
-
/* @__PURE__ */ jsx(TempoValue, { value: pauseTop, color: phaseColors.pauseTop, fontSize })
|
|
2279
|
-
] }) : /* @__PURE__ */ jsxs(
|
|
2280
|
-
reactNative.Text,
|
|
2281
|
-
{
|
|
2282
|
-
style: {
|
|
2283
|
-
fontFamily: INTER,
|
|
2284
|
-
fontSize,
|
|
2285
|
-
color: monoColor,
|
|
2286
|
-
fontWeight: "600",
|
|
2287
|
-
letterSpacing: 1
|
|
2288
|
-
},
|
|
2289
|
-
children: [
|
|
2290
|
-
eccentric,
|
|
2291
|
-
"-",
|
|
2292
|
-
pauseBottom,
|
|
2293
|
-
"-",
|
|
2294
|
-
concentric,
|
|
2295
|
-
"-",
|
|
2296
|
-
pauseTop
|
|
2297
|
-
]
|
|
2501
|
+
fontSize,
|
|
2502
|
+
readout: liveReadout
|
|
2298
2503
|
}
|
|
2504
|
+
) : (
|
|
2505
|
+
// Static prescription: the phase-coloured lockup (the same colours the live row rests at).
|
|
2506
|
+
/* @__PURE__ */ jsxs(jsxRuntime.Fragment, { children: [
|
|
2507
|
+
/* @__PURE__ */ jsx(TempoValue, { value: eccentric, color: phaseColors.eccentric, fontSize }),
|
|
2508
|
+
/* @__PURE__ */ jsx(TempoSeparator, { color: phaseColors.dash, fontSize }),
|
|
2509
|
+
/* @__PURE__ */ jsx(TempoValue, { value: pauseBottom, color: phaseColors.pauseBottom, fontSize }),
|
|
2510
|
+
/* @__PURE__ */ jsx(TempoSeparator, { color: phaseColors.dash, fontSize }),
|
|
2511
|
+
/* @__PURE__ */ jsx(TempoValue, { value: concentric, color: phaseColors.concentric, fontSize }),
|
|
2512
|
+
/* @__PURE__ */ jsx(TempoSeparator, { color: phaseColors.dash, fontSize }),
|
|
2513
|
+
/* @__PURE__ */ jsx(TempoValue, { value: pauseTop, color: phaseColors.pauseTop, fontSize })
|
|
2514
|
+
] })
|
|
2299
2515
|
) })
|
|
2300
2516
|
]
|
|
2301
2517
|
}
|
|
@@ -2380,14 +2596,14 @@ function TempoDisplay({
|
|
|
2380
2596
|
}
|
|
2381
2597
|
);
|
|
2382
2598
|
}
|
|
2383
|
-
var
|
|
2599
|
+
var t3 = getSemanticColors("dark");
|
|
2384
2600
|
var INDICATOR_CONFIG = {
|
|
2385
|
-
imbalance: { Icon: ScaleIcon, color:
|
|
2386
|
-
overshoot: { Icon: AlertTriangleIcon, color:
|
|
2387
|
-
"velocity-loss": { Icon: TrendingDownIcon, color:
|
|
2388
|
-
"missed-reps": { Icon: CircleSlashIcon, color:
|
|
2389
|
-
pr: { Icon: AwardIcon, color:
|
|
2390
|
-
info: { Icon: InfoIcon, color:
|
|
2601
|
+
imbalance: { Icon: ScaleIcon, color: t3["status-error"], label: "Left/right imbalance" },
|
|
2602
|
+
overshoot: { Icon: AlertTriangleIcon, color: t3["status-error"], label: "Load overshoot" },
|
|
2603
|
+
"velocity-loss": { Icon: TrendingDownIcon, color: t3["status-warning"], label: "Velocity loss" },
|
|
2604
|
+
"missed-reps": { Icon: CircleSlashIcon, color: t3["status-warning"], label: "Missed reps" },
|
|
2605
|
+
pr: { Icon: AwardIcon, color: t3["status-success"], label: "Personal record" },
|
|
2606
|
+
info: { Icon: InfoIcon, color: t3["status-info"], label: "More info" }
|
|
2391
2607
|
};
|
|
2392
2608
|
function ExerciseIndicator({ kind, onPress, className, ...props }) {
|
|
2393
2609
|
const { Icon, color, label } = INDICATOR_CONFIG[kind];
|
|
@@ -2993,9 +3209,270 @@ function useTimer(options = {}) {
|
|
|
2993
3209
|
const done = durationMs != null && elapsedMs >= durationMs;
|
|
2994
3210
|
return { elapsedMs, remainingMs, progress, label, done };
|
|
2995
3211
|
}
|
|
3212
|
+
var colorVarMap = {
|
|
3213
|
+
primary: "var(--color-brand-primary)",
|
|
3214
|
+
secondary: "var(--color-brand-secondary)",
|
|
3215
|
+
success: "var(--color-status-success)",
|
|
3216
|
+
error: "var(--color-status-error)",
|
|
3217
|
+
warning: "var(--color-status-warning)",
|
|
3218
|
+
info: "var(--color-status-info)"
|
|
3219
|
+
};
|
|
3220
|
+
function CircularProgress({
|
|
3221
|
+
value = 0,
|
|
3222
|
+
max = 100,
|
|
3223
|
+
isIndeterminate = false,
|
|
3224
|
+
size = 48,
|
|
3225
|
+
strokeWidth = 4,
|
|
3226
|
+
color = "primary",
|
|
3227
|
+
showValue = false,
|
|
3228
|
+
formatValue: formatValue2 = (v, m) => `${Math.round(v / m * 100)}%`,
|
|
3229
|
+
children,
|
|
3230
|
+
fill = false,
|
|
3231
|
+
className,
|
|
3232
|
+
...props
|
|
3233
|
+
}) {
|
|
3234
|
+
const percentage = Math.min(Math.max(value / max * 100, 0), 100);
|
|
3235
|
+
const radius = (size - strokeWidth) / 2;
|
|
3236
|
+
const circumference = 2 * Math.PI * radius;
|
|
3237
|
+
const strokeDashoffset = circumference - percentage / 100 * circumference;
|
|
3238
|
+
const center = size / 2;
|
|
3239
|
+
const boxStyle = fill ? { width: "100%", aspectRatio: 1 } : { width: size, height: size };
|
|
3240
|
+
return /* @__PURE__ */ jsxs(
|
|
3241
|
+
reactNative.View,
|
|
3242
|
+
{
|
|
3243
|
+
className: cn("items-center justify-center", className),
|
|
3244
|
+
style: boxStyle,
|
|
3245
|
+
accessibilityRole: "progressbar",
|
|
3246
|
+
accessibilityValue: {
|
|
3247
|
+
min: 0,
|
|
3248
|
+
max,
|
|
3249
|
+
now: isIndeterminate ? void 0 : value
|
|
3250
|
+
},
|
|
3251
|
+
...props,
|
|
3252
|
+
children: [
|
|
3253
|
+
/* @__PURE__ */ jsx(reactNative.View, { className: cn(isIndeterminate && "animate-spin"), style: boxStyle, children: /* @__PURE__ */ jsxs(
|
|
3254
|
+
"svg",
|
|
3255
|
+
{
|
|
3256
|
+
width: "100%",
|
|
3257
|
+
height: "100%",
|
|
3258
|
+
viewBox: `0 0 ${size} ${size}`,
|
|
3259
|
+
style: { position: "absolute" },
|
|
3260
|
+
children: [
|
|
3261
|
+
/* @__PURE__ */ jsx(
|
|
3262
|
+
"circle",
|
|
3263
|
+
{
|
|
3264
|
+
cx: center,
|
|
3265
|
+
cy: center,
|
|
3266
|
+
r: radius,
|
|
3267
|
+
fill: "none",
|
|
3268
|
+
stroke: "var(--color-border-default)",
|
|
3269
|
+
strokeWidth
|
|
3270
|
+
}
|
|
3271
|
+
),
|
|
3272
|
+
/* @__PURE__ */ jsx(
|
|
3273
|
+
"circle",
|
|
3274
|
+
{
|
|
3275
|
+
cx: center,
|
|
3276
|
+
cy: center,
|
|
3277
|
+
r: radius,
|
|
3278
|
+
fill: "none",
|
|
3279
|
+
stroke: colorVarMap[color],
|
|
3280
|
+
strokeWidth,
|
|
3281
|
+
strokeLinecap: "round",
|
|
3282
|
+
strokeDasharray: circumference,
|
|
3283
|
+
strokeDashoffset: isIndeterminate ? circumference * 0.75 : strokeDashoffset,
|
|
3284
|
+
transform: `rotate(-90 ${center} ${center})`,
|
|
3285
|
+
style: { transition: "stroke-dashoffset 300ms cubic-bezier(0.22, 1, 0.36, 1)" }
|
|
3286
|
+
}
|
|
3287
|
+
)
|
|
3288
|
+
]
|
|
3289
|
+
}
|
|
3290
|
+
) }),
|
|
3291
|
+
children != null ? /* @__PURE__ */ jsx(
|
|
3292
|
+
reactNative.View,
|
|
3293
|
+
{
|
|
3294
|
+
style: {
|
|
3295
|
+
position: "absolute",
|
|
3296
|
+
alignItems: "center",
|
|
3297
|
+
justifyContent: "center",
|
|
3298
|
+
pointerEvents: "none"
|
|
3299
|
+
},
|
|
3300
|
+
children
|
|
3301
|
+
}
|
|
3302
|
+
) : showValue && !isIndeterminate && /* @__PURE__ */ jsx(
|
|
3303
|
+
reactNative.Text,
|
|
3304
|
+
{
|
|
3305
|
+
className: "text-xs font-semibold text-text-primary absolute",
|
|
3306
|
+
style: { fontSize: Math.max(size * 0.22, 10) },
|
|
3307
|
+
children: formatValue2(value, max)
|
|
3308
|
+
}
|
|
3309
|
+
)
|
|
3310
|
+
]
|
|
3311
|
+
}
|
|
3312
|
+
);
|
|
3313
|
+
}
|
|
3314
|
+
|
|
3315
|
+
// src/components/custom/CircularTimer/CircularTimer.tsx
|
|
3316
|
+
function CircularTimer({
|
|
3317
|
+
durationMs,
|
|
3318
|
+
elapsedMs,
|
|
3319
|
+
mode = "down",
|
|
3320
|
+
size = 160,
|
|
3321
|
+
strokeWidth = 8,
|
|
3322
|
+
fill = false,
|
|
3323
|
+
color = "primary",
|
|
3324
|
+
doneLabel,
|
|
3325
|
+
doneColor = "success",
|
|
3326
|
+
controls,
|
|
3327
|
+
accessibilityLabel: accessibilityLabel2,
|
|
3328
|
+
testID
|
|
3329
|
+
}) {
|
|
3330
|
+
const { remainingMs, progress, label, done } = useTimer({ mode, durationMs, elapsedMs });
|
|
3331
|
+
const isDone = done && mode === "down";
|
|
3332
|
+
const showDone = isDone && doneLabel != null;
|
|
3333
|
+
const remainingFrac = durationMs > 0 ? Math.max(0, Math.min(1, remainingMs / durationMs)) : 0;
|
|
3334
|
+
const arc = mode === "down" ? showDone ? 1 : remainingFrac : progress;
|
|
3335
|
+
const ringColor = showDone ? doneColor : color;
|
|
3336
|
+
const remainingSec = Math.ceil(Math.max(0, remainingMs) / 1e3);
|
|
3337
|
+
const a11y = accessibilityLabel2 ?? (isDone ? "Timer complete" : `${remainingSec} seconds remaining`);
|
|
3338
|
+
return /* @__PURE__ */ jsxs(
|
|
3339
|
+
reactNative.View,
|
|
3340
|
+
{
|
|
3341
|
+
style: { alignItems: "center", gap: 16 },
|
|
3342
|
+
accessibilityRole: "timer",
|
|
3343
|
+
accessibilityLabel: a11y,
|
|
3344
|
+
testID: testID ?? "circular-timer",
|
|
3345
|
+
children: [
|
|
3346
|
+
/* @__PURE__ */ jsx(
|
|
3347
|
+
CircularProgress,
|
|
3348
|
+
{
|
|
3349
|
+
value: arc,
|
|
3350
|
+
max: 1,
|
|
3351
|
+
size,
|
|
3352
|
+
strokeWidth,
|
|
3353
|
+
fill,
|
|
3354
|
+
color: ringColor,
|
|
3355
|
+
accessibilityLabel: "Timer ring",
|
|
3356
|
+
testID: "circular-timer-ring",
|
|
3357
|
+
children: /* @__PURE__ */ jsx(
|
|
3358
|
+
reactNative.Text,
|
|
3359
|
+
{
|
|
3360
|
+
className: showDone ? void 0 : "text-text-primary",
|
|
3361
|
+
style: {
|
|
3362
|
+
fontSize: Math.round(size * (showDone ? 0.28 : 0.24)),
|
|
3363
|
+
fontFamily: '"Space Grotesk", sans-serif',
|
|
3364
|
+
fontWeight: "800",
|
|
3365
|
+
fontVariant: ["tabular-nums"],
|
|
3366
|
+
letterSpacing: showDone ? 1 : -1,
|
|
3367
|
+
...showDone ? { color: colorVarMap[doneColor] } : null
|
|
3368
|
+
},
|
|
3369
|
+
testID: "circular-timer-label",
|
|
3370
|
+
children: showDone ? doneLabel : label
|
|
3371
|
+
}
|
|
3372
|
+
)
|
|
3373
|
+
}
|
|
3374
|
+
),
|
|
3375
|
+
controls
|
|
3376
|
+
]
|
|
3377
|
+
}
|
|
3378
|
+
);
|
|
3379
|
+
}
|
|
2996
3380
|
|
|
2997
3381
|
// src/components/custom/Workout/RestTimer.tsx
|
|
2998
3382
|
var BRAND_PRIMARY3 = getSemanticColors("dark")["brand-primary"];
|
|
3383
|
+
var RING_DEFAULT_SIZE = 180;
|
|
3384
|
+
function RestActions({ onAddTime, onSkip }) {
|
|
3385
|
+
return /* @__PURE__ */ jsxs(reactNative.View, { style: { flexDirection: "row", gap: 8 }, children: [
|
|
3386
|
+
/* @__PURE__ */ jsx(
|
|
3387
|
+
reactNative.Pressable,
|
|
3388
|
+
{
|
|
3389
|
+
onPress: onAddTime,
|
|
3390
|
+
style: {
|
|
3391
|
+
backgroundColor: "rgba(255,255,255,0.06)",
|
|
3392
|
+
paddingVertical: 8,
|
|
3393
|
+
paddingHorizontal: 20,
|
|
3394
|
+
borderRadius: 8
|
|
3395
|
+
},
|
|
3396
|
+
accessibilityRole: "button",
|
|
3397
|
+
accessibilityLabel: "Add 30 seconds",
|
|
3398
|
+
testID: "rest-timer-add-time",
|
|
3399
|
+
children: /* @__PURE__ */ jsx(
|
|
3400
|
+
reactNative.Text,
|
|
3401
|
+
{
|
|
3402
|
+
className: "text-text-secondary",
|
|
3403
|
+
style: { fontSize: 11, fontFamily: "Inter, sans-serif", fontWeight: "600" },
|
|
3404
|
+
children: "+30s"
|
|
3405
|
+
}
|
|
3406
|
+
)
|
|
3407
|
+
}
|
|
3408
|
+
),
|
|
3409
|
+
/* @__PURE__ */ jsx(
|
|
3410
|
+
reactNative.Pressable,
|
|
3411
|
+
{
|
|
3412
|
+
onPress: onSkip,
|
|
3413
|
+
style: {
|
|
3414
|
+
backgroundColor: "rgba(255,121,0,0.12)",
|
|
3415
|
+
paddingVertical: 8,
|
|
3416
|
+
paddingHorizontal: 20,
|
|
3417
|
+
borderRadius: 8
|
|
3418
|
+
},
|
|
3419
|
+
accessibilityRole: "button",
|
|
3420
|
+
accessibilityLabel: "Skip rest",
|
|
3421
|
+
testID: "rest-timer-skip",
|
|
3422
|
+
children: /* @__PURE__ */ jsx(
|
|
3423
|
+
reactNative.Text,
|
|
3424
|
+
{
|
|
3425
|
+
style: {
|
|
3426
|
+
fontSize: 11,
|
|
3427
|
+
fontFamily: "Inter, sans-serif",
|
|
3428
|
+
fontWeight: "600",
|
|
3429
|
+
color: BRAND_PRIMARY3
|
|
3430
|
+
},
|
|
3431
|
+
children: "Skip"
|
|
3432
|
+
}
|
|
3433
|
+
)
|
|
3434
|
+
}
|
|
3435
|
+
)
|
|
3436
|
+
] });
|
|
3437
|
+
}
|
|
3438
|
+
function RestTimerRing({
|
|
3439
|
+
totalSeconds,
|
|
3440
|
+
elapsedMs,
|
|
3441
|
+
remainingSec,
|
|
3442
|
+
done,
|
|
3443
|
+
size,
|
|
3444
|
+
nextSetInfo,
|
|
3445
|
+
displayOnly,
|
|
3446
|
+
onSkip,
|
|
3447
|
+
onAddTime
|
|
3448
|
+
}) {
|
|
3449
|
+
const a11yLabel = done ? "Rest complete, next set ready" : `Rest timer, ${Math.max(0, remainingSec)} seconds remaining`;
|
|
3450
|
+
return /* @__PURE__ */ jsxs(reactNative.View, { style: { alignItems: "center", gap: 16 }, testID: "rest-timer", children: [
|
|
3451
|
+
/* @__PURE__ */ jsx(
|
|
3452
|
+
CircularTimer,
|
|
3453
|
+
{
|
|
3454
|
+
durationMs: totalSeconds * 1e3,
|
|
3455
|
+
elapsedMs,
|
|
3456
|
+
mode: "down",
|
|
3457
|
+
size,
|
|
3458
|
+
doneLabel: "GO",
|
|
3459
|
+
doneColor: "success",
|
|
3460
|
+
accessibilityLabel: a11yLabel,
|
|
3461
|
+
controls: !displayOnly ? /* @__PURE__ */ jsx(RestActions, { onAddTime, onSkip }) : void 0,
|
|
3462
|
+
testID: "rest-timer-ring"
|
|
3463
|
+
}
|
|
3464
|
+
),
|
|
3465
|
+
nextSetInfo != null && /* @__PURE__ */ jsx(
|
|
3466
|
+
reactNative.Text,
|
|
3467
|
+
{
|
|
3468
|
+
className: "text-text-tertiary",
|
|
3469
|
+
style: { fontSize: 13, fontFamily: "Inter, sans-serif" },
|
|
3470
|
+
testID: "rest-timer-next-set",
|
|
3471
|
+
children: nextSetInfo
|
|
3472
|
+
}
|
|
3473
|
+
)
|
|
3474
|
+
] });
|
|
3475
|
+
}
|
|
2999
3476
|
function RestTimer({
|
|
3000
3477
|
totalSeconds,
|
|
3001
3478
|
elapsedMs,
|
|
@@ -3003,12 +3480,15 @@ function RestTimer({
|
|
|
3003
3480
|
onAddTime,
|
|
3004
3481
|
nextSetInfo,
|
|
3005
3482
|
visible,
|
|
3006
|
-
displayOnly = false
|
|
3483
|
+
displayOnly = false,
|
|
3484
|
+
variant = "bar",
|
|
3485
|
+
size = RING_DEFAULT_SIZE
|
|
3007
3486
|
}) {
|
|
3008
3487
|
const {
|
|
3009
3488
|
remainingMs,
|
|
3010
3489
|
progress,
|
|
3011
|
-
label: timeDisplay
|
|
3490
|
+
label: timeDisplay,
|
|
3491
|
+
done
|
|
3012
3492
|
} = useTimer({
|
|
3013
3493
|
mode: "down",
|
|
3014
3494
|
durationMs: totalSeconds * 1e3,
|
|
@@ -3017,6 +3497,22 @@ function RestTimer({
|
|
|
3017
3497
|
const remainingSec = Math.ceil(remainingMs / 1e3);
|
|
3018
3498
|
const progressPct = progress * 100;
|
|
3019
3499
|
if (!visible) return null;
|
|
3500
|
+
if (variant === "ring") {
|
|
3501
|
+
return /* @__PURE__ */ jsx(
|
|
3502
|
+
RestTimerRing,
|
|
3503
|
+
{
|
|
3504
|
+
totalSeconds,
|
|
3505
|
+
elapsedMs,
|
|
3506
|
+
remainingSec,
|
|
3507
|
+
done,
|
|
3508
|
+
size,
|
|
3509
|
+
nextSetInfo,
|
|
3510
|
+
displayOnly,
|
|
3511
|
+
onSkip,
|
|
3512
|
+
onAddTime
|
|
3513
|
+
}
|
|
3514
|
+
);
|
|
3515
|
+
}
|
|
3020
3516
|
return /* @__PURE__ */ jsxs(
|
|
3021
3517
|
reactNative.View,
|
|
3022
3518
|
{
|
|
@@ -3114,62 +3610,7 @@ function RestTimer({
|
|
|
3114
3610
|
)
|
|
3115
3611
|
}
|
|
3116
3612
|
),
|
|
3117
|
-
!displayOnly && /* @__PURE__ */
|
|
3118
|
-
/* @__PURE__ */ jsx(
|
|
3119
|
-
reactNative.Pressable,
|
|
3120
|
-
{
|
|
3121
|
-
onPress: onAddTime,
|
|
3122
|
-
style: {
|
|
3123
|
-
backgroundColor: "rgba(255,255,255,0.06)",
|
|
3124
|
-
paddingVertical: 8,
|
|
3125
|
-
paddingHorizontal: 20,
|
|
3126
|
-
borderRadius: 8
|
|
3127
|
-
},
|
|
3128
|
-
accessibilityRole: "button",
|
|
3129
|
-
accessibilityLabel: "Add 30 seconds",
|
|
3130
|
-
testID: "rest-timer-add-time",
|
|
3131
|
-
children: /* @__PURE__ */ jsx(
|
|
3132
|
-
reactNative.Text,
|
|
3133
|
-
{
|
|
3134
|
-
className: "text-text-secondary",
|
|
3135
|
-
style: {
|
|
3136
|
-
fontSize: 11,
|
|
3137
|
-
fontFamily: "Inter, sans-serif",
|
|
3138
|
-
fontWeight: "600"
|
|
3139
|
-
},
|
|
3140
|
-
children: "+30s"
|
|
3141
|
-
}
|
|
3142
|
-
)
|
|
3143
|
-
}
|
|
3144
|
-
),
|
|
3145
|
-
/* @__PURE__ */ jsx(
|
|
3146
|
-
reactNative.Pressable,
|
|
3147
|
-
{
|
|
3148
|
-
onPress: onSkip,
|
|
3149
|
-
style: {
|
|
3150
|
-
backgroundColor: "rgba(255,121,0,0.12)",
|
|
3151
|
-
paddingVertical: 8,
|
|
3152
|
-
paddingHorizontal: 20,
|
|
3153
|
-
borderRadius: 8
|
|
3154
|
-
},
|
|
3155
|
-
accessibilityRole: "button",
|
|
3156
|
-
accessibilityLabel: "Skip rest",
|
|
3157
|
-
testID: "rest-timer-skip",
|
|
3158
|
-
children: /* @__PURE__ */ jsx(
|
|
3159
|
-
reactNative.Text,
|
|
3160
|
-
{
|
|
3161
|
-
style: {
|
|
3162
|
-
fontSize: 11,
|
|
3163
|
-
fontFamily: "Inter, sans-serif",
|
|
3164
|
-
fontWeight: "600",
|
|
3165
|
-
color: BRAND_PRIMARY3
|
|
3166
|
-
},
|
|
3167
|
-
children: "Skip"
|
|
3168
|
-
}
|
|
3169
|
-
)
|
|
3170
|
-
}
|
|
3171
|
-
)
|
|
3172
|
-
] })
|
|
3613
|
+
!displayOnly && /* @__PURE__ */ jsx(RestActions, { onAddTime, onSkip })
|
|
3173
3614
|
]
|
|
3174
3615
|
}
|
|
3175
3616
|
);
|
|
@@ -3959,11 +4400,11 @@ function CardContent({ children, className }) {
|
|
|
3959
4400
|
function CardFooter({ children, className }) {
|
|
3960
4401
|
return /* @__PURE__ */ jsx(reactNative.View, { className: cn("px-6 py-4 flex-row items-center gap-2", className), children });
|
|
3961
4402
|
}
|
|
3962
|
-
var
|
|
4403
|
+
var t4 = getSemanticColors("dark");
|
|
3963
4404
|
var solidVariantColors = {
|
|
3964
|
-
success:
|
|
3965
|
-
warning:
|
|
3966
|
-
error:
|
|
4405
|
+
success: t4["status-success"],
|
|
4406
|
+
warning: t4["status-warning"],
|
|
4407
|
+
error: t4["status-error"],
|
|
3967
4408
|
neutral: "#6B7280"
|
|
3968
4409
|
};
|
|
3969
4410
|
var ringVariantStyles = {
|
|
@@ -4003,8 +4444,8 @@ var iconColors = {
|
|
|
4003
4444
|
warning: "#6B4000",
|
|
4004
4445
|
error: "#5C1A1A",
|
|
4005
4446
|
neutral: "#D1D5DB",
|
|
4006
|
-
"on-track":
|
|
4007
|
-
deviation:
|
|
4447
|
+
"on-track": t4["status-success"],
|
|
4448
|
+
deviation: t4["status-warning"],
|
|
4008
4449
|
future: "#6B7280"
|
|
4009
4450
|
};
|
|
4010
4451
|
var sizeDimensions = {
|
|
@@ -4090,13 +4531,13 @@ var MESO_ACCENT_GRADIENT_LIGHT = primitiveRamps.orange[300];
|
|
|
4090
4531
|
var WORKOUT_PILL_DELOAD = primitiveRamps.magenta[600];
|
|
4091
4532
|
|
|
4092
4533
|
// src/components/custom/Workout/MesoStatusCard.tsx
|
|
4093
|
-
var
|
|
4094
|
-
var BRAND_PRIMARY5 =
|
|
4534
|
+
var t5 = getSemanticColors("dark");
|
|
4535
|
+
var BRAND_PRIMARY5 = t5["brand-primary"];
|
|
4095
4536
|
var BRAND_PRIMARY_DARK = MESO_ACCENT_GRADIENT_DARK;
|
|
4096
4537
|
var BRAND_PRIMARY_LIGHT = MESO_ACCENT_GRADIENT_LIGHT;
|
|
4097
|
-
var SUCCESS =
|
|
4098
|
-
var WARNING =
|
|
4099
|
-
var ERROR =
|
|
4538
|
+
var SUCCESS = t5["status-success"];
|
|
4539
|
+
var WARNING = t5["status-warning"];
|
|
4540
|
+
var ERROR = t5["status-error"];
|
|
4100
4541
|
var ACCENT_STOPS = [BRAND_PRIMARY_DARK, BRAND_PRIMARY5, BRAND_PRIMARY_LIGHT];
|
|
4101
4542
|
var CARD_GRADIENT = `linear-gradient(135deg, ${resolveColor("surface-elevated")} 0%, ${resolveColor("surface-raised")} 100%)`;
|
|
4102
4543
|
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%)";
|
|
@@ -4456,9 +4897,9 @@ function MesoStatusCard({
|
|
|
4456
4897
|
var sem = getSemanticColors("dark");
|
|
4457
4898
|
var BRAND_PRIMARY6 = sem["brand-primary"];
|
|
4458
4899
|
var PROJECTION_LINE_COLOR = resolveColor("text-tertiary");
|
|
4459
|
-
var
|
|
4900
|
+
var STATUS_SUCCESS2 = sem["status-success"];
|
|
4460
4901
|
var STATUS_ERROR2 = sem["status-error"];
|
|
4461
|
-
var
|
|
4902
|
+
var STATUS_WARNING2 = sem["status-warning"];
|
|
4462
4903
|
var GRID_LINE = "rgba(255,255,255,0.06)";
|
|
4463
4904
|
var SUCCESS_PILL_BG = "rgba(46,213,115,0.10)";
|
|
4464
4905
|
var SUCCESS_PILL_BORDER = "rgba(46,213,115,0.20)";
|
|
@@ -4467,8 +4908,8 @@ var ERROR_PILL_BORDER = "rgba(209,67,67,0.20)";
|
|
|
4467
4908
|
var PLOT_LEFT = 26;
|
|
4468
4909
|
var TOOLTIP_WIDTH = 124;
|
|
4469
4910
|
function timeOf(dateStr) {
|
|
4470
|
-
const
|
|
4471
|
-
return Number.isNaN(
|
|
4911
|
+
const t11 = Date.parse(dateStr);
|
|
4912
|
+
return Number.isNaN(t11) ? 0 : t11;
|
|
4472
4913
|
}
|
|
4473
4914
|
function formatValue(value) {
|
|
4474
4915
|
return `${Math.round(value)}`;
|
|
@@ -4764,7 +5205,7 @@ function StrengthTrendChart({
|
|
|
4764
5205
|
left: c.x - 7,
|
|
4765
5206
|
top: c.y - 20,
|
|
4766
5207
|
fontSize: 12,
|
|
4767
|
-
color:
|
|
5208
|
+
color: STATUS_WARNING2
|
|
4768
5209
|
},
|
|
4769
5210
|
children: "\u2605"
|
|
4770
5211
|
},
|
|
@@ -4857,7 +5298,7 @@ function StrengthTrendChart({
|
|
|
4857
5298
|
marginTop: 1,
|
|
4858
5299
|
fontSize: 10,
|
|
4859
5300
|
fontFamily: "Inter, sans-serif",
|
|
4860
|
-
color: selectedCoord.point.e1rm - geometry.actual[selected - 1].point.e1rm >= 0 ?
|
|
5301
|
+
color: selectedCoord.point.e1rm - geometry.actual[selected - 1].point.e1rm >= 0 ? STATUS_SUCCESS2 : STATUS_ERROR2
|
|
4861
5302
|
},
|
|
4862
5303
|
children: `${selectedCoord.point.e1rm - geometry.actual[selected - 1].point.e1rm >= 0 ? "+" : "-"}${Math.abs(
|
|
4863
5304
|
selectedCoord.point.e1rm - geometry.actual[selected - 1].point.e1rm
|
|
@@ -4913,7 +5354,7 @@ function StrengthTrendChart({
|
|
|
4913
5354
|
fontSize: 11,
|
|
4914
5355
|
fontFamily: "Inter, sans-serif",
|
|
4915
5356
|
fontWeight: "600",
|
|
4916
|
-
color: trend.positive ?
|
|
5357
|
+
color: trend.positive ? STATUS_SUCCESS2 : STATUS_ERROR2
|
|
4917
5358
|
},
|
|
4918
5359
|
children: trendText
|
|
4919
5360
|
}
|
|
@@ -4947,7 +5388,7 @@ function StrengthTrendChart({
|
|
|
4947
5388
|
/* @__PURE__ */ jsx(reactNative.Text, { className: "text-text-secondary", style: { fontSize: 10, fontFamily: "Inter, sans-serif" }, children: "Projected" })
|
|
4948
5389
|
] }),
|
|
4949
5390
|
/* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", style: { gap: 5 }, children: [
|
|
4950
|
-
/* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 12, color:
|
|
5391
|
+
/* @__PURE__ */ jsx(reactNative.Text, { style: { fontSize: 12, color: STATUS_WARNING2 }, children: "\u2605" }),
|
|
4951
5392
|
/* @__PURE__ */ jsx(reactNative.Text, { className: "text-text-secondary", style: { fontSize: 10, fontFamily: "Inter, sans-serif" }, children: "PR" })
|
|
4952
5393
|
] })
|
|
4953
5394
|
]
|
|
@@ -4957,10 +5398,10 @@ function StrengthTrendChart({
|
|
|
4957
5398
|
}
|
|
4958
5399
|
);
|
|
4959
5400
|
}
|
|
4960
|
-
var
|
|
4961
|
-
var
|
|
4962
|
-
var
|
|
4963
|
-
var STATUS_INFO =
|
|
5401
|
+
var t6 = getSemanticColors("dark");
|
|
5402
|
+
var STATUS_SUCCESS3 = t6["status-success"];
|
|
5403
|
+
var STATUS_WARNING3 = t6["status-warning"];
|
|
5404
|
+
var STATUS_INFO = t6["status-info"];
|
|
4964
5405
|
var DOT_BORDER = "#F3F4F6";
|
|
4965
5406
|
var BAND_FILL = "rgba(46,213,115,0.1)";
|
|
4966
5407
|
var BAND_EDGE = "rgba(46,213,115,0.45)";
|
|
@@ -4972,8 +5413,8 @@ var PADDING_BOTTOM = 16;
|
|
|
4972
5413
|
var COLUMN_STEP = 4;
|
|
4973
5414
|
var DOT_SIZE = 8;
|
|
4974
5415
|
var DOT_COLORS = {
|
|
4975
|
-
within:
|
|
4976
|
-
above:
|
|
5416
|
+
within: STATUS_SUCCESS3,
|
|
5417
|
+
above: STATUS_WARNING3,
|
|
4977
5418
|
below: STATUS_INFO
|
|
4978
5419
|
};
|
|
4979
5420
|
var STATUS_PHRASES = {
|
|
@@ -5003,8 +5444,8 @@ function interpEdge(pixels, x, key) {
|
|
|
5003
5444
|
const a = pixels[i];
|
|
5004
5445
|
const b = pixels[i + 1];
|
|
5005
5446
|
if (x >= a.x && x <= b.x) {
|
|
5006
|
-
const
|
|
5007
|
-
return a[key] +
|
|
5447
|
+
const t11 = b.x === a.x ? 0 : (x - a.x) / (b.x - a.x);
|
|
5448
|
+
return a[key] + t11 * (b[key] - a[key]);
|
|
5008
5449
|
}
|
|
5009
5450
|
}
|
|
5010
5451
|
return pixels[pixels.length - 1][key];
|
|
@@ -5198,8 +5639,8 @@ function CapacityBandChart({
|
|
|
5198
5639
|
projection && /* @__PURE__ */ jsxs(reactNative.View, { testID: "capacity-band-chart-projection", children: [
|
|
5199
5640
|
renderColumns(buildColumns2(trainingPixels, COLUMN_STEP), PROJECTION_FILL, "capacity-band-chart-projection-fill"),
|
|
5200
5641
|
renderColumns(buildColumns2(restPixels, COLUMN_STEP), PROJECTION_FILL, "capacity-band-chart-projection-fill"),
|
|
5201
|
-
renderEdges(buildEdges(trainingPixels, "yHigh"),
|
|
5202
|
-
renderEdges(buildEdges(trainingPixels, "yLow"),
|
|
5642
|
+
renderEdges(buildEdges(trainingPixels, "yHigh"), STATUS_SUCCESS3, true, "capacity-band-chart-projection-training"),
|
|
5643
|
+
renderEdges(buildEdges(trainingPixels, "yLow"), STATUS_SUCCESS3, true, "capacity-band-chart-projection-training"),
|
|
5203
5644
|
renderEdges(buildEdges(restPixels, "yHigh"), STATUS_INFO, true, "capacity-band-chart-projection-rest"),
|
|
5204
5645
|
renderEdges(buildEdges(restPixels, "yLow"), STATUS_INFO, true, "capacity-band-chart-projection-rest"),
|
|
5205
5646
|
/* @__PURE__ */ jsx(
|
|
@@ -5211,7 +5652,7 @@ function CapacityBandChart({
|
|
|
5211
5652
|
top: trainingPixels[trainingPixels.length - 1]?.yHigh - 12,
|
|
5212
5653
|
fontSize: 9,
|
|
5213
5654
|
fontFamily: "Inter, sans-serif",
|
|
5214
|
-
color:
|
|
5655
|
+
color: STATUS_SUCCESS3
|
|
5215
5656
|
},
|
|
5216
5657
|
testID: "capacity-band-chart-projection-training-label",
|
|
5217
5658
|
children: "Training"
|
|
@@ -6043,7 +6484,7 @@ function Badge({
|
|
|
6043
6484
|
}
|
|
6044
6485
|
);
|
|
6045
6486
|
}
|
|
6046
|
-
var
|
|
6487
|
+
var t7 = getSemanticColors("dark");
|
|
6047
6488
|
var statusBgColors = {
|
|
6048
6489
|
completed: "rgba(46,213,115,0.15)",
|
|
6049
6490
|
current: "rgba(255,121,0,0.15)",
|
|
@@ -6061,9 +6502,9 @@ var statusBorderStyles = {
|
|
|
6061
6502
|
deload: { borderWidth: 1, borderColor: "rgba(186,41,150,0.3)" }
|
|
6062
6503
|
};
|
|
6063
6504
|
var textColors = {
|
|
6064
|
-
completed:
|
|
6065
|
-
current:
|
|
6066
|
-
next:
|
|
6505
|
+
completed: t7["status-success"],
|
|
6506
|
+
current: t7["brand-primary"],
|
|
6507
|
+
next: t7["brand-primary"],
|
|
6067
6508
|
upcoming: "#6B7280",
|
|
6068
6509
|
missed: "rgba(209,67,67,0.7)",
|
|
6069
6510
|
deload: WORKOUT_PILL_DELOAD
|
|
@@ -6196,19 +6637,19 @@ function WorkoutPill({
|
|
|
6196
6637
|
}
|
|
6197
6638
|
return pill;
|
|
6198
6639
|
}
|
|
6199
|
-
var
|
|
6640
|
+
var t8 = getSemanticColors("dark");
|
|
6200
6641
|
var TRACK_BG = "#333333";
|
|
6201
6642
|
var LABEL_COLOR = "#6B7280";
|
|
6202
6643
|
var TARGET_LINE_COLOR = "rgba(33, 150, 243, 0.5)";
|
|
6203
6644
|
var AT_TARGET_GLOW = "0 0 5px 1px rgba(33, 150, 243, 0.35), 0 0 10px 3px rgba(33, 150, 243, 0.15)";
|
|
6204
6645
|
var ZONE = {
|
|
6205
|
-
building:
|
|
6646
|
+
building: t8["status-success"],
|
|
6206
6647
|
// below target ramp-up
|
|
6207
|
-
approaching:
|
|
6648
|
+
approaching: t8["status-warning"],
|
|
6208
6649
|
// nearing target
|
|
6209
|
-
target:
|
|
6650
|
+
target: t8["brand-primary"],
|
|
6210
6651
|
// exactly at target
|
|
6211
|
-
over1:
|
|
6652
|
+
over1: t8["status-error"],
|
|
6212
6653
|
// mild over-target
|
|
6213
6654
|
over2: WORKOUT_TOKENS.intensity.over2,
|
|
6214
6655
|
// moderate over-target
|
|
@@ -6631,13 +7072,13 @@ function MesoCard({
|
|
|
6631
7072
|
}
|
|
6632
7073
|
) });
|
|
6633
7074
|
}
|
|
6634
|
-
var
|
|
7075
|
+
var t9 = getSemanticColors("dark");
|
|
6635
7076
|
var dotColorMap = {
|
|
6636
7077
|
untrained: "#2C2C2C",
|
|
6637
|
-
behind:
|
|
6638
|
-
ontrack:
|
|
6639
|
-
target:
|
|
6640
|
-
over:
|
|
7078
|
+
behind: t9["brand-secondary"],
|
|
7079
|
+
ontrack: t9["status-success"],
|
|
7080
|
+
target: t9["brand-primary"],
|
|
7081
|
+
over: t9["status-error"]
|
|
6641
7082
|
};
|
|
6642
7083
|
function MuscleGroupChip({
|
|
6643
7084
|
name,
|
|
@@ -6711,10 +7152,10 @@ function MuscleGroupChip({
|
|
|
6711
7152
|
}
|
|
6712
7153
|
|
|
6713
7154
|
// src/components/custom/Workout/WorkoutCard.tsx
|
|
6714
|
-
var
|
|
7155
|
+
var t10 = getSemanticColors("dark");
|
|
6715
7156
|
var COLORS = {
|
|
6716
|
-
statusSuccess:
|
|
6717
|
-
brandPrimary:
|
|
7157
|
+
statusSuccess: t10["status-success"],
|
|
7158
|
+
brandPrimary: t10["brand-primary"],
|
|
6718
7159
|
borderDefault: "#1F1F1F",
|
|
6719
7160
|
brandPrimarySubtle: "rgba(255,121,0,0.06)"
|
|
6720
7161
|
};
|