@titan-design/react-ui 0.3.0 → 0.5.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.
Files changed (90) hide show
  1. package/dist/MesoStatusCard-CQk71hSi.d.mts +77 -0
  2. package/dist/MesoStatusCard-CQk71hSi.d.ts +77 -0
  3. package/dist/bodymap.d.mts +246 -3
  4. package/dist/bodymap.d.ts +246 -3
  5. package/dist/bodymap.js +441 -97
  6. package/dist/bodymap.js.map +1 -1
  7. package/dist/bodymap.mjs +1958 -66
  8. package/dist/bodymap.mjs.map +1 -1
  9. package/dist/index.d.mts +71 -738
  10. package/dist/index.d.ts +71 -738
  11. package/dist/index.js +888 -1583
  12. package/dist/index.js.map +1 -1
  13. package/dist/index.mjs +4515 -2348
  14. package/dist/index.mjs.map +1 -1
  15. package/dist/pages-D7Jlssvp.d.ts +791 -0
  16. package/dist/pages-MO0JCySL.d.mts +791 -0
  17. package/dist/pages.d.mts +4 -0
  18. package/dist/pages.d.ts +4 -0
  19. package/dist/pages.js +6646 -0
  20. package/dist/pages.js.map +1 -0
  21. package/dist/pages.mjs +6626 -0
  22. package/dist/pages.mjs.map +1 -0
  23. package/dist/theme/index.d.mts +28 -2
  24. package/dist/theme/index.d.ts +28 -2
  25. package/dist/theme/index.js +37 -0
  26. package/dist/theme/index.js.map +1 -1
  27. package/dist/theme/index.mjs +1880 -2
  28. package/dist/theme/index.mjs.map +1 -1
  29. package/dist/theme/tokens-css.mjs +573 -1
  30. package/dist/theme/tokens-css.mjs.map +1 -1
  31. package/package.json +9 -7
  32. package/src/components/custom/Workout/ActiveWorkoutPage.tsx +10 -15
  33. package/src/components/custom/Workout/BaseBadge.stories.tsx +3 -3
  34. package/src/components/custom/Workout/BaseBadge.test.tsx +1 -1
  35. package/src/components/custom/Workout/BaseBadge.tsx +1 -1
  36. package/src/components/custom/Workout/BodyMap.tsx +7 -8
  37. package/src/components/custom/Workout/BodyMapDetailPanel.tsx +25 -28
  38. package/src/components/custom/Workout/CapacityBandChart.tsx +2 -3
  39. package/src/components/custom/Workout/ExerciseCard.tsx +17 -28
  40. package/src/components/custom/Workout/ExerciseDetailPage.tsx +38 -31
  41. package/src/components/custom/Workout/InputBar.tsx +10 -11
  42. package/src/components/custom/Workout/IntensityBar.test.tsx +112 -60
  43. package/src/components/custom/Workout/IntensityBar.tsx +109 -58
  44. package/src/components/custom/Workout/MesoCard.tsx +2 -6
  45. package/src/components/custom/Workout/MesoStatusCard.tsx +17 -15
  46. package/src/components/custom/Workout/MuscleGroupChip.tsx +2 -4
  47. package/src/components/custom/Workout/PlaceholderStrip.tsx +5 -10
  48. package/src/components/custom/Workout/PrBadge.tsx +3 -3
  49. package/src/components/custom/Workout/PrHistoryModal.tsx +14 -16
  50. package/src/components/custom/Workout/ProgramPlanningPage.tsx +8 -12
  51. package/src/components/custom/Workout/README.md +50 -0
  52. package/src/components/custom/Workout/ReadinessCheck.tsx +13 -11
  53. package/src/components/custom/Workout/RestTimer.test.tsx +41 -10
  54. package/src/components/custom/Workout/RestTimer.tsx +55 -49
  55. package/src/components/custom/Workout/SetRow.tsx +20 -8
  56. package/src/components/custom/Workout/StrengthTrendChart.tsx +15 -17
  57. package/src/components/custom/Workout/TempoBar.stories.tsx +95 -0
  58. package/src/components/custom/Workout/TempoBar.test.tsx +103 -0
  59. package/src/components/custom/Workout/TempoBar.tsx +215 -0
  60. package/src/components/custom/Workout/TempoDisplay.stories.tsx +69 -2
  61. package/src/components/custom/Workout/TempoDisplay.test.tsx +35 -0
  62. package/src/components/custom/Workout/TempoDisplay.tsx +104 -1
  63. package/src/components/custom/Workout/TrainingStatusPage.tsx +8 -17
  64. package/src/components/custom/Workout/VelocityStrip.test.tsx +89 -2
  65. package/src/components/custom/Workout/VelocityStrip.tsx +210 -43
  66. package/src/components/custom/Workout/WeekRow.test.tsx +2 -2
  67. package/src/components/custom/Workout/WeekRow.tsx +2 -1
  68. package/src/components/custom/Workout/WeightBadge.test.tsx +2 -2
  69. package/src/components/custom/Workout/WeightBadge.tsx +2 -2
  70. package/src/components/custom/Workout/WorkoutCard.tsx +3 -8
  71. package/src/components/custom/Workout/icons.tsx +68 -0
  72. package/src/components/custom/Workout/index.ts +47 -47
  73. package/src/index.ts +3 -2
  74. package/src/pages.ts +61 -0
  75. package/src/test/nativewind-stub.ts +13 -0
  76. package/src/test/stories-smoke.test.tsx +50 -0
  77. package/src/theme/ThemeProvider.test.tsx +24 -0
  78. package/src/theme/ThemeProvider.tsx +50 -0
  79. package/src/theme/barrel.ts +53 -0
  80. package/src/theme/index.ts +8 -41
  81. package/src/theme/native-theming-guard.test.ts +117 -0
  82. package/src/theme/resolve-color.ts +19 -0
  83. package/dist/bodymap-BhG55xHM.d.mts +0 -318
  84. package/dist/bodymap-BhG55xHM.d.ts +0 -318
  85. package/dist/chunk-7XPB4NAO.mjs +0 -1013
  86. package/dist/chunk-7XPB4NAO.mjs.map +0 -1
  87. package/dist/chunk-P7TSQUN6.mjs +0 -846
  88. package/dist/chunk-P7TSQUN6.mjs.map +0 -1
  89. package/dist/chunk-TOD2WQBG.mjs +0 -1048
  90. package/dist/chunk-TOD2WQBG.mjs.map +0 -1
@@ -8,7 +8,6 @@ const STATUS_INFO = '#2196F3'
8
8
  /** Dot outline: near-white ring so load dots read on the band fill and any
9
9
  * surface (matches the MesoStatusCard gauge-marker convention). */
10
10
  const DOT_BORDER = '#F3F4F6'
11
- const TEXT_TERTIARY = 'var(--color-text-tertiary)'
12
11
  const BAND_FILL = 'rgba(20,184,166,0.1)'
13
12
  const BAND_EDGE = 'rgba(20,184,166,0.45)'
14
13
  const PROJECTION_FILL = 'rgba(20,184,166,0.05)'
@@ -398,6 +397,7 @@ export function CapacityBandChart({
398
397
 
399
398
  {/* Y axis conceptual label (no numbers). */}
400
399
  <Text
400
+ className="text-text-tertiary"
401
401
  style={{
402
402
  position: 'absolute',
403
403
  left: PADDING_LEFT / 2 - 14,
@@ -406,7 +406,6 @@ export function CapacityBandChart({
406
406
  textAlign: 'center',
407
407
  fontSize: 9,
408
408
  fontFamily: 'Inter, sans-serif',
409
- color: TEXT_TERTIARY,
410
409
  transform: [{ rotate: '-90deg' }],
411
410
  }}
412
411
  accessibilityElementsHidden
@@ -422,6 +421,7 @@ export function CapacityBandChart({
422
421
  return (
423
422
  <Text
424
423
  key={`x-${point.date}`}
424
+ className="text-text-tertiary"
425
425
  style={{
426
426
  position: 'absolute',
427
427
  left: toX(point.date) - 14,
@@ -430,7 +430,6 @@ export function CapacityBandChart({
430
430
  textAlign: 'center',
431
431
  fontSize: 10,
432
432
  fontFamily: 'Inter, sans-serif',
433
- color: TEXT_TERTIARY,
434
433
  }}
435
434
  accessibilityElementsHidden
436
435
  importantForAccessibility="no-hide-descendants"
@@ -1,13 +1,14 @@
1
1
  // Font mapping: font-heading=Space Grotesk, font-body=Nunito Sans (UI), font-sans=Inter (body)
2
2
  import { useState } from 'react'
3
3
  import { View, Text, Pressable } from 'react-native'
4
- import { VelocityStrip } from './VelocityStrip'
4
+ import { VelocityStrip, type VelocityZoneBandProp } from './VelocityStrip'
5
5
  import { PlaceholderStrip } from './PlaceholderStrip'
6
6
  import { WeightBadge } from './WeightBadge'
7
7
  import { PrBadge } from './PrBadge'
8
8
  import { TempoDisplay } from './TempoDisplay'
9
9
  import { SetRow, type SetRowProps } from './SetRow'
10
10
  import { roundWeight } from '../../../utils/workout-format'
11
+ import { resolveColor } from '../../../theme/resolve-color'
11
12
 
12
13
  export type ExerciseCardState = 'collapsed' | 'expanded' | 'upcoming'
13
14
 
@@ -25,6 +26,8 @@ export interface ExerciseCardProps {
25
26
  e1rm?: { value: number; unit: 'lbs' | 'kg' }
26
27
  isPR?: boolean
27
28
  setVelocities?: number[][]
29
+ /** Optional velocity-zone bands shared across this exercise's sets (WA bands). */
30
+ velocityZones?: readonly VelocityZoneBandProp[]
28
31
  totalPlannedSets?: number
29
32
  sets?: SetRowProps[]
30
33
  tempo?: [number, number, number, number]
@@ -34,21 +37,6 @@ export interface ExerciseCardProps {
34
37
  supersetColor?: string
35
38
  }
36
39
 
37
- const COLORS = {
38
- // Theme-aware tokens: text foregrounds and this card's own surfaces/borders
39
- // must flip together so text stays readable in both light and dark. The
40
- // expanded/pressed surfaces are self-owned here (not from a themed Card), so
41
- // hardcoding dark values would leave dark-on-dark once the text flips.
42
- // react-native-web passes the CSS var through to the inline style.
43
- textPrimary: 'var(--color-text-primary)',
44
- textSecondary: 'var(--color-text-secondary)',
45
- textTertiary: 'var(--color-text-tertiary)',
46
- brandPrimary: '#FF7900',
47
- surfaceRaised: 'var(--color-surface-raised)',
48
- surfaceElevated: 'var(--color-surface-elevated)',
49
- borderDefault: 'var(--color-border-default)',
50
- }
51
-
52
40
  /** Column headers; the weight column reflects the card's unit (LBS / KG). */
53
41
  function buildColumnHeaders(unit: 'lbs' | 'kg'): string[] {
54
42
  return ['SET', 'PREV', 'REPS', unit.toUpperCase(), 'RPE']
@@ -120,6 +108,7 @@ function CollapsedCard({
120
108
  e1rm,
121
109
  isPR,
122
110
  setVelocities,
111
+ velocityZones,
123
112
  totalPlannedSets,
124
113
  supersetPosition,
125
114
  }: ExerciseCardProps) {
@@ -139,11 +128,11 @@ function CollapsedCard({
139
128
  testID="exercise-card"
140
129
  >
141
130
  <View
131
+ className={pressed ? 'bg-surface-raised' : undefined}
142
132
  style={{
143
133
  padding: 12,
144
134
  paddingHorizontal: 14,
145
135
  cursor: 'pointer',
146
- backgroundColor: pressed ? COLORS.surfaceRaised : 'transparent',
147
136
  ...borderRadius,
148
137
  ...supersetMargin,
149
138
  }}
@@ -153,11 +142,11 @@ function CollapsedCard({
153
142
  testID="exercise-card-header"
154
143
  >
155
144
  <Text
145
+ className="text-text-primary"
156
146
  style={{
157
147
  fontSize: 14,
158
148
  fontFamily: '"Space Grotesk", sans-serif',
159
149
  fontWeight: '700',
160
- color: COLORS.textPrimary,
161
150
  }}
162
151
  testID="exercise-card-name"
163
152
  >
@@ -166,10 +155,10 @@ function CollapsedCard({
166
155
  <View className="flex-1" />
167
156
  {summary && (
168
157
  <Text
158
+ className="text-text-secondary"
169
159
  style={{
170
160
  fontSize: 12,
171
161
  fontFamily: 'Inter, sans-serif',
172
- color: COLORS.textSecondary,
173
162
  marginRight: 8,
174
163
  }}
175
164
  testID="exercise-card-summary"
@@ -203,6 +192,7 @@ function CollapsedCard({
203
192
  <VelocityStrip
204
193
  key={i}
205
194
  velocities={velocities}
195
+ zones={velocityZones}
206
196
  variant="mini"
207
197
  testID={`exercise-card-velocity-strip-${i}`}
208
198
  />
@@ -239,10 +229,9 @@ function ExpandedCard({
239
229
 
240
230
  return (
241
231
  <View
232
+ className="bg-surface-elevated border-border"
242
233
  style={{
243
- backgroundColor: COLORS.surfaceElevated,
244
234
  borderWidth: 1,
245
- borderColor: COLORS.borderDefault,
246
235
  ...borderRadius,
247
236
  ...supersetMargin,
248
237
  }}
@@ -262,15 +251,15 @@ function ExpandedCard({
262
251
  paddingHorizontal: 14,
263
252
  paddingBottom: 10,
264
253
  borderBottomWidth: 1,
265
- borderBottomColor: COLORS.borderDefault,
254
+ borderBottomColor: resolveColor('border-default'),
266
255
  }}
267
256
  >
268
257
  <Text
258
+ className="text-text-primary"
269
259
  style={{
270
260
  fontSize: 14,
271
261
  fontFamily: '"Space Grotesk", sans-serif',
272
262
  fontWeight: '700',
273
- color: COLORS.textPrimary,
274
263
  }}
275
264
  testID="exercise-card-name"
276
265
  >
@@ -279,10 +268,10 @@ function ExpandedCard({
279
268
  <View className="flex-1" />
280
269
  {summary && (
281
270
  <Text
271
+ className="text-text-secondary"
282
272
  style={{
283
273
  fontSize: 12,
284
274
  fontFamily: 'Inter, sans-serif',
285
- color: COLORS.textSecondary,
286
275
  marginRight: 8,
287
276
  }}
288
277
  testID="exercise-card-summary"
@@ -339,13 +328,13 @@ function ExpandedCard({
339
328
  {...(isFlex ? { className: 'flex-1' } : {})}
340
329
  >
341
330
  <Text
331
+ className="text-text-tertiary"
342
332
  style={{
343
333
  fontSize: 10,
344
334
  fontWeight: '600',
345
335
  fontFamily: 'Inter, sans-serif',
346
336
  textTransform: 'uppercase',
347
337
  letterSpacing: 0.8,
348
- color: COLORS.textTertiary,
349
338
  }}
350
339
  >
351
340
  {header}
@@ -389,11 +378,11 @@ function UpcomingCard({
389
378
  >
390
379
  <View className="flex-row items-center">
391
380
  <Text
381
+ className="text-text-primary"
392
382
  style={{
393
383
  fontSize: 14,
394
384
  fontFamily: '"Space Grotesk", sans-serif',
395
385
  fontWeight: '700',
396
- color: COLORS.textPrimary,
397
386
  }}
398
387
  testID="exercise-card-name"
399
388
  >
@@ -401,10 +390,10 @@ function UpcomingCard({
401
390
  </Text>
402
391
  {prescription && (
403
392
  <Text
393
+ className="text-text-secondary"
404
394
  style={{
405
395
  fontSize: 12,
406
396
  fontFamily: 'Inter, sans-serif',
407
- color: COLORS.textSecondary,
408
397
  marginLeft: 8,
409
398
  }}
410
399
  testID="exercise-card-prescription"
@@ -415,10 +404,10 @@ function UpcomingCard({
415
404
  <View className="flex-1" />
416
405
  {previousBest && (
417
406
  <Text
407
+ className="text-text-tertiary"
418
408
  style={{
419
409
  fontSize: 11,
420
410
  fontFamily: 'Inter, sans-serif',
421
- color: COLORS.textTertiary,
422
411
  }}
423
412
  testID="exercise-card-previous-best"
424
413
  >
@@ -15,15 +15,16 @@ import {
15
15
  } from './CapacityBandChart'
16
16
  import { ExerciseCard, type ExerciseCardProps } from './ExerciseCard'
17
17
  import { type SetRowProps } from './SetRow'
18
- import { VelocityStrip, calculateMeanVelocity, calculateVelocityLoss } from './VelocityStrip'
18
+ import {
19
+ VelocityStrip,
20
+ calculateMeanVelocity,
21
+ calculateVelocityLoss,
22
+ type VelocityZoneBandProp,
23
+ } from './VelocityStrip'
24
+ import { resolveColor } from '../../../theme/resolve-color'
25
+ import { cn } from '../../../utils/cn'
19
26
 
20
- const SURFACE_ELEVATED = 'var(--color-surface-elevated)'
21
- const BORDER_DEFAULT = 'var(--color-border-default)'
22
27
  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
28
 
28
29
  /** Inner plot width: page width 390 − 16 page padding − 12 card padding on each side. */
29
30
  const CHART_WIDTH = 326
@@ -101,6 +102,8 @@ export interface ExerciseVbt {
101
102
  projection?: CapacityBandProjection
102
103
  /** Per-set velocity traces for the most recent session. */
103
104
  sets: ExerciseVbtSet[]
105
+ /** Optional velocity-zone bands for this exercise (WA `VelocityZones.bands`). */
106
+ zones?: readonly VelocityZoneBandProp[]
104
107
  }
105
108
 
106
109
  /** Page-level roll-up of the logged sessions. */
@@ -190,7 +193,7 @@ function TabBar({ active, onSelect }: TabBarProps) {
190
193
  className="flex-row"
191
194
  style={{
192
195
  borderBottomWidth: 1,
193
- borderBottomColor: BORDER_DEFAULT,
196
+ borderBottomColor: resolveColor('border-default'),
194
197
  }}
195
198
  accessibilityRole={'tablist' as ViewProps['accessibilityRole']}
196
199
  testID="exercise-detail-page-tabs"
@@ -213,11 +216,11 @@ function TabBar({ active, onSelect }: TabBarProps) {
213
216
  testID={`exercise-detail-page-tab-${key}`}
214
217
  >
215
218
  <Text
219
+ className={isActive ? 'text-text-primary' : 'text-text-tertiary'}
216
220
  style={{
217
221
  fontSize: 13,
218
222
  fontFamily: 'Inter, sans-serif',
219
223
  fontWeight: isActive ? '700' : '500',
220
- color: isActive ? TEXT_PRIMARY : TEXT_TERTIARY,
221
224
  }}
222
225
  >
223
226
  {label}
@@ -244,27 +247,27 @@ function StatStrip({ stats, unit }: { stats: ExerciseDetailStats; unit: 'lbs' |
244
247
  return (
245
248
  <View
246
249
  key={key}
250
+ className="bg-surface-elevated border-border"
247
251
  style={{
248
252
  flex: 1,
249
253
  padding: 12,
250
254
  borderRadius: 10,
251
- backgroundColor: SURFACE_ELEVATED,
252
255
  borderWidth: 1,
253
- borderColor: BORDER_DEFAULT,
254
256
  }}
255
257
  testID={`exercise-detail-page-stat-${key}`}
256
258
  >
257
259
  <Text
260
+ className="text-text-primary"
258
261
  style={{
259
262
  fontSize: 18,
260
263
  fontFamily: '"Space Grotesk", sans-serif',
261
264
  fontWeight: '700',
262
- color: TEXT_PRIMARY,
263
265
  }}
264
266
  >
265
267
  {value}
266
268
  </Text>
267
269
  <Text
270
+ className="text-text-tertiary"
268
271
  style={{
269
272
  marginTop: 2,
270
273
  fontSize: 10,
@@ -272,7 +275,6 @@ function StatStrip({ stats, unit }: { stats: ExerciseDetailStats; unit: 'lbs' |
272
275
  fontWeight: '600',
273
276
  letterSpacing: 0.4,
274
277
  textTransform: 'uppercase',
275
- color: TEXT_TERTIARY,
276
278
  }}
277
279
  >
278
280
  {label}
@@ -295,10 +297,9 @@ function SectionCard({
295
297
  }) {
296
298
  return (
297
299
  <View
300
+ className="bg-surface-elevated border-border"
298
301
  style={{
299
- backgroundColor: SURFACE_ELEVATED,
300
302
  borderWidth: 1,
301
- borderColor: BORDER_DEFAULT,
302
303
  borderRadius: 12,
303
304
  padding: 12,
304
305
  gap: 10,
@@ -306,13 +307,13 @@ function SectionCard({
306
307
  testID={testID}
307
308
  >
308
309
  <Text
310
+ className="text-text-tertiary"
309
311
  style={{
310
312
  fontSize: 11,
311
313
  fontFamily: 'Inter, sans-serif',
312
314
  fontWeight: '600',
313
315
  letterSpacing: 0.6,
314
316
  textTransform: 'uppercase',
315
- color: TEXT_TERTIARY,
316
317
  }}
317
318
  >
318
319
  {title}
@@ -334,7 +335,8 @@ function EntryList({ entries, expandedId, onToggle, emptyLabel, testID }: EntryL
334
335
  if (entries.length === 0) {
335
336
  return (
336
337
  <Text
337
- style={{ fontSize: 12, fontFamily: 'Inter, sans-serif', color: TEXT_TERTIARY }}
338
+ className="text-text-tertiary"
339
+ style={{ fontSize: 12, fontFamily: 'Inter, sans-serif' }}
338
340
  testID={`${testID}-empty`}
339
341
  >
340
342
  {emptyLabel}
@@ -353,7 +355,13 @@ function EntryList({ entries, expandedId, onToggle, emptyLabel, testID }: EntryL
353
355
  )
354
356
  }
355
357
 
356
- function VbtBreakdown({ sets }: { sets: ExerciseVbtSet[] }) {
358
+ function VbtBreakdown({
359
+ sets,
360
+ zones,
361
+ }: {
362
+ sets: ExerciseVbtSet[]
363
+ zones?: readonly VelocityZoneBandProp[]
364
+ }) {
357
365
  return (
358
366
  <View style={{ gap: 10 }} testID="exercise-detail-page-vbt-breakdown">
359
367
  {sets.map((set) => {
@@ -367,25 +375,25 @@ function VbtBreakdown({ sets }: { sets: ExerciseVbtSet[] }) {
367
375
  testID="exercise-detail-page-vbt-set"
368
376
  >
369
377
  <Text
378
+ className="text-text-secondary"
370
379
  style={{
371
380
  width: 44,
372
381
  fontSize: 11,
373
382
  fontFamily: 'Inter, sans-serif',
374
383
  fontWeight: '600',
375
- color: TEXT_SECONDARY,
376
384
  }}
377
385
  >
378
386
  {set.label}
379
387
  </Text>
380
388
  <View className="flex-1" style={{ height: 8, justifyContent: 'center' }}>
381
- <VelocityStrip velocities={set.velocities} variant="mini" />
389
+ <VelocityStrip velocities={set.velocities} zones={zones} variant="mini" />
382
390
  </View>
383
391
  <Text
392
+ className="text-text-tertiary"
384
393
  style={{
385
394
  fontSize: 11,
386
395
  fontFamily: 'Inter, sans-serif',
387
396
  fontVariant: ['tabular-nums'],
388
- color: TEXT_TERTIARY,
389
397
  }}
390
398
  >
391
399
  {`${mean.toFixed(2)} · -${loss}%`}
@@ -407,26 +415,26 @@ function VbtSummaryRow({ summary }: { summary: VbtSummary }) {
407
415
  {cells.map((cell) => (
408
416
  <View
409
417
  key={cell.label}
418
+ className="bg-surface-elevated border-border"
410
419
  style={{
411
420
  flex: 1,
412
421
  padding: 12,
413
422
  borderRadius: 10,
414
- backgroundColor: SURFACE_ELEVATED,
415
423
  borderWidth: 1,
416
- borderColor: BORDER_DEFAULT,
417
424
  }}
418
425
  >
419
426
  <Text
427
+ className="text-text-primary"
420
428
  style={{
421
429
  fontSize: 16,
422
430
  fontFamily: '"Space Grotesk", sans-serif',
423
431
  fontWeight: '700',
424
- color: TEXT_PRIMARY,
425
432
  }}
426
433
  >
427
434
  {cell.value}
428
435
  </Text>
429
436
  <Text
437
+ className="text-text-tertiary"
430
438
  style={{
431
439
  marginTop: 2,
432
440
  fontSize: 10,
@@ -434,7 +442,6 @@ function VbtSummaryRow({ summary }: { summary: VbtSummary }) {
434
442
  fontWeight: '600',
435
443
  letterSpacing: 0.4,
436
444
  textTransform: 'uppercase',
437
- color: TEXT_TERTIARY,
438
445
  }}
439
446
  >
440
447
  {cell.label}
@@ -488,8 +495,8 @@ export function ExerciseDetailPage({
488
495
 
489
496
  return (
490
497
  <View
491
- className={className}
492
- style={{ width: 390, backgroundColor: PAGE_BG }}
498
+ className={cn('bg-background-base', className)}
499
+ style={{ width: 390 }}
493
500
  accessibilityRole={'main' as ViewProps['accessibilityRole']}
494
501
  aria-label={exercise.name}
495
502
  testID="exercise-detail-page"
@@ -504,22 +511,22 @@ export function ExerciseDetailPage({
504
511
  <View style={{ flexShrink: 1 }}>
505
512
  <Text
506
513
  accessibilityRole="header"
514
+ className="text-text-primary"
507
515
  style={{
508
516
  fontSize: 20,
509
517
  fontFamily: '"Space Grotesk", sans-serif',
510
518
  fontWeight: '700',
511
- color: TEXT_PRIMARY,
512
519
  }}
513
520
  testID="exercise-detail-page-title"
514
521
  >
515
522
  {exercise.name}
516
523
  </Text>
517
524
  <Text
525
+ className="text-text-secondary"
518
526
  style={{
519
527
  marginTop: 2,
520
528
  fontSize: 12,
521
529
  fontFamily: 'Inter, sans-serif',
522
- color: TEXT_SECONDARY,
523
530
  }}
524
531
  testID="exercise-detail-page-subtitle"
525
532
  >
@@ -539,13 +546,13 @@ export function ExerciseDetailPage({
539
546
  testID="exercise-detail-page-e1rm"
540
547
  >
541
548
  <Text
549
+ className="text-text-tertiary"
542
550
  style={{
543
551
  fontSize: 9,
544
552
  fontFamily: 'Inter, sans-serif',
545
553
  fontWeight: '600',
546
554
  letterSpacing: 0.4,
547
555
  textTransform: 'uppercase',
548
- color: TEXT_TERTIARY,
549
556
  }}
550
557
  >
551
558
  e1RM
@@ -620,7 +627,7 @@ export function ExerciseDetailPage({
620
627
  </SectionCard>
621
628
  <VbtSummaryRow summary={vbtSummary} />
622
629
  <SectionCard title="Velocity Breakdown" testID="exercise-detail-page-velocity">
623
- <VbtBreakdown sets={vbt.sets} />
630
+ <VbtBreakdown sets={vbt.sets} zones={vbt.zones} />
624
631
  </SectionCard>
625
632
  </View>
626
633
  )}
@@ -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 TEXT_PRIMARY = 'var(--color-text-primary)'
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: 'var(--color-border-default)',
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
  >