@titan-design/react-ui 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bodymap.js +441 -97
- package/dist/bodymap.js.map +1 -1
- package/dist/bodymap.mjs +49 -62
- package/dist/bodymap.mjs.map +1 -1
- package/dist/{chunk-TOD2WQBG.mjs → chunk-2SISKTWM.mjs} +22 -43
- package/dist/chunk-2SISKTWM.mjs.map +1 -0
- package/dist/{chunk-P7TSQUN6.mjs → chunk-SNVKL5WZ.mjs} +42 -5
- package/dist/chunk-SNVKL5WZ.mjs.map +1 -0
- package/dist/index.d.mts +42 -2
- package/dist/index.d.ts +42 -2
- package/dist/index.js +431 -328
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +397 -314
- package/dist/index.mjs.map +1 -1
- package/dist/theme/index.d.mts +28 -2
- package/dist/theme/index.d.ts +28 -2
- package/dist/theme/index.js +37 -0
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/index.mjs +1 -1
- package/package.json +1 -1
- package/src/components/custom/Workout/ActiveWorkoutPage.tsx +10 -15
- package/src/components/custom/Workout/BodyMap.tsx +7 -8
- package/src/components/custom/Workout/BodyMapDetailPanel.tsx +25 -28
- package/src/components/custom/Workout/CapacityBandChart.tsx +2 -3
- package/src/components/custom/Workout/ExerciseCard.tsx +12 -27
- package/src/components/custom/Workout/ExerciseDetailPage.tsx +21 -27
- package/src/components/custom/Workout/InputBar.tsx +10 -11
- package/src/components/custom/Workout/MesoCard.tsx +2 -6
- package/src/components/custom/Workout/MesoStatusCard.tsx +17 -15
- package/src/components/custom/Workout/MuscleGroupChip.tsx +2 -4
- package/src/components/custom/Workout/PlaceholderStrip.tsx +2 -3
- package/src/components/custom/Workout/PrHistoryModal.tsx +12 -14
- package/src/components/custom/Workout/ProgramPlanningPage.tsx +8 -12
- package/src/components/custom/Workout/ReadinessCheck.tsx +13 -11
- package/src/components/custom/Workout/RestTimer.tsx +8 -7
- package/src/components/custom/Workout/SetRow.tsx +10 -7
- package/src/components/custom/Workout/StrengthTrendChart.tsx +15 -17
- package/src/components/custom/Workout/TempoBar.stories.tsx +95 -0
- package/src/components/custom/Workout/TempoBar.test.tsx +103 -0
- package/src/components/custom/Workout/TempoBar.tsx +215 -0
- package/src/components/custom/Workout/TrainingStatusPage.tsx +8 -17
- package/src/components/custom/Workout/VelocityStrip.tsx +7 -5
- package/src/components/custom/Workout/WeekRow.tsx +2 -1
- package/src/components/custom/Workout/WorkoutCard.tsx +3 -8
- package/src/components/custom/Workout/index.ts +9 -0
- package/src/test/nativewind-stub.ts +13 -0
- package/src/theme/ThemeProvider.test.tsx +24 -0
- package/src/theme/ThemeProvider.tsx +50 -0
- package/src/theme/index.ts +2 -0
- package/src/theme/resolve-color.ts +19 -0
- package/dist/chunk-P7TSQUN6.mjs.map +0 -1
- package/dist/chunk-TOD2WQBG.mjs.map +0 -1
|
@@ -16,14 +16,10 @@ import {
|
|
|
16
16
|
import { ExerciseCard, type ExerciseCardProps } from './ExerciseCard'
|
|
17
17
|
import { type SetRowProps } from './SetRow'
|
|
18
18
|
import { VelocityStrip, calculateMeanVelocity, calculateVelocityLoss } from './VelocityStrip'
|
|
19
|
+
import { resolveColor } from '../../../theme/resolve-color'
|
|
20
|
+
import { cn } from '../../../utils/cn'
|
|
19
21
|
|
|
20
|
-
const SURFACE_ELEVATED = 'var(--color-surface-elevated)'
|
|
21
|
-
const BORDER_DEFAULT = 'var(--color-border-default)'
|
|
22
22
|
const BRAND_PRIMARY = '#FF7900'
|
|
23
|
-
const TEXT_PRIMARY = 'var(--color-text-primary)'
|
|
24
|
-
const TEXT_SECONDARY = 'var(--color-text-secondary)'
|
|
25
|
-
const TEXT_TERTIARY = 'var(--color-text-tertiary)'
|
|
26
|
-
const PAGE_BG = 'var(--color-background-base)'
|
|
27
23
|
|
|
28
24
|
/** Inner plot width: page width 390 − 16 page padding − 12 card padding on each side. */
|
|
29
25
|
const CHART_WIDTH = 326
|
|
@@ -190,7 +186,7 @@ function TabBar({ active, onSelect }: TabBarProps) {
|
|
|
190
186
|
className="flex-row"
|
|
191
187
|
style={{
|
|
192
188
|
borderBottomWidth: 1,
|
|
193
|
-
borderBottomColor:
|
|
189
|
+
borderBottomColor: resolveColor('border-default'),
|
|
194
190
|
}}
|
|
195
191
|
accessibilityRole={'tablist' as ViewProps['accessibilityRole']}
|
|
196
192
|
testID="exercise-detail-page-tabs"
|
|
@@ -213,11 +209,11 @@ function TabBar({ active, onSelect }: TabBarProps) {
|
|
|
213
209
|
testID={`exercise-detail-page-tab-${key}`}
|
|
214
210
|
>
|
|
215
211
|
<Text
|
|
212
|
+
className={isActive ? 'text-text-primary' : 'text-text-tertiary'}
|
|
216
213
|
style={{
|
|
217
214
|
fontSize: 13,
|
|
218
215
|
fontFamily: 'Inter, sans-serif',
|
|
219
216
|
fontWeight: isActive ? '700' : '500',
|
|
220
|
-
color: isActive ? TEXT_PRIMARY : TEXT_TERTIARY,
|
|
221
217
|
}}
|
|
222
218
|
>
|
|
223
219
|
{label}
|
|
@@ -244,27 +240,27 @@ function StatStrip({ stats, unit }: { stats: ExerciseDetailStats; unit: 'lbs' |
|
|
|
244
240
|
return (
|
|
245
241
|
<View
|
|
246
242
|
key={key}
|
|
243
|
+
className="bg-surface-elevated border-border"
|
|
247
244
|
style={{
|
|
248
245
|
flex: 1,
|
|
249
246
|
padding: 12,
|
|
250
247
|
borderRadius: 10,
|
|
251
|
-
backgroundColor: SURFACE_ELEVATED,
|
|
252
248
|
borderWidth: 1,
|
|
253
|
-
borderColor: BORDER_DEFAULT,
|
|
254
249
|
}}
|
|
255
250
|
testID={`exercise-detail-page-stat-${key}`}
|
|
256
251
|
>
|
|
257
252
|
<Text
|
|
253
|
+
className="text-text-primary"
|
|
258
254
|
style={{
|
|
259
255
|
fontSize: 18,
|
|
260
256
|
fontFamily: '"Space Grotesk", sans-serif',
|
|
261
257
|
fontWeight: '700',
|
|
262
|
-
color: TEXT_PRIMARY,
|
|
263
258
|
}}
|
|
264
259
|
>
|
|
265
260
|
{value}
|
|
266
261
|
</Text>
|
|
267
262
|
<Text
|
|
263
|
+
className="text-text-tertiary"
|
|
268
264
|
style={{
|
|
269
265
|
marginTop: 2,
|
|
270
266
|
fontSize: 10,
|
|
@@ -272,7 +268,6 @@ function StatStrip({ stats, unit }: { stats: ExerciseDetailStats; unit: 'lbs' |
|
|
|
272
268
|
fontWeight: '600',
|
|
273
269
|
letterSpacing: 0.4,
|
|
274
270
|
textTransform: 'uppercase',
|
|
275
|
-
color: TEXT_TERTIARY,
|
|
276
271
|
}}
|
|
277
272
|
>
|
|
278
273
|
{label}
|
|
@@ -295,10 +290,9 @@ function SectionCard({
|
|
|
295
290
|
}) {
|
|
296
291
|
return (
|
|
297
292
|
<View
|
|
293
|
+
className="bg-surface-elevated border-border"
|
|
298
294
|
style={{
|
|
299
|
-
backgroundColor: SURFACE_ELEVATED,
|
|
300
295
|
borderWidth: 1,
|
|
301
|
-
borderColor: BORDER_DEFAULT,
|
|
302
296
|
borderRadius: 12,
|
|
303
297
|
padding: 12,
|
|
304
298
|
gap: 10,
|
|
@@ -306,13 +300,13 @@ function SectionCard({
|
|
|
306
300
|
testID={testID}
|
|
307
301
|
>
|
|
308
302
|
<Text
|
|
303
|
+
className="text-text-tertiary"
|
|
309
304
|
style={{
|
|
310
305
|
fontSize: 11,
|
|
311
306
|
fontFamily: 'Inter, sans-serif',
|
|
312
307
|
fontWeight: '600',
|
|
313
308
|
letterSpacing: 0.6,
|
|
314
309
|
textTransform: 'uppercase',
|
|
315
|
-
color: TEXT_TERTIARY,
|
|
316
310
|
}}
|
|
317
311
|
>
|
|
318
312
|
{title}
|
|
@@ -334,7 +328,8 @@ function EntryList({ entries, expandedId, onToggle, emptyLabel, testID }: EntryL
|
|
|
334
328
|
if (entries.length === 0) {
|
|
335
329
|
return (
|
|
336
330
|
<Text
|
|
337
|
-
|
|
331
|
+
className="text-text-tertiary"
|
|
332
|
+
style={{ fontSize: 12, fontFamily: 'Inter, sans-serif' }}
|
|
338
333
|
testID={`${testID}-empty`}
|
|
339
334
|
>
|
|
340
335
|
{emptyLabel}
|
|
@@ -367,12 +362,12 @@ function VbtBreakdown({ sets }: { sets: ExerciseVbtSet[] }) {
|
|
|
367
362
|
testID="exercise-detail-page-vbt-set"
|
|
368
363
|
>
|
|
369
364
|
<Text
|
|
365
|
+
className="text-text-secondary"
|
|
370
366
|
style={{
|
|
371
367
|
width: 44,
|
|
372
368
|
fontSize: 11,
|
|
373
369
|
fontFamily: 'Inter, sans-serif',
|
|
374
370
|
fontWeight: '600',
|
|
375
|
-
color: TEXT_SECONDARY,
|
|
376
371
|
}}
|
|
377
372
|
>
|
|
378
373
|
{set.label}
|
|
@@ -381,11 +376,11 @@ function VbtBreakdown({ sets }: { sets: ExerciseVbtSet[] }) {
|
|
|
381
376
|
<VelocityStrip velocities={set.velocities} variant="mini" />
|
|
382
377
|
</View>
|
|
383
378
|
<Text
|
|
379
|
+
className="text-text-tertiary"
|
|
384
380
|
style={{
|
|
385
381
|
fontSize: 11,
|
|
386
382
|
fontFamily: 'Inter, sans-serif',
|
|
387
383
|
fontVariant: ['tabular-nums'],
|
|
388
|
-
color: TEXT_TERTIARY,
|
|
389
384
|
}}
|
|
390
385
|
>
|
|
391
386
|
{`${mean.toFixed(2)} · -${loss}%`}
|
|
@@ -407,26 +402,26 @@ function VbtSummaryRow({ summary }: { summary: VbtSummary }) {
|
|
|
407
402
|
{cells.map((cell) => (
|
|
408
403
|
<View
|
|
409
404
|
key={cell.label}
|
|
405
|
+
className="bg-surface-elevated border-border"
|
|
410
406
|
style={{
|
|
411
407
|
flex: 1,
|
|
412
408
|
padding: 12,
|
|
413
409
|
borderRadius: 10,
|
|
414
|
-
backgroundColor: SURFACE_ELEVATED,
|
|
415
410
|
borderWidth: 1,
|
|
416
|
-
borderColor: BORDER_DEFAULT,
|
|
417
411
|
}}
|
|
418
412
|
>
|
|
419
413
|
<Text
|
|
414
|
+
className="text-text-primary"
|
|
420
415
|
style={{
|
|
421
416
|
fontSize: 16,
|
|
422
417
|
fontFamily: '"Space Grotesk", sans-serif',
|
|
423
418
|
fontWeight: '700',
|
|
424
|
-
color: TEXT_PRIMARY,
|
|
425
419
|
}}
|
|
426
420
|
>
|
|
427
421
|
{cell.value}
|
|
428
422
|
</Text>
|
|
429
423
|
<Text
|
|
424
|
+
className="text-text-tertiary"
|
|
430
425
|
style={{
|
|
431
426
|
marginTop: 2,
|
|
432
427
|
fontSize: 10,
|
|
@@ -434,7 +429,6 @@ function VbtSummaryRow({ summary }: { summary: VbtSummary }) {
|
|
|
434
429
|
fontWeight: '600',
|
|
435
430
|
letterSpacing: 0.4,
|
|
436
431
|
textTransform: 'uppercase',
|
|
437
|
-
color: TEXT_TERTIARY,
|
|
438
432
|
}}
|
|
439
433
|
>
|
|
440
434
|
{cell.label}
|
|
@@ -488,8 +482,8 @@ export function ExerciseDetailPage({
|
|
|
488
482
|
|
|
489
483
|
return (
|
|
490
484
|
<View
|
|
491
|
-
className={className}
|
|
492
|
-
style={{ width: 390
|
|
485
|
+
className={cn('bg-background-base', className)}
|
|
486
|
+
style={{ width: 390 }}
|
|
493
487
|
accessibilityRole={'main' as ViewProps['accessibilityRole']}
|
|
494
488
|
aria-label={exercise.name}
|
|
495
489
|
testID="exercise-detail-page"
|
|
@@ -504,22 +498,22 @@ export function ExerciseDetailPage({
|
|
|
504
498
|
<View style={{ flexShrink: 1 }}>
|
|
505
499
|
<Text
|
|
506
500
|
accessibilityRole="header"
|
|
501
|
+
className="text-text-primary"
|
|
507
502
|
style={{
|
|
508
503
|
fontSize: 20,
|
|
509
504
|
fontFamily: '"Space Grotesk", sans-serif',
|
|
510
505
|
fontWeight: '700',
|
|
511
|
-
color: TEXT_PRIMARY,
|
|
512
506
|
}}
|
|
513
507
|
testID="exercise-detail-page-title"
|
|
514
508
|
>
|
|
515
509
|
{exercise.name}
|
|
516
510
|
</Text>
|
|
517
511
|
<Text
|
|
512
|
+
className="text-text-secondary"
|
|
518
513
|
style={{
|
|
519
514
|
marginTop: 2,
|
|
520
515
|
fontSize: 12,
|
|
521
516
|
fontFamily: 'Inter, sans-serif',
|
|
522
|
-
color: TEXT_SECONDARY,
|
|
523
517
|
}}
|
|
524
518
|
testID="exercise-detail-page-subtitle"
|
|
525
519
|
>
|
|
@@ -539,13 +533,13 @@ export function ExerciseDetailPage({
|
|
|
539
533
|
testID="exercise-detail-page-e1rm"
|
|
540
534
|
>
|
|
541
535
|
<Text
|
|
536
|
+
className="text-text-tertiary"
|
|
542
537
|
style={{
|
|
543
538
|
fontSize: 9,
|
|
544
539
|
fontFamily: 'Inter, sans-serif',
|
|
545
540
|
fontWeight: '600',
|
|
546
541
|
letterSpacing: 0.4,
|
|
547
542
|
textTransform: 'uppercase',
|
|
548
|
-
color: TEXT_TERTIARY,
|
|
549
543
|
}}
|
|
550
544
|
>
|
|
551
545
|
e1RM
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Font mapping: font-heading=Space Grotesk, font-body=Nunito Sans (UI), font-sans=Inter (body)
|
|
2
2
|
import React from 'react'
|
|
3
3
|
import { View, Text, Pressable, TextInput } from 'react-native'
|
|
4
|
+
import { resolveColor } from '../../../theme/resolve-color'
|
|
4
5
|
|
|
5
6
|
export interface InputBarProps {
|
|
6
7
|
exerciseName: string
|
|
@@ -17,19 +18,15 @@ export interface InputBarProps {
|
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
const BRAND_PRIMARY = '#FF7900'
|
|
20
|
-
const
|
|
21
|
-
const TEXT_TERTIARY = 'var(--color-text-tertiary)'
|
|
21
|
+
const INPUT_CLASSNAME = 'bg-surface-raised border-border-strong text-text-primary'
|
|
22
22
|
|
|
23
23
|
const inputStyle = {
|
|
24
24
|
fontSize: 14,
|
|
25
25
|
fontWeight: '600' as const,
|
|
26
26
|
fontFamily: 'Inter, sans-serif',
|
|
27
|
-
backgroundColor: 'var(--color-surface-raised)',
|
|
28
27
|
borderWidth: 1,
|
|
29
|
-
borderColor: 'var(--color-border-strong)',
|
|
30
28
|
borderRadius: 6,
|
|
31
29
|
textAlign: 'center' as const,
|
|
32
|
-
color: TEXT_PRIMARY,
|
|
33
30
|
paddingVertical: 5,
|
|
34
31
|
paddingHorizontal: 2,
|
|
35
32
|
}
|
|
@@ -53,11 +50,11 @@ export function InputBar({
|
|
|
53
50
|
|
|
54
51
|
return (
|
|
55
52
|
<View
|
|
53
|
+
className="bg-surface-elevated"
|
|
56
54
|
style={{
|
|
57
55
|
width: '100%',
|
|
58
|
-
backgroundColor: 'var(--color-surface-elevated)',
|
|
59
56
|
borderTopWidth: 1,
|
|
60
|
-
borderTopColor: '
|
|
57
|
+
borderTopColor: resolveColor('border-default'),
|
|
61
58
|
paddingTop: 10,
|
|
62
59
|
paddingHorizontal: 16,
|
|
63
60
|
paddingBottom: 12,
|
|
@@ -70,11 +67,11 @@ export function InputBar({
|
|
|
70
67
|
>
|
|
71
68
|
<View style={{ minWidth: 80, flexDirection: 'column' }}>
|
|
72
69
|
<Text
|
|
70
|
+
className="text-text-primary"
|
|
73
71
|
style={{
|
|
74
72
|
fontSize: 12,
|
|
75
73
|
fontWeight: '700',
|
|
76
74
|
fontFamily: '"Space Grotesk", sans-serif',
|
|
77
|
-
color: TEXT_PRIMARY,
|
|
78
75
|
}}
|
|
79
76
|
testID="input-bar-exercise-name"
|
|
80
77
|
numberOfLines={1}
|
|
@@ -82,10 +79,10 @@ export function InputBar({
|
|
|
82
79
|
{exerciseName}
|
|
83
80
|
</Text>
|
|
84
81
|
<Text
|
|
82
|
+
className="text-text-tertiary"
|
|
85
83
|
style={{
|
|
86
84
|
fontSize: 10,
|
|
87
85
|
fontFamily: 'Inter, sans-serif',
|
|
88
|
-
color: TEXT_TERTIARY,
|
|
89
86
|
}}
|
|
90
87
|
testID="input-bar-set-info"
|
|
91
88
|
>
|
|
@@ -97,16 +94,17 @@ export function InputBar({
|
|
|
97
94
|
<TextInput
|
|
98
95
|
value={reps}
|
|
99
96
|
onChangeText={onRepsChange}
|
|
97
|
+
className={INPUT_CLASSNAME}
|
|
100
98
|
style={{ ...inputStyle, width: 36 }}
|
|
101
99
|
accessibilityLabel="Reps"
|
|
102
100
|
testID="input-bar-reps"
|
|
103
101
|
keyboardType="numeric"
|
|
104
102
|
/>
|
|
105
103
|
<Text
|
|
104
|
+
className="text-text-tertiary"
|
|
106
105
|
style={{
|
|
107
106
|
fontSize: 12,
|
|
108
107
|
fontFamily: 'Inter, sans-serif',
|
|
109
|
-
color: TEXT_TERTIARY,
|
|
110
108
|
}}
|
|
111
109
|
>
|
|
112
110
|
{'\u00D7'}
|
|
@@ -114,17 +112,18 @@ export function InputBar({
|
|
|
114
112
|
<TextInput
|
|
115
113
|
value={weight}
|
|
116
114
|
onChangeText={onWeightChange}
|
|
115
|
+
className={INPUT_CLASSNAME}
|
|
117
116
|
style={{ ...inputStyle, width: 52 }}
|
|
118
117
|
accessibilityLabel={`Weight in ${unit}`}
|
|
119
118
|
testID="input-bar-weight"
|
|
120
119
|
keyboardType="numeric"
|
|
121
120
|
/>
|
|
122
121
|
<Text
|
|
122
|
+
className="text-text-tertiary"
|
|
123
123
|
style={{
|
|
124
124
|
fontSize: 12,
|
|
125
125
|
fontWeight: '500',
|
|
126
126
|
fontFamily: 'Inter, sans-serif',
|
|
127
|
-
color: TEXT_TERTIARY,
|
|
128
127
|
}}
|
|
129
128
|
testID="input-bar-unit"
|
|
130
129
|
>
|
|
@@ -9,10 +9,6 @@ const BRAND_PRIMARY = '#FF7900'
|
|
|
9
9
|
const BRAND_PRIMARY_DARK = '#C45E00'
|
|
10
10
|
const BRAND_PRIMARY_LIGHT = '#FFB066'
|
|
11
11
|
const BORDER_DEFAULT = '#1F1F1F'
|
|
12
|
-
// Theme-aware foregrounds: resolve to a readable color in both light and dark
|
|
13
|
-
// (react-native-web passes the CSS var through to the inline style).
|
|
14
|
-
const TEXT_PRIMARY = 'var(--color-text-primary)'
|
|
15
|
-
const TEXT_SECONDARY = 'var(--color-text-secondary)'
|
|
16
12
|
|
|
17
13
|
/** Gradient stops for the 3px top accent: dark -> primary -> light. */
|
|
18
14
|
const ACCENT_STOPS = [BRAND_PRIMARY_DARK, BRAND_PRIMARY, BRAND_PRIMARY_LIGHT]
|
|
@@ -119,11 +115,11 @@ export function MesoCard({
|
|
|
119
115
|
<View style={{ paddingHorizontal: 14, paddingTop: 12, paddingBottom: 10 }} testID="meso-card-body">
|
|
120
116
|
<View className="flex-row items-center" style={{ gap: 8 }} testID="meso-card-header">
|
|
121
117
|
<Text
|
|
118
|
+
className="text-text-primary"
|
|
122
119
|
style={{
|
|
123
120
|
fontSize: 15,
|
|
124
121
|
fontFamily: '"Space Grotesk", sans-serif',
|
|
125
122
|
fontWeight: '700',
|
|
126
|
-
color: TEXT_PRIMARY,
|
|
127
123
|
}}
|
|
128
124
|
testID="meso-card-name"
|
|
129
125
|
>
|
|
@@ -135,11 +131,11 @@ export function MesoCard({
|
|
|
135
131
|
</View>
|
|
136
132
|
|
|
137
133
|
<Text
|
|
134
|
+
className="text-text-secondary"
|
|
138
135
|
style={{
|
|
139
136
|
marginTop: 4,
|
|
140
137
|
fontSize: 12,
|
|
141
138
|
fontFamily: 'Inter, sans-serif',
|
|
142
|
-
color: TEXT_SECONDARY,
|
|
143
139
|
}}
|
|
144
140
|
testID="meso-card-subheader"
|
|
145
141
|
>
|
|
@@ -3,13 +3,11 @@ import { Fragment, type ReactNode } from 'react'
|
|
|
3
3
|
import { View, Text, type ViewProps, type ViewStyle } from 'react-native'
|
|
4
4
|
import { Card } from '../../ui/card'
|
|
5
5
|
import { StatusDot } from './StatusDot'
|
|
6
|
+
import { resolveColor } from '../../../theme/resolve-color'
|
|
6
7
|
|
|
7
8
|
const BRAND_PRIMARY = '#FF7900'
|
|
8
9
|
const BRAND_PRIMARY_DARK = '#C45E00'
|
|
9
10
|
const BRAND_PRIMARY_LIGHT = '#FFB066'
|
|
10
|
-
const TEXT_PRIMARY = 'var(--color-text-primary)'
|
|
11
|
-
const TEXT_SECONDARY = 'var(--color-text-secondary)'
|
|
12
|
-
const TEXT_TERTIARY = 'var(--color-text-tertiary)'
|
|
13
11
|
|
|
14
12
|
const SUCCESS = '#14B8A6'
|
|
15
13
|
const WARNING = '#FFB020'
|
|
@@ -18,9 +16,12 @@ const ERROR = '#D14343'
|
|
|
18
16
|
/** Gradient stops for the 3px top accent: dark -> primary -> light (matches MesoCard). */
|
|
19
17
|
const ACCENT_STOPS = [BRAND_PRIMARY_DARK, BRAND_PRIMARY, BRAND_PRIMARY_LIGHT]
|
|
20
18
|
|
|
21
|
-
/**
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Card surface gradient: elevated -> raised at 135deg. Uses resolved dark-theme
|
|
21
|
+
* hexes (a gradient string can't carry a className token, and var() renders
|
|
22
|
+
* black on native).
|
|
23
|
+
*/
|
|
24
|
+
const CARD_GRADIENT = `linear-gradient(135deg, ${resolveColor('surface-elevated')} 0%, ${resolveColor('surface-raised')} 100%)`
|
|
24
25
|
|
|
25
26
|
/** Gauge track gradient (teal -> amber -> red) at 0.25 alpha. */
|
|
26
27
|
const GAUGE_GRADIENT =
|
|
@@ -118,7 +119,8 @@ function renderCoachingText(text: string, highlights?: string[]): ReactNode {
|
|
|
118
119
|
highlights.includes(part) ? (
|
|
119
120
|
<Text
|
|
120
121
|
key={`${part}-${index}`}
|
|
121
|
-
|
|
122
|
+
className="text-text-primary"
|
|
123
|
+
style={{ fontWeight: '700' }}
|
|
122
124
|
>
|
|
123
125
|
{part}
|
|
124
126
|
</Text>
|
|
@@ -166,24 +168,24 @@ function MetricCell({ metric }: { metric: MesoStatusMetric }) {
|
|
|
166
168
|
return (
|
|
167
169
|
<View style={{ width: '48%' }} testID="meso-status-card-metric">
|
|
168
170
|
<Text
|
|
171
|
+
className="text-text-tertiary"
|
|
169
172
|
style={{
|
|
170
173
|
fontSize: 10,
|
|
171
174
|
fontFamily: 'Inter, sans-serif',
|
|
172
175
|
fontWeight: '600',
|
|
173
176
|
letterSpacing: 0.5,
|
|
174
177
|
textTransform: 'uppercase',
|
|
175
|
-
color: TEXT_TERTIARY,
|
|
176
178
|
}}
|
|
177
179
|
>
|
|
178
180
|
{metric.label}
|
|
179
181
|
</Text>
|
|
180
182
|
<Text
|
|
183
|
+
className="text-text-primary"
|
|
181
184
|
style={{
|
|
182
185
|
marginTop: 2,
|
|
183
186
|
fontSize: 13,
|
|
184
187
|
fontFamily: 'Inter, sans-serif',
|
|
185
188
|
fontWeight: '600',
|
|
186
|
-
color: TEXT_PRIMARY,
|
|
187
189
|
}}
|
|
188
190
|
>
|
|
189
191
|
{metric.value}
|
|
@@ -212,24 +214,24 @@ function Gauge({ gauge }: { gauge: MesoStatusGauge }) {
|
|
|
212
214
|
accessibilityElementsHidden
|
|
213
215
|
>
|
|
214
216
|
<Text
|
|
217
|
+
className="text-text-secondary"
|
|
215
218
|
style={{
|
|
216
219
|
fontSize: 10,
|
|
217
220
|
fontFamily: 'Inter, sans-serif',
|
|
218
221
|
fontWeight: '500',
|
|
219
222
|
letterSpacing: 0.5,
|
|
220
223
|
textTransform: 'uppercase',
|
|
221
|
-
color: TEXT_SECONDARY,
|
|
222
224
|
}}
|
|
223
225
|
>
|
|
224
226
|
{gauge.label}
|
|
225
227
|
</Text>
|
|
226
228
|
{gauge.sublabel != null && (
|
|
227
229
|
<Text
|
|
230
|
+
className="text-text-tertiary"
|
|
228
231
|
style={{
|
|
229
232
|
fontSize: 10,
|
|
230
233
|
fontFamily: 'Inter, sans-serif',
|
|
231
234
|
fontWeight: '500',
|
|
232
|
-
color: TEXT_TERTIARY,
|
|
233
235
|
}}
|
|
234
236
|
>
|
|
235
237
|
{gauge.sublabel}
|
|
@@ -261,6 +263,7 @@ function Gauge({ gauge }: { gauge: MesoStatusGauge }) {
|
|
|
261
263
|
testID="meso-status-card-gauge-center"
|
|
262
264
|
/>
|
|
263
265
|
<View
|
|
266
|
+
className="border-text-primary"
|
|
264
267
|
style={{
|
|
265
268
|
position: 'absolute',
|
|
266
269
|
left: `${percentage}%`,
|
|
@@ -270,7 +273,6 @@ function Gauge({ gauge }: { gauge: MesoStatusGauge }) {
|
|
|
270
273
|
height: 14,
|
|
271
274
|
borderRadius: 9999,
|
|
272
275
|
borderWidth: 2,
|
|
273
|
-
borderColor: TEXT_PRIMARY,
|
|
274
276
|
backgroundColor: markerColor,
|
|
275
277
|
boxShadow: '0 0 4px rgba(0,0,0,0.5)',
|
|
276
278
|
}}
|
|
@@ -349,12 +351,12 @@ export function MesoStatusCard({
|
|
|
349
351
|
style={{ gap: 8 }}
|
|
350
352
|
>
|
|
351
353
|
<Text
|
|
354
|
+
className="text-text-primary"
|
|
352
355
|
style={{
|
|
353
356
|
flexShrink: 1,
|
|
354
357
|
fontSize: 15,
|
|
355
358
|
fontFamily: '"Space Grotesk", sans-serif',
|
|
356
359
|
fontWeight: '700',
|
|
357
|
-
color: TEXT_PRIMARY,
|
|
358
360
|
}}
|
|
359
361
|
testID="meso-status-card-name"
|
|
360
362
|
>
|
|
@@ -363,11 +365,11 @@ export function MesoStatusCard({
|
|
|
363
365
|
<StatusPill badge={statusBadge} />
|
|
364
366
|
</View>
|
|
365
367
|
<Text
|
|
368
|
+
className="text-text-secondary"
|
|
366
369
|
style={{
|
|
367
370
|
marginTop: 4,
|
|
368
371
|
fontSize: 12,
|
|
369
372
|
fontFamily: 'Inter, sans-serif',
|
|
370
|
-
color: TEXT_SECONDARY,
|
|
371
373
|
}}
|
|
372
374
|
testID="meso-status-card-subtitle"
|
|
373
375
|
>
|
|
@@ -408,11 +410,11 @@ export function MesoStatusCard({
|
|
|
408
410
|
testID="meso-status-card-coaching"
|
|
409
411
|
>
|
|
410
412
|
<Text
|
|
413
|
+
className="text-text-secondary"
|
|
411
414
|
style={{
|
|
412
415
|
fontSize: 12,
|
|
413
416
|
lineHeight: 17,
|
|
414
417
|
fontFamily: 'Inter, sans-serif',
|
|
415
|
-
color: TEXT_SECONDARY,
|
|
416
418
|
}}
|
|
417
419
|
>
|
|
418
420
|
{renderCoachingText(coaching.text, coaching.highlights)}
|
|
@@ -34,16 +34,14 @@ export function MuscleGroupChip({
|
|
|
34
34
|
|
|
35
35
|
const content = (
|
|
36
36
|
<View
|
|
37
|
-
className={className}
|
|
37
|
+
className={['bg-surface-raised border-border', className].filter(Boolean).join(' ')}
|
|
38
38
|
style={{
|
|
39
39
|
flexDirection: 'row',
|
|
40
40
|
alignItems: 'center',
|
|
41
41
|
borderRadius: 9999,
|
|
42
42
|
paddingHorizontal: 9,
|
|
43
43
|
paddingVertical: 3,
|
|
44
|
-
backgroundColor: 'var(--color-surface-raised)',
|
|
45
44
|
borderWidth: 1,
|
|
46
|
-
borderColor: 'var(--color-border-default)',
|
|
47
45
|
}}
|
|
48
46
|
accessibilityLabel={onPress ? undefined : `${name}, volume status: ${statusLabel}`}
|
|
49
47
|
testID="muscle-group-chip"
|
|
@@ -62,11 +60,11 @@ export function MuscleGroupChip({
|
|
|
62
60
|
testID="muscle-group-chip-dot"
|
|
63
61
|
/>
|
|
64
62
|
<Text
|
|
63
|
+
className="text-text-secondary"
|
|
65
64
|
style={{
|
|
66
65
|
fontFamily: 'Inter, sans-serif',
|
|
67
66
|
fontWeight: '500',
|
|
68
67
|
fontSize: 11,
|
|
69
|
-
color: 'var(--color-text-secondary)',
|
|
70
68
|
}}
|
|
71
69
|
accessibilityElementsHidden
|
|
72
70
|
>
|
|
@@ -18,14 +18,13 @@ function SingleStrip({
|
|
|
18
18
|
}: Omit<PlaceholderStripProps, 'mode' | 'segments'>) {
|
|
19
19
|
return (
|
|
20
20
|
<View
|
|
21
|
-
className={cn(className)}
|
|
21
|
+
className={cn('border-border-strong', className)}
|
|
22
22
|
style={[
|
|
23
23
|
{
|
|
24
24
|
height: 3,
|
|
25
25
|
backgroundColor: 'transparent',
|
|
26
26
|
borderWidth: 1,
|
|
27
27
|
borderStyle: 'dashed',
|
|
28
|
-
borderColor: 'var(--color-border-strong)',
|
|
29
28
|
borderRadius: 1,
|
|
30
29
|
opacity: 0.5,
|
|
31
30
|
},
|
|
@@ -60,13 +59,13 @@ function SegmentedStrip({
|
|
|
60
59
|
{Array.from({ length: segments }, (_, i) => (
|
|
61
60
|
<View
|
|
62
61
|
key={i}
|
|
62
|
+
className="border-border-strong"
|
|
63
63
|
style={{
|
|
64
64
|
flex: 1,
|
|
65
65
|
height: 3,
|
|
66
66
|
backgroundColor: 'transparent',
|
|
67
67
|
borderWidth: 1,
|
|
68
68
|
borderStyle: 'dashed',
|
|
69
|
-
borderColor: 'var(--color-border-strong)',
|
|
70
69
|
borderRadius: 1,
|
|
71
70
|
minWidth: 4,
|
|
72
71
|
}}
|