@titan-design/react-ui 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/MesoStatusCard-CQk71hSi.d.mts +77 -0
- package/dist/MesoStatusCard-CQk71hSi.d.ts +77 -0
- package/dist/bodymap.d.mts +246 -3
- package/dist/bodymap.d.ts +246 -3
- package/dist/bodymap.js +232 -185
- package/dist/bodymap.js.map +1 -1
- package/dist/bodymap.mjs +1963 -11
- package/dist/bodymap.mjs.map +1 -1
- package/dist/index.d.mts +193 -744
- package/dist/index.d.ts +193 -744
- package/dist/index.js +1551 -1856
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +10770 -8213
- package/dist/index.mjs.map +1 -1
- package/dist/pages-D7Jlssvp.d.ts +791 -0
- package/dist/pages-MO0JCySL.d.mts +791 -0
- package/dist/pages.d.mts +4 -0
- package/dist/pages.d.ts +4 -0
- package/dist/pages.js +6694 -0
- package/dist/pages.js.map +1 -0
- package/dist/pages.mjs +6674 -0
- package/dist/pages.mjs.map +1 -0
- package/dist/theme/index.d.mts +473 -211
- package/dist/theme/index.d.ts +473 -211
- package/dist/theme/index.js +341 -127
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/index.mjs +2085 -2
- package/dist/theme/index.mjs.map +1 -1
- package/dist/theme/tokens-css.js +148 -139
- package/dist/theme/tokens-css.js.map +1 -1
- package/dist/theme/tokens-css.mjs +582 -1
- package/dist/theme/tokens-css.mjs.map +1 -1
- package/package.json +11 -7
- package/src/components/custom/DateTime/DateTime.stories.tsx +82 -6
- package/src/components/custom/DateTime/DateTime.test.tsx +29 -3
- package/src/components/custom/DateTime/DateTime.tsx +55 -15
- package/src/components/custom/Gauge/Gauge.test.tsx +2 -2
- package/src/components/custom/Gauge/Gauge.tsx +6 -3
- package/src/components/custom/Scatter/Scatter.tsx +3 -5
- package/src/components/custom/Treemap/Treemap.tsx +3 -5
- package/src/components/custom/Typography/Typography.stories.tsx +45 -27
- package/src/components/custom/Typography/Typography.test.tsx +13 -3
- package/src/components/custom/Typography/Typography.tsx +5 -0
- package/src/components/custom/Workout/ActiveWorkoutPage.tsx +2 -1
- package/src/components/custom/Workout/BaseBadge.stories.tsx +3 -3
- package/src/components/custom/Workout/BaseBadge.test.tsx +1 -1
- package/src/components/custom/Workout/BaseBadge.tsx +1 -1
- package/src/components/custom/Workout/BodyMap.tsx +6 -3
- package/src/components/custom/Workout/BodyMapDetailPanel.tsx +6 -3
- package/src/components/custom/Workout/CapacityBandChart.test.tsx +2 -2
- package/src/components/custom/Workout/CapacityBandChart.tsx +9 -6
- package/src/components/custom/Workout/DeviationBar.test.tsx +1 -1
- package/src/components/custom/Workout/DeviationBar.tsx +7 -4
- package/src/components/custom/Workout/ExerciseCard.tsx +5 -1
- package/src/components/custom/Workout/ExerciseDetailPage.tsx +19 -5
- package/src/components/custom/Workout/InputBar.tsx +2 -1
- package/src/components/custom/Workout/IntensityBar.test.tsx +112 -60
- package/src/components/custom/Workout/IntensityBar.tsx +113 -58
- package/src/components/custom/Workout/MesoCard.tsx +8 -3
- package/src/components/custom/Workout/MesoProgressBar.test.tsx +1 -1
- package/src/components/custom/Workout/MesoProgressBar.tsx +3 -2
- package/src/components/custom/Workout/MesoStatusCard.tsx +20 -13
- package/src/components/custom/Workout/MuscleGroupChip.tsx +7 -4
- package/src/components/custom/Workout/PlaceholderStrip.tsx +5 -9
- package/src/components/custom/Workout/PrBadge.tsx +7 -4
- package/src/components/custom/Workout/PrHistoryModal.tsx +6 -5
- package/src/components/custom/Workout/ProgramPlanningPage.tsx +2 -1
- package/src/components/custom/Workout/README.md +50 -0
- package/src/components/custom/Workout/ReadinessCheck.tsx +7 -4
- package/src/components/custom/Workout/RestTimer.test.tsx +41 -10
- package/src/components/custom/Workout/RestTimer.tsx +50 -44
- package/src/components/custom/Workout/SetRow.tsx +12 -2
- package/src/components/custom/Workout/Sparkline.tsx +2 -1
- package/src/components/custom/Workout/StatusDot.test.tsx +2 -2
- package/src/components/custom/Workout/StatusDot.tsx +12 -9
- package/src/components/custom/Workout/StrengthTrendChart.tsx +9 -6
- package/src/components/custom/Workout/SupersetWrapper.tsx +2 -1
- package/src/components/custom/Workout/TempoDisplay.stories.tsx +69 -2
- package/src/components/custom/Workout/TempoDisplay.test.tsx +35 -0
- package/src/components/custom/Workout/TempoDisplay.tsx +109 -3
- package/src/components/custom/Workout/VelocityStrip.test.tsx +89 -2
- package/src/components/custom/Workout/VelocityStrip.tsx +203 -38
- package/src/components/custom/Workout/WeekRow.test.tsx +2 -2
- package/src/components/custom/Workout/WeekRow.tsx +3 -2
- package/src/components/custom/Workout/WeightBadge.test.tsx +2 -2
- package/src/components/custom/Workout/WeightBadge.tsx +8 -4
- package/src/components/custom/Workout/WorkoutCard.tsx +5 -2
- package/src/components/custom/Workout/WorkoutPill.tsx +12 -8
- package/src/components/custom/Workout/icons.tsx +7 -0
- package/src/components/custom/Workout/index.ts +38 -47
- package/src/components/icons/SvgIcon.tsx +50 -0
- package/src/components/icons/icons.stories.tsx +57 -0
- package/src/components/icons/icons.test.tsx +43 -0
- package/src/components/icons/icons.tsx +45 -0
- package/src/components/icons/index.ts +4 -0
- package/src/components/index.ts +6 -0
- package/src/components/shell/BrandLockup.stories.tsx +27 -0
- package/src/components/shell/BrandLockup.test.tsx +23 -0
- package/src/components/shell/BrandLockup.tsx +47 -0
- package/src/components/shell/DeviceIndicator.stories.tsx +28 -0
- package/src/components/shell/DeviceIndicator.test.tsx +26 -0
- package/src/components/shell/DeviceIndicator.tsx +52 -0
- package/src/components/shell/DeviceMenu.stories.tsx +47 -0
- package/src/components/shell/DeviceMenu.test.tsx +40 -0
- package/src/components/shell/DeviceMenu.tsx +65 -0
- package/src/components/shell/DeviceRow.stories.tsx +38 -0
- package/src/components/shell/DeviceRow.test.tsx +37 -0
- package/src/components/shell/DeviceRow.tsx +58 -0
- package/src/components/shell/README.md +86 -0
- package/src/components/shell/SessionStatePill.stories.tsx +27 -0
- package/src/components/shell/SessionStatePill.test.tsx +25 -0
- package/src/components/shell/SessionStatePill.tsx +46 -0
- package/src/components/shell/TopBar.stories.tsx +49 -0
- package/src/components/shell/TopBar.test.tsx +36 -0
- package/src/components/shell/TopBar.tsx +89 -0
- package/src/components/shell/index.ts +8 -0
- package/src/components/ui/indicator/Indicator.stories.tsx +37 -1
- package/src/components/ui/indicator/Indicator.test.tsx +19 -1
- package/src/components/ui/indicator/Indicator.tsx +45 -6
- package/src/components/ui/indicator/index.ts +1 -1
- package/src/components/ui/spinner/Spinner.tsx +3 -2
- package/src/components/ui/toolbar-button/ToolbarButton.tsx +2 -1
- package/src/index.ts +3 -2
- package/src/pages.ts +61 -0
- package/src/test/stories-smoke.test.tsx +50 -0
- package/src/theme/ColorSystem.stories.tsx +323 -0
- package/src/theme/Colors.stories.tsx +69 -1
- package/src/theme/barrel.ts +54 -0
- package/src/theme/config.ts +16 -3
- package/src/theme/extracted-colors-dataviz.ts +21 -0
- package/src/theme/extracted-colors-ui.ts +20 -0
- package/src/theme/global.css +64 -52
- package/src/theme/gradients.test.ts +25 -0
- package/src/theme/gradients.ts +36 -0
- package/src/theme/index.ts +8 -43
- package/src/theme/native-theming-guard.test.ts +117 -0
- package/src/theme/tokens/primitives.test.ts +232 -0
- package/src/theme/tokens/primitives.ts +247 -0
- package/src/theme/tokens/semantic.ts +93 -81
- package/src/theme/workout-tokens.ts +22 -21
- package/src/utils/avatar-color.ts +3 -3
- package/tailwind.config.js +10 -3
- package/dist/bodymap-BhG55xHM.d.mts +0 -318
- package/dist/bodymap-BhG55xHM.d.ts +0 -318
- package/dist/chunk-2SISKTWM.mjs +0 -1027
- package/dist/chunk-2SISKTWM.mjs.map +0 -1
- package/dist/chunk-7XPB4NAO.mjs +0 -1013
- package/dist/chunk-7XPB4NAO.mjs.map +0 -1
- package/dist/chunk-SNVKL5WZ.mjs +0 -883
- package/dist/chunk-SNVKL5WZ.mjs.map +0 -1
package/dist/bodymap.mjs
CHANGED
|
@@ -1,9 +1,421 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import './chunk-7XPB4NAO.mjs';
|
|
4
|
-
import { useMemo, useState, useEffect } from 'react';
|
|
5
|
-
import { Animated, Easing, View, Text, Pressable, ScrollView } from 'react-native';
|
|
1
|
+
import { useMemo, useState, useEffect, Fragment as Fragment$1, useSyncExternalStore } from 'react';
|
|
2
|
+
import { Platform, Animated, Easing, View, Text, Pressable, ScrollView } from 'react-native';
|
|
6
3
|
import BodyHighlighter from 'react-native-body-highlighter';
|
|
4
|
+
import { clsx } from 'clsx';
|
|
5
|
+
import { twMerge } from 'tailwind-merge';
|
|
6
|
+
import { Fragment, jsx as jsx$1, jsxs as jsxs$1 } from 'react/jsx-runtime';
|
|
7
|
+
|
|
8
|
+
// src/components/custom/Workout/BodyMap.tsx
|
|
9
|
+
function cn(...inputs) {
|
|
10
|
+
return twMerge(clsx(inputs));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// src/theme/tokens/primitives.ts
|
|
14
|
+
var primitiveColors = {
|
|
15
|
+
// Blue scale (primary brand)
|
|
16
|
+
blue: {
|
|
17
|
+
400: "#60A5FA",
|
|
18
|
+
600: "#5048E5",
|
|
19
|
+
// Primary main
|
|
20
|
+
700: "#3832A0"},
|
|
21
|
+
// Red scale (error)
|
|
22
|
+
red: {
|
|
23
|
+
// Error light
|
|
24
|
+
500: "#EF4444",
|
|
25
|
+
600: "#D14343"},
|
|
26
|
+
// Vivid red scale (alert)
|
|
27
|
+
redVivid: {
|
|
28
|
+
400: "#FF6070",
|
|
29
|
+
// Error vivid light
|
|
30
|
+
500: "#FF4757",
|
|
31
|
+
700: "#C42539"},
|
|
32
|
+
// Neutral/Gray scale
|
|
33
|
+
neutral: {
|
|
34
|
+
50: "#FAFAFA",
|
|
35
|
+
100: "#F3F4F6",
|
|
36
|
+
300: "#D1D5DB",
|
|
37
|
+
400: "#9CA3AF",
|
|
38
|
+
500: "#6B7280",
|
|
39
|
+
600: "#4B5563",
|
|
40
|
+
900: "#111827"},
|
|
41
|
+
// Charcoal scale (dark backgrounds)
|
|
42
|
+
charcoal: {
|
|
43
|
+
200: "#3C3C3C",
|
|
44
|
+
300: "#2C2C2C",
|
|
45
|
+
400: "#1F1F1F",
|
|
46
|
+
500: "#1C1C1C",
|
|
47
|
+
600: "#191919",
|
|
48
|
+
700: "#161616",
|
|
49
|
+
900: "#101010"
|
|
50
|
+
},
|
|
51
|
+
// Pure colors
|
|
52
|
+
white: "#FFFFFF"};
|
|
53
|
+
var primitiveRamps = {
|
|
54
|
+
red: {
|
|
55
|
+
50: "#FFF4F4",
|
|
56
|
+
500: "#E05254",
|
|
57
|
+
600: "#D14343",
|
|
58
|
+
// pin
|
|
59
|
+
700: "#A4221C"},
|
|
60
|
+
orange: {
|
|
61
|
+
200: "#FFC7A2",
|
|
62
|
+
300: "#FFA063",
|
|
63
|
+
400: "#FF7900",
|
|
64
|
+
// pin
|
|
65
|
+
500: "#DA5F00",
|
|
66
|
+
600: "#B94A00"},
|
|
67
|
+
amber: {
|
|
68
|
+
50: "#FFF7DD",
|
|
69
|
+
200: "#FFD352",
|
|
70
|
+
300: "#F9B415",
|
|
71
|
+
500: "#C27400"},
|
|
72
|
+
green: {
|
|
73
|
+
50: "#E3FFEE",
|
|
74
|
+
200: "#58F69E",
|
|
75
|
+
300: "#2ED573",
|
|
76
|
+
600: "#298732"},
|
|
77
|
+
cyan: {
|
|
78
|
+
300: "#22D3EE",
|
|
79
|
+
// pin
|
|
80
|
+
400: "#01B5D1",
|
|
81
|
+
500: "#2697B7",
|
|
82
|
+
600: "#307B9B",
|
|
83
|
+
700: "#2A617F",
|
|
84
|
+
800: "#22465F"},
|
|
85
|
+
blue: {
|
|
86
|
+
50: "#EFF8FF",
|
|
87
|
+
300: "#78C2FF",
|
|
88
|
+
500: "#2196F3",
|
|
89
|
+
// pin
|
|
90
|
+
600: "#1072CB"}};
|
|
91
|
+
var divergingScale = [
|
|
92
|
+
primitiveRamps.blue[500],
|
|
93
|
+
// under
|
|
94
|
+
primitiveRamps.cyan[300],
|
|
95
|
+
// maintenance
|
|
96
|
+
primitiveRamps.green[200],
|
|
97
|
+
// optimal (light center)
|
|
98
|
+
primitiveRamps.amber[300],
|
|
99
|
+
// approaching
|
|
100
|
+
primitiveRamps.red[600]
|
|
101
|
+
// over
|
|
102
|
+
];
|
|
103
|
+
var discreteRainbow = [
|
|
104
|
+
"#E8ECFB",
|
|
105
|
+
"#D9CCE3",
|
|
106
|
+
"#D1BBD7",
|
|
107
|
+
"#CAACCB",
|
|
108
|
+
"#BA8DB4",
|
|
109
|
+
"#AE76A3",
|
|
110
|
+
"#AA6F9E",
|
|
111
|
+
"#994F88",
|
|
112
|
+
"#882E72",
|
|
113
|
+
"#1965B0",
|
|
114
|
+
"#437DBF",
|
|
115
|
+
"#5289C7",
|
|
116
|
+
"#6195CF",
|
|
117
|
+
"#7BAFDE",
|
|
118
|
+
"#4EB265",
|
|
119
|
+
"#90C987",
|
|
120
|
+
"#CAE0AB",
|
|
121
|
+
"#F7F056",
|
|
122
|
+
"#F7CB45",
|
|
123
|
+
"#F6C141",
|
|
124
|
+
"#F4A736",
|
|
125
|
+
"#F1932D",
|
|
126
|
+
"#EE8026",
|
|
127
|
+
"#E8601C",
|
|
128
|
+
"#E65518",
|
|
129
|
+
"#DC050C",
|
|
130
|
+
"#A5170E",
|
|
131
|
+
"#72190E",
|
|
132
|
+
"#42150A"
|
|
133
|
+
];
|
|
134
|
+
|
|
135
|
+
// src/theme/tokens/semantic.ts
|
|
136
|
+
var semanticColorsLight = {
|
|
137
|
+
// Brand colors (brand-*)
|
|
138
|
+
"brand-primary": primitiveRamps.orange[400],
|
|
139
|
+
"brand-primary-light": primitiveRamps.orange[300],
|
|
140
|
+
"brand-primary-dark": primitiveRamps.orange[500],
|
|
141
|
+
"brand-primary-subtle": "rgba(255, 121, 0, 0.08)",
|
|
142
|
+
"brand-primary-hover": primitiveRamps.orange[500],
|
|
143
|
+
"brand-primary-active": primitiveRamps.orange[600],
|
|
144
|
+
"brand-secondary": primitiveRamps.cyan[600],
|
|
145
|
+
"brand-secondary-light": primitiveRamps.cyan[500],
|
|
146
|
+
"brand-secondary-dark": primitiveRamps.cyan[700],
|
|
147
|
+
"brand-secondary-subtle": "rgba(48, 123, 155, 0.08)",
|
|
148
|
+
"brand-secondary-hover": primitiveRamps.cyan[700],
|
|
149
|
+
"brand-secondary-active": primitiveRamps.cyan[800],
|
|
150
|
+
// Text on brand backgrounds (on-*)
|
|
151
|
+
"on-brand-primary": primitiveColors.white,
|
|
152
|
+
"on-brand-secondary": primitiveColors.white,
|
|
153
|
+
// Status colors (status-*)
|
|
154
|
+
"status-success": primitiveRamps.green[300],
|
|
155
|
+
"status-success-light": primitiveRamps.green[200],
|
|
156
|
+
"status-success-dark": primitiveRamps.green[600],
|
|
157
|
+
"status-success-subtle": primitiveRamps.green[50],
|
|
158
|
+
"status-error": primitiveRamps.red[600],
|
|
159
|
+
"status-error-light": primitiveRamps.red[500],
|
|
160
|
+
"status-error-dark": primitiveRamps.red[700],
|
|
161
|
+
"status-error-subtle": primitiveRamps.red[50],
|
|
162
|
+
"status-error-vivid": primitiveColors.redVivid[500],
|
|
163
|
+
// vivid alert red
|
|
164
|
+
"status-error-vivid-light": primitiveColors.redVivid[400],
|
|
165
|
+
"status-error-vivid-dark": primitiveColors.redVivid[700],
|
|
166
|
+
"status-error-vivid-subtle": "rgba(255, 71, 87, 0.12)",
|
|
167
|
+
"status-warning": primitiveRamps.amber[300],
|
|
168
|
+
"status-warning-light": primitiveRamps.amber[200],
|
|
169
|
+
"status-warning-dark": primitiveRamps.amber[500],
|
|
170
|
+
"status-warning-subtle": primitiveRamps.amber[50],
|
|
171
|
+
"status-info": primitiveRamps.blue[500],
|
|
172
|
+
"status-info-light": primitiveRamps.blue[300],
|
|
173
|
+
"status-info-dark": primitiveRamps.blue[600],
|
|
174
|
+
"status-info-subtle": primitiveRamps.blue[50],
|
|
175
|
+
// Text on status backgrounds (on-status-*)
|
|
176
|
+
"on-status-success": primitiveColors.white,
|
|
177
|
+
"on-status-error": primitiveColors.white,
|
|
178
|
+
"on-status-warning": primitiveColors.white,
|
|
179
|
+
"on-status-info": primitiveColors.white,
|
|
180
|
+
// Result/outcome indicators (result-*)
|
|
181
|
+
"result-improve": "#4caf50",
|
|
182
|
+
// Green - positive outcome
|
|
183
|
+
"result-improve-light": "rgba(76, 175, 80, 0.12)",
|
|
184
|
+
"result-improve-dark": "#248a24",
|
|
185
|
+
"result-degrade": "#ef5350",
|
|
186
|
+
// Red - negative outcome
|
|
187
|
+
"result-degrade-light": "rgba(239, 83, 80, 0.12)",
|
|
188
|
+
"result-degrade-dark": "#b30000",
|
|
189
|
+
"result-inconclusive": "#9E9A97",
|
|
190
|
+
// Gray - no clear result
|
|
191
|
+
"result-inconclusive-light": "rgba(158, 154, 151, 0.12)",
|
|
192
|
+
"result-neutral": primitiveColors.neutral[500],
|
|
193
|
+
// Neutral baseline
|
|
194
|
+
// Text on result backgrounds (on-result-*)
|
|
195
|
+
"on-result-improve": primitiveColors.white,
|
|
196
|
+
"on-result-degrade": primitiveColors.white,
|
|
197
|
+
"on-result-inconclusive": primitiveColors.white,
|
|
198
|
+
// Data visualization colors (data-*)
|
|
199
|
+
// First 10 colors from discrete rainbow optimized for charts
|
|
200
|
+
"data-1": discreteRainbow[9],
|
|
201
|
+
// Blue
|
|
202
|
+
"data-2": discreteRainbow[14],
|
|
203
|
+
// Green
|
|
204
|
+
"data-3": discreteRainbow[17],
|
|
205
|
+
// Yellow
|
|
206
|
+
"data-4": discreteRainbow[25],
|
|
207
|
+
// Red
|
|
208
|
+
"data-5": discreteRainbow[8],
|
|
209
|
+
// Purple
|
|
210
|
+
"data-6": discreteRainbow[20],
|
|
211
|
+
// Orange
|
|
212
|
+
"data-7": discreteRainbow[13],
|
|
213
|
+
// Light Blue
|
|
214
|
+
"data-8": discreteRainbow[15],
|
|
215
|
+
// Light Green
|
|
216
|
+
"data-9": discreteRainbow[3],
|
|
217
|
+
// Lavender
|
|
218
|
+
"data-10": discreteRainbow[22],
|
|
219
|
+
// Dark Orange
|
|
220
|
+
// Text colors (text-*)
|
|
221
|
+
"text-primary": "#121828",
|
|
222
|
+
"text-secondary": "#65748B",
|
|
223
|
+
"text-tertiary": primitiveColors.neutral[400],
|
|
224
|
+
"text-disabled": "rgba(55, 65, 81, 0.48)",
|
|
225
|
+
"text-inverse": primitiveColors.white,
|
|
226
|
+
"text-link": primitiveColors.blue[600],
|
|
227
|
+
"text-link-hover": primitiveColors.blue[700],
|
|
228
|
+
// Surface colors (surface-*) - for elevated containers
|
|
229
|
+
"surface-base": primitiveColors.white,
|
|
230
|
+
"surface-elevated": primitiveColors.neutral[50],
|
|
231
|
+
// slightly off-white for elevated cards
|
|
232
|
+
"surface-raised": primitiveColors.neutral[100],
|
|
233
|
+
// light gray for raised cards
|
|
234
|
+
"surface-overlay": primitiveColors.white,
|
|
235
|
+
"surface-input": primitiveColors.neutral[50],
|
|
236
|
+
// Input field background (filled variant)
|
|
237
|
+
// Background colors (background-*)
|
|
238
|
+
"background-base": "#EBEBEB",
|
|
239
|
+
"background-default": primitiveColors.white,
|
|
240
|
+
"background-subtle": primitiveColors.neutral[50],
|
|
241
|
+
// Border colors (border-*)
|
|
242
|
+
"border-default": "#E8E9EB",
|
|
243
|
+
"border-subtle": primitiveColors.neutral[100],
|
|
244
|
+
"border-strong": primitiveColors.neutral[300],
|
|
245
|
+
"border-prominent": primitiveColors.neutral[400],
|
|
246
|
+
// high-visibility divider
|
|
247
|
+
"border-focus": primitiveColors.blue[600],
|
|
248
|
+
"border-input": primitiveColors.neutral[300],
|
|
249
|
+
// Input field border
|
|
250
|
+
"border-input-hover": primitiveColors.neutral[400],
|
|
251
|
+
// Input field border on hover
|
|
252
|
+
"border-input-focus": primitiveColors.blue[600],
|
|
253
|
+
// Input field border on focus
|
|
254
|
+
"border-input-error": primitiveColors.red[600],
|
|
255
|
+
// Input field border on error
|
|
256
|
+
// Interactive states (interactive-*)
|
|
257
|
+
"interactive-hover": "rgba(55, 65, 81, 0.04)",
|
|
258
|
+
"interactive-focus": "rgba(55, 65, 81, 0.12)",
|
|
259
|
+
"interactive-active": "rgba(55, 65, 81, 0.16)",
|
|
260
|
+
"interactive-selected": "rgba(55, 65, 81, 0.08)",
|
|
261
|
+
"interactive-disabled": "rgba(55, 65, 81, 0.12)",
|
|
262
|
+
"interactive-disabled-text": "rgba(55, 65, 81, 0.26)",
|
|
263
|
+
// Divider
|
|
264
|
+
"divider": "#E8E9EB",
|
|
265
|
+
// Avatar default
|
|
266
|
+
"avatar-background": primitiveColors.neutral[500],
|
|
267
|
+
"avatar-text": primitiveColors.white
|
|
268
|
+
};
|
|
269
|
+
var semanticColorsDark = {
|
|
270
|
+
// Brand colors stay the same in dark mode
|
|
271
|
+
"brand-primary": primitiveRamps.orange[400],
|
|
272
|
+
"brand-primary-light": primitiveRamps.orange[300],
|
|
273
|
+
"brand-primary-dark": primitiveRamps.orange[500],
|
|
274
|
+
"brand-primary-subtle": "rgba(255, 121, 0, 0.12)",
|
|
275
|
+
"brand-primary-hover": primitiveRamps.orange[300],
|
|
276
|
+
"brand-primary-active": primitiveRamps.orange[200],
|
|
277
|
+
"brand-secondary": primitiveRamps.cyan[600],
|
|
278
|
+
"brand-secondary-light": primitiveRamps.cyan[500],
|
|
279
|
+
"brand-secondary-dark": primitiveRamps.cyan[700],
|
|
280
|
+
"brand-secondary-subtle": "rgba(48, 123, 155, 0.12)",
|
|
281
|
+
"brand-secondary-hover": primitiveRamps.cyan[500],
|
|
282
|
+
"brand-secondary-active": primitiveRamps.cyan[400],
|
|
283
|
+
// Text on brand backgrounds
|
|
284
|
+
"on-brand-primary": primitiveColors.white,
|
|
285
|
+
"on-brand-secondary": primitiveColors.white,
|
|
286
|
+
// Status colors
|
|
287
|
+
"status-success": primitiveRamps.green[300],
|
|
288
|
+
"status-success-light": primitiveRamps.green[200],
|
|
289
|
+
"status-success-dark": primitiveRamps.green[600],
|
|
290
|
+
"status-success-subtle": "rgba(46, 213, 115, 0.12)",
|
|
291
|
+
"status-error": primitiveRamps.red[600],
|
|
292
|
+
"status-error-light": primitiveRamps.red[500],
|
|
293
|
+
"status-error-dark": primitiveRamps.red[700],
|
|
294
|
+
"status-error-subtle": "rgba(209, 67, 67, 0.12)",
|
|
295
|
+
"status-error-vivid": primitiveColors.redVivid[500],
|
|
296
|
+
"status-error-vivid-light": primitiveColors.redVivid[400],
|
|
297
|
+
"status-error-vivid-dark": primitiveColors.redVivid[700],
|
|
298
|
+
"status-error-vivid-subtle": "rgba(255, 71, 87, 0.12)",
|
|
299
|
+
"status-warning": primitiveRamps.amber[300],
|
|
300
|
+
"status-warning-light": primitiveRamps.amber[200],
|
|
301
|
+
"status-warning-dark": primitiveRamps.amber[500],
|
|
302
|
+
"status-warning-subtle": "rgba(249, 180, 21, 0.12)",
|
|
303
|
+
"status-info": primitiveRamps.blue[500],
|
|
304
|
+
"status-info-light": primitiveRamps.blue[300],
|
|
305
|
+
"status-info-dark": primitiveRamps.blue[600],
|
|
306
|
+
"status-info-subtle": "rgba(33, 150, 243, 0.12)",
|
|
307
|
+
// Text on status backgrounds
|
|
308
|
+
"on-status-success": primitiveColors.white,
|
|
309
|
+
"on-status-error": primitiveColors.white,
|
|
310
|
+
"on-status-warning": primitiveColors.white,
|
|
311
|
+
"on-status-info": primitiveColors.white,
|
|
312
|
+
// Result/outcome indicators (result-*)
|
|
313
|
+
"result-improve": "#4caf50",
|
|
314
|
+
"result-improve-light": "rgba(76, 175, 80, 0.16)",
|
|
315
|
+
"result-improve-dark": "#248a24",
|
|
316
|
+
"result-degrade": "#ef5350",
|
|
317
|
+
"result-degrade-light": "rgba(239, 83, 80, 0.16)",
|
|
318
|
+
"result-degrade-dark": "#b30000",
|
|
319
|
+
"result-inconclusive": "#9E9A97",
|
|
320
|
+
"result-inconclusive-light": "rgba(158, 154, 151, 0.16)",
|
|
321
|
+
"result-neutral": primitiveColors.neutral[400],
|
|
322
|
+
// Text on result backgrounds
|
|
323
|
+
"on-result-improve": primitiveColors.white,
|
|
324
|
+
"on-result-degrade": primitiveColors.white,
|
|
325
|
+
"on-result-inconclusive": primitiveColors.white,
|
|
326
|
+
// Data visualization colors (same in dark mode for consistency)
|
|
327
|
+
"data-1": discreteRainbow[9],
|
|
328
|
+
"data-2": discreteRainbow[14],
|
|
329
|
+
"data-3": discreteRainbow[17],
|
|
330
|
+
"data-4": discreteRainbow[25],
|
|
331
|
+
"data-5": discreteRainbow[8],
|
|
332
|
+
"data-6": discreteRainbow[20],
|
|
333
|
+
"data-7": discreteRainbow[13],
|
|
334
|
+
"data-8": discreteRainbow[15],
|
|
335
|
+
"data-9": discreteRainbow[3],
|
|
336
|
+
"data-10": discreteRainbow[22],
|
|
337
|
+
// Text colors - inverted for dark mode
|
|
338
|
+
"text-primary": primitiveColors.neutral[100],
|
|
339
|
+
"text-secondary": primitiveColors.neutral[400],
|
|
340
|
+
"text-tertiary": primitiveColors.neutral[500],
|
|
341
|
+
"text-disabled": "rgba(255, 255, 255, 0.38)",
|
|
342
|
+
"text-inverse": primitiveColors.neutral[900],
|
|
343
|
+
"text-link": "#828DF8",
|
|
344
|
+
"text-link-hover": primitiveColors.blue[400],
|
|
345
|
+
// Surface colors - dark backgrounds
|
|
346
|
+
"surface-base": primitiveColors.charcoal[700],
|
|
347
|
+
// main surface
|
|
348
|
+
"surface-elevated": primitiveColors.charcoal[600],
|
|
349
|
+
// elevated surface
|
|
350
|
+
"surface-raised": primitiveColors.charcoal[500],
|
|
351
|
+
// raised surface
|
|
352
|
+
"surface-overlay": primitiveColors.charcoal[600],
|
|
353
|
+
// overlay surface
|
|
354
|
+
"surface-input": primitiveColors.charcoal[600],
|
|
355
|
+
// input surface
|
|
356
|
+
// Background colors
|
|
357
|
+
"background-base": primitiveColors.charcoal[900],
|
|
358
|
+
// darkest charcoal
|
|
359
|
+
"background-default": primitiveColors.charcoal[700],
|
|
360
|
+
// main background
|
|
361
|
+
"background-subtle": primitiveColors.charcoal[500],
|
|
362
|
+
// subtle background
|
|
363
|
+
// Border colors
|
|
364
|
+
"border-default": primitiveColors.charcoal[400],
|
|
365
|
+
// default border
|
|
366
|
+
"border-subtle": primitiveColors.charcoal[500],
|
|
367
|
+
// subtle border
|
|
368
|
+
"border-strong": primitiveColors.charcoal[300],
|
|
369
|
+
// strong border
|
|
370
|
+
"border-prominent": primitiveColors.charcoal[200],
|
|
371
|
+
// high-visibility divider
|
|
372
|
+
"border-focus": "#828DF8",
|
|
373
|
+
"border-input": primitiveColors.neutral[600],
|
|
374
|
+
"border-input-hover": primitiveColors.neutral[500],
|
|
375
|
+
"border-input-focus": "#828DF8",
|
|
376
|
+
"border-input-error": primitiveColors.red[500],
|
|
377
|
+
// Interactive states
|
|
378
|
+
"interactive-hover": "rgba(255, 255, 255, 0.04)",
|
|
379
|
+
"interactive-focus": "rgba(255, 255, 255, 0.12)",
|
|
380
|
+
"interactive-active": "rgba(255, 255, 255, 0.16)",
|
|
381
|
+
"interactive-selected": "rgba(255, 255, 255, 0.08)",
|
|
382
|
+
"interactive-disabled": "rgba(255, 255, 255, 0.12)",
|
|
383
|
+
"interactive-disabled-text": "rgba(255, 255, 255, 0.26)",
|
|
384
|
+
// Divider
|
|
385
|
+
"divider": primitiveColors.charcoal[400],
|
|
386
|
+
// divider color
|
|
387
|
+
// Avatar default
|
|
388
|
+
"avatar-background": primitiveColors.neutral[600],
|
|
389
|
+
"avatar-text": primitiveColors.white
|
|
390
|
+
};
|
|
391
|
+
function getSemanticColors(mode) {
|
|
392
|
+
return mode === "dark" ? semanticColorsDark : semanticColorsLight;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// src/theme/resolve-color.ts
|
|
396
|
+
function resolveColor(token, mode = "dark") {
|
|
397
|
+
return Platform.OS === "web" ? `var(--color-${token})` : getSemanticColors(mode)[token];
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// src/theme/workout-tokens.ts
|
|
401
|
+
var WORKOUT_TOKENS = {
|
|
402
|
+
// BodyMap volume heatmap — the canonical `divergingScale` (under → optimal →
|
|
403
|
+
// over): a true diverging shape with a light green center, cool-blue under-
|
|
404
|
+
// trained end and warm-red over-reaching end (colorblind-robust in lightness).
|
|
405
|
+
heatmap: {
|
|
406
|
+
none: "#E0E0E0",
|
|
407
|
+
// no training data
|
|
408
|
+
under: divergingScale[0],
|
|
409
|
+
// below MEV
|
|
410
|
+
maintenance: divergingScale[1],
|
|
411
|
+
// MEV to MAV
|
|
412
|
+
productive: divergingScale[2],
|
|
413
|
+
// optimal center — MAV to MRV
|
|
414
|
+
approaching: divergingScale[3],
|
|
415
|
+
// near MRV
|
|
416
|
+
over: divergingScale[4]
|
|
417
|
+
// over MRV
|
|
418
|
+
}};
|
|
7
419
|
|
|
8
420
|
// src/components/custom/Workout/muscleTaxonomy.ts
|
|
9
421
|
var MuscleGroup = /* @__PURE__ */ ((MuscleGroup5) => {
|
|
@@ -188,9 +600,27 @@ var SLUG_TO_PRIMARY_MUSCLE = {
|
|
|
188
600
|
abs: "abs" /* ABS */,
|
|
189
601
|
obliques: "obliques" /* OBLIQUES */
|
|
190
602
|
};
|
|
603
|
+
function wrapJsx(fn) {
|
|
604
|
+
return function(type, props, ...rest) {
|
|
605
|
+
if (props && typeof props.className === "string" && props.className) {
|
|
606
|
+
const cn2 = props.className;
|
|
607
|
+
const cssStyle = { $$css: true, [cn2]: cn2 };
|
|
608
|
+
const existing = props.style;
|
|
609
|
+
props = {
|
|
610
|
+
...props,
|
|
611
|
+
style: existing ? [cssStyle, existing] : cssStyle
|
|
612
|
+
};
|
|
613
|
+
delete props.className;
|
|
614
|
+
}
|
|
615
|
+
return fn(type, props, ...rest);
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
var jsx = wrapJsx(jsx$1);
|
|
619
|
+
var jsxs = wrapJsx(jsxs$1);
|
|
191
620
|
|
|
192
621
|
// src/components/custom/Workout/BodyMap.tsx
|
|
193
622
|
var Body = BodyHighlighter.default ?? BodyHighlighter;
|
|
623
|
+
var BRAND_PRIMARY = getSemanticColors("dark")["brand-primary"];
|
|
194
624
|
var OUTLINE_FILL = "rgba(255,255,255,0.08)";
|
|
195
625
|
var OUTLINE_BORDER = "rgba(255,255,255,0.12)";
|
|
196
626
|
var BODY_SCALE = 0.8;
|
|
@@ -369,7 +799,7 @@ function ViewToggle({ view, onViewChange }) {
|
|
|
369
799
|
borderRadius: 9999,
|
|
370
800
|
backgroundColor: active ? "rgba(255,121,0,0.16)" : "transparent",
|
|
371
801
|
borderWidth: 1,
|
|
372
|
-
borderColor: active ?
|
|
802
|
+
borderColor: active ? BRAND_PRIMARY : resolveColor("border-strong")
|
|
373
803
|
},
|
|
374
804
|
testID: `body-map-toggle-${side}`,
|
|
375
805
|
children: /* @__PURE__ */ jsx(
|
|
@@ -379,7 +809,7 @@ function ViewToggle({ view, onViewChange }) {
|
|
|
379
809
|
fontSize: 12,
|
|
380
810
|
fontFamily: "Inter, sans-serif",
|
|
381
811
|
fontWeight: active ? "700" : "500",
|
|
382
|
-
color: active ?
|
|
812
|
+
color: active ? BRAND_PRIMARY : resolveColor("text-secondary"),
|
|
383
813
|
textTransform: "capitalize"
|
|
384
814
|
},
|
|
385
815
|
children: side
|
|
@@ -411,7 +841,7 @@ function MuscleButton({ entry, highlighted, onMusclePress }) {
|
|
|
411
841
|
paddingVertical: 3,
|
|
412
842
|
borderRadius: 9999,
|
|
413
843
|
borderWidth: 1,
|
|
414
|
-
borderColor: highlighted ?
|
|
844
|
+
borderColor: highlighted ? BRAND_PRIMARY : resolveColor("border-default")
|
|
415
845
|
},
|
|
416
846
|
testID: `body-map-muscle-${entry.key}`,
|
|
417
847
|
children: [
|
|
@@ -440,8 +870,310 @@ function MuscleButton({ entry, highlighted, onMusclePress }) {
|
|
|
440
870
|
}
|
|
441
871
|
);
|
|
442
872
|
}
|
|
443
|
-
var
|
|
444
|
-
|
|
873
|
+
var sizeStyles = {
|
|
874
|
+
xs: "w-1 h-1",
|
|
875
|
+
sm: "w-1.5 h-1.5",
|
|
876
|
+
md: "w-2 h-2",
|
|
877
|
+
lg: "w-2.5 h-2.5"
|
|
878
|
+
};
|
|
879
|
+
var colorStyles = {
|
|
880
|
+
default: "bg-text-tertiary",
|
|
881
|
+
primary: "bg-brand-primary",
|
|
882
|
+
success: "bg-status-success",
|
|
883
|
+
error: "bg-status-error",
|
|
884
|
+
warning: "bg-status-warning",
|
|
885
|
+
info: "bg-status-info",
|
|
886
|
+
"error-vivid": "bg-status-error-vivid"
|
|
887
|
+
};
|
|
888
|
+
function Indicator({
|
|
889
|
+
size = "sm",
|
|
890
|
+
color = "default",
|
|
891
|
+
customColor,
|
|
892
|
+
glow = false,
|
|
893
|
+
ring = false,
|
|
894
|
+
pulse = false,
|
|
895
|
+
className,
|
|
896
|
+
style,
|
|
897
|
+
...props
|
|
898
|
+
}) {
|
|
899
|
+
const pulseMode = pulse === true ? "opacity" : pulse || false;
|
|
900
|
+
const colorClass = !customColor ? colorStyles[color] : void 0;
|
|
901
|
+
const colorStyle = customColor ? { backgroundColor: customColor } : void 0;
|
|
902
|
+
if (pulseMode === "ping") {
|
|
903
|
+
return /* @__PURE__ */ jsxs(View, { className: cn("relative", sizeStyles[size], className), style, ...props, children: [
|
|
904
|
+
/* @__PURE__ */ jsx(
|
|
905
|
+
View,
|
|
906
|
+
{
|
|
907
|
+
className: cn("absolute inset-0 rounded-full animate-ping", colorClass),
|
|
908
|
+
style: colorStyle
|
|
909
|
+
}
|
|
910
|
+
),
|
|
911
|
+
/* @__PURE__ */ jsx(
|
|
912
|
+
View,
|
|
913
|
+
{
|
|
914
|
+
className: cn(
|
|
915
|
+
"relative rounded-full",
|
|
916
|
+
sizeStyles[size],
|
|
917
|
+
colorClass,
|
|
918
|
+
ring && "border-2 border-background-base"
|
|
919
|
+
),
|
|
920
|
+
style: colorStyle
|
|
921
|
+
}
|
|
922
|
+
)
|
|
923
|
+
] });
|
|
924
|
+
}
|
|
925
|
+
const dynamicStyle = {
|
|
926
|
+
...typeof style === "object" ? style : {},
|
|
927
|
+
...colorStyle ?? {},
|
|
928
|
+
...glow && customColor ? { boxShadow: `0 0 6px ${customColor}` } : {}
|
|
929
|
+
};
|
|
930
|
+
return /* @__PURE__ */ jsx(
|
|
931
|
+
View,
|
|
932
|
+
{
|
|
933
|
+
className: cn(
|
|
934
|
+
"rounded-full shrink-0",
|
|
935
|
+
sizeStyles[size],
|
|
936
|
+
colorClass,
|
|
937
|
+
pulseMode === "opacity" && "animate-pulse",
|
|
938
|
+
ring && "border-2 border-background-base",
|
|
939
|
+
glow && !customColor && color === "success" && "shadow-[0_0_6px_rgba(46,213,115,0.6)]",
|
|
940
|
+
glow && !customColor && color === "error" && "shadow-[0_0_6px_rgba(239,68,68,0.6)]",
|
|
941
|
+
glow && !customColor && color === "warning" && "shadow-[0_0_6px_rgba(245,158,11,0.6)]",
|
|
942
|
+
glow && !customColor && color === "primary" && "shadow-[0_0_6px_rgba(255,121,0,0.6)]",
|
|
943
|
+
glow && !customColor && color === "error-vivid" && "shadow-[0_0_6px_rgba(255,71,87,0.6)]",
|
|
944
|
+
className
|
|
945
|
+
),
|
|
946
|
+
style: Object.keys(dynamicStyle).length > 0 ? dynamicStyle : style,
|
|
947
|
+
...props
|
|
948
|
+
}
|
|
949
|
+
);
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
// src/components/ui/badge/Badge.tsx
|
|
953
|
+
var variantColorStyles = {
|
|
954
|
+
solid: {
|
|
955
|
+
default: "bg-border-strong text-text-inverse",
|
|
956
|
+
primary: "bg-brand-primary text-text-inverse",
|
|
957
|
+
secondary: "bg-brand-secondary text-text-inverse",
|
|
958
|
+
success: "bg-status-success text-text-inverse",
|
|
959
|
+
error: "bg-status-error text-text-inverse",
|
|
960
|
+
warning: "bg-status-warning text-text-inverse",
|
|
961
|
+
info: "bg-status-info text-text-inverse"
|
|
962
|
+
},
|
|
963
|
+
subtle: {
|
|
964
|
+
default: "bg-surface-raised text-text-secondary",
|
|
965
|
+
primary: "bg-brand-primary-subtle text-brand-primary",
|
|
966
|
+
secondary: "bg-brand-secondary-subtle text-brand-secondary",
|
|
967
|
+
success: "bg-status-success-subtle text-status-success",
|
|
968
|
+
error: "bg-status-error-subtle text-status-error",
|
|
969
|
+
warning: "bg-status-warning-subtle text-status-warning",
|
|
970
|
+
info: "bg-status-info-subtle text-status-info"
|
|
971
|
+
},
|
|
972
|
+
outline: {
|
|
973
|
+
default: "border border-border-strong text-text-secondary",
|
|
974
|
+
primary: "border border-brand-primary text-brand-primary",
|
|
975
|
+
secondary: "border border-brand-secondary text-brand-secondary",
|
|
976
|
+
success: "border border-status-success text-status-success",
|
|
977
|
+
error: "border border-status-error text-status-error",
|
|
978
|
+
warning: "border border-status-warning text-status-warning",
|
|
979
|
+
info: "border border-status-info text-status-info"
|
|
980
|
+
}
|
|
981
|
+
};
|
|
982
|
+
var sizeStyles2 = {
|
|
983
|
+
sm: "px-1.5 py-0.5 text-xs",
|
|
984
|
+
md: "px-2 py-0.5 text-xs",
|
|
985
|
+
lg: "px-2.5 py-1 text-sm"
|
|
986
|
+
};
|
|
987
|
+
function Badge({
|
|
988
|
+
variant = "subtle",
|
|
989
|
+
color = "default",
|
|
990
|
+
size = "md",
|
|
991
|
+
dot,
|
|
992
|
+
dotColor,
|
|
993
|
+
className,
|
|
994
|
+
children,
|
|
995
|
+
...props
|
|
996
|
+
}) {
|
|
997
|
+
return /* @__PURE__ */ jsxs(
|
|
998
|
+
View,
|
|
999
|
+
{
|
|
1000
|
+
className: cn(
|
|
1001
|
+
"inline-flex items-center justify-center rounded-full font-medium",
|
|
1002
|
+
variantColorStyles[variant][color],
|
|
1003
|
+
sizeStyles2[size],
|
|
1004
|
+
className
|
|
1005
|
+
),
|
|
1006
|
+
...props,
|
|
1007
|
+
children: [
|
|
1008
|
+
dot && /* @__PURE__ */ jsx(
|
|
1009
|
+
Indicator,
|
|
1010
|
+
{
|
|
1011
|
+
size: "xs",
|
|
1012
|
+
color: dotColor ?? (color === "default" || color === "secondary" ? "default" : color),
|
|
1013
|
+
className: "mr-0.5"
|
|
1014
|
+
}
|
|
1015
|
+
),
|
|
1016
|
+
typeof children === "string" ? /* @__PURE__ */ jsx(Text, { className: "text-inherit font-medium", children }) : children
|
|
1017
|
+
]
|
|
1018
|
+
}
|
|
1019
|
+
);
|
|
1020
|
+
}
|
|
1021
|
+
var BRAND_PRIMARY2 = getSemanticColors("dark")["brand-primary"];
|
|
1022
|
+
function normalizeData(data, height) {
|
|
1023
|
+
if (data.length === 0) return [];
|
|
1024
|
+
const min = Math.min(...data);
|
|
1025
|
+
const max = Math.max(...data);
|
|
1026
|
+
const range = max - min || 1;
|
|
1027
|
+
return data.map((v) => height - (v - min) / range * height);
|
|
1028
|
+
}
|
|
1029
|
+
function normalizeValue(value, data, height) {
|
|
1030
|
+
const min = Math.min(...data);
|
|
1031
|
+
const max = Math.max(...data);
|
|
1032
|
+
const range = max - min || 1;
|
|
1033
|
+
return height - (value - min) / range * height;
|
|
1034
|
+
}
|
|
1035
|
+
function Sparkline({
|
|
1036
|
+
data,
|
|
1037
|
+
width = 80,
|
|
1038
|
+
height = 30,
|
|
1039
|
+
color,
|
|
1040
|
+
showDots = false,
|
|
1041
|
+
referenceLines,
|
|
1042
|
+
highlightLast = false,
|
|
1043
|
+
className,
|
|
1044
|
+
...props
|
|
1045
|
+
}) {
|
|
1046
|
+
if (data.length === 0) {
|
|
1047
|
+
return /* @__PURE__ */ jsx(
|
|
1048
|
+
View,
|
|
1049
|
+
{
|
|
1050
|
+
style: { width, height },
|
|
1051
|
+
className,
|
|
1052
|
+
testID: "sparkline-empty",
|
|
1053
|
+
accessibilityLabel: "Sparkline chart, no data",
|
|
1054
|
+
...props
|
|
1055
|
+
}
|
|
1056
|
+
);
|
|
1057
|
+
}
|
|
1058
|
+
const resolvedColor = color ?? BRAND_PRIMARY2;
|
|
1059
|
+
const normalized = normalizeData(data, height);
|
|
1060
|
+
const stepX = data.length > 1 ? width / (data.length - 1) : 0;
|
|
1061
|
+
const dotSize = 3;
|
|
1062
|
+
const highlightSize = 6;
|
|
1063
|
+
return /* @__PURE__ */ jsxs(
|
|
1064
|
+
View,
|
|
1065
|
+
{
|
|
1066
|
+
style: { width, height, position: "relative" },
|
|
1067
|
+
className: cn(className),
|
|
1068
|
+
accessibilityRole: "image",
|
|
1069
|
+
accessibilityLabel: `Sparkline chart with ${data.length} data points`,
|
|
1070
|
+
testID: "sparkline",
|
|
1071
|
+
...props,
|
|
1072
|
+
children: [
|
|
1073
|
+
referenceLines?.map((line, i) => {
|
|
1074
|
+
const y = normalizeValue(line.value, data, height);
|
|
1075
|
+
return /* @__PURE__ */ jsx(
|
|
1076
|
+
View,
|
|
1077
|
+
{
|
|
1078
|
+
style: [
|
|
1079
|
+
{
|
|
1080
|
+
position: "absolute",
|
|
1081
|
+
top: y,
|
|
1082
|
+
left: 0,
|
|
1083
|
+
right: 0,
|
|
1084
|
+
opacity: 0.6
|
|
1085
|
+
},
|
|
1086
|
+
line.dashed ? {
|
|
1087
|
+
height: 0,
|
|
1088
|
+
borderStyle: "dashed",
|
|
1089
|
+
borderTopWidth: 1,
|
|
1090
|
+
borderTopColor: line.color
|
|
1091
|
+
} : {
|
|
1092
|
+
height: 1,
|
|
1093
|
+
backgroundColor: line.color
|
|
1094
|
+
}
|
|
1095
|
+
],
|
|
1096
|
+
accessibilityElementsHidden: true,
|
|
1097
|
+
testID: `sparkline-reference-${i}`,
|
|
1098
|
+
children: line.label && /* @__PURE__ */ jsx(
|
|
1099
|
+
Text,
|
|
1100
|
+
{
|
|
1101
|
+
style: {
|
|
1102
|
+
position: "absolute",
|
|
1103
|
+
right: 0,
|
|
1104
|
+
top: -10,
|
|
1105
|
+
fontSize: 7,
|
|
1106
|
+
color: line.color,
|
|
1107
|
+
opacity: 1
|
|
1108
|
+
},
|
|
1109
|
+
testID: `sparkline-reference-label-${i}`,
|
|
1110
|
+
children: line.label
|
|
1111
|
+
}
|
|
1112
|
+
)
|
|
1113
|
+
},
|
|
1114
|
+
`ref-${i}`
|
|
1115
|
+
);
|
|
1116
|
+
}),
|
|
1117
|
+
normalized.map((y, i) => {
|
|
1118
|
+
if (i === 0) return null;
|
|
1119
|
+
const prevY = normalized[i - 1];
|
|
1120
|
+
const x1 = (i - 1) * stepX;
|
|
1121
|
+
const x2 = i * stepX;
|
|
1122
|
+
const dx = x2 - x1;
|
|
1123
|
+
const dy = y - prevY;
|
|
1124
|
+
const length = Math.sqrt(dx * dx + dy * dy);
|
|
1125
|
+
const angle = Math.atan2(dy, dx) * (180 / Math.PI);
|
|
1126
|
+
return /* @__PURE__ */ jsx(
|
|
1127
|
+
View,
|
|
1128
|
+
{
|
|
1129
|
+
style: {
|
|
1130
|
+
position: "absolute",
|
|
1131
|
+
left: x1,
|
|
1132
|
+
top: prevY,
|
|
1133
|
+
width: length,
|
|
1134
|
+
height: 1.5,
|
|
1135
|
+
backgroundColor: resolvedColor,
|
|
1136
|
+
transformOrigin: "0 0",
|
|
1137
|
+
transform: [{ rotate: `${angle}deg` }]
|
|
1138
|
+
},
|
|
1139
|
+
accessibilityElementsHidden: true,
|
|
1140
|
+
testID: `sparkline-segment-${i}`
|
|
1141
|
+
},
|
|
1142
|
+
`line-${i}`
|
|
1143
|
+
);
|
|
1144
|
+
}),
|
|
1145
|
+
(showDots || highlightLast) && normalized.map((y, i) => {
|
|
1146
|
+
const isLast = i === data.length - 1;
|
|
1147
|
+
const shouldShow = showDots || highlightLast && isLast;
|
|
1148
|
+
if (!shouldShow) return null;
|
|
1149
|
+
const size = highlightLast && isLast ? highlightSize : dotSize;
|
|
1150
|
+
return /* @__PURE__ */ jsx(
|
|
1151
|
+
View,
|
|
1152
|
+
{
|
|
1153
|
+
style: {
|
|
1154
|
+
position: "absolute",
|
|
1155
|
+
left: i * stepX - size / 2,
|
|
1156
|
+
top: y - size / 2,
|
|
1157
|
+
width: size,
|
|
1158
|
+
height: size,
|
|
1159
|
+
borderRadius: size / 2,
|
|
1160
|
+
backgroundColor: resolvedColor
|
|
1161
|
+
},
|
|
1162
|
+
accessibilityElementsHidden: true,
|
|
1163
|
+
testID: `sparkline-dot-${i}`
|
|
1164
|
+
},
|
|
1165
|
+
`dot-${i}`
|
|
1166
|
+
);
|
|
1167
|
+
})
|
|
1168
|
+
]
|
|
1169
|
+
}
|
|
1170
|
+
);
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
// src/components/custom/Workout/BodyMapDetailPanel.tsx
|
|
1174
|
+
var t = getSemanticColors("dark");
|
|
1175
|
+
var BRAND_PRIMARY3 = t["brand-primary"];
|
|
1176
|
+
var VOLUME_GRADIENT = `linear-gradient(90deg, ${t["status-info"]} 0%, ${t["status-success"]} 50%, ${t["status-error"]} 100%)`;
|
|
445
1177
|
var SLIDE_OFFSET = 400;
|
|
446
1178
|
var BACKDROP_OPACITY = 0.4;
|
|
447
1179
|
var STATUS_BADGE_COLOR = {
|
|
@@ -839,7 +1571,7 @@ function BodyMapDetailPanel({
|
|
|
839
1571
|
borderColor: "rgba(255,121,0,0.3)"
|
|
840
1572
|
},
|
|
841
1573
|
testID: "body-map-detail-panel-view-exercises",
|
|
842
|
-
children: /* @__PURE__ */ jsx(Text, { style: { fontSize: 13, fontFamily: "Inter, sans-serif", fontWeight: "700", color:
|
|
1574
|
+
children: /* @__PURE__ */ jsx(Text, { style: { fontSize: 13, fontFamily: "Inter, sans-serif", fontWeight: "700", color: BRAND_PRIMARY3 }, children: "View exercises" })
|
|
843
1575
|
}
|
|
844
1576
|
)
|
|
845
1577
|
]
|
|
@@ -852,6 +1584,1226 @@ function BodyMapDetailPanel({
|
|
|
852
1584
|
}
|
|
853
1585
|
);
|
|
854
1586
|
}
|
|
1587
|
+
function hexToRgb(hex) {
|
|
1588
|
+
const cleaned = hex.replace("#", "");
|
|
1589
|
+
let r, g, b;
|
|
1590
|
+
if (cleaned.length === 3) {
|
|
1591
|
+
r = parseInt(cleaned[0] + cleaned[0], 16);
|
|
1592
|
+
g = parseInt(cleaned[1] + cleaned[1], 16);
|
|
1593
|
+
b = parseInt(cleaned[2] + cleaned[2], 16);
|
|
1594
|
+
} else if (cleaned.length === 6) {
|
|
1595
|
+
r = parseInt(cleaned.slice(0, 2), 16);
|
|
1596
|
+
g = parseInt(cleaned.slice(2, 4), 16);
|
|
1597
|
+
b = parseInt(cleaned.slice(4, 6), 16);
|
|
1598
|
+
} else {
|
|
1599
|
+
return null;
|
|
1600
|
+
}
|
|
1601
|
+
return { r, g, b };
|
|
1602
|
+
}
|
|
1603
|
+
function rgbToHsv(r, g, b) {
|
|
1604
|
+
const rNorm = r / 255;
|
|
1605
|
+
const gNorm = g / 255;
|
|
1606
|
+
const bNorm = b / 255;
|
|
1607
|
+
const max = Math.max(rNorm, gNorm, bNorm);
|
|
1608
|
+
const min = Math.min(rNorm, gNorm, bNorm);
|
|
1609
|
+
const delta = max - min;
|
|
1610
|
+
const v = max;
|
|
1611
|
+
const s = max === 0 ? 0 : delta / max;
|
|
1612
|
+
let h = 0;
|
|
1613
|
+
if (delta !== 0) {
|
|
1614
|
+
if (max === rNorm) {
|
|
1615
|
+
h = 60 * ((gNorm - bNorm) / delta % 6);
|
|
1616
|
+
} else if (max === gNorm) {
|
|
1617
|
+
h = 60 * ((bNorm - rNorm) / delta + 2);
|
|
1618
|
+
} else {
|
|
1619
|
+
h = 60 * ((rNorm - gNorm) / delta + 4);
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
if (h < 0) h += 360;
|
|
1623
|
+
return { h, s, v };
|
|
1624
|
+
}
|
|
1625
|
+
function hsvToRgb(h, s, v) {
|
|
1626
|
+
const c = v * s;
|
|
1627
|
+
const x = c * (1 - Math.abs(h / 60 % 2 - 1));
|
|
1628
|
+
const m = v - c;
|
|
1629
|
+
let rPrime, gPrime, bPrime;
|
|
1630
|
+
if (h >= 0 && h < 60) {
|
|
1631
|
+
rPrime = c;
|
|
1632
|
+
gPrime = x;
|
|
1633
|
+
bPrime = 0;
|
|
1634
|
+
} else if (h >= 60 && h < 120) {
|
|
1635
|
+
rPrime = x;
|
|
1636
|
+
gPrime = c;
|
|
1637
|
+
bPrime = 0;
|
|
1638
|
+
} else if (h >= 120 && h < 180) {
|
|
1639
|
+
rPrime = 0;
|
|
1640
|
+
gPrime = c;
|
|
1641
|
+
bPrime = x;
|
|
1642
|
+
} else if (h >= 180 && h < 240) {
|
|
1643
|
+
rPrime = 0;
|
|
1644
|
+
gPrime = x;
|
|
1645
|
+
bPrime = c;
|
|
1646
|
+
} else if (h >= 240 && h < 300) {
|
|
1647
|
+
rPrime = x;
|
|
1648
|
+
gPrime = 0;
|
|
1649
|
+
bPrime = c;
|
|
1650
|
+
} else {
|
|
1651
|
+
rPrime = c;
|
|
1652
|
+
gPrime = 0;
|
|
1653
|
+
bPrime = x;
|
|
1654
|
+
}
|
|
1655
|
+
return {
|
|
1656
|
+
r: Math.round((rPrime + m) * 255),
|
|
1657
|
+
g: Math.round((gPrime + m) * 255),
|
|
1658
|
+
b: Math.round((bPrime + m) * 255)
|
|
1659
|
+
};
|
|
1660
|
+
}
|
|
1661
|
+
function rgbToHex(r, g, b) {
|
|
1662
|
+
const toHex = (n) => {
|
|
1663
|
+
const clamped = Math.max(0, Math.min(255, Math.round(n)));
|
|
1664
|
+
return clamped.toString(16).padStart(2, "0");
|
|
1665
|
+
};
|
|
1666
|
+
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
1667
|
+
}
|
|
1668
|
+
function lighten(hex, amount = 0.1) {
|
|
1669
|
+
const rgb = hexToRgb(hex);
|
|
1670
|
+
if (!rgb) return hex;
|
|
1671
|
+
const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
|
|
1672
|
+
const newV = Math.min(1, hsv.v + amount);
|
|
1673
|
+
const newRgb = hsvToRgb(hsv.h, hsv.s, newV);
|
|
1674
|
+
return rgbToHex(newRgb.r, newRgb.g, newRgb.b);
|
|
1675
|
+
}
|
|
1676
|
+
var shadowColors = {
|
|
1677
|
+
// For charcoal surfaces (~#2C2C2C to #3C3C3C)
|
|
1678
|
+
charcoal: {
|
|
1679
|
+
dark: "rgba(0, 0, 0, 0.5)",
|
|
1680
|
+
light: "rgba(255, 255, 255, 0.12)",
|
|
1681
|
+
// brighter for crisp rim light
|
|
1682
|
+
darker: "rgba(0, 0, 0, 0.6)"
|
|
1683
|
+
},
|
|
1684
|
+
// For neutral dark surfaces (~#1F2937)
|
|
1685
|
+
neutralDark: {
|
|
1686
|
+
dark: "rgba(0, 0, 0, 0.4)",
|
|
1687
|
+
light: "rgba(255, 255, 255, 0.08)",
|
|
1688
|
+
darker: "rgba(0, 0, 0, 0.5)"
|
|
1689
|
+
},
|
|
1690
|
+
// For light surfaces (white/light gray backgrounds)
|
|
1691
|
+
neutralLight: {
|
|
1692
|
+
dark: "rgba(0, 0, 0, 0.15)",
|
|
1693
|
+
// Visible dark shadow for depth on light backgrounds
|
|
1694
|
+
light: "rgba(255, 255, 255, 1)",
|
|
1695
|
+
// Bright highlight for raised effect (visible on light gray)
|
|
1696
|
+
darker: "rgba(0, 0, 0, 0.2)"
|
|
1697
|
+
// Deeper shadow for pressed states
|
|
1698
|
+
}
|
|
1699
|
+
};
|
|
1700
|
+
var intensityConfig = {
|
|
1701
|
+
subtle: { offset: 1, blur: 2 },
|
|
1702
|
+
// very light, barely visible
|
|
1703
|
+
medium: { offset: 2, blur: 4 },
|
|
1704
|
+
// noticeable but restrained
|
|
1705
|
+
strong: { offset: 2, blur: 5 }
|
|
1706
|
+
// slightly deeper blur, same offset as medium
|
|
1707
|
+
};
|
|
1708
|
+
function createRaisedShadow(surface = "charcoal", intensity = "medium") {
|
|
1709
|
+
const colors = shadowColors[surface];
|
|
1710
|
+
const { offset, blur } = intensityConfig[intensity];
|
|
1711
|
+
const rimBlur = 1;
|
|
1712
|
+
return Platform.select({
|
|
1713
|
+
web: {
|
|
1714
|
+
boxShadow: `${offset}px ${offset}px ${blur}px ${colors.dark}, -${offset}px -${offset}px ${rimBlur}px ${colors.light}`
|
|
1715
|
+
},
|
|
1716
|
+
default: {
|
|
1717
|
+
// React Native shadow approximation (limited compared to web)
|
|
1718
|
+
shadowColor: "#000",
|
|
1719
|
+
shadowOffset: { width: offset, height: offset },
|
|
1720
|
+
shadowOpacity: 0.3,
|
|
1721
|
+
shadowRadius: blur / 2,
|
|
1722
|
+
elevation: offset
|
|
1723
|
+
}
|
|
1724
|
+
});
|
|
1725
|
+
}
|
|
1726
|
+
function createPressedShadow(surface = "charcoal", intensity = "medium") {
|
|
1727
|
+
const colors = shadowColors[surface];
|
|
1728
|
+
const { offset, blur } = intensityConfig[intensity];
|
|
1729
|
+
const rimOffset = 1;
|
|
1730
|
+
const rimBlur = 1;
|
|
1731
|
+
return Platform.select({
|
|
1732
|
+
web: {
|
|
1733
|
+
boxShadow: `inset ${offset}px ${offset}px ${blur}px ${colors.darker}, inset -${rimOffset}px -${rimOffset}px ${rimBlur}px ${colors.light}`
|
|
1734
|
+
},
|
|
1735
|
+
default: {
|
|
1736
|
+
// React Native doesn't support inset shadows, approximate with darker bg
|
|
1737
|
+
shadowOpacity: 0,
|
|
1738
|
+
elevation: 0
|
|
1739
|
+
}
|
|
1740
|
+
});
|
|
1741
|
+
}
|
|
1742
|
+
function createFlatShadow() {
|
|
1743
|
+
return Platform.select({
|
|
1744
|
+
web: {
|
|
1745
|
+
boxShadow: "none"
|
|
1746
|
+
},
|
|
1747
|
+
default: {
|
|
1748
|
+
shadowOpacity: 0,
|
|
1749
|
+
elevation: 0
|
|
1750
|
+
}
|
|
1751
|
+
});
|
|
1752
|
+
}
|
|
1753
|
+
function createRaisedHoverShadow(surface = "charcoal", intensity = "medium") {
|
|
1754
|
+
const colors = shadowColors[surface];
|
|
1755
|
+
const { offset, blur } = intensityConfig[intensity];
|
|
1756
|
+
const hoverOffset = Math.max(1, Math.round(offset / 2));
|
|
1757
|
+
const hoverBlur = Math.max(1, Math.round(blur / 2));
|
|
1758
|
+
const rimBlur = 1;
|
|
1759
|
+
return Platform.select({
|
|
1760
|
+
web: {
|
|
1761
|
+
// Keep same offsets as normal state for rim to prevent "shrinking" effect
|
|
1762
|
+
boxShadow: `${hoverOffset}px ${hoverOffset}px ${hoverBlur}px ${colors.dark}, -${offset}px -${offset}px ${rimBlur}px ${colors.light}`
|
|
1763
|
+
},
|
|
1764
|
+
default: {
|
|
1765
|
+
shadowColor: "#000",
|
|
1766
|
+
shadowOffset: { width: hoverOffset, height: hoverOffset },
|
|
1767
|
+
shadowOpacity: 0.2,
|
|
1768
|
+
shadowRadius: hoverBlur / 2,
|
|
1769
|
+
elevation: hoverOffset
|
|
1770
|
+
}
|
|
1771
|
+
});
|
|
1772
|
+
}
|
|
1773
|
+
function createPressedHoverShadow(surface = "charcoal", intensity = "medium") {
|
|
1774
|
+
const colors = shadowColors[surface];
|
|
1775
|
+
const { offset, blur } = intensityConfig[intensity];
|
|
1776
|
+
const hoverOffset = Math.max(1, Math.round(offset / 2));
|
|
1777
|
+
const hoverBlur = Math.max(1, Math.round(blur / 2));
|
|
1778
|
+
const rimBlur = 1;
|
|
1779
|
+
return Platform.select({
|
|
1780
|
+
web: {
|
|
1781
|
+
// Keep rim offset at 1px (same as pressed normal) to prevent "shrinking" effect
|
|
1782
|
+
boxShadow: `inset ${hoverOffset}px ${hoverOffset}px ${hoverBlur}px ${colors.darker}, inset -1px -1px ${rimBlur}px ${colors.light}`
|
|
1783
|
+
},
|
|
1784
|
+
default: {
|
|
1785
|
+
shadowOpacity: 0,
|
|
1786
|
+
elevation: 0
|
|
1787
|
+
}
|
|
1788
|
+
});
|
|
1789
|
+
}
|
|
1790
|
+
({
|
|
1791
|
+
// Charcoal surface shadows (for dark toolbars, cards)
|
|
1792
|
+
charcoal: {
|
|
1793
|
+
raised: {
|
|
1794
|
+
subtle: createRaisedShadow("charcoal", "subtle"),
|
|
1795
|
+
medium: createRaisedShadow("charcoal", "medium"),
|
|
1796
|
+
strong: createRaisedShadow("charcoal", "strong")
|
|
1797
|
+
},
|
|
1798
|
+
raisedHover: {
|
|
1799
|
+
subtle: createRaisedHoverShadow("charcoal", "subtle"),
|
|
1800
|
+
medium: createRaisedHoverShadow("charcoal", "medium"),
|
|
1801
|
+
strong: createRaisedHoverShadow("charcoal", "strong")
|
|
1802
|
+
},
|
|
1803
|
+
pressed: {
|
|
1804
|
+
subtle: createPressedShadow("charcoal", "subtle"),
|
|
1805
|
+
medium: createPressedShadow("charcoal", "medium"),
|
|
1806
|
+
strong: createPressedShadow("charcoal", "strong")
|
|
1807
|
+
},
|
|
1808
|
+
pressedHover: {
|
|
1809
|
+
subtle: createPressedHoverShadow("charcoal", "subtle"),
|
|
1810
|
+
medium: createPressedHoverShadow("charcoal", "medium"),
|
|
1811
|
+
strong: createPressedHoverShadow("charcoal", "strong")
|
|
1812
|
+
},
|
|
1813
|
+
flat: createFlatShadow()
|
|
1814
|
+
},
|
|
1815
|
+
// Neutral dark surface shadows
|
|
1816
|
+
neutralDark: {
|
|
1817
|
+
raised: {
|
|
1818
|
+
subtle: createRaisedShadow("neutralDark", "subtle"),
|
|
1819
|
+
medium: createRaisedShadow("neutralDark", "medium"),
|
|
1820
|
+
strong: createRaisedShadow("neutralDark", "strong")
|
|
1821
|
+
},
|
|
1822
|
+
raisedHover: {
|
|
1823
|
+
subtle: createRaisedHoverShadow("neutralDark", "subtle"),
|
|
1824
|
+
medium: createRaisedHoverShadow("neutralDark", "medium"),
|
|
1825
|
+
strong: createRaisedHoverShadow("neutralDark", "strong")
|
|
1826
|
+
},
|
|
1827
|
+
pressed: {
|
|
1828
|
+
subtle: createPressedShadow("neutralDark", "subtle"),
|
|
1829
|
+
medium: createPressedShadow("neutralDark", "medium"),
|
|
1830
|
+
strong: createPressedShadow("neutralDark", "strong")
|
|
1831
|
+
},
|
|
1832
|
+
pressedHover: {
|
|
1833
|
+
subtle: createPressedHoverShadow("neutralDark", "subtle"),
|
|
1834
|
+
medium: createPressedHoverShadow("neutralDark", "medium"),
|
|
1835
|
+
strong: createPressedHoverShadow("neutralDark", "strong")
|
|
1836
|
+
},
|
|
1837
|
+
flat: createFlatShadow()
|
|
1838
|
+
},
|
|
1839
|
+
// Neutral light surface shadows
|
|
1840
|
+
neutralLight: {
|
|
1841
|
+
raised: {
|
|
1842
|
+
subtle: createRaisedShadow("neutralLight", "subtle"),
|
|
1843
|
+
medium: createRaisedShadow("neutralLight", "medium"),
|
|
1844
|
+
strong: createRaisedShadow("neutralLight", "strong")
|
|
1845
|
+
},
|
|
1846
|
+
raisedHover: {
|
|
1847
|
+
subtle: createRaisedHoverShadow("neutralLight", "subtle"),
|
|
1848
|
+
medium: createRaisedHoverShadow("neutralLight", "medium"),
|
|
1849
|
+
strong: createRaisedHoverShadow("neutralLight", "strong")
|
|
1850
|
+
},
|
|
1851
|
+
pressed: {
|
|
1852
|
+
subtle: createPressedShadow("neutralLight", "subtle"),
|
|
1853
|
+
medium: createPressedShadow("neutralLight", "medium"),
|
|
1854
|
+
strong: createPressedShadow("neutralLight", "strong")
|
|
1855
|
+
},
|
|
1856
|
+
pressedHover: {
|
|
1857
|
+
subtle: createPressedHoverShadow("neutralLight", "subtle"),
|
|
1858
|
+
medium: createPressedHoverShadow("neutralLight", "medium"),
|
|
1859
|
+
strong: createPressedHoverShadow("neutralLight", "strong")
|
|
1860
|
+
},
|
|
1861
|
+
flat: createFlatShadow()
|
|
1862
|
+
}
|
|
1863
|
+
});
|
|
1864
|
+
var elevationSystem = {
|
|
1865
|
+
// Deep inset (recessed input fields, deeply pressed buttons)
|
|
1866
|
+
[-2]: {
|
|
1867
|
+
name: "deep-inset",
|
|
1868
|
+
colorAdjustment: 0,
|
|
1869
|
+
shadowIntensity: "strong",
|
|
1870
|
+
shadowStyle: "pressed",
|
|
1871
|
+
description: "Deeply recessed elements (e.g., input fields, deeply pressed buttons)"
|
|
1872
|
+
},
|
|
1873
|
+
// Shallow inset (pressed buttons, sunken panels)
|
|
1874
|
+
[-1]: {
|
|
1875
|
+
name: "inset",
|
|
1876
|
+
colorAdjustment: 0,
|
|
1877
|
+
shadowIntensity: "medium",
|
|
1878
|
+
shadowStyle: "pressed",
|
|
1879
|
+
description: "Shallow inset elements (e.g., pressed buttons, sunken panels within cards)"
|
|
1880
|
+
},
|
|
1881
|
+
// Base level (page background, default surface)
|
|
1882
|
+
[0]: {
|
|
1883
|
+
name: "base",
|
|
1884
|
+
colorAdjustment: 0,
|
|
1885
|
+
shadowIntensity: "subtle",
|
|
1886
|
+
shadowStyle: "raised",
|
|
1887
|
+
description: "Base surface level (page background, default containers)"
|
|
1888
|
+
},
|
|
1889
|
+
// Level 1: Subtle elevation (outline cards, subtle containers)
|
|
1890
|
+
[1]: {
|
|
1891
|
+
name: "subtle",
|
|
1892
|
+
colorAdjustment: 0.01,
|
|
1893
|
+
shadowIntensity: "subtle",
|
|
1894
|
+
shadowStyle: "raised",
|
|
1895
|
+
description: "Subtle elevation (outline cards, subtle containers)"
|
|
1896
|
+
},
|
|
1897
|
+
// Level 2: Standard elevation (default cards, buttons)
|
|
1898
|
+
[2]: {
|
|
1899
|
+
name: "standard",
|
|
1900
|
+
colorAdjustment: 0.02,
|
|
1901
|
+
shadowIntensity: "medium",
|
|
1902
|
+
shadowStyle: "raised",
|
|
1903
|
+
description: "Standard elevation (default cards, raised buttons)"
|
|
1904
|
+
},
|
|
1905
|
+
// Level 3: Prominent elevation (important cards, modals)
|
|
1906
|
+
[3]: {
|
|
1907
|
+
name: "prominent",
|
|
1908
|
+
colorAdjustment: 0.04,
|
|
1909
|
+
shadowIntensity: "strong",
|
|
1910
|
+
shadowStyle: "raised",
|
|
1911
|
+
description: "Prominent elevation (important cards, modals, dropdowns)"
|
|
1912
|
+
},
|
|
1913
|
+
// Level 4: High elevation (overlays, popovers)
|
|
1914
|
+
[4]: {
|
|
1915
|
+
name: "high",
|
|
1916
|
+
colorAdjustment: 0.06,
|
|
1917
|
+
shadowIntensity: "strong",
|
|
1918
|
+
shadowStyle: "raised",
|
|
1919
|
+
description: "High elevation (overlays, popovers, tooltips)"
|
|
1920
|
+
},
|
|
1921
|
+
// Level 5: Floating (toasts, floating action buttons)
|
|
1922
|
+
[5]: {
|
|
1923
|
+
name: "floating",
|
|
1924
|
+
colorAdjustment: 0.08,
|
|
1925
|
+
shadowIntensity: "strong",
|
|
1926
|
+
shadowStyle: "raised",
|
|
1927
|
+
description: "Floating elevation (toasts, floating action buttons, highest z-index)"
|
|
1928
|
+
}
|
|
1929
|
+
};
|
|
1930
|
+
function calculateRimLightColor(baseColor, level) {
|
|
1931
|
+
const rgb = hexToRgb(baseColor);
|
|
1932
|
+
if (!rgb) {
|
|
1933
|
+
return "rgba(255, 255, 255, 0.5)";
|
|
1934
|
+
}
|
|
1935
|
+
const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
|
|
1936
|
+
const isLight = hsv.v > 0.6;
|
|
1937
|
+
const isSaturated = hsv.s > 0.3;
|
|
1938
|
+
const absLevel = Math.abs(level);
|
|
1939
|
+
const opacityBoost = Math.max(0, (absLevel - 1) * 0.05);
|
|
1940
|
+
if (isSaturated) {
|
|
1941
|
+
const rimLightValue = 0.95;
|
|
1942
|
+
const rimLightRgb = hsvToRgb(hsv.h, hsv.s * 0.3, rimLightValue);
|
|
1943
|
+
const baseOpacity = isLight ? 0.9 : 0.5;
|
|
1944
|
+
const finalOpacity = Math.min(1, baseOpacity + opacityBoost);
|
|
1945
|
+
return `rgba(${rimLightRgb.r}, ${rimLightRgb.g}, ${rimLightRgb.b}, ${finalOpacity.toFixed(2)})`;
|
|
1946
|
+
} else {
|
|
1947
|
+
const baseOpacity = isLight ? 0.9 : 0.12;
|
|
1948
|
+
const finalOpacity = Math.min(1, baseOpacity + opacityBoost);
|
|
1949
|
+
return `rgba(255, 255, 255, ${finalOpacity.toFixed(2)})`;
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
function calculateDarkShadowColors(surfaceColor) {
|
|
1953
|
+
const rgb = hexToRgb(surfaceColor);
|
|
1954
|
+
if (!rgb) {
|
|
1955
|
+
return {
|
|
1956
|
+
dark: "rgba(0, 0, 0, 0.3)",
|
|
1957
|
+
darker: "rgba(0, 0, 0, 0.4)"
|
|
1958
|
+
};
|
|
1959
|
+
}
|
|
1960
|
+
const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
|
|
1961
|
+
const isLight = hsv.v > 0.6;
|
|
1962
|
+
const isSaturated = hsv.s > 0.3;
|
|
1963
|
+
if (isSaturated) {
|
|
1964
|
+
const darkShadowValue = 0.15;
|
|
1965
|
+
const darkShadowRgb = hsvToRgb(hsv.h, hsv.s, darkShadowValue);
|
|
1966
|
+
if (isLight) {
|
|
1967
|
+
return {
|
|
1968
|
+
dark: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.3)`,
|
|
1969
|
+
darker: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.4)`
|
|
1970
|
+
};
|
|
1971
|
+
} else {
|
|
1972
|
+
return {
|
|
1973
|
+
dark: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.5)`,
|
|
1974
|
+
darker: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.6)`
|
|
1975
|
+
};
|
|
1976
|
+
}
|
|
1977
|
+
} else {
|
|
1978
|
+
if (isLight) {
|
|
1979
|
+
return {
|
|
1980
|
+
dark: "rgba(0, 0, 0, 0.2)",
|
|
1981
|
+
darker: "rgba(0, 0, 0, 0.3)"
|
|
1982
|
+
};
|
|
1983
|
+
} else {
|
|
1984
|
+
return {
|
|
1985
|
+
dark: "rgba(0, 0, 0, 0.5)",
|
|
1986
|
+
darker: "rgba(0, 0, 0, 0.6)"
|
|
1987
|
+
};
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
function getRimLightConfig() {
|
|
1992
|
+
return {
|
|
1993
|
+
offset: 1,
|
|
1994
|
+
// Fixed 1px for crisp rim
|
|
1995
|
+
blur: 1
|
|
1996
|
+
// Tight blur for crisp edge
|
|
1997
|
+
};
|
|
1998
|
+
}
|
|
1999
|
+
var elevationSurfaceCache = /* @__PURE__ */ new Map();
|
|
2000
|
+
var MAX_CACHE_SIZE = 100;
|
|
2001
|
+
function getCacheKey(baseColor, level, theme) {
|
|
2002
|
+
return `${baseColor}-${level}-${theme}`;
|
|
2003
|
+
}
|
|
2004
|
+
function calculateElevationSurface(baseColor, level, theme) {
|
|
2005
|
+
const config = elevationSystem[level];
|
|
2006
|
+
if (config.colorAdjustment === 0) {
|
|
2007
|
+
return baseColor;
|
|
2008
|
+
}
|
|
2009
|
+
if (level < 0) {
|
|
2010
|
+
return baseColor;
|
|
2011
|
+
}
|
|
2012
|
+
return lighten(baseColor, config.colorAdjustment);
|
|
2013
|
+
}
|
|
2014
|
+
function getElevationSurface(baseColor, level, theme) {
|
|
2015
|
+
const cacheKey = getCacheKey(baseColor, level, theme);
|
|
2016
|
+
if (elevationSurfaceCache.has(cacheKey)) {
|
|
2017
|
+
return elevationSurfaceCache.get(cacheKey);
|
|
2018
|
+
}
|
|
2019
|
+
const result = calculateElevationSurface(baseColor, level);
|
|
2020
|
+
if (elevationSurfaceCache.size >= MAX_CACHE_SIZE) {
|
|
2021
|
+
const firstKey = elevationSurfaceCache.keys().next().value;
|
|
2022
|
+
elevationSurfaceCache.delete(firstKey);
|
|
2023
|
+
}
|
|
2024
|
+
elevationSurfaceCache.set(cacheKey, result);
|
|
2025
|
+
return result;
|
|
2026
|
+
}
|
|
2027
|
+
var elevationShadowCache = /* @__PURE__ */ new Map();
|
|
2028
|
+
var MAX_SHADOW_CACHE_SIZE = 50;
|
|
2029
|
+
function getShadowCacheKey(baseColor, level, theme, isHovered) {
|
|
2030
|
+
return `${baseColor}-${level}-${theme}-${isHovered}`;
|
|
2031
|
+
}
|
|
2032
|
+
function calculateElevationShadow(baseColor, level, theme, isHovered = false) {
|
|
2033
|
+
const config = elevationSystem[level];
|
|
2034
|
+
if (level === 0) {
|
|
2035
|
+
return {};
|
|
2036
|
+
}
|
|
2037
|
+
const elevatedSurfaceColor = calculateElevationSurface(baseColor, level);
|
|
2038
|
+
const rimLightColor = calculateRimLightColor(baseColor, level);
|
|
2039
|
+
const darkShadowColors = calculateDarkShadowColors(elevatedSurfaceColor);
|
|
2040
|
+
const intensityConfig2 = {
|
|
2041
|
+
subtle: { offset: 1, blur: 2 },
|
|
2042
|
+
medium: { offset: 2, blur: 4 },
|
|
2043
|
+
strong: { offset: 2, blur: 5 }
|
|
2044
|
+
};
|
|
2045
|
+
const { offset, blur } = intensityConfig2[config.shadowIntensity];
|
|
2046
|
+
const rimConfig = getRimLightConfig();
|
|
2047
|
+
if (config.shadowStyle === "pressed") {
|
|
2048
|
+
if (isHovered) {
|
|
2049
|
+
const hoverOffset = Math.max(1, Math.round(offset / 2));
|
|
2050
|
+
const hoverBlur = Math.max(1, Math.round(blur / 2));
|
|
2051
|
+
return Platform.select({
|
|
2052
|
+
web: {
|
|
2053
|
+
boxShadow: `inset ${hoverOffset}px ${hoverOffset}px ${hoverBlur}px ${darkShadowColors.darker}, inset -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
|
|
2054
|
+
},
|
|
2055
|
+
default: {
|
|
2056
|
+
shadowOpacity: 0,
|
|
2057
|
+
elevation: 0
|
|
2058
|
+
}
|
|
2059
|
+
});
|
|
2060
|
+
}
|
|
2061
|
+
return Platform.select({
|
|
2062
|
+
web: {
|
|
2063
|
+
boxShadow: `inset ${offset}px ${offset}px ${blur}px ${darkShadowColors.darker}, inset -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
|
|
2064
|
+
},
|
|
2065
|
+
default: {
|
|
2066
|
+
shadowOpacity: 0,
|
|
2067
|
+
elevation: 0
|
|
2068
|
+
}
|
|
2069
|
+
});
|
|
2070
|
+
} else {
|
|
2071
|
+
if (isHovered) {
|
|
2072
|
+
const hoverOffset = Math.max(1, Math.round(offset / 2));
|
|
2073
|
+
const hoverBlur = Math.max(1, Math.round(blur / 2));
|
|
2074
|
+
return Platform.select({
|
|
2075
|
+
web: {
|
|
2076
|
+
boxShadow: `${hoverOffset}px ${hoverOffset}px ${hoverBlur}px ${darkShadowColors.dark}, -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
|
|
2077
|
+
},
|
|
2078
|
+
default: {
|
|
2079
|
+
shadowColor: "#000",
|
|
2080
|
+
shadowOffset: { width: hoverOffset, height: hoverOffset },
|
|
2081
|
+
shadowOpacity: 0.2,
|
|
2082
|
+
shadowRadius: hoverBlur / 2,
|
|
2083
|
+
elevation: hoverOffset
|
|
2084
|
+
}
|
|
2085
|
+
});
|
|
2086
|
+
}
|
|
2087
|
+
return Platform.select({
|
|
2088
|
+
web: {
|
|
2089
|
+
boxShadow: `${offset}px ${offset}px ${blur}px ${darkShadowColors.dark}, -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
|
|
2090
|
+
},
|
|
2091
|
+
default: {
|
|
2092
|
+
shadowColor: "#000",
|
|
2093
|
+
shadowOffset: { width: offset, height: offset },
|
|
2094
|
+
shadowOpacity: 0.3,
|
|
2095
|
+
shadowRadius: blur / 2,
|
|
2096
|
+
elevation: offset
|
|
2097
|
+
}
|
|
2098
|
+
});
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
function getElevationShadow(baseColor, level, theme, isHovered = false) {
|
|
2102
|
+
const cacheKey = getShadowCacheKey(baseColor, level, theme, isHovered);
|
|
2103
|
+
if (elevationShadowCache.has(cacheKey)) {
|
|
2104
|
+
return elevationShadowCache.get(cacheKey);
|
|
2105
|
+
}
|
|
2106
|
+
const result = calculateElevationShadow(baseColor, level, theme, isHovered);
|
|
2107
|
+
if (elevationShadowCache.size >= MAX_SHADOW_CACHE_SIZE) {
|
|
2108
|
+
const firstKey = elevationShadowCache.keys().next().value;
|
|
2109
|
+
elevationShadowCache.delete(firstKey);
|
|
2110
|
+
}
|
|
2111
|
+
elevationShadowCache.set(cacheKey, result);
|
|
2112
|
+
return result;
|
|
2113
|
+
}
|
|
2114
|
+
function getBaseSurfaceColor(theme) {
|
|
2115
|
+
return theme === "light" ? semanticColorsLight["surface-raised"] : semanticColorsDark["surface-elevated"];
|
|
2116
|
+
}
|
|
2117
|
+
var componentElevationRanges = {
|
|
2118
|
+
button: {
|
|
2119
|
+
allowed: [2],
|
|
2120
|
+
default: 2,
|
|
2121
|
+
hover: 3
|
|
2122
|
+
},
|
|
2123
|
+
card: {
|
|
2124
|
+
allowed: [1, 2, 3],
|
|
2125
|
+
default: 2,
|
|
2126
|
+
hover: 3
|
|
2127
|
+
},
|
|
2128
|
+
input: {
|
|
2129
|
+
allowed: [-2, -1, 0],
|
|
2130
|
+
default: -1
|
|
2131
|
+
},
|
|
2132
|
+
overlay: {
|
|
2133
|
+
allowed: [4, 5],
|
|
2134
|
+
default: 4
|
|
2135
|
+
}
|
|
2136
|
+
};
|
|
2137
|
+
function getValidatedElevation(component, requested) {
|
|
2138
|
+
const range = componentElevationRanges[component];
|
|
2139
|
+
if (range.allowed.includes(requested)) {
|
|
2140
|
+
return requested;
|
|
2141
|
+
}
|
|
2142
|
+
const sorted = [...range.allowed].sort((a, b) => a - b);
|
|
2143
|
+
if (requested < sorted[0]) return sorted[0];
|
|
2144
|
+
if (requested > sorted[sorted.length - 1]) return sorted[sorted.length - 1];
|
|
2145
|
+
return sorted.reduce(
|
|
2146
|
+
(prev, curr) => Math.abs(curr - requested) < Math.abs(prev - requested) ? curr : prev
|
|
2147
|
+
);
|
|
2148
|
+
}
|
|
2149
|
+
function getTheme() {
|
|
2150
|
+
if (typeof document === "undefined") return "dark";
|
|
2151
|
+
return document.documentElement.classList.contains("light") ? "light" : "dark";
|
|
2152
|
+
}
|
|
2153
|
+
var listeners = [];
|
|
2154
|
+
function subscribe(listener) {
|
|
2155
|
+
listeners = [...listeners, listener];
|
|
2156
|
+
if (typeof document !== "undefined" && listeners.length === 1) {
|
|
2157
|
+
const observer = new MutationObserver((mutations) => {
|
|
2158
|
+
for (const mutation of mutations) {
|
|
2159
|
+
if (mutation.type === "attributes" && mutation.attributeName === "class") {
|
|
2160
|
+
listeners.forEach((l) => l());
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
});
|
|
2164
|
+
observer.observe(document.documentElement, {
|
|
2165
|
+
attributes: true,
|
|
2166
|
+
attributeFilter: ["class"]
|
|
2167
|
+
});
|
|
2168
|
+
subscribe._observer = observer;
|
|
2169
|
+
}
|
|
2170
|
+
return () => {
|
|
2171
|
+
listeners = listeners.filter((l) => l !== listener);
|
|
2172
|
+
if (listeners.length === 0 && subscribe._observer) {
|
|
2173
|
+
subscribe._observer.disconnect();
|
|
2174
|
+
subscribe._observer = null;
|
|
2175
|
+
}
|
|
2176
|
+
};
|
|
2177
|
+
}
|
|
2178
|
+
function getSnapshot() {
|
|
2179
|
+
return getTheme();
|
|
2180
|
+
}
|
|
2181
|
+
function getServerSnapshot() {
|
|
2182
|
+
return "dark";
|
|
2183
|
+
}
|
|
2184
|
+
function useTheme() {
|
|
2185
|
+
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
2186
|
+
}
|
|
2187
|
+
|
|
2188
|
+
// src/components/ui/card/Card.tsx
|
|
2189
|
+
var variantStyles = {
|
|
2190
|
+
elevated: "",
|
|
2191
|
+
// Will be set dynamically via elevation system
|
|
2192
|
+
outline: "border-2 border-border-strong",
|
|
2193
|
+
// Thicker border with stronger contrast
|
|
2194
|
+
filled: "",
|
|
2195
|
+
// Will be set dynamically via elevation system
|
|
2196
|
+
accent: "border border-border",
|
|
2197
|
+
subtle: "border border-border-subtle"
|
|
2198
|
+
};
|
|
2199
|
+
function Card({
|
|
2200
|
+
variant = "elevated",
|
|
2201
|
+
elevation = 2,
|
|
2202
|
+
isInteractive = false,
|
|
2203
|
+
isLoading = false,
|
|
2204
|
+
onPress,
|
|
2205
|
+
borderColor,
|
|
2206
|
+
bgColor,
|
|
2207
|
+
accentColor,
|
|
2208
|
+
accentWidth,
|
|
2209
|
+
className,
|
|
2210
|
+
children,
|
|
2211
|
+
style,
|
|
2212
|
+
skeletonHasHeader = true,
|
|
2213
|
+
skeletonHasFooter = false,
|
|
2214
|
+
skeletonContentLines = 3,
|
|
2215
|
+
...props
|
|
2216
|
+
}) {
|
|
2217
|
+
const isClickable = isInteractive || !!onPress;
|
|
2218
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
2219
|
+
const theme = useTheme();
|
|
2220
|
+
const elevationLevel = useMemo(() => {
|
|
2221
|
+
const validated = getValidatedElevation("card", elevation);
|
|
2222
|
+
if (variant === "outline" || variant === "accent" || variant === "subtle") {
|
|
2223
|
+
return 1;
|
|
2224
|
+
}
|
|
2225
|
+
return validated;
|
|
2226
|
+
}, [variant, elevation]);
|
|
2227
|
+
const baseColor = useMemo(() => getBaseSurfaceColor(theme), [theme]);
|
|
2228
|
+
const surfaceColor = useMemo(() => {
|
|
2229
|
+
if ((variant === "outline" || variant === "accent") && theme === "light") {
|
|
2230
|
+
return "#FAFAFA";
|
|
2231
|
+
}
|
|
2232
|
+
if (variant === "subtle") {
|
|
2233
|
+
return getElevationSurface(baseColor, 0, theme);
|
|
2234
|
+
}
|
|
2235
|
+
return getElevationSurface(baseColor, elevationLevel, theme);
|
|
2236
|
+
}, [baseColor, elevationLevel, theme, variant]);
|
|
2237
|
+
const shadowStyle = useMemo(() => {
|
|
2238
|
+
const shouldHover = isHovered && isClickable;
|
|
2239
|
+
return getElevationShadow(baseColor, elevationLevel, theme, shouldHover);
|
|
2240
|
+
}, [baseColor, elevationLevel, theme, isHovered, isClickable]);
|
|
2241
|
+
const cardContent = isLoading ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2242
|
+
skeletonHasHeader && /* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
2243
|
+
/* @__PURE__ */ jsx(View, { className: "h-5 w-1/3 bg-interactive-disabled rounded" }),
|
|
2244
|
+
/* @__PURE__ */ jsx(View, { className: "mt-2 h-4 w-2/3 bg-interactive-disabled rounded" })
|
|
2245
|
+
] }),
|
|
2246
|
+
/* @__PURE__ */ jsx(CardContent, { children: Array.from({ length: skeletonContentLines }).map((_, i) => /* @__PURE__ */ jsx(
|
|
2247
|
+
View,
|
|
2248
|
+
{
|
|
2249
|
+
className: cn(
|
|
2250
|
+
"h-4 bg-interactive-disabled rounded",
|
|
2251
|
+
i < skeletonContentLines - 1 ? "mb-2 w-full" : "w-4/5"
|
|
2252
|
+
)
|
|
2253
|
+
},
|
|
2254
|
+
i
|
|
2255
|
+
)) }),
|
|
2256
|
+
skeletonHasFooter && /* @__PURE__ */ jsx(CardFooter, { children: /* @__PURE__ */ jsx(View, { className: "h-9 w-24 bg-interactive-disabled rounded" }) })
|
|
2257
|
+
] }) : children;
|
|
2258
|
+
const baseClassName = cn(
|
|
2259
|
+
"rounded-lg overflow-hidden relative",
|
|
2260
|
+
// Apply variant styles, but only use default border color if no custom borderColor
|
|
2261
|
+
variant === "outline" ? borderColor ? "border-2" : variantStyles[variant] : variantStyles[variant],
|
|
2262
|
+
// Remove Tailwind shadow classes - we're using elevation shadows via style prop
|
|
2263
|
+
isClickable && "web:cursor-pointer web:transition-all web:duration-150",
|
|
2264
|
+
isClickable && "web:hover:-translate-y-0.5 active:scale-[0.99]",
|
|
2265
|
+
isLoading && "pointer-events-none animate-pulse",
|
|
2266
|
+
className
|
|
2267
|
+
);
|
|
2268
|
+
const accentStyle = useMemo(() => variant === "accent" ? {
|
|
2269
|
+
borderLeftWidth: accentWidth ?? 3,
|
|
2270
|
+
borderLeftColor: accentColor ?? "var(--color-brand-primary)"
|
|
2271
|
+
} : {}, [variant, accentWidth, accentColor]);
|
|
2272
|
+
const mergedStyle = useMemo(() => {
|
|
2273
|
+
const elevationStyle = {
|
|
2274
|
+
backgroundColor: bgColor || surfaceColor,
|
|
2275
|
+
borderRadius: 8,
|
|
2276
|
+
overflow: "hidden",
|
|
2277
|
+
...shadowStyle,
|
|
2278
|
+
...accentStyle
|
|
2279
|
+
};
|
|
2280
|
+
if (borderColor) {
|
|
2281
|
+
elevationStyle.borderColor = borderColor;
|
|
2282
|
+
}
|
|
2283
|
+
if (!style) return elevationStyle;
|
|
2284
|
+
return [elevationStyle, style];
|
|
2285
|
+
}, [style, surfaceColor, shadowStyle, borderColor, bgColor, accentStyle]);
|
|
2286
|
+
if (isClickable) {
|
|
2287
|
+
return /* @__PURE__ */ jsx(
|
|
2288
|
+
Pressable,
|
|
2289
|
+
{
|
|
2290
|
+
onPress,
|
|
2291
|
+
onHoverIn: () => setIsHovered(true),
|
|
2292
|
+
onHoverOut: () => setIsHovered(false),
|
|
2293
|
+
accessibilityRole: "button",
|
|
2294
|
+
className: baseClassName,
|
|
2295
|
+
style: mergedStyle,
|
|
2296
|
+
...props,
|
|
2297
|
+
children: cardContent
|
|
2298
|
+
}
|
|
2299
|
+
);
|
|
2300
|
+
}
|
|
2301
|
+
return /* @__PURE__ */ jsx(View, { className: baseClassName, style: mergedStyle, ...props, children: cardContent });
|
|
2302
|
+
}
|
|
2303
|
+
function CardHeader({ children, className }) {
|
|
2304
|
+
return /* @__PURE__ */ jsx(View, { className: cn("px-6 py-6", className), children });
|
|
2305
|
+
}
|
|
2306
|
+
function CardContent({ children, className }) {
|
|
2307
|
+
return /* @__PURE__ */ jsx(View, { className: cn("px-6 py-4", className), children });
|
|
2308
|
+
}
|
|
2309
|
+
function CardFooter({ children, className }) {
|
|
2310
|
+
return /* @__PURE__ */ jsx(View, { className: cn("px-6 py-4 flex-row items-center gap-2", className), children });
|
|
2311
|
+
}
|
|
2312
|
+
var t2 = getSemanticColors("dark");
|
|
2313
|
+
var solidVariantColors = {
|
|
2314
|
+
success: t2["status-success"],
|
|
2315
|
+
warning: t2["status-warning"],
|
|
2316
|
+
error: t2["status-error"],
|
|
2317
|
+
neutral: "#6B7280"
|
|
2318
|
+
};
|
|
2319
|
+
var ringVariantStyles = {
|
|
2320
|
+
"on-track": {
|
|
2321
|
+
backgroundColor: "rgba(46,213,115,0.15)",
|
|
2322
|
+
borderWidth: 1,
|
|
2323
|
+
borderColor: "rgba(46,213,115,0.3)"
|
|
2324
|
+
},
|
|
2325
|
+
deviation: {
|
|
2326
|
+
backgroundColor: "rgba(245,158,11,0.15)",
|
|
2327
|
+
borderWidth: 1,
|
|
2328
|
+
borderColor: "rgba(245,158,11,0.25)"
|
|
2329
|
+
},
|
|
2330
|
+
future: {
|
|
2331
|
+
backgroundColor: "rgba(107,114,128,0.1)",
|
|
2332
|
+
borderWidth: 1,
|
|
2333
|
+
borderStyle: "dashed",
|
|
2334
|
+
borderColor: "rgba(107,114,128,0.2)"
|
|
2335
|
+
}
|
|
2336
|
+
};
|
|
2337
|
+
var glowStyles = {
|
|
2338
|
+
success: { boxShadow: "0 0 4px rgba(46,213,115,0.4)" },
|
|
2339
|
+
warning: { boxShadow: "0 0 4px rgba(245,158,11,0.4)" },
|
|
2340
|
+
error: { boxShadow: "0 0 4px rgba(239,68,68,0.4)" },
|
|
2341
|
+
neutral: { boxShadow: "0 0 4px rgba(107,114,128,0.4)" },
|
|
2342
|
+
"on-track": { boxShadow: "0 0 4px rgba(46,213,115,0.4)" },
|
|
2343
|
+
deviation: { boxShadow: "0 0 4px rgba(245,158,11,0.4)" },
|
|
2344
|
+
future: { boxShadow: "0 0 4px rgba(107,114,128,0.4)" }
|
|
2345
|
+
};
|
|
2346
|
+
var iconChars = {
|
|
2347
|
+
check: "\u2713",
|
|
2348
|
+
exclamation: "!",
|
|
2349
|
+
dash: "\u2014"
|
|
2350
|
+
};
|
|
2351
|
+
var iconColors = {
|
|
2352
|
+
success: "#0A5C52",
|
|
2353
|
+
warning: "#6B4000",
|
|
2354
|
+
error: "#5C1A1A",
|
|
2355
|
+
neutral: "#D1D5DB",
|
|
2356
|
+
"on-track": t2["status-success"],
|
|
2357
|
+
deviation: t2["status-warning"],
|
|
2358
|
+
future: "#6B7280"
|
|
2359
|
+
};
|
|
2360
|
+
var sizeDimensions = {
|
|
2361
|
+
sm: { size: 8, showIcon: false },
|
|
2362
|
+
md: { size: 18, showIcon: true }
|
|
2363
|
+
};
|
|
2364
|
+
function isSolidVariant(variant) {
|
|
2365
|
+
return variant in solidVariantColors;
|
|
2366
|
+
}
|
|
2367
|
+
function StatusDot({
|
|
2368
|
+
variant,
|
|
2369
|
+
icon,
|
|
2370
|
+
size = "sm",
|
|
2371
|
+
glow,
|
|
2372
|
+
label,
|
|
2373
|
+
className,
|
|
2374
|
+
...props
|
|
2375
|
+
}) {
|
|
2376
|
+
const config = sizeDimensions[size];
|
|
2377
|
+
const solid = isSolidVariant(variant);
|
|
2378
|
+
const ring = ringVariantStyles[variant];
|
|
2379
|
+
const glowStyle = glow ? glowStyles[variant] : null;
|
|
2380
|
+
const dot = /* @__PURE__ */ jsx(
|
|
2381
|
+
View,
|
|
2382
|
+
{
|
|
2383
|
+
style: [
|
|
2384
|
+
{
|
|
2385
|
+
width: config.size,
|
|
2386
|
+
height: config.size,
|
|
2387
|
+
borderRadius: 9999,
|
|
2388
|
+
alignItems: "center",
|
|
2389
|
+
justifyContent: "center",
|
|
2390
|
+
flexShrink: 0
|
|
2391
|
+
},
|
|
2392
|
+
solid ? { backgroundColor: solidVariantColors[variant] } : void 0,
|
|
2393
|
+
ring ? ring : void 0,
|
|
2394
|
+
glowStyle ? glowStyle : void 0
|
|
2395
|
+
],
|
|
2396
|
+
accessibilityRole: "image",
|
|
2397
|
+
accessibilityLabel: `${variant} status`,
|
|
2398
|
+
testID: "status-dot",
|
|
2399
|
+
children: config.showIcon && icon && /* @__PURE__ */ jsx(
|
|
2400
|
+
Text,
|
|
2401
|
+
{
|
|
2402
|
+
style: {
|
|
2403
|
+
fontSize: 11,
|
|
2404
|
+
lineHeight: 11,
|
|
2405
|
+
fontWeight: "900",
|
|
2406
|
+
color: iconColors[variant]
|
|
2407
|
+
},
|
|
2408
|
+
accessibilityElementsHidden: true,
|
|
2409
|
+
children: iconChars[icon]
|
|
2410
|
+
}
|
|
2411
|
+
)
|
|
2412
|
+
}
|
|
2413
|
+
);
|
|
2414
|
+
if (label) {
|
|
2415
|
+
return /* @__PURE__ */ jsxs(
|
|
2416
|
+
View,
|
|
2417
|
+
{
|
|
2418
|
+
className,
|
|
2419
|
+
style: { flexDirection: "row", alignItems: "center", gap: 6 },
|
|
2420
|
+
accessibilityLabel: `${variant} status: ${label}`,
|
|
2421
|
+
...props,
|
|
2422
|
+
children: [
|
|
2423
|
+
/* @__PURE__ */ jsx(View, { accessibilityElementsHidden: true, children: dot }),
|
|
2424
|
+
/* @__PURE__ */ jsx(
|
|
2425
|
+
Text,
|
|
2426
|
+
{
|
|
2427
|
+
style: { fontSize: 12, lineHeight: 16, color: "#9CA3AF" },
|
|
2428
|
+
accessibilityElementsHidden: true,
|
|
2429
|
+
children: label
|
|
2430
|
+
}
|
|
2431
|
+
)
|
|
2432
|
+
]
|
|
2433
|
+
}
|
|
2434
|
+
);
|
|
2435
|
+
}
|
|
2436
|
+
return /* @__PURE__ */ jsx(View, { className, ...props, children: dot });
|
|
2437
|
+
}
|
|
2438
|
+
var MESO_ACCENT_GRADIENT_DARK = primitiveRamps.orange[500];
|
|
2439
|
+
var MESO_ACCENT_GRADIENT_LIGHT = primitiveRamps.orange[300];
|
|
2440
|
+
|
|
2441
|
+
// src/components/custom/Workout/MesoStatusCard.tsx
|
|
2442
|
+
var t3 = getSemanticColors("dark");
|
|
2443
|
+
var BRAND_PRIMARY4 = t3["brand-primary"];
|
|
2444
|
+
var BRAND_PRIMARY_DARK = MESO_ACCENT_GRADIENT_DARK;
|
|
2445
|
+
var BRAND_PRIMARY_LIGHT = MESO_ACCENT_GRADIENT_LIGHT;
|
|
2446
|
+
var SUCCESS = t3["status-success"];
|
|
2447
|
+
var WARNING = t3["status-warning"];
|
|
2448
|
+
var ERROR = t3["status-error"];
|
|
2449
|
+
var ACCENT_STOPS = [BRAND_PRIMARY_DARK, BRAND_PRIMARY4, BRAND_PRIMARY_LIGHT];
|
|
2450
|
+
var CARD_GRADIENT = `linear-gradient(135deg, ${resolveColor("surface-elevated")} 0%, ${resolveColor("surface-raised")} 100%)`;
|
|
2451
|
+
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%)";
|
|
2452
|
+
var STATUS_VARIANTS = {
|
|
2453
|
+
success: { bg: "rgba(46,213,115,0.15)", border: "rgba(46,213,115,0.3)", text: SUCCESS },
|
|
2454
|
+
warning: { bg: "rgba(249,180,21,0.15)", border: "rgba(249,180,21,0.3)", text: WARNING },
|
|
2455
|
+
error: { bg: "rgba(209,67,67,0.15)", border: "rgba(209,67,67,0.25)", text: ERROR }
|
|
2456
|
+
};
|
|
2457
|
+
function clamp012(value) {
|
|
2458
|
+
if (!Number.isFinite(value)) return 0;
|
|
2459
|
+
if (value < 0) return 0;
|
|
2460
|
+
if (value > 1) return 1;
|
|
2461
|
+
return value;
|
|
2462
|
+
}
|
|
2463
|
+
function getGaugeZoneColor(level) {
|
|
2464
|
+
if (level >= 0.7) return ERROR;
|
|
2465
|
+
if (level >= 0.4) return WARNING;
|
|
2466
|
+
return SUCCESS;
|
|
2467
|
+
}
|
|
2468
|
+
function renderCoachingText(text, highlights) {
|
|
2469
|
+
if (!highlights || highlights.length === 0) return text;
|
|
2470
|
+
const escaped = highlights.filter(Boolean).map((h) => h.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
|
|
2471
|
+
if (escaped.length === 0) return text;
|
|
2472
|
+
const regex = new RegExp(`(${escaped.join("|")})`, "g");
|
|
2473
|
+
return text.split(regex).map(
|
|
2474
|
+
(part, index) => highlights.includes(part) ? /* @__PURE__ */ jsx(
|
|
2475
|
+
Text,
|
|
2476
|
+
{
|
|
2477
|
+
className: "text-text-primary",
|
|
2478
|
+
style: { fontWeight: "700" },
|
|
2479
|
+
children: part
|
|
2480
|
+
},
|
|
2481
|
+
`${part}-${index}`
|
|
2482
|
+
) : /* @__PURE__ */ jsx(Fragment$1, { children: part }, `t-${index}`)
|
|
2483
|
+
);
|
|
2484
|
+
}
|
|
2485
|
+
function StatusPill({ badge }) {
|
|
2486
|
+
const colors = STATUS_VARIANTS[badge.variant];
|
|
2487
|
+
return /* @__PURE__ */ jsxs(
|
|
2488
|
+
View,
|
|
2489
|
+
{
|
|
2490
|
+
className: "flex-row items-center",
|
|
2491
|
+
style: {
|
|
2492
|
+
gap: 5,
|
|
2493
|
+
paddingVertical: 3,
|
|
2494
|
+
paddingHorizontal: 8,
|
|
2495
|
+
borderRadius: 4,
|
|
2496
|
+
borderWidth: 1,
|
|
2497
|
+
backgroundColor: colors.bg,
|
|
2498
|
+
borderColor: colors.border
|
|
2499
|
+
},
|
|
2500
|
+
testID: "meso-status-card-badge",
|
|
2501
|
+
children: [
|
|
2502
|
+
/* @__PURE__ */ jsx(View, { accessibilityElementsHidden: true, children: /* @__PURE__ */ jsx(StatusDot, { variant: badge.variant, size: "sm" }) }),
|
|
2503
|
+
/* @__PURE__ */ jsx(
|
|
2504
|
+
Text,
|
|
2505
|
+
{
|
|
2506
|
+
style: {
|
|
2507
|
+
fontSize: 10,
|
|
2508
|
+
fontFamily: "Inter, sans-serif",
|
|
2509
|
+
fontWeight: "700",
|
|
2510
|
+
letterSpacing: 0.3,
|
|
2511
|
+
color: colors.text
|
|
2512
|
+
},
|
|
2513
|
+
children: badge.label
|
|
2514
|
+
}
|
|
2515
|
+
)
|
|
2516
|
+
]
|
|
2517
|
+
}
|
|
2518
|
+
);
|
|
2519
|
+
}
|
|
2520
|
+
function MetricCell({ metric }) {
|
|
2521
|
+
return /* @__PURE__ */ jsxs(View, { style: { width: "48%" }, testID: "meso-status-card-metric", children: [
|
|
2522
|
+
/* @__PURE__ */ jsx(
|
|
2523
|
+
Text,
|
|
2524
|
+
{
|
|
2525
|
+
className: "text-text-tertiary",
|
|
2526
|
+
style: {
|
|
2527
|
+
fontSize: 10,
|
|
2528
|
+
fontFamily: "Inter, sans-serif",
|
|
2529
|
+
fontWeight: "600",
|
|
2530
|
+
letterSpacing: 0.5,
|
|
2531
|
+
textTransform: "uppercase"
|
|
2532
|
+
},
|
|
2533
|
+
children: metric.label
|
|
2534
|
+
}
|
|
2535
|
+
),
|
|
2536
|
+
/* @__PURE__ */ jsx(
|
|
2537
|
+
Text,
|
|
2538
|
+
{
|
|
2539
|
+
className: "text-text-primary",
|
|
2540
|
+
style: {
|
|
2541
|
+
marginTop: 2,
|
|
2542
|
+
fontSize: 13,
|
|
2543
|
+
fontFamily: "Inter, sans-serif",
|
|
2544
|
+
fontWeight: "600"
|
|
2545
|
+
},
|
|
2546
|
+
children: metric.value
|
|
2547
|
+
}
|
|
2548
|
+
)
|
|
2549
|
+
] });
|
|
2550
|
+
}
|
|
2551
|
+
function Gauge({ gauge }) {
|
|
2552
|
+
const level = clamp012(gauge.level);
|
|
2553
|
+
const percentage = Math.round(level * 100);
|
|
2554
|
+
const markerColor = getGaugeZoneColor(level);
|
|
2555
|
+
return /* @__PURE__ */ jsxs(
|
|
2556
|
+
View,
|
|
2557
|
+
{
|
|
2558
|
+
style: { gap: 6 },
|
|
2559
|
+
accessibilityRole: "progressbar",
|
|
2560
|
+
accessibilityValue: { min: 0, max: 100, now: percentage },
|
|
2561
|
+
accessibilityLabel: `${gauge.label}: ${percentage}%`,
|
|
2562
|
+
"aria-valuenow": percentage,
|
|
2563
|
+
"aria-valuemin": 0,
|
|
2564
|
+
"aria-valuemax": 100,
|
|
2565
|
+
testID: "meso-status-card-gauge",
|
|
2566
|
+
children: [
|
|
2567
|
+
/* @__PURE__ */ jsxs(
|
|
2568
|
+
View,
|
|
2569
|
+
{
|
|
2570
|
+
className: "flex-row items-center justify-between",
|
|
2571
|
+
accessibilityElementsHidden: true,
|
|
2572
|
+
children: [
|
|
2573
|
+
/* @__PURE__ */ jsx(
|
|
2574
|
+
Text,
|
|
2575
|
+
{
|
|
2576
|
+
className: "text-text-secondary",
|
|
2577
|
+
style: {
|
|
2578
|
+
fontSize: 10,
|
|
2579
|
+
fontFamily: "Inter, sans-serif",
|
|
2580
|
+
fontWeight: "500",
|
|
2581
|
+
letterSpacing: 0.5,
|
|
2582
|
+
textTransform: "uppercase"
|
|
2583
|
+
},
|
|
2584
|
+
children: gauge.label
|
|
2585
|
+
}
|
|
2586
|
+
),
|
|
2587
|
+
gauge.sublabel != null && /* @__PURE__ */ jsx(
|
|
2588
|
+
Text,
|
|
2589
|
+
{
|
|
2590
|
+
className: "text-text-tertiary",
|
|
2591
|
+
style: {
|
|
2592
|
+
fontSize: 10,
|
|
2593
|
+
fontFamily: "Inter, sans-serif",
|
|
2594
|
+
fontWeight: "500"
|
|
2595
|
+
},
|
|
2596
|
+
children: gauge.sublabel
|
|
2597
|
+
}
|
|
2598
|
+
)
|
|
2599
|
+
]
|
|
2600
|
+
}
|
|
2601
|
+
),
|
|
2602
|
+
/* @__PURE__ */ jsxs(
|
|
2603
|
+
View,
|
|
2604
|
+
{
|
|
2605
|
+
style: {
|
|
2606
|
+
height: 8,
|
|
2607
|
+
borderRadius: 4,
|
|
2608
|
+
position: "relative",
|
|
2609
|
+
backgroundImage: GAUGE_GRADIENT
|
|
2610
|
+
},
|
|
2611
|
+
accessibilityElementsHidden: true,
|
|
2612
|
+
children: [
|
|
2613
|
+
/* @__PURE__ */ jsx(
|
|
2614
|
+
View,
|
|
2615
|
+
{
|
|
2616
|
+
style: {
|
|
2617
|
+
position: "absolute",
|
|
2618
|
+
left: "50%",
|
|
2619
|
+
top: 0,
|
|
2620
|
+
bottom: 0,
|
|
2621
|
+
width: 1,
|
|
2622
|
+
marginLeft: -0.5,
|
|
2623
|
+
backgroundColor: "rgba(255,255,255,0.3)"
|
|
2624
|
+
},
|
|
2625
|
+
testID: "meso-status-card-gauge-center"
|
|
2626
|
+
}
|
|
2627
|
+
),
|
|
2628
|
+
/* @__PURE__ */ jsx(
|
|
2629
|
+
View,
|
|
2630
|
+
{
|
|
2631
|
+
className: "border-text-primary",
|
|
2632
|
+
style: {
|
|
2633
|
+
position: "absolute",
|
|
2634
|
+
left: `${percentage}%`,
|
|
2635
|
+
top: -3,
|
|
2636
|
+
marginLeft: -7,
|
|
2637
|
+
width: 14,
|
|
2638
|
+
height: 14,
|
|
2639
|
+
borderRadius: 9999,
|
|
2640
|
+
borderWidth: 2,
|
|
2641
|
+
backgroundColor: markerColor,
|
|
2642
|
+
boxShadow: "0 0 4px rgba(0,0,0,0.5)"
|
|
2643
|
+
},
|
|
2644
|
+
testID: "meso-status-card-gauge-marker"
|
|
2645
|
+
}
|
|
2646
|
+
)
|
|
2647
|
+
]
|
|
2648
|
+
}
|
|
2649
|
+
)
|
|
2650
|
+
]
|
|
2651
|
+
}
|
|
2652
|
+
);
|
|
2653
|
+
}
|
|
2654
|
+
function MesoStatusCard({
|
|
2655
|
+
mesoName,
|
|
2656
|
+
mesoSubtitle,
|
|
2657
|
+
statusBadge,
|
|
2658
|
+
metrics,
|
|
2659
|
+
gauges,
|
|
2660
|
+
coaching,
|
|
2661
|
+
nextTarget,
|
|
2662
|
+
className,
|
|
2663
|
+
...props
|
|
2664
|
+
}) {
|
|
2665
|
+
return /* @__PURE__ */ jsxs(
|
|
2666
|
+
Card,
|
|
2667
|
+
{
|
|
2668
|
+
variant: "outline",
|
|
2669
|
+
elevation: 1,
|
|
2670
|
+
borderColor: BRAND_PRIMARY_DARK,
|
|
2671
|
+
className,
|
|
2672
|
+
style: {
|
|
2673
|
+
borderColor: BRAND_PRIMARY_DARK,
|
|
2674
|
+
borderWidth: 1,
|
|
2675
|
+
backgroundImage: CARD_GRADIENT
|
|
2676
|
+
},
|
|
2677
|
+
role: "article",
|
|
2678
|
+
"aria-label": `Mesocycle status for ${mesoName}`,
|
|
2679
|
+
testID: "meso-status-card",
|
|
2680
|
+
...props,
|
|
2681
|
+
children: [
|
|
2682
|
+
/* @__PURE__ */ jsx(
|
|
2683
|
+
View,
|
|
2684
|
+
{
|
|
2685
|
+
className: "flex-row",
|
|
2686
|
+
style: { position: "absolute", top: 0, left: 0, right: 0, height: 3, zIndex: 1 },
|
|
2687
|
+
accessibilityElementsHidden: true,
|
|
2688
|
+
testID: "meso-status-card-accent",
|
|
2689
|
+
children: ACCENT_STOPS.map((color) => /* @__PURE__ */ jsx(View, { style: { flex: 1, backgroundColor: color } }, color))
|
|
2690
|
+
}
|
|
2691
|
+
),
|
|
2692
|
+
/* @__PURE__ */ jsxs(View, { style: { padding: 14, gap: 14 }, testID: "meso-status-card-body", children: [
|
|
2693
|
+
/* @__PURE__ */ jsxs(View, { testID: "meso-status-card-header", children: [
|
|
2694
|
+
/* @__PURE__ */ jsxs(
|
|
2695
|
+
View,
|
|
2696
|
+
{
|
|
2697
|
+
className: "flex-row items-center justify-between",
|
|
2698
|
+
style: { gap: 8 },
|
|
2699
|
+
children: [
|
|
2700
|
+
/* @__PURE__ */ jsx(
|
|
2701
|
+
Text,
|
|
2702
|
+
{
|
|
2703
|
+
className: "text-text-primary",
|
|
2704
|
+
style: {
|
|
2705
|
+
flexShrink: 1,
|
|
2706
|
+
fontSize: 15,
|
|
2707
|
+
fontFamily: '"Space Grotesk", sans-serif',
|
|
2708
|
+
fontWeight: "700"
|
|
2709
|
+
},
|
|
2710
|
+
testID: "meso-status-card-name",
|
|
2711
|
+
children: mesoName
|
|
2712
|
+
}
|
|
2713
|
+
),
|
|
2714
|
+
/* @__PURE__ */ jsx(StatusPill, { badge: statusBadge })
|
|
2715
|
+
]
|
|
2716
|
+
}
|
|
2717
|
+
),
|
|
2718
|
+
/* @__PURE__ */ jsx(
|
|
2719
|
+
Text,
|
|
2720
|
+
{
|
|
2721
|
+
className: "text-text-secondary",
|
|
2722
|
+
style: {
|
|
2723
|
+
marginTop: 4,
|
|
2724
|
+
fontSize: 12,
|
|
2725
|
+
fontFamily: "Inter, sans-serif"
|
|
2726
|
+
},
|
|
2727
|
+
testID: "meso-status-card-subtitle",
|
|
2728
|
+
children: mesoSubtitle
|
|
2729
|
+
}
|
|
2730
|
+
)
|
|
2731
|
+
] }),
|
|
2732
|
+
metrics.length > 0 && /* @__PURE__ */ jsx(
|
|
2733
|
+
View,
|
|
2734
|
+
{
|
|
2735
|
+
className: "flex-row flex-wrap",
|
|
2736
|
+
style: { gap: 8 },
|
|
2737
|
+
testID: "meso-status-card-metrics",
|
|
2738
|
+
children: metrics.map((metric, index) => /* @__PURE__ */ jsx(MetricCell, { metric }, `${metric.label}-${index}`))
|
|
2739
|
+
}
|
|
2740
|
+
),
|
|
2741
|
+
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}`)) }),
|
|
2742
|
+
coaching != null && /* @__PURE__ */ jsx(
|
|
2743
|
+
View,
|
|
2744
|
+
{
|
|
2745
|
+
style: {
|
|
2746
|
+
backgroundColor: "rgba(249,180,21,0.06)",
|
|
2747
|
+
borderWidth: 1,
|
|
2748
|
+
borderColor: "rgba(249,180,21,0.15)",
|
|
2749
|
+
borderRadius: 8,
|
|
2750
|
+
paddingVertical: 10,
|
|
2751
|
+
paddingHorizontal: 12
|
|
2752
|
+
},
|
|
2753
|
+
testID: "meso-status-card-coaching",
|
|
2754
|
+
children: /* @__PURE__ */ jsx(
|
|
2755
|
+
Text,
|
|
2756
|
+
{
|
|
2757
|
+
className: "text-text-secondary",
|
|
2758
|
+
style: {
|
|
2759
|
+
fontSize: 12,
|
|
2760
|
+
lineHeight: 17,
|
|
2761
|
+
fontFamily: "Inter, sans-serif"
|
|
2762
|
+
},
|
|
2763
|
+
children: renderCoachingText(coaching.text, coaching.highlights)
|
|
2764
|
+
}
|
|
2765
|
+
)
|
|
2766
|
+
}
|
|
2767
|
+
),
|
|
2768
|
+
nextTarget != null && /* @__PURE__ */ jsxs(
|
|
2769
|
+
View,
|
|
2770
|
+
{
|
|
2771
|
+
className: "flex-row items-center",
|
|
2772
|
+
style: {
|
|
2773
|
+
gap: 8,
|
|
2774
|
+
backgroundColor: "rgba(46,213,115,0.06)",
|
|
2775
|
+
borderWidth: 1,
|
|
2776
|
+
borderColor: "rgba(46,213,115,0.2)",
|
|
2777
|
+
borderRadius: 8,
|
|
2778
|
+
paddingVertical: 10,
|
|
2779
|
+
paddingHorizontal: 12
|
|
2780
|
+
},
|
|
2781
|
+
testID: "meso-status-card-next-target",
|
|
2782
|
+
children: [
|
|
2783
|
+
/* @__PURE__ */ jsx(Text, { style: { fontSize: 14, color: SUCCESS }, accessibilityElementsHidden: true, children: nextTarget.icon }),
|
|
2784
|
+
/* @__PURE__ */ jsx(
|
|
2785
|
+
Text,
|
|
2786
|
+
{
|
|
2787
|
+
style: {
|
|
2788
|
+
flexShrink: 1,
|
|
2789
|
+
fontSize: 12,
|
|
2790
|
+
fontFamily: "Inter, sans-serif",
|
|
2791
|
+
fontWeight: "600",
|
|
2792
|
+
color: SUCCESS
|
|
2793
|
+
},
|
|
2794
|
+
children: nextTarget.text
|
|
2795
|
+
}
|
|
2796
|
+
)
|
|
2797
|
+
]
|
|
2798
|
+
}
|
|
2799
|
+
)
|
|
2800
|
+
] })
|
|
2801
|
+
]
|
|
2802
|
+
}
|
|
2803
|
+
);
|
|
2804
|
+
}
|
|
2805
|
+
|
|
2806
|
+
// src/components/custom/Workout/TrainingStatusPage.tsx
|
|
855
2807
|
var STATUS_ORDER = ["under", "maintenance", "productive", "over"];
|
|
856
2808
|
function deriveTrainingSummary(muscles) {
|
|
857
2809
|
const statusCounts = {
|