@titan-design/react-ui 0.13.0 → 0.14.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/README.md +14 -0
- package/dist/bodymap.js +129 -76
- package/dist/bodymap.js.map +1 -1
- package/dist/bodymap.mjs +129 -76
- package/dist/bodymap.mjs.map +1 -1
- package/dist/index.d.mts +117 -26
- package/dist/index.d.ts +117 -26
- package/dist/index.js +677 -450
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +673 -451
- package/dist/index.mjs.map +1 -1
- package/dist/{pages-_3Ajpiqu.d.ts → pages-CsjsUn0G.d.ts} +30 -13
- package/dist/{pages-CpW3OB3g.d.mts → pages-ZbT_pD_U.d.mts} +30 -13
- package/dist/pages.d.mts +1 -1
- package/dist/pages.d.ts +1 -1
- package/dist/pages.js +676 -701
- package/dist/pages.js.map +1 -1
- package/dist/pages.mjs +676 -701
- package/dist/pages.mjs.map +1 -1
- package/dist/theme/index.d.mts +31 -7
- package/dist/theme/index.d.ts +31 -7
- package/dist/theme/index.js +84 -20
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/index.mjs +83 -21
- package/dist/theme/index.mjs.map +1 -1
- package/dist/theme/tokens-css.js +84 -20
- package/dist/theme/tokens-css.js.map +1 -1
- package/dist/theme/tokens-css.mjs +84 -20
- package/dist/theme/tokens-css.mjs.map +1 -1
- package/dist/theme/tokens.d.mts +56 -7
- package/dist/theme/tokens.d.ts +56 -7
- package/dist/theme/tokens.js +72 -20
- package/dist/theme/tokens.js.map +1 -1
- package/dist/theme/tokens.mjs +71 -21
- package/dist/theme/tokens.mjs.map +1 -1
- package/docs/render-testing-pattern.md +130 -0
- package/package.json +1 -1
- package/src/arch/Architecture.stories.tsx +3 -1
- package/src/arch/arch-graph.json +74 -72
- package/src/components/custom/ActiveWork/InitiativeBrief.tsx +2 -1
- package/src/components/custom/CircularTimer/CircularTimer.stories.tsx +8 -3
- package/src/components/custom/EmptyState/EmptyState.stories.tsx +1 -1
- package/src/components/custom/Gauge/Gauge.stories.tsx +4 -1
- package/src/components/custom/Gauge/Gauge.tsx +3 -1
- package/src/components/custom/Scatter/Scatter.stories.tsx +10 -7
- package/src/components/custom/Scatter/Scatter.tsx +6 -4
- package/src/components/custom/Sidebar/Sidebar.stories.tsx +1 -1
- package/src/components/custom/Table/Table.stories.tsx +1 -1
- package/src/components/custom/Table/Table.tsx +2 -2
- package/src/components/custom/Treemap/Treemap.stories.tsx +13 -10
- package/src/components/custom/Treemap/Treemap.tsx +4 -1
- package/src/components/custom/Workout/ActiveWorkoutPage.stories.tsx +2 -1
- package/src/components/custom/Workout/BaseBadge.stories.tsx +11 -7
- package/src/components/custom/Workout/BaseBadge.tsx +3 -2
- package/src/components/custom/Workout/BodyMap.tsx +5 -3
- package/src/components/custom/Workout/BodyMapDetailPanel.stories.tsx +13 -3
- package/src/components/custom/Workout/BodyMapDetailPanel.tsx +5 -3
- package/src/components/custom/Workout/CapacityBandChart.stories.tsx +2 -1
- package/src/components/custom/Workout/CapacityBandChart.tsx +5 -3
- package/src/components/custom/Workout/DeviationBar.test.tsx +5 -2
- package/src/components/custom/Workout/DeviationBar.tsx +5 -2
- package/src/components/custom/Workout/DualVelocityStrip.stories.tsx +7 -6
- package/src/components/custom/Workout/DualVelocityStrip.test.tsx +29 -16
- package/src/components/custom/Workout/ExerciseCard.stories.tsx +8 -8
- package/src/components/custom/Workout/ExerciseCard.test.tsx +39 -19
- package/src/components/custom/Workout/ExerciseCard.tsx +92 -167
- package/src/components/custom/Workout/ExerciseCardHeading.stories.tsx +89 -6
- package/src/components/custom/Workout/ExerciseCardHeading.test.tsx +189 -1
- package/src/components/custom/Workout/ExerciseCardHeading.tsx +167 -18
- package/src/components/custom/Workout/ExerciseDetailPage.tsx +3 -2
- package/src/components/custom/Workout/ExerciseHeading.tsx +192 -47
- package/src/components/custom/Workout/ExerciseIndicator.stories.tsx +6 -5
- package/src/components/custom/Workout/InputBar.tsx +4 -2
- package/src/components/custom/Workout/IntensityBar.tsx +4 -1
- package/src/components/custom/Workout/MesoCard.tsx +2 -1
- package/src/components/custom/Workout/MesoStatusCard.tsx +11 -10
- package/src/components/custom/Workout/PlaceholderStrip.stories.tsx +8 -3
- package/src/components/custom/Workout/PrHistoryModal.stories.tsx +12 -2
- package/src/components/custom/Workout/README.md +58 -12
- package/src/components/custom/Workout/ReadinessCheck.tsx +4 -2
- package/src/components/custom/Workout/RestTimer.stories.tsx +13 -2
- package/src/components/custom/Workout/RestTimer.tsx +4 -2
- package/src/components/custom/Workout/SegmentedBar.stories.tsx +16 -12
- package/src/components/custom/Workout/SegmentedBar.tsx +4 -3
- package/src/components/custom/Workout/SetStrip.stories.tsx +3 -2
- package/src/components/custom/Workout/SetsRepsLoad.tsx +23 -9
- package/src/components/custom/Workout/Sparkline.stories.tsx +13 -10
- package/src/components/custom/Workout/StrengthTrendChart.stories.tsx +2 -1
- package/src/components/custom/Workout/StrengthTrendChart.tsx +8 -6
- package/src/components/custom/Workout/TempoDisplay.stories.tsx +4 -3
- package/src/components/custom/Workout/TempoDisplay.tsx +2 -0
- package/src/components/custom/Workout/VelocityStrip.dual.stories.tsx +3 -2
- package/src/components/custom/Workout/VelocityStrip.expanded.stories.tsx +1 -1
- package/src/components/custom/Workout/VelocityStrip.hero.stories.tsx +40 -0
- package/src/components/custom/Workout/VelocityStrip.test.tsx +48 -6
- package/src/components/custom/Workout/VelocityStrip.tsx +23 -14
- package/src/components/custom/Workout/ZoneTrack.stories.tsx +3 -1
- package/src/components/custom/Workout/exerciseRowState.ts +29 -0
- package/src/components/custom/Workout/index.ts +12 -2
- package/src/components/custom/Workout/metricText.stories.tsx +9 -8
- package/src/components/custom/Workout/metricText.tsx +4 -2
- package/src/components/custom/Workout/setHeadingKit.tsx +12 -10
- package/src/components/custom/Workout/velocity-story-kit.tsx +2 -2
- package/src/components/custom/charts/README.md +5 -0
- package/src/components/custom/charts/SetBarChart.test.tsx +16 -0
- package/src/components/custom/charts/SetBarChart.tsx +14 -5
- package/src/components/custom/charts/flatBarGeometry.test.ts +41 -0
- package/src/components/custom/charts/flatBarGeometry.ts +32 -0
- package/src/components/custom/stepper/Stepper.tsx +8 -6
- package/src/components/ui/alert/Alert.stories.tsx +14 -4
- package/src/components/ui/alert/Alert.tsx +24 -3
- package/src/components/ui/button/Button.tsx +12 -12
- package/src/components/ui/checkbox/Checkbox.tsx +2 -2
- package/src/components/ui/data-row/DataRow.stories.tsx +6 -2
- package/src/components/ui/drawer/Drawer.tsx +4 -1
- package/src/components/ui/icon-box/IconBox.tsx +8 -6
- package/src/components/ui/indicator/Indicator.stories.tsx +4 -3
- package/src/components/ui/list-item/ListItem.stories.tsx +7 -4
- package/src/components/ui/modal/Modal.tsx +2 -0
- package/src/components/ui/pill/Pill.stories.tsx +53 -0
- package/src/components/ui/pill/Pill.tsx +10 -6
- package/src/components/ui/popover/Popover.stories.tsx +1 -1
- package/src/components/ui/progress/Progress.tsx +9 -6
- package/src/components/ui/radio/Radio.tsx +1 -1
- package/src/components/ui/section/Section.stories.tsx +10 -10
- package/src/components/ui/select/Select.tsx +2 -1
- package/src/components/ui/spinner/Spinner.tsx +3 -1
- package/src/components/ui/stack/Stack.stories.tsx +7 -7
- package/src/components/ui/surface/Surface.stories.tsx +75 -28
- package/src/components/ui/switch/Switch.tsx +1 -1
- package/src/components/ui/tabs/Tabs.tsx +4 -2
- package/src/components/ui/toast/Toast.tsx +6 -4
- package/src/components/ui/toolbar-button/ToolbarButton.tsx +13 -6
- package/src/stories/PresetShowcase.stories.tsx +1 -1
- package/src/test/no-raw-color.test.ts +39 -0
- package/src/theme/Alpha.stories.tsx +103 -0
- package/src/theme/ProposedTokensVW82.stories.tsx +414 -0
- package/src/theme/config.ts +12 -0
- package/src/theme/global.css +15 -3
- package/src/theme/subtle-tone-weight.test.ts +163 -0
- package/src/theme/tailwind-var-opacity.test.ts +163 -0
- package/src/theme/tokens/primitives.ts +33 -0
- package/src/theme/tokens/semantic-hex-guard.test.ts +322 -0
- package/src/theme/tokens/semantic.ts +56 -20
- package/src/utils/colors.alpha-adoption.test.ts +408 -0
- package/tailwind.config.js +50 -9
package/dist/pages.js
CHANGED
|
@@ -6,12 +6,37 @@ var jsxRuntime = require('react/jsx-runtime');
|
|
|
6
6
|
var clsx = require('clsx');
|
|
7
7
|
var tailwindMerge = require('tailwind-merge');
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
10
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
11
|
+
}) : x)(function(x) {
|
|
12
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
13
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
14
|
+
});
|
|
10
15
|
|
|
11
16
|
// src/theme/tokens/primitives.ts
|
|
12
17
|
var primitiveColors = {
|
|
13
18
|
white: "#FFFFFF"};
|
|
14
19
|
var alertRedVivid = "#FF4757";
|
|
20
|
+
var resultPaletteColors = {
|
|
21
|
+
improve: "#4caf50",
|
|
22
|
+
improveDark: "#248a24",
|
|
23
|
+
degrade: "#ef5350",
|
|
24
|
+
degradeDark: "#b30000",
|
|
25
|
+
inconclusive: "#9E9A97"
|
|
26
|
+
};
|
|
27
|
+
var semanticPins = {
|
|
28
|
+
// Cool navy-black; darker and more blue-shifted than any warm greyRamp step.
|
|
29
|
+
textPrimaryLight: "#121828",
|
|
30
|
+
// Cool blue-grey; outside greyRamp's warm (R>=G>=B) scale.
|
|
31
|
+
textSecondaryLight: "#65748B",
|
|
32
|
+
// Pure neutral grey (R=G=B); no warm greyRamp step lands on it exactly.
|
|
33
|
+
backgroundBaseLight: "#EBEBEB",
|
|
34
|
+
// Near-neutral grey, kept one step off backgroundBaseLight by design.
|
|
35
|
+
dividerLight: "#E8E9EB",
|
|
36
|
+
// Periwinkle/indigo; more purple than any primitiveRamps.blue step. Shared by
|
|
37
|
+
// dark-mode text-link, border-focus and border-input-focus.
|
|
38
|
+
focusIndigoDark: "#828DF8"
|
|
39
|
+
};
|
|
15
40
|
var greyRamp = {
|
|
16
41
|
50: "#F9F6F3",
|
|
17
42
|
// L*97.0 W6
|
|
@@ -45,6 +70,7 @@ var greyRamp = {
|
|
|
45
70
|
var primitiveRamps = {
|
|
46
71
|
red: {
|
|
47
72
|
50: "#FFF4F4",
|
|
73
|
+
400: "#F77175",
|
|
48
74
|
500: "#E05254",
|
|
49
75
|
600: "#D14343",
|
|
50
76
|
// pin
|
|
@@ -186,6 +212,12 @@ var semanticColorsLight = {
|
|
|
186
212
|
// Text on brand backgrounds (on-*)
|
|
187
213
|
"on-brand-primary": primitiveColors.white,
|
|
188
214
|
"on-brand-secondary": primitiveColors.white,
|
|
215
|
+
// Text ON a `-subtle` fill. Light mode keeps today's pairing (the base token) so
|
|
216
|
+
// nothing moves here: light has the same disease mirrored — a light rung on a
|
|
217
|
+
// near-white ramp[50] fill — but correcting it belongs with the light-mode pass
|
|
218
|
+
// in AW-121, not this one.
|
|
219
|
+
"on-brand-primary-subtle": primitiveRamps.orange[400],
|
|
220
|
+
"on-brand-secondary-subtle": primitiveRamps.cyan[600],
|
|
189
221
|
// Status colors (status-*)
|
|
190
222
|
"status-success": primitiveRamps.green[300],
|
|
191
223
|
"status-success-light": primitiveRamps.green[200],
|
|
@@ -221,21 +253,26 @@ var semanticColorsLight = {
|
|
|
221
253
|
"status-info-subtle": primitiveRamps.blue[50],
|
|
222
254
|
"status-info-muted": "rgba(33, 150, 243, 0.30)",
|
|
223
255
|
"status-info-strong": "rgba(33, 150, 243, 0.50)",
|
|
256
|
+
// Text ON a `-subtle` fill — see the on-brand-*-subtle note above.
|
|
257
|
+
"on-status-success-subtle": primitiveRamps.green[300],
|
|
258
|
+
"on-status-error-subtle": primitiveRamps.red[600],
|
|
259
|
+
"on-status-warning-subtle": primitiveRamps.amber[300],
|
|
260
|
+
"on-status-info-subtle": primitiveRamps.blue[500],
|
|
224
261
|
// Text on status backgrounds (on-status-*)
|
|
225
262
|
"on-status-success": primitiveColors.white,
|
|
226
263
|
"on-status-error": primitiveColors.white,
|
|
227
264
|
"on-status-warning": primitiveColors.white,
|
|
228
265
|
"on-status-info": primitiveColors.white,
|
|
229
266
|
// Result/outcome indicators (result-*)
|
|
230
|
-
"result-improve":
|
|
267
|
+
"result-improve": resultPaletteColors.improve,
|
|
231
268
|
// Green - positive outcome
|
|
232
269
|
"result-improve-light": "rgba(76, 175, 80, 0.12)",
|
|
233
|
-
"result-improve-dark":
|
|
234
|
-
"result-degrade":
|
|
270
|
+
"result-improve-dark": resultPaletteColors.improveDark,
|
|
271
|
+
"result-degrade": resultPaletteColors.degrade,
|
|
235
272
|
// Red - negative outcome
|
|
236
273
|
"result-degrade-light": "rgba(239, 83, 80, 0.12)",
|
|
237
|
-
"result-degrade-dark":
|
|
238
|
-
"result-inconclusive":
|
|
274
|
+
"result-degrade-dark": resultPaletteColors.degradeDark,
|
|
275
|
+
"result-inconclusive": resultPaletteColors.inconclusive,
|
|
239
276
|
// Gray - no clear result
|
|
240
277
|
"result-inconclusive-light": "rgba(158, 154, 151, 0.12)",
|
|
241
278
|
"result-neutral": greyRamp[600],
|
|
@@ -267,8 +304,8 @@ var semanticColorsLight = {
|
|
|
267
304
|
"data-10": discreteRainbow[22],
|
|
268
305
|
// Dark Orange
|
|
269
306
|
// Text colors (text-*)
|
|
270
|
-
"text-primary":
|
|
271
|
-
"text-secondary":
|
|
307
|
+
"text-primary": semanticPins.textPrimaryLight,
|
|
308
|
+
"text-secondary": semanticPins.textSecondaryLight,
|
|
272
309
|
"text-tertiary": greyRamp[400],
|
|
273
310
|
"text-disabled": "rgba(55, 65, 81, 0.48)",
|
|
274
311
|
"text-inverse": primitiveColors.white,
|
|
@@ -284,7 +321,7 @@ var semanticColorsLight = {
|
|
|
284
321
|
"surface-input": greyRamp[50],
|
|
285
322
|
// Input field background (filled variant)
|
|
286
323
|
// Background colors (background-*)
|
|
287
|
-
"background-base":
|
|
324
|
+
"background-base": semanticPins.backgroundBaseLight,
|
|
288
325
|
"background-default": primitiveColors.white,
|
|
289
326
|
"background-subtle": greyRamp[50],
|
|
290
327
|
// Frame/bezel chrome — top bar + side nav shell, one step below
|
|
@@ -315,7 +352,7 @@ var semanticColorsLight = {
|
|
|
315
352
|
"interactive-disabled": "rgba(55, 65, 81, 0.12)",
|
|
316
353
|
"interactive-disabled-text": "rgba(55, 65, 81, 0.26)",
|
|
317
354
|
// Divider
|
|
318
|
-
divider:
|
|
355
|
+
divider: semanticPins.dividerLight,
|
|
319
356
|
// Avatar default
|
|
320
357
|
"avatar-background": greyRamp[600],
|
|
321
358
|
"avatar-text": primitiveColors.white
|
|
@@ -333,7 +370,7 @@ var semanticColorsDark = {
|
|
|
333
370
|
"brand-secondary": primitiveRamps.cyan[600],
|
|
334
371
|
"brand-secondary-light": primitiveRamps.cyan[500],
|
|
335
372
|
"brand-secondary-dark": primitiveRamps.cyan[700],
|
|
336
|
-
"brand-secondary-subtle": "rgba(
|
|
373
|
+
"brand-secondary-subtle": "rgba(34, 211, 238, 0.12)",
|
|
337
374
|
"brand-secondary-muted": "rgba(48, 123, 155, 0.30)",
|
|
338
375
|
"brand-secondary-strong": "rgba(48, 123, 155, 0.50)",
|
|
339
376
|
"brand-secondary-hover": primitiveRamps.cyan[500],
|
|
@@ -341,6 +378,14 @@ var semanticColorsDark = {
|
|
|
341
378
|
// Text on brand backgrounds
|
|
342
379
|
"on-brand-primary": primitiveColors.white,
|
|
343
380
|
"on-brand-secondary": primitiveColors.white,
|
|
381
|
+
// Text ON a `-subtle` fill. Its own role: `brand-primary` and friends are tuned to
|
|
382
|
+
// carry a white label as a solid fill, which makes the two deepest of them
|
|
383
|
+
// (cyan[600], red[600]) too dark to read as text on a dark plane. Levelling the
|
|
384
|
+
// family at rung 300 puts every tone within OKLCH L 0.769-0.813 instead of
|
|
385
|
+
// 0.550-0.813. Brand is deliberately left at its own orange[400] (operator, AW-133)
|
|
386
|
+
// so the Voltras tone never drifts; it is the one tone under AA on a raised card.
|
|
387
|
+
"on-brand-primary-subtle": primitiveRamps.orange[400],
|
|
388
|
+
"on-brand-secondary-subtle": primitiveRamps.cyan[300],
|
|
344
389
|
// Status colors
|
|
345
390
|
"status-success": primitiveRamps.green[300],
|
|
346
391
|
"status-success-light": primitiveRamps.green[200],
|
|
@@ -354,7 +399,10 @@ var semanticColorsDark = {
|
|
|
354
399
|
"status-error": primitiveRamps.red[600],
|
|
355
400
|
"status-error-light": primitiveRamps.red[500],
|
|
356
401
|
"status-error-dark": primitiveRamps.red[700],
|
|
357
|
-
|
|
402
|
+
// Alpha 0.08, not the family's 0.12: error's label is red[400], a rung darker than
|
|
403
|
+
// its siblings so it reads RED rather than pink (rung 300 has only 0.121 chroma).
|
|
404
|
+
// Thinning the fill buys back the contrast that extra darkness costs. See AW-133.
|
|
405
|
+
"status-error-subtle": "rgba(247, 113, 117, 0.08)",
|
|
358
406
|
"status-error-muted": "rgba(209, 67, 67, 0.30)",
|
|
359
407
|
"status-error-strong": "rgba(209, 67, 67, 0.50)",
|
|
360
408
|
"status-error-vivid": alertRedVivid,
|
|
@@ -372,7 +420,7 @@ var semanticColorsDark = {
|
|
|
372
420
|
"status-info": primitiveRamps.blue[500],
|
|
373
421
|
"status-info-light": primitiveRamps.blue[300],
|
|
374
422
|
"status-info-dark": primitiveRamps.blue[600],
|
|
375
|
-
"status-info-subtle": "rgba(
|
|
423
|
+
"status-info-subtle": "rgba(120, 194, 255, 0.12)",
|
|
376
424
|
"status-info-muted": "rgba(33, 150, 243, 0.30)",
|
|
377
425
|
"status-info-strong": "rgba(33, 150, 243, 0.50)",
|
|
378
426
|
// Text on status backgrounds
|
|
@@ -380,14 +428,22 @@ var semanticColorsDark = {
|
|
|
380
428
|
"on-status-error": primitiveColors.white,
|
|
381
429
|
"on-status-warning": primitiveColors.white,
|
|
382
430
|
"on-status-info": primitiveColors.white,
|
|
431
|
+
// Text ON a `-subtle` fill — see the on-brand-*-subtle note above. Error is the
|
|
432
|
+
// second deliberate exception to the rung-300 rule (operator, AW-133): red[300]
|
|
433
|
+
// levelled perfectly but read PINK, because a red that light can only hold 0.121
|
|
434
|
+
// chroma. red[400] carries 0.165 and reads red; its fill is thinned to compensate.
|
|
435
|
+
"on-status-success-subtle": primitiveRamps.green[300],
|
|
436
|
+
"on-status-error-subtle": primitiveRamps.red[400],
|
|
437
|
+
"on-status-warning-subtle": primitiveRamps.amber[300],
|
|
438
|
+
"on-status-info-subtle": primitiveRamps.blue[300],
|
|
383
439
|
// Result/outcome indicators (result-*)
|
|
384
|
-
"result-improve":
|
|
440
|
+
"result-improve": resultPaletteColors.improve,
|
|
385
441
|
"result-improve-light": "rgba(76, 175, 80, 0.16)",
|
|
386
|
-
"result-improve-dark":
|
|
387
|
-
"result-degrade":
|
|
442
|
+
"result-improve-dark": resultPaletteColors.improveDark,
|
|
443
|
+
"result-degrade": resultPaletteColors.degrade,
|
|
388
444
|
"result-degrade-light": "rgba(239, 83, 80, 0.16)",
|
|
389
|
-
"result-degrade-dark":
|
|
390
|
-
"result-inconclusive":
|
|
445
|
+
"result-degrade-dark": resultPaletteColors.degradeDark,
|
|
446
|
+
"result-inconclusive": resultPaletteColors.inconclusive,
|
|
391
447
|
"result-inconclusive-light": "rgba(158, 154, 151, 0.16)",
|
|
392
448
|
"result-neutral": greyRamp[400],
|
|
393
449
|
// Text on result backgrounds
|
|
@@ -418,7 +474,7 @@ var semanticColorsDark = {
|
|
|
418
474
|
"text-tertiary": greyRamp[500],
|
|
419
475
|
"text-disabled": "rgba(255, 255, 255, 0.38)",
|
|
420
476
|
"text-inverse": greyRamp[950],
|
|
421
|
-
"text-link":
|
|
477
|
+
"text-link": semanticPins.focusIndigoDark,
|
|
422
478
|
"text-link-hover": primitiveRamps.blue[400],
|
|
423
479
|
// Surface colors - dark backgrounds — warm-tapered DERIVED ramp (TD-surface-tokens,
|
|
424
480
|
// S-1, re-spaced S-3). Shipped verbatim from `deriveSurfaceRamp()` — see
|
|
@@ -468,10 +524,10 @@ var semanticColorsDark = {
|
|
|
468
524
|
// plane, so it keeps its job without collision.
|
|
469
525
|
"border-prominent": greyRamp[800],
|
|
470
526
|
// high-visibility divider
|
|
471
|
-
"border-focus":
|
|
527
|
+
"border-focus": semanticPins.focusIndigoDark,
|
|
472
528
|
"border-input": greyRamp[700],
|
|
473
529
|
"border-input-hover": greyRamp[600],
|
|
474
|
-
"border-input-focus":
|
|
530
|
+
"border-input-focus": semanticPins.focusIndigoDark,
|
|
475
531
|
"border-input-error": primitiveRamps.red[500],
|
|
476
532
|
// Alpha hairline separators — the primary separation cue (§4/S-2). Self-
|
|
477
533
|
// normalizing: composites toward white by ~the same amount on ANY plane, so
|
|
@@ -736,6 +792,22 @@ function useLiveRepGrowth(active, liveRepIndex, liveVelocity, isNewPeak) {
|
|
|
736
792
|
}, [active, liveRepIndex, liveVelocity, isNewPeak, prefersReducedMotion, liveGrowth]);
|
|
737
793
|
return liveGrowth;
|
|
738
794
|
}
|
|
795
|
+
|
|
796
|
+
// src/components/custom/charts/flatBarGeometry.ts
|
|
797
|
+
var SET_LEVEL_FLAT_BAR = {
|
|
798
|
+
/** Track height (px). */
|
|
799
|
+
height: 8,
|
|
800
|
+
/** Gap between segment slots (px) — also SetStrip's between-set gap, see `SEGMENTED_BAR_GAP`. */
|
|
801
|
+
gap: 5,
|
|
802
|
+
/** Corner radius (px). */
|
|
803
|
+
radius: 2
|
|
804
|
+
};
|
|
805
|
+
var REP_LEVEL_FLAT_BAR = {
|
|
806
|
+
/** Inter-bar gap is proportional (`gapRatio · barWidth`), floored at this many px. */
|
|
807
|
+
gapFloor: 2,
|
|
808
|
+
/** Corner radius (px) default. */
|
|
809
|
+
radius: 5
|
|
810
|
+
};
|
|
739
811
|
function wrapJsx(fn) {
|
|
740
812
|
return function(type, props, ...rest) {
|
|
741
813
|
if (props && typeof props.className === "string" && props.className) {
|
|
@@ -770,7 +842,7 @@ var CONTINUE_OUTLINE = primitiveRamps.cyan[800];
|
|
|
770
842
|
var FIXED_MAX_VALUE = 1.15;
|
|
771
843
|
var PEAK_HEADROOM = 1.03;
|
|
772
844
|
function scaleDenominator(scale, maxValue) {
|
|
773
|
-
return scale === "fixed" ? FIXED_MAX_VALUE : maxValue * PEAK_HEADROOM;
|
|
845
|
+
return (scale === "fixed" ? FIXED_MAX_VALUE : maxValue) * PEAK_HEADROOM;
|
|
774
846
|
}
|
|
775
847
|
function valueLabelFontSize(height) {
|
|
776
848
|
return Math.round(Math.max(8, Math.min(12, height * 0.11)));
|
|
@@ -786,12 +858,12 @@ var SET_BAR_DEFAULT_HEIGHT = 220;
|
|
|
786
858
|
var LABEL_ROW_HEIGHT = 16;
|
|
787
859
|
var LABEL_GAP = 3;
|
|
788
860
|
var GAP_RATIO = 0.08;
|
|
789
|
-
var MIN_BAR_GAP =
|
|
861
|
+
var MIN_BAR_GAP = REP_LEVEL_FLAT_BAR.gapFloor;
|
|
790
862
|
var CHUNK_NOTCH_RATIO = 0.25;
|
|
791
863
|
var CHUNK_NOTCH_MIN_PX = 10;
|
|
792
864
|
var BAR_MAX_WIDTH = 120;
|
|
793
865
|
var LABEL_MIN_BAR_WIDTH = 30;
|
|
794
|
-
var DEFAULT_BAR_RADIUS =
|
|
866
|
+
var DEFAULT_BAR_RADIUS = REP_LEVEL_FLAT_BAR.radius;
|
|
795
867
|
var MIN_BAR_HEIGHT = 4;
|
|
796
868
|
var FLAT_BAR_FRACTION = 0.5;
|
|
797
869
|
var STUB_HEIGHT = 9;
|
|
@@ -1667,232 +1739,8 @@ function VelocityStrip({
|
|
|
1667
1739
|
function cn(...inputs) {
|
|
1668
1740
|
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
1669
1741
|
}
|
|
1670
|
-
function resolveColor(token, mode = "dark") {
|
|
1671
|
-
return reactNative.Platform.OS === "web" ? `var(--color-${token})` : getSemanticColors(mode)[token];
|
|
1672
|
-
}
|
|
1673
|
-
|
|
1674
|
-
// src/components/custom/Workout/PlaceholderStrip.tsx
|
|
1675
|
-
var RAIL_TOKEN = "border-prominent";
|
|
1676
|
-
function SingleStrip({
|
|
1677
|
-
width,
|
|
1678
|
-
className,
|
|
1679
|
-
...props
|
|
1680
|
-
}) {
|
|
1681
|
-
return /* @__PURE__ */ jsx(
|
|
1682
|
-
reactNative.View,
|
|
1683
|
-
{
|
|
1684
|
-
className,
|
|
1685
|
-
style: [
|
|
1686
|
-
{
|
|
1687
|
-
height: 3,
|
|
1688
|
-
backgroundColor: resolveColor(RAIL_TOKEN),
|
|
1689
|
-
borderRadius: 2,
|
|
1690
|
-
opacity: 0.5
|
|
1691
|
-
},
|
|
1692
|
-
width != null ? { width } : { flex: 1 }
|
|
1693
|
-
],
|
|
1694
|
-
accessibilityRole: "image",
|
|
1695
|
-
accessibilityLabel: "Planned set, not yet completed",
|
|
1696
|
-
testID: "placeholder-strip",
|
|
1697
|
-
...props
|
|
1698
|
-
}
|
|
1699
|
-
);
|
|
1700
|
-
}
|
|
1701
|
-
function SegmentedStrip({
|
|
1702
|
-
segments = 3,
|
|
1703
|
-
width,
|
|
1704
|
-
className,
|
|
1705
|
-
...props
|
|
1706
|
-
}) {
|
|
1707
|
-
return /* @__PURE__ */ jsx(
|
|
1708
|
-
reactNative.View,
|
|
1709
|
-
{
|
|
1710
|
-
className: cn("flex-row", className),
|
|
1711
|
-
style: [
|
|
1712
|
-
{ height: 3, gap: 2, opacity: 0.5 },
|
|
1713
|
-
width != null ? { width } : { flex: 1 }
|
|
1714
|
-
],
|
|
1715
|
-
accessibilityRole: "image",
|
|
1716
|
-
accessibilityLabel: "Planned set, not yet completed",
|
|
1717
|
-
testID: "placeholder-strip",
|
|
1718
|
-
...props,
|
|
1719
|
-
children: Array.from({ length: segments }, (_, i) => /* @__PURE__ */ jsx(
|
|
1720
|
-
reactNative.View,
|
|
1721
|
-
{
|
|
1722
|
-
style: {
|
|
1723
|
-
flex: 1,
|
|
1724
|
-
height: 3,
|
|
1725
|
-
backgroundColor: resolveColor(RAIL_TOKEN),
|
|
1726
|
-
borderRadius: 1,
|
|
1727
|
-
minWidth: 4
|
|
1728
|
-
},
|
|
1729
|
-
accessibilityElementsHidden: true,
|
|
1730
|
-
testID: "placeholder-segment"
|
|
1731
|
-
},
|
|
1732
|
-
i
|
|
1733
|
-
))
|
|
1734
|
-
}
|
|
1735
|
-
);
|
|
1736
|
-
}
|
|
1737
|
-
function PlaceholderStrip({ mode = "single", segments, ...props }) {
|
|
1738
|
-
if (mode === "segmented") {
|
|
1739
|
-
return /* @__PURE__ */ jsx(SegmentedStrip, { segments, ...props });
|
|
1740
|
-
}
|
|
1741
|
-
return /* @__PURE__ */ jsx(SingleStrip, { ...props });
|
|
1742
|
-
}
|
|
1743
|
-
|
|
1744
|
-
// src/components/icons/SvgIcon.tsx
|
|
1745
|
-
function SvgIcon({
|
|
1746
|
-
size = 24,
|
|
1747
|
-
color = "currentColor",
|
|
1748
|
-
strokeWidth = 2,
|
|
1749
|
-
fill = "none",
|
|
1750
|
-
title,
|
|
1751
|
-
children
|
|
1752
|
-
}) {
|
|
1753
|
-
return /* @__PURE__ */ jsxs(
|
|
1754
|
-
"svg",
|
|
1755
|
-
{
|
|
1756
|
-
width: size,
|
|
1757
|
-
height: size,
|
|
1758
|
-
viewBox: "0 0 24 24",
|
|
1759
|
-
fill,
|
|
1760
|
-
stroke: color,
|
|
1761
|
-
strokeWidth,
|
|
1762
|
-
strokeLinecap: "round",
|
|
1763
|
-
strokeLinejoin: "round",
|
|
1764
|
-
...title ? { role: "img", "aria-label": title } : { "aria-hidden": true },
|
|
1765
|
-
children: [
|
|
1766
|
-
title ? /* @__PURE__ */ jsx("title", { children: title }) : null,
|
|
1767
|
-
children
|
|
1768
|
-
]
|
|
1769
|
-
}
|
|
1770
|
-
);
|
|
1771
|
-
}
|
|
1772
1742
|
|
|
1773
|
-
// src/components/
|
|
1774
|
-
function StarIcon(props) {
|
|
1775
|
-
return /* @__PURE__ */ jsx(SvgIcon, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z" }) });
|
|
1776
|
-
}
|
|
1777
|
-
function ScaleIcon(props) {
|
|
1778
|
-
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
1779
|
-
/* @__PURE__ */ jsx("path", { d: "m16 16 3-8 3 8c-.87.65-1.92 1-3 1s-2.13-.35-3-1Z" }),
|
|
1780
|
-
/* @__PURE__ */ jsx("path", { d: "m2 16 3-8 3 8c-.87.65-1.92 1-3 1s-2.13-.35-3-1Z" }),
|
|
1781
|
-
/* @__PURE__ */ jsx("path", { d: "M7 21h10" }),
|
|
1782
|
-
/* @__PURE__ */ jsx("path", { d: "M12 3v18" }),
|
|
1783
|
-
/* @__PURE__ */ jsx("path", { d: "M3 7h2c2 0 5-1 7-2 2 1 5 2 7 2h2" })
|
|
1784
|
-
] });
|
|
1785
|
-
}
|
|
1786
|
-
function AlertTriangleIcon(props) {
|
|
1787
|
-
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
1788
|
-
/* @__PURE__ */ jsx("path", { d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z" }),
|
|
1789
|
-
/* @__PURE__ */ jsx("path", { d: "M12 9v4" }),
|
|
1790
|
-
/* @__PURE__ */ jsx("path", { d: "M12 17h.01" })
|
|
1791
|
-
] });
|
|
1792
|
-
}
|
|
1793
|
-
function TrendingDownIcon(props) {
|
|
1794
|
-
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
1795
|
-
/* @__PURE__ */ jsx("path", { d: "M16 17h6v-6" }),
|
|
1796
|
-
/* @__PURE__ */ jsx("path", { d: "m22 17-8.5-8.5-5 5L2 7" })
|
|
1797
|
-
] });
|
|
1798
|
-
}
|
|
1799
|
-
function CircleSlashIcon(props) {
|
|
1800
|
-
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
1801
|
-
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
1802
|
-
/* @__PURE__ */ jsx("path", { d: "m9 15 6-6" })
|
|
1803
|
-
] });
|
|
1804
|
-
}
|
|
1805
|
-
function AwardIcon(props) {
|
|
1806
|
-
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
1807
|
-
/* @__PURE__ */ jsx("path", { d: "m15.477 12.89 1.515 8.526a.5.5 0 0 1-.81.47l-3.58-2.687a1 1 0 0 0-1.197 0l-3.586 2.686a.5.5 0 0 1-.81-.469l1.514-8.526" }),
|
|
1808
|
-
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "8", r: "6" })
|
|
1809
|
-
] });
|
|
1810
|
-
}
|
|
1811
|
-
function InfoIcon(props) {
|
|
1812
|
-
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
1813
|
-
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
1814
|
-
/* @__PURE__ */ jsx("path", { d: "M12 16v-4" }),
|
|
1815
|
-
/* @__PURE__ */ jsx("path", { d: "M12 8h.01" })
|
|
1816
|
-
] });
|
|
1817
|
-
}
|
|
1818
|
-
var t = getSemanticColors("dark");
|
|
1819
|
-
var baseBadgeSizeConfig = {
|
|
1820
|
-
sm: { fontSize: 9, paddingH: 6, paddingV: 2, iconSize: 10 },
|
|
1821
|
-
md: { fontSize: 10, paddingH: 8, paddingV: 2, iconSize: 12 },
|
|
1822
|
-
lg: { fontSize: 12, paddingH: 10, paddingV: 4, iconSize: 14 }
|
|
1823
|
-
};
|
|
1824
|
-
var variantColors = {
|
|
1825
|
-
plain: { backgroundColor: t["surface-raised"], borderColor: t["hairline-default"] },
|
|
1826
|
-
pr: {
|
|
1827
|
-
backgroundColor: "rgba(255, 121, 0, 0.12)",
|
|
1828
|
-
borderColor: "rgba(255, 121, 0, 0.3)"
|
|
1829
|
-
}
|
|
1830
|
-
};
|
|
1831
|
-
function BaseBadge({
|
|
1832
|
-
variant = "plain",
|
|
1833
|
-
size = "md",
|
|
1834
|
-
icon,
|
|
1835
|
-
onPress,
|
|
1836
|
-
className,
|
|
1837
|
-
children,
|
|
1838
|
-
...props
|
|
1839
|
-
}) {
|
|
1840
|
-
const [scaleAnim] = react.useState(() => new reactNative.Animated.Value(1));
|
|
1841
|
-
const config = baseBadgeSizeConfig[size];
|
|
1842
|
-
const colors = variantColors[variant];
|
|
1843
|
-
const handlePressIn = () => {
|
|
1844
|
-
reactNative.Animated.timing(scaleAnim, {
|
|
1845
|
-
toValue: 0.97,
|
|
1846
|
-
duration: 150,
|
|
1847
|
-
useNativeDriver: true
|
|
1848
|
-
}).start();
|
|
1849
|
-
};
|
|
1850
|
-
const handlePressOut = () => {
|
|
1851
|
-
reactNative.Animated.timing(scaleAnim, {
|
|
1852
|
-
toValue: 1,
|
|
1853
|
-
duration: 150,
|
|
1854
|
-
useNativeDriver: true
|
|
1855
|
-
}).start();
|
|
1856
|
-
};
|
|
1857
|
-
const badge = /* @__PURE__ */ jsxs(
|
|
1858
|
-
reactNative.View,
|
|
1859
|
-
{
|
|
1860
|
-
className,
|
|
1861
|
-
style: {
|
|
1862
|
-
flexDirection: "row",
|
|
1863
|
-
alignItems: "center",
|
|
1864
|
-
gap: 3,
|
|
1865
|
-
// borderRadius 2 is intentional per workout-tokens.ts (squared-off pill)
|
|
1866
|
-
borderRadius: 2,
|
|
1867
|
-
borderWidth: 1,
|
|
1868
|
-
borderColor: colors.borderColor,
|
|
1869
|
-
backgroundColor: colors.backgroundColor,
|
|
1870
|
-
paddingHorizontal: config.paddingH,
|
|
1871
|
-
paddingVertical: config.paddingV
|
|
1872
|
-
},
|
|
1873
|
-
...props,
|
|
1874
|
-
children: [
|
|
1875
|
-
icon != null && /* @__PURE__ */ jsx(reactNative.View, { accessibilityElementsHidden: true, testID: "base-badge-icon", children: icon }),
|
|
1876
|
-
children
|
|
1877
|
-
]
|
|
1878
|
-
}
|
|
1879
|
-
);
|
|
1880
|
-
if (onPress) {
|
|
1881
|
-
return /* @__PURE__ */ jsx(reactNative.Animated.View, { style: { transform: [{ scale: scaleAnim }] }, children: /* @__PURE__ */ jsx(
|
|
1882
|
-
reactNative.Pressable,
|
|
1883
|
-
{
|
|
1884
|
-
onPress,
|
|
1885
|
-
onPressIn: handlePressIn,
|
|
1886
|
-
onPressOut: handlePressOut,
|
|
1887
|
-
accessibilityRole: "button",
|
|
1888
|
-
accessibilityLabel: props.accessibilityLabel,
|
|
1889
|
-
testID: "base-badge-pressable",
|
|
1890
|
-
children: badge
|
|
1891
|
-
}
|
|
1892
|
-
) });
|
|
1893
|
-
}
|
|
1894
|
-
return badge;
|
|
1895
|
-
}
|
|
1743
|
+
// src/components/custom/Typography/Typography.tsx
|
|
1896
1744
|
var variantStyles = {
|
|
1897
1745
|
h1: "font-heading text-5xl font-bold leading-tight",
|
|
1898
1746
|
h2: "font-heading text-4xl font-bold leading-tight",
|
|
@@ -1983,81 +1831,11 @@ function Typography({
|
|
|
1983
1831
|
}
|
|
1984
1832
|
);
|
|
1985
1833
|
}
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
var typeLabels = {
|
|
1989
|
-
e1rm: "PR e1RM",
|
|
1990
|
-
weight: "PR Weight",
|
|
1991
|
-
reps: "PR Reps",
|
|
1992
|
-
volume: "PR Volume",
|
|
1993
|
-
velocity: "PR Velocity"
|
|
1994
|
-
};
|
|
1995
|
-
function PrBadge({
|
|
1996
|
-
type = "e1rm",
|
|
1997
|
-
label: labelProp,
|
|
1998
|
-
compact = false,
|
|
1999
|
-
animate = true,
|
|
2000
|
-
className,
|
|
2001
|
-
...props
|
|
2002
|
-
}) {
|
|
2003
|
-
const resolvedLabel = labelProp ?? typeLabels[type];
|
|
2004
|
-
const brandPrimary = resolveColor("brand-primary");
|
|
2005
|
-
const [scale] = react.useState(() => new reactNative.Animated.Value(animate ? 0.8 : 1));
|
|
2006
|
-
const [opacity] = react.useState(() => new reactNative.Animated.Value(animate ? 0 : 1));
|
|
2007
|
-
react.useEffect(() => {
|
|
2008
|
-
if (!animate) return;
|
|
2009
|
-
reactNative.Animated.parallel([
|
|
2010
|
-
reactNative.Animated.timing(scale, {
|
|
2011
|
-
toValue: 1,
|
|
2012
|
-
duration: 400,
|
|
2013
|
-
easing: reactNative.Easing.bezier(0.34, 1.56, 0.64, 1),
|
|
2014
|
-
useNativeDriver: true
|
|
2015
|
-
}),
|
|
2016
|
-
reactNative.Animated.timing(opacity, {
|
|
2017
|
-
toValue: 1,
|
|
2018
|
-
duration: 400,
|
|
2019
|
-
easing: reactNative.Easing.bezier(0.34, 1.56, 0.64, 1),
|
|
2020
|
-
useNativeDriver: true
|
|
2021
|
-
})
|
|
2022
|
-
]).start();
|
|
2023
|
-
}, [animate, scale, opacity]);
|
|
2024
|
-
const badge = compact ? /* @__PURE__ */ jsx(
|
|
2025
|
-
reactNative.View,
|
|
2026
|
-
{
|
|
2027
|
-
className,
|
|
2028
|
-
accessibilityRole: "image",
|
|
2029
|
-
accessibilityLabel: `Personal record: ${resolvedLabel}`,
|
|
2030
|
-
testID: "pr-badge-star",
|
|
2031
|
-
...props,
|
|
2032
|
-
children: /* @__PURE__ */ jsx(StarIcon, { size: 14, color: brandPrimary, fill: brandPrimary, strokeWidth: 2 })
|
|
2033
|
-
}
|
|
2034
|
-
) : /* @__PURE__ */ jsx(
|
|
2035
|
-
BaseBadge,
|
|
2036
|
-
{
|
|
2037
|
-
variant: "pr",
|
|
2038
|
-
className,
|
|
2039
|
-
accessibilityLabel: `Personal record: ${resolvedLabel}`,
|
|
2040
|
-
...props,
|
|
2041
|
-
children: /* @__PURE__ */ jsxs(
|
|
2042
|
-
Typography,
|
|
2043
|
-
{
|
|
2044
|
-
variant: "boldLabel",
|
|
2045
|
-
color: "inherit",
|
|
2046
|
-
className: "leading-[normal] text-brand-primary",
|
|
2047
|
-
children: [
|
|
2048
|
-
"\u2605",
|
|
2049
|
-
" ",
|
|
2050
|
-
resolvedLabel
|
|
2051
|
-
]
|
|
2052
|
-
}
|
|
2053
|
-
)
|
|
2054
|
-
}
|
|
2055
|
-
);
|
|
2056
|
-
if (animate) {
|
|
2057
|
-
return /* @__PURE__ */ jsx(reactNative.Animated.View, { style: { transform: [{ scale }], opacity }, testID: "pr-badge-animated", children: badge });
|
|
2058
|
-
}
|
|
2059
|
-
return badge;
|
|
1834
|
+
function resolveColor(token, mode = "dark") {
|
|
1835
|
+
return reactNative.Platform.OS === "web" ? `var(--color-${token})` : getSemanticColors(mode)[token];
|
|
2060
1836
|
}
|
|
1837
|
+
|
|
1838
|
+
// src/components/custom/Workout/SetRow.tsx
|
|
2061
1839
|
var TEXT_ACTIVE = "text-primary";
|
|
2062
1840
|
var TEXT_MUTED = "text-secondary";
|
|
2063
1841
|
var COL = { set: 36, reps: 44, load: 56, rpe: 36 };
|
|
@@ -2242,37 +2020,180 @@ function SetTableHeader({
|
|
|
2242
2020
|
}
|
|
2243
2021
|
);
|
|
2244
2022
|
}
|
|
2245
|
-
var
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
{
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
}
|
|
2023
|
+
var FLOATING_LIFT_MIN = 4;
|
|
2024
|
+
var LIFT_RIM_ALPHA = { dark: 0.12, light: 0.9 };
|
|
2025
|
+
var AMBIENT = {
|
|
2026
|
+
1: [
|
|
2027
|
+
{ y: 1, blur: 2, alpha: 0.35 },
|
|
2028
|
+
{ y: 2, blur: 6, alpha: 0.3 }
|
|
2029
|
+
],
|
|
2030
|
+
2: [
|
|
2031
|
+
{ y: 1, blur: 2, alpha: 0.35 },
|
|
2032
|
+
{ y: 4, blur: 12, alpha: 0.32 }
|
|
2033
|
+
],
|
|
2034
|
+
3: [
|
|
2035
|
+
{ y: 2, blur: 4, alpha: 0.35 },
|
|
2036
|
+
{ y: 8, blur: 22, alpha: 0.35 }
|
|
2037
|
+
],
|
|
2038
|
+
4: [
|
|
2039
|
+
{ y: 1, blur: 2, alpha: 0.35 },
|
|
2040
|
+
{ y: 10, blur: 24, alpha: 0.3 },
|
|
2041
|
+
{ y: 24, blur: 48, alpha: 0.2 }
|
|
2042
|
+
],
|
|
2043
|
+
5: [
|
|
2044
|
+
{ y: 2, blur: 4, alpha: 0.4 },
|
|
2045
|
+
{ y: 16, blur: 32, alpha: 0.35 },
|
|
2046
|
+
{ y: 32, blur: 64, alpha: 0.25 }
|
|
2047
|
+
]
|
|
2048
|
+
};
|
|
2049
|
+
var AMBIENT_ALPHA_SCALE = { dark: 1, light: 0.4 };
|
|
2050
|
+
function ambientLayers(step, mode) {
|
|
2051
|
+
const scale = AMBIENT_ALPHA_SCALE[mode];
|
|
2052
|
+
return AMBIENT[step].map(
|
|
2053
|
+
({ y, blur, alpha: alpha2 }) => `0 ${y}px ${blur}px rgba(0,0,0,${(alpha2 * scale).toFixed(2)})`
|
|
2259
2054
|
);
|
|
2260
2055
|
}
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2056
|
+
function liftShadow(step, mode = "dark", opts = {}) {
|
|
2057
|
+
const rim = opts.rim ?? LIFT_RIM_ALPHA[mode];
|
|
2058
|
+
const layers = ambientLayers(step, mode);
|
|
2059
|
+
if (rim > 0) layers.unshift(`inset 0 1px 0 rgba(255,255,255,${rim.toFixed(2)})`);
|
|
2060
|
+
return layers.join(", ");
|
|
2061
|
+
}
|
|
2062
|
+
function liftStyle(step, mode = "dark", opts = {}) {
|
|
2063
|
+
const deepest = AMBIENT[step][AMBIENT[step].length - 1];
|
|
2064
|
+
return reactNative.Platform.select({
|
|
2065
|
+
web: { boxShadow: liftShadow(step, mode, opts) },
|
|
2066
|
+
default: {
|
|
2067
|
+
shadowColor: "#000",
|
|
2068
|
+
shadowOffset: { width: 0, height: Math.round(deepest.y / 2) },
|
|
2069
|
+
shadowOpacity: deepest.alpha * AMBIENT_ALPHA_SCALE[mode],
|
|
2070
|
+
shadowRadius: deepest.blur / 2,
|
|
2071
|
+
elevation: step
|
|
2072
|
+
}
|
|
2073
|
+
});
|
|
2074
|
+
}
|
|
2075
|
+
|
|
2076
|
+
// src/theme/elevation.ts
|
|
2077
|
+
var FLOATING_ELEVATION_MIN = FLOATING_LIFT_MIN;
|
|
2078
|
+
function getPressedRecessShadow(fillColor, _mode = "dark") {
|
|
2079
|
+
const { boxShadow } = insetWell(fillColor);
|
|
2080
|
+
return reactNative.Platform.select({
|
|
2081
|
+
web: { boxShadow },
|
|
2082
|
+
default: {}
|
|
2083
|
+
});
|
|
2084
|
+
}
|
|
2085
|
+
var glowConfig = {
|
|
2086
|
+
tight: { blur: 4, spread: 0, opacity: 0.4 },
|
|
2087
|
+
subtle: { blur: 12, spread: 0, opacity: 0.25 },
|
|
2088
|
+
medium: { blur: 20, spread: 2, opacity: 0.4 },
|
|
2089
|
+
strong: { blur: 30, spread: 4, opacity: 0.55 }
|
|
2090
|
+
};
|
|
2091
|
+
function getGlowShadow(color, intensity = "medium") {
|
|
2092
|
+
const config = glowConfig[intensity];
|
|
2093
|
+
const rgb = hexToRgb(color);
|
|
2094
|
+
if (!rgb) return {};
|
|
2095
|
+
return reactNative.Platform.select({
|
|
2096
|
+
web: {
|
|
2097
|
+
boxShadow: `0 0 ${config.blur}px ${config.spread}px rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${config.opacity})`
|
|
2098
|
+
},
|
|
2099
|
+
default: {
|
|
2100
|
+
shadowColor: color,
|
|
2101
|
+
shadowOffset: { width: 0, height: 0 },
|
|
2102
|
+
shadowOpacity: config.opacity,
|
|
2103
|
+
shadowRadius: config.blur / 2,
|
|
2104
|
+
elevation: 0
|
|
2105
|
+
}
|
|
2106
|
+
});
|
|
2107
|
+
}
|
|
2108
|
+
function recessDepth(inherited, planesDown, mode) {
|
|
2109
|
+
let plane = inherited.level;
|
|
2110
|
+
for (let i = 0; i < planesDown; i++) plane = pressedLevel(plane);
|
|
2111
|
+
const backgroundColor = surfaceBackground(plane, mode);
|
|
2112
|
+
return { plane, backgroundColor, depthStyle: getPressedRecessShadow(backgroundColor, mode) };
|
|
2113
|
+
}
|
|
2114
|
+
function resolveSurfaceDepth(inherited, props) {
|
|
2115
|
+
const mode = props.theme ?? inherited.mode;
|
|
2116
|
+
const elevation = props.elevation ?? 0;
|
|
2117
|
+
if (props.pressed || elevation < 0) {
|
|
2118
|
+
const down = props.pressed ? 1 : -elevation;
|
|
2119
|
+
return { mode, step: 0, lifted: false, ...recessDepth(inherited, down, mode) };
|
|
2120
|
+
}
|
|
2121
|
+
const step = props.level != null ? 0 : props.raise ?? elevation;
|
|
2122
|
+
const floating = step >= FLOATING_ELEVATION_MIN;
|
|
2123
|
+
const plane = props.level ?? (floating ? "overlay" : raisedLevel(inherited.level, step));
|
|
2124
|
+
const lifted = props.lift ?? step > 0;
|
|
2125
|
+
const liftStep = Math.max(1, Math.min(5, step));
|
|
2126
|
+
const depthStyle = lifted ? liftStyle(liftStep, mode, props.liftOptions) : {};
|
|
2127
|
+
return { mode, plane, backgroundColor: surfaceBackground(plane, mode), depthStyle, step, lifted };
|
|
2128
|
+
}
|
|
2129
|
+
function useResolvedSurface(props) {
|
|
2130
|
+
const inherited = useSurface();
|
|
2131
|
+
const { level, raise, elevation, pressed, lift, liftOptions, theme } = props;
|
|
2132
|
+
return react.useMemo(
|
|
2133
|
+
() => resolveSurfaceDepth(inherited, {
|
|
2134
|
+
level,
|
|
2135
|
+
raise,
|
|
2136
|
+
elevation,
|
|
2137
|
+
pressed,
|
|
2138
|
+
lift,
|
|
2139
|
+
liftOptions,
|
|
2140
|
+
theme
|
|
2141
|
+
}),
|
|
2142
|
+
[inherited, level, raise, elevation, pressed, lift, liftOptions, theme]
|
|
2143
|
+
);
|
|
2144
|
+
}
|
|
2145
|
+
|
|
2146
|
+
// src/components/ui/tooltip/Tooltip.tsx
|
|
2147
|
+
var createPortal;
|
|
2148
|
+
if (reactNative.Platform.OS === "web") {
|
|
2149
|
+
try {
|
|
2150
|
+
createPortal = __require("react-dom").createPortal;
|
|
2151
|
+
} catch {
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
function useHoverState() {
|
|
2155
|
+
const [hovered, setHovered] = react.useState(false);
|
|
2156
|
+
const onPointerEnter = react.useCallback(() => setHovered(true), []);
|
|
2157
|
+
const onPointerLeave = react.useCallback(() => setHovered(false), []);
|
|
2158
|
+
return { hovered, hoverProps: { onPointerEnter, onPointerLeave } };
|
|
2159
|
+
}
|
|
2160
|
+
var METRIC_FONT = "Inter, sans-serif";
|
|
2161
|
+
function MetricCell({ children, color, fontSize = 11, weight = 600 }) {
|
|
2162
|
+
return /* @__PURE__ */ jsx(
|
|
2163
|
+
reactNative.Text,
|
|
2164
|
+
{
|
|
2165
|
+
style: {
|
|
2166
|
+
fontFamily: METRIC_FONT,
|
|
2167
|
+
fontSize,
|
|
2168
|
+
color,
|
|
2169
|
+
fontWeight: String(weight),
|
|
2170
|
+
letterSpacing: 1
|
|
2171
|
+
},
|
|
2172
|
+
children
|
|
2173
|
+
}
|
|
2174
|
+
);
|
|
2175
|
+
}
|
|
2176
|
+
|
|
2177
|
+
// src/components/custom/Workout/SetsRepsLoad.tsx
|
|
2178
|
+
var TIMES = "\xD7";
|
|
2179
|
+
var AT = "@";
|
|
2180
|
+
function SetsRepsLoad({
|
|
2181
|
+
sets,
|
|
2182
|
+
reps,
|
|
2183
|
+
load,
|
|
2184
|
+
unit = "lb",
|
|
2270
2185
|
fontSize,
|
|
2186
|
+
muted = false,
|
|
2271
2187
|
className,
|
|
2272
2188
|
...props
|
|
2273
2189
|
}) {
|
|
2274
|
-
const
|
|
2275
|
-
const
|
|
2190
|
+
const primary = useOnSurfaceColor("primary");
|
|
2191
|
+
const tertiary = useOnSurfaceColor("tertiary");
|
|
2192
|
+
const secondary = useOnSurfaceColor("secondary");
|
|
2193
|
+
const value = muted ? secondary : primary;
|
|
2194
|
+
const sep = muted ? secondary : tertiary;
|
|
2195
|
+
const weight = muted ? 400 : 600;
|
|
2196
|
+
const times = muted ? TIMES : ` ${TIMES} `;
|
|
2276
2197
|
return /* @__PURE__ */ jsxs(
|
|
2277
2198
|
reactNative.View,
|
|
2278
2199
|
{
|
|
@@ -2282,29 +2203,29 @@ function SetsRepsLoad({
|
|
|
2282
2203
|
testID: "sets-reps-load",
|
|
2283
2204
|
...props,
|
|
2284
2205
|
children: [
|
|
2285
|
-
/* @__PURE__ */ jsx(MetricCell, { color: value, fontSize, children: sets }),
|
|
2286
|
-
/* @__PURE__ */ jsx(MetricCell, { color: sep, fontSize, children:
|
|
2287
|
-
/* @__PURE__ */ jsx(MetricCell, { color: value, fontSize, children: reps }),
|
|
2288
|
-
/* @__PURE__ */ jsx(MetricCell, { color: sep, fontSize, children: ` ${AT} ` }),
|
|
2289
|
-
/* @__PURE__ */ jsx(MetricCell, { color: value, fontSize, children: load }),
|
|
2290
|
-
/* @__PURE__ */ jsx(MetricCell, { color: sep, fontSize, children: ` ${unit}` })
|
|
2206
|
+
/* @__PURE__ */ jsx(MetricCell, { color: value, fontSize, weight, children: sets }),
|
|
2207
|
+
/* @__PURE__ */ jsx(MetricCell, { color: sep, fontSize, weight, children: times }),
|
|
2208
|
+
/* @__PURE__ */ jsx(MetricCell, { color: value, fontSize, weight, children: reps }),
|
|
2209
|
+
/* @__PURE__ */ jsx(MetricCell, { color: sep, fontSize, weight, children: ` ${AT} ` }),
|
|
2210
|
+
/* @__PURE__ */ jsx(MetricCell, { color: value, fontSize, weight, children: load }),
|
|
2211
|
+
/* @__PURE__ */ jsx(MetricCell, { color: sep, fontSize, weight, children: ` ${unit}` })
|
|
2291
2212
|
]
|
|
2292
2213
|
}
|
|
2293
2214
|
);
|
|
2294
2215
|
}
|
|
2295
|
-
var
|
|
2216
|
+
var t = getSemanticColors("dark");
|
|
2296
2217
|
var INTER = "Inter, sans-serif";
|
|
2297
2218
|
var TEXT_TERTIARY = "#6B7280";
|
|
2298
|
-
var STATUS_ERROR =
|
|
2299
|
-
var STATUS_SUCCESS =
|
|
2300
|
-
var STATUS_WARNING =
|
|
2219
|
+
var STATUS_ERROR = t["status-error"];
|
|
2220
|
+
var STATUS_SUCCESS = t["status-success"];
|
|
2221
|
+
var STATUS_WARNING = t["status-warning"];
|
|
2301
2222
|
var ON_TARGET_MS = 100;
|
|
2302
2223
|
function getTempoFillPct(elapsedMs, targetMs) {
|
|
2303
2224
|
if (!targetMs) return 100;
|
|
2304
2225
|
return Math.min(100, elapsedMs / targetMs * 100);
|
|
2305
2226
|
}
|
|
2306
2227
|
function activeNumberTone(elapsedMs, targetMs) {
|
|
2307
|
-
if (targetMs == null) return
|
|
2228
|
+
if (targetMs == null) return t["text-primary"];
|
|
2308
2229
|
const remainingMs = targetMs - elapsedMs;
|
|
2309
2230
|
if (remainingMs > ON_TARGET_MS) return STATUS_WARNING;
|
|
2310
2231
|
if (remainingMs >= -ON_TARGET_MS) return STATUS_SUCCESS;
|
|
@@ -2456,7 +2377,7 @@ function TempoDisplay({
|
|
|
2456
2377
|
style: {
|
|
2457
2378
|
flexDirection: "row",
|
|
2458
2379
|
alignItems: "center",
|
|
2459
|
-
backgroundColor:
|
|
2380
|
+
backgroundColor: t["surface-raised"],
|
|
2460
2381
|
paddingHorizontal: chromePadX,
|
|
2461
2382
|
paddingVertical: chromePadY,
|
|
2462
2383
|
borderRadius: chromeRadius
|
|
@@ -2471,7 +2392,7 @@ function TempoDisplay({
|
|
|
2471
2392
|
fontSize: labelFont,
|
|
2472
2393
|
fontWeight: "500",
|
|
2473
2394
|
// Live-muted green while a rep is running, tertiary at rest.
|
|
2474
|
-
color: live ?
|
|
2395
|
+
color: live ? t["status-live-muted"] : TEXT_TERTIARY,
|
|
2475
2396
|
letterSpacing: 0.5,
|
|
2476
2397
|
textTransform: "uppercase",
|
|
2477
2398
|
marginRight: Math.round(fontSize * 0.5)
|
|
@@ -2529,7 +2450,7 @@ function TempoDisplay({
|
|
|
2529
2450
|
reactNative.View,
|
|
2530
2451
|
{
|
|
2531
2452
|
style: {
|
|
2532
|
-
backgroundColor:
|
|
2453
|
+
backgroundColor: t["surface-overlay"],
|
|
2533
2454
|
borderRadius: 6,
|
|
2534
2455
|
paddingVertical: 8,
|
|
2535
2456
|
paddingHorizontal: 12,
|
|
@@ -2582,6 +2503,80 @@ function TempoDisplay({
|
|
|
2582
2503
|
}
|
|
2583
2504
|
);
|
|
2584
2505
|
}
|
|
2506
|
+
|
|
2507
|
+
// src/components/icons/SvgIcon.tsx
|
|
2508
|
+
function SvgIcon({
|
|
2509
|
+
size = 24,
|
|
2510
|
+
color = "currentColor",
|
|
2511
|
+
strokeWidth = 2,
|
|
2512
|
+
fill = "none",
|
|
2513
|
+
title,
|
|
2514
|
+
children
|
|
2515
|
+
}) {
|
|
2516
|
+
return /* @__PURE__ */ jsxs(
|
|
2517
|
+
"svg",
|
|
2518
|
+
{
|
|
2519
|
+
width: size,
|
|
2520
|
+
height: size,
|
|
2521
|
+
viewBox: "0 0 24 24",
|
|
2522
|
+
fill,
|
|
2523
|
+
stroke: color,
|
|
2524
|
+
strokeWidth,
|
|
2525
|
+
strokeLinecap: "round",
|
|
2526
|
+
strokeLinejoin: "round",
|
|
2527
|
+
...title ? { role: "img", "aria-label": title } : { "aria-hidden": true },
|
|
2528
|
+
children: [
|
|
2529
|
+
title ? /* @__PURE__ */ jsx("title", { children: title }) : null,
|
|
2530
|
+
children
|
|
2531
|
+
]
|
|
2532
|
+
}
|
|
2533
|
+
);
|
|
2534
|
+
}
|
|
2535
|
+
|
|
2536
|
+
// src/components/icons/icons.tsx
|
|
2537
|
+
function ScaleIcon(props) {
|
|
2538
|
+
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
2539
|
+
/* @__PURE__ */ jsx("path", { d: "m16 16 3-8 3 8c-.87.65-1.92 1-3 1s-2.13-.35-3-1Z" }),
|
|
2540
|
+
/* @__PURE__ */ jsx("path", { d: "m2 16 3-8 3 8c-.87.65-1.92 1-3 1s-2.13-.35-3-1Z" }),
|
|
2541
|
+
/* @__PURE__ */ jsx("path", { d: "M7 21h10" }),
|
|
2542
|
+
/* @__PURE__ */ jsx("path", { d: "M12 3v18" }),
|
|
2543
|
+
/* @__PURE__ */ jsx("path", { d: "M3 7h2c2 0 5-1 7-2 2 1 5 2 7 2h2" })
|
|
2544
|
+
] });
|
|
2545
|
+
}
|
|
2546
|
+
function AlertTriangleIcon(props) {
|
|
2547
|
+
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
2548
|
+
/* @__PURE__ */ jsx("path", { d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z" }),
|
|
2549
|
+
/* @__PURE__ */ jsx("path", { d: "M12 9v4" }),
|
|
2550
|
+
/* @__PURE__ */ jsx("path", { d: "M12 17h.01" })
|
|
2551
|
+
] });
|
|
2552
|
+
}
|
|
2553
|
+
function TrendingDownIcon(props) {
|
|
2554
|
+
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
2555
|
+
/* @__PURE__ */ jsx("path", { d: "M16 17h6v-6" }),
|
|
2556
|
+
/* @__PURE__ */ jsx("path", { d: "m22 17-8.5-8.5-5 5L2 7" })
|
|
2557
|
+
] });
|
|
2558
|
+
}
|
|
2559
|
+
function CircleSlashIcon(props) {
|
|
2560
|
+
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
2561
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
2562
|
+
/* @__PURE__ */ jsx("path", { d: "m9 15 6-6" })
|
|
2563
|
+
] });
|
|
2564
|
+
}
|
|
2565
|
+
function AwardIcon(props) {
|
|
2566
|
+
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
2567
|
+
/* @__PURE__ */ jsx("path", { d: "m15.477 12.89 1.515 8.526a.5.5 0 0 1-.81.47l-3.58-2.687a1 1 0 0 0-1.197 0l-3.586 2.686a.5.5 0 0 1-.81-.469l1.514-8.526" }),
|
|
2568
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "8", r: "6" })
|
|
2569
|
+
] });
|
|
2570
|
+
}
|
|
2571
|
+
function InfoIcon(props) {
|
|
2572
|
+
return /* @__PURE__ */ jsxs(SvgIcon, { ...props, children: [
|
|
2573
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
2574
|
+
/* @__PURE__ */ jsx("path", { d: "M12 16v-4" }),
|
|
2575
|
+
/* @__PURE__ */ jsx("path", { d: "M12 8h.01" })
|
|
2576
|
+
] });
|
|
2577
|
+
}
|
|
2578
|
+
|
|
2579
|
+
// src/components/custom/Workout/ExerciseIndicator.tsx
|
|
2585
2580
|
var INDICATOR_CONFIG = {
|
|
2586
2581
|
imbalance: { Icon: ScaleIcon, token: "status-error", label: "Left/right imbalance" },
|
|
2587
2582
|
overshoot: { Icon: AlertTriangleIcon, token: "status-error", label: "Load overshoot" },
|
|
@@ -2619,42 +2614,101 @@ function ExerciseIndicator({ kind, onPress, className, ...props }) {
|
|
|
2619
2614
|
return chip;
|
|
2620
2615
|
}
|
|
2621
2616
|
|
|
2617
|
+
// src/components/custom/Workout/exerciseRowState.ts
|
|
2618
|
+
var ROW_STATE_TOKEN = {
|
|
2619
|
+
hovered: "interactive-hover",
|
|
2620
|
+
selected: "interactive-selected",
|
|
2621
|
+
pressed: "interactive-active"
|
|
2622
|
+
};
|
|
2623
|
+
function exerciseRowStateColor(state, mode = "dark") {
|
|
2624
|
+
return getSemanticColors(mode)[ROW_STATE_TOKEN[state]];
|
|
2625
|
+
}
|
|
2626
|
+
function exerciseLiveColor(mode = "dark") {
|
|
2627
|
+
return getSemanticColors(mode)["status-live"];
|
|
2628
|
+
}
|
|
2629
|
+
|
|
2622
2630
|
// src/components/custom/Workout/ExerciseHeading.tsx
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2631
|
+
var DIMMED_OPACITY = 0.55;
|
|
2632
|
+
function prescriptionText(p, unit) {
|
|
2633
|
+
if (p.prescription !== void 0) return p.prescription;
|
|
2634
|
+
if (p.sets === void 0) return void 0;
|
|
2635
|
+
const loadLabel = typeof p.load === "number" ? roundWeight(p.load) : p.load;
|
|
2636
|
+
return `${p.sets}\xD7${p.reps} @ ${loadLabel} ${unit}`;
|
|
2637
|
+
}
|
|
2638
|
+
function exerciseHeadingLabel(p, unit = p.unit ?? "lbs") {
|
|
2639
|
+
const prescription = prescriptionText(p, unit);
|
|
2640
|
+
return prescription ? `${p.name}, ${prescription}` : p.name;
|
|
2641
|
+
}
|
|
2642
|
+
function pressProps(p, unit) {
|
|
2643
|
+
return {
|
|
2644
|
+
onPress: p.onPress,
|
|
2645
|
+
onPressIn: p.onPressIn,
|
|
2646
|
+
onPressOut: p.onPressOut,
|
|
2647
|
+
onHoverIn: p.onHoverIn,
|
|
2648
|
+
onHoverOut: p.onHoverOut,
|
|
2649
|
+
accessibilityRole: "button",
|
|
2650
|
+
accessibilityLabel: exerciseHeadingLabel(p, unit)
|
|
2651
|
+
};
|
|
2626
2652
|
}
|
|
2627
|
-
function
|
|
2653
|
+
function HeadingName({
|
|
2628
2654
|
name,
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
load,
|
|
2632
|
-
unit = "lbs",
|
|
2633
|
-
tempo,
|
|
2634
|
-
indicator,
|
|
2635
|
-
dimmed,
|
|
2636
|
-
onPress
|
|
2655
|
+
nameStyle,
|
|
2656
|
+
className
|
|
2637
2657
|
}) {
|
|
2638
|
-
return
|
|
2658
|
+
return (
|
|
2659
|
+
// The row is a button label, not a heading, so `boldLabel` carries the weight and
|
|
2660
|
+
// no header role has to be undone. Size and the Space Grotesk face are pinned.
|
|
2661
|
+
/* @__PURE__ */ jsx(
|
|
2662
|
+
Typography,
|
|
2663
|
+
{
|
|
2664
|
+
variant: "boldLabel",
|
|
2665
|
+
color: nameStyle ? "inherit" : "primary",
|
|
2666
|
+
style: nameStyle,
|
|
2667
|
+
className: cn("font-heading text-sm leading-[normal]", className),
|
|
2668
|
+
testID: "exercise-card-name",
|
|
2669
|
+
children: name
|
|
2670
|
+
}
|
|
2671
|
+
)
|
|
2672
|
+
);
|
|
2673
|
+
}
|
|
2674
|
+
function prescriptionNode(p, unit) {
|
|
2675
|
+
if (p.prescription !== void 0) {
|
|
2676
|
+
return /* @__PURE__ */ jsx(
|
|
2677
|
+
Typography,
|
|
2678
|
+
{
|
|
2679
|
+
variant: "caption",
|
|
2680
|
+
color: "secondary",
|
|
2681
|
+
maxLines: 1,
|
|
2682
|
+
className: "font-sans shrink leading-[normal]",
|
|
2683
|
+
testID: "exercise-card-prescription",
|
|
2684
|
+
children: p.prescription
|
|
2685
|
+
}
|
|
2686
|
+
);
|
|
2687
|
+
}
|
|
2688
|
+
if (p.sets === void 0) return null;
|
|
2689
|
+
return /* @__PURE__ */ jsx(
|
|
2690
|
+
SetsRepsLoad,
|
|
2691
|
+
{
|
|
2692
|
+
sets: p.sets,
|
|
2693
|
+
reps: p.reps,
|
|
2694
|
+
load: p.load,
|
|
2695
|
+
unit,
|
|
2696
|
+
muted: p.mutedPrescription
|
|
2697
|
+
}
|
|
2698
|
+
);
|
|
2699
|
+
}
|
|
2700
|
+
function StackedHeading({ heading, nameStyle }) {
|
|
2701
|
+
const { unit = "lbs", tempo, indicator } = heading;
|
|
2702
|
+
return /* @__PURE__ */ jsxs(jsxRuntime.Fragment, { children: [
|
|
2639
2703
|
/* @__PURE__ */ jsxs(
|
|
2640
2704
|
reactNative.Pressable,
|
|
2641
2705
|
{
|
|
2642
|
-
|
|
2643
|
-
accessibilityRole: "button",
|
|
2644
|
-
accessibilityLabel: headingLabel(name, sets, reps, load, unit),
|
|
2706
|
+
...pressProps(heading, unit),
|
|
2645
2707
|
className: "flex-row items-center",
|
|
2646
2708
|
style: { gap: 8 },
|
|
2647
2709
|
testID: "exercise-card-header",
|
|
2648
2710
|
children: [
|
|
2649
|
-
/* @__PURE__ */ jsx(
|
|
2650
|
-
Typography,
|
|
2651
|
-
{
|
|
2652
|
-
variant: "boldLabel",
|
|
2653
|
-
className: "font-heading text-sm leading-[normal]",
|
|
2654
|
-
testID: "exercise-card-name",
|
|
2655
|
-
children: name
|
|
2656
|
-
}
|
|
2657
|
-
),
|
|
2711
|
+
/* @__PURE__ */ jsx(HeadingName, { name: heading.name, nameStyle }),
|
|
2658
2712
|
/* @__PURE__ */ jsx(reactNative.View, { className: "flex-1" }),
|
|
2659
2713
|
indicator && /* @__PURE__ */ jsx(ExerciseIndicator, { kind: indicator })
|
|
2660
2714
|
]
|
|
@@ -2667,7 +2721,7 @@ function ExerciseHeading({
|
|
|
2667
2721
|
style: { gap: 8, marginTop: 1 },
|
|
2668
2722
|
testID: "exercise-card-summary",
|
|
2669
2723
|
children: [
|
|
2670
|
-
|
|
2724
|
+
prescriptionNode(heading, unit),
|
|
2671
2725
|
/* @__PURE__ */ jsx(reactNative.View, { className: "flex-1" }),
|
|
2672
2726
|
tempo && /* @__PURE__ */ jsx(TempoDisplay, { tempo, size: "sm", showLabel: false, showInfo: false })
|
|
2673
2727
|
]
|
|
@@ -2675,9 +2729,44 @@ function ExerciseHeading({
|
|
|
2675
2729
|
)
|
|
2676
2730
|
] });
|
|
2677
2731
|
}
|
|
2732
|
+
function InlineHeading({ heading, nameStyle }) {
|
|
2733
|
+
const { unit = "lbs", indicator, previousBest } = heading;
|
|
2734
|
+
const Row = heading.pressTarget === "ancestor" ? reactNative.View : reactNative.Pressable;
|
|
2735
|
+
return /* @__PURE__ */ jsxs(
|
|
2736
|
+
Row,
|
|
2737
|
+
{
|
|
2738
|
+
...heading.pressTarget === "ancestor" ? {} : pressProps(heading, unit),
|
|
2739
|
+
className: "flex-row items-center",
|
|
2740
|
+
style: { gap: 8 },
|
|
2741
|
+
testID: "exercise-card-header",
|
|
2742
|
+
children: [
|
|
2743
|
+
/* @__PURE__ */ jsx(HeadingName, { name: heading.name, nameStyle, className: "shrink-0" }),
|
|
2744
|
+
/* @__PURE__ */ jsx(reactNative.View, { className: "shrink flex-row items-center", testID: "exercise-card-summary", children: prescriptionNode(heading, unit) }),
|
|
2745
|
+
/* @__PURE__ */ jsx(reactNative.View, { className: "flex-1", style: { minWidth: 8 } }),
|
|
2746
|
+
indicator && /* @__PURE__ */ jsx(ExerciseIndicator, { kind: indicator }),
|
|
2747
|
+
previousBest && /* @__PURE__ */ jsx(
|
|
2748
|
+
Typography,
|
|
2749
|
+
{
|
|
2750
|
+
variant: "caption",
|
|
2751
|
+
color: "tertiary",
|
|
2752
|
+
maxLines: 1,
|
|
2753
|
+
className: "font-sans shrink text-2xs leading-[normal]",
|
|
2754
|
+
testID: "exercise-card-previous-best",
|
|
2755
|
+
children: previousBest
|
|
2756
|
+
}
|
|
2757
|
+
)
|
|
2758
|
+
]
|
|
2759
|
+
}
|
|
2760
|
+
);
|
|
2761
|
+
}
|
|
2762
|
+
function ExerciseHeading(props) {
|
|
2763
|
+
const mode = useSurfaceMode();
|
|
2764
|
+
const nameStyle = props.isLive ? { color: exerciseLiveColor(mode) } : void 0;
|
|
2765
|
+
return /* @__PURE__ */ jsx(reactNative.View, { style: { opacity: props.dimmed ? DIMMED_OPACITY : 1 }, testID: "exercise-heading", children: props.layout === "inline" ? /* @__PURE__ */ jsx(InlineHeading, { heading: props, nameStyle }) : /* @__PURE__ */ jsx(StackedHeading, { heading: props, nameStyle }) });
|
|
2766
|
+
}
|
|
2678
2767
|
var PULSE_HALF_MS = 950;
|
|
2679
2768
|
var PULSE_MIN_OPACITY = 0.45;
|
|
2680
|
-
var SEGMENTED_BAR_GAP =
|
|
2769
|
+
var SEGMENTED_BAR_GAP = SET_LEVEL_FLAT_BAR.gap;
|
|
2681
2770
|
function usePulse(active) {
|
|
2682
2771
|
const [value] = react.useState(() => new reactNative.Animated.Value(0));
|
|
2683
2772
|
react.useEffect(() => {
|
|
@@ -2705,9 +2794,9 @@ function usePulse(active) {
|
|
|
2705
2794
|
}
|
|
2706
2795
|
function SegmentedBar({
|
|
2707
2796
|
segments,
|
|
2708
|
-
height =
|
|
2797
|
+
height = SET_LEVEL_FLAT_BAR.height,
|
|
2709
2798
|
gap = SEGMENTED_BAR_GAP,
|
|
2710
|
-
radius =
|
|
2799
|
+
radius = SET_LEVEL_FLAT_BAR.radius,
|
|
2711
2800
|
marker = null,
|
|
2712
2801
|
segmentTestID,
|
|
2713
2802
|
style,
|
|
@@ -2933,20 +3022,113 @@ function SetStrip({ sets, height = 8, className, ...props }) {
|
|
|
2933
3022
|
}
|
|
2934
3023
|
|
|
2935
3024
|
// src/components/custom/Workout/ExerciseCardHeading.tsx
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
3025
|
+
var DENSITY = {
|
|
3026
|
+
rail: {
|
|
3027
|
+
paddingVertical: 9,
|
|
3028
|
+
paddingHorizontal: 12,
|
|
3029
|
+
layout: "stacked",
|
|
3030
|
+
dimOpacity: 0.55,
|
|
3031
|
+
dimByDefault: false,
|
|
3032
|
+
mutedPrescription: false
|
|
3033
|
+
},
|
|
3034
|
+
compact: {
|
|
3035
|
+
paddingVertical: 12,
|
|
3036
|
+
paddingHorizontal: 14,
|
|
3037
|
+
layout: "inline",
|
|
3038
|
+
dimOpacity: 0.55,
|
|
3039
|
+
dimByDefault: false,
|
|
3040
|
+
mutedPrescription: true
|
|
3041
|
+
},
|
|
3042
|
+
upcoming: {
|
|
3043
|
+
paddingVertical: 12,
|
|
3044
|
+
paddingHorizontal: 14,
|
|
3045
|
+
layout: "inline",
|
|
3046
|
+
dimOpacity: 0.6,
|
|
3047
|
+
dimByDefault: true,
|
|
3048
|
+
mutedPrescription: true
|
|
3049
|
+
}
|
|
3050
|
+
};
|
|
3051
|
+
function useRowInteraction() {
|
|
3052
|
+
const { hovered: rowHovered, hoverProps } = useHoverState();
|
|
3053
|
+
const [headingHovered, setHeadingHovered] = react.useState(false);
|
|
3054
|
+
const [pressed, setPressed] = react.useState(false);
|
|
3055
|
+
return {
|
|
3056
|
+
hoverProps,
|
|
3057
|
+
pressed,
|
|
3058
|
+
hovered: rowHovered || headingHovered,
|
|
3059
|
+
headingHandlers: {
|
|
3060
|
+
onHoverIn: () => setHeadingHovered(true),
|
|
3061
|
+
onHoverOut: () => setHeadingHovered(false),
|
|
3062
|
+
onPressIn: () => setPressed(true),
|
|
3063
|
+
onPressOut: () => setPressed(false)
|
|
3064
|
+
}
|
|
3065
|
+
};
|
|
3066
|
+
}
|
|
3067
|
+
function rowWash(mode, state) {
|
|
3068
|
+
if (state.pressed) return exerciseRowStateColor("pressed", mode);
|
|
3069
|
+
if (state.isSelected) return exerciseRowStateColor("selected", mode);
|
|
3070
|
+
if (state.hovered) return exerciseRowStateColor("hovered", mode);
|
|
3071
|
+
return void 0;
|
|
3072
|
+
}
|
|
3073
|
+
function prescriptionProps(p) {
|
|
3074
|
+
const base = { name: p.name };
|
|
3075
|
+
if (p.prescription !== void 0) return { ...base, prescription: p.prescription };
|
|
3076
|
+
if (p.sets === void 0) return base;
|
|
3077
|
+
return { ...base, sets: p.sets, reps: p.reps, load: p.load };
|
|
3078
|
+
}
|
|
3079
|
+
function ExerciseCardHeading(props) {
|
|
3080
|
+
const {
|
|
3081
|
+
density = "rail",
|
|
3082
|
+
setStates = [],
|
|
3083
|
+
stripHeight = 8,
|
|
3084
|
+
dimmed,
|
|
3085
|
+
isSelected = false,
|
|
3086
|
+
isLive = false,
|
|
3087
|
+
testID = "exercise-card",
|
|
3088
|
+
style
|
|
3089
|
+
} = props;
|
|
3090
|
+
const spec = DENSITY[density];
|
|
3091
|
+
const { hoverProps, pressed, hovered, headingHandlers } = useRowInteraction();
|
|
3092
|
+
const wash = rowWash(useSurfaceMode(), { pressed, isSelected, hovered });
|
|
3093
|
+
const rowIsButton = spec.layout === "inline";
|
|
3094
|
+
const Root = rowIsButton ? reactNative.Pressable : reactNative.View;
|
|
3095
|
+
const rootPress = rowIsButton ? {
|
|
3096
|
+
...headingHandlers,
|
|
3097
|
+
onPress: props.onPress,
|
|
3098
|
+
accessibilityRole: "button",
|
|
3099
|
+
accessibilityLabel: exerciseHeadingLabel(props)
|
|
3100
|
+
} : {};
|
|
2943
3101
|
return /* @__PURE__ */ jsxs(
|
|
2944
|
-
|
|
3102
|
+
Root,
|
|
2945
3103
|
{
|
|
2946
|
-
|
|
3104
|
+
...hoverProps,
|
|
3105
|
+
...rootPress,
|
|
3106
|
+
style: [
|
|
3107
|
+
{
|
|
3108
|
+
paddingVertical: spec.paddingVertical,
|
|
3109
|
+
paddingHorizontal: spec.paddingHorizontal,
|
|
3110
|
+
opacity: dimmed ?? spec.dimByDefault ? spec.dimOpacity : 1
|
|
3111
|
+
},
|
|
3112
|
+
wash ? { backgroundColor: wash } : null,
|
|
3113
|
+
style
|
|
3114
|
+
],
|
|
2947
3115
|
testID,
|
|
2948
3116
|
children: [
|
|
2949
|
-
/* @__PURE__ */ jsx(
|
|
3117
|
+
/* @__PURE__ */ jsx(
|
|
3118
|
+
ExerciseHeading,
|
|
3119
|
+
{
|
|
3120
|
+
...prescriptionProps(props),
|
|
3121
|
+
...rowIsButton ? { pressTarget: "ancestor" } : headingHandlers,
|
|
3122
|
+
unit: props.unit,
|
|
3123
|
+
tempo: props.tempo,
|
|
3124
|
+
indicator: props.indicator,
|
|
3125
|
+
previousBest: props.previousBest,
|
|
3126
|
+
onPress: rowIsButton ? void 0 : props.onPress,
|
|
3127
|
+
layout: spec.layout,
|
|
3128
|
+
mutedPrescription: spec.mutedPrescription,
|
|
3129
|
+
isLive
|
|
3130
|
+
}
|
|
3131
|
+
),
|
|
2950
3132
|
setStates.length > 0 && /* @__PURE__ */ jsx(reactNative.View, { style: { marginTop: 7 }, testID: "exercise-card-strip", children: /* @__PURE__ */ jsx(SetStrip, { sets: setStates, height: stripHeight }) })
|
|
2951
3133
|
]
|
|
2952
3134
|
}
|
|
@@ -2992,103 +3174,58 @@ function getSupersetMargin(position) {
|
|
|
2992
3174
|
}
|
|
2993
3175
|
return {};
|
|
2994
3176
|
}
|
|
2995
|
-
function
|
|
2996
|
-
|
|
2997
|
-
return `${summary.sets}\xD7${summary.reps} @ ${roundWeight(summary.weight)} ${summary.unit}`;
|
|
3177
|
+
function supersetChrome(position) {
|
|
3178
|
+
return { ...getSupersetBorderRadius(position), ...getSupersetMargin(position) };
|
|
2998
3179
|
}
|
|
2999
|
-
function
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3180
|
+
function deriveCollapsedSetStates(setVelocities, totalPlannedSets, plannedReps2) {
|
|
3181
|
+
const done = (setVelocities ?? []).map(
|
|
3182
|
+
(velocities) => ({ status: "done", velocities })
|
|
3183
|
+
);
|
|
3184
|
+
const remaining = Math.max(0, (totalPlannedSets ?? 0) - done.length);
|
|
3185
|
+
return [
|
|
3186
|
+
...done,
|
|
3187
|
+
...Array.from(
|
|
3188
|
+
{ length: remaining },
|
|
3189
|
+
() => ({ status: "todo", planned: plannedReps2 })
|
|
3190
|
+
)
|
|
3191
|
+
];
|
|
3003
3192
|
}
|
|
3004
3193
|
function CollapsedCard({
|
|
3005
3194
|
name,
|
|
3006
3195
|
onToggle,
|
|
3007
3196
|
summary,
|
|
3008
3197
|
isPR,
|
|
3198
|
+
indicator,
|
|
3009
3199
|
setVelocities,
|
|
3010
|
-
|
|
3200
|
+
setStates,
|
|
3011
3201
|
totalPlannedSets,
|
|
3012
|
-
|
|
3202
|
+
stripHeight,
|
|
3203
|
+
supersetPosition,
|
|
3204
|
+
isSelected,
|
|
3205
|
+
isLive
|
|
3013
3206
|
}) {
|
|
3014
|
-
const
|
|
3015
|
-
const
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3207
|
+
const plannedReps2 = typeof summary?.reps === "number" ? summary.reps : 0;
|
|
3208
|
+
const row = {
|
|
3209
|
+
density: "compact",
|
|
3210
|
+
name,
|
|
3211
|
+
indicator: indicator ?? (isPR ? "pr" : void 0),
|
|
3212
|
+
setStates: setStates ?? deriveCollapsedSetStates(setVelocities, totalPlannedSets, plannedReps2),
|
|
3213
|
+
stripHeight,
|
|
3214
|
+
isSelected,
|
|
3215
|
+
isLive,
|
|
3216
|
+
onPress: onToggle,
|
|
3217
|
+
style: supersetChrome(supersetPosition)
|
|
3218
|
+
};
|
|
3219
|
+
return summary ? /* @__PURE__ */ jsx(
|
|
3220
|
+
ExerciseCardHeading,
|
|
3021
3221
|
{
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
testID: "exercise-card",
|
|
3028
|
-
children: /* @__PURE__ */ jsxs(
|
|
3029
|
-
reactNative.View,
|
|
3030
|
-
{
|
|
3031
|
-
className: pressed ? "bg-surface-raised" : void 0,
|
|
3032
|
-
style: {
|
|
3033
|
-
padding: 12,
|
|
3034
|
-
paddingHorizontal: 14,
|
|
3035
|
-
cursor: "pointer",
|
|
3036
|
-
...borderRadius,
|
|
3037
|
-
...supersetMargin
|
|
3038
|
-
},
|
|
3039
|
-
children: [
|
|
3040
|
-
/* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", testID: "exercise-card-header", children: [
|
|
3041
|
-
/* @__PURE__ */ jsx(
|
|
3042
|
-
Typography,
|
|
3043
|
-
{
|
|
3044
|
-
variant: "h6",
|
|
3045
|
-
color: "primary",
|
|
3046
|
-
className: "text-sm font-bold leading-[normal]",
|
|
3047
|
-
testID: "exercise-card-name",
|
|
3048
|
-
children: name
|
|
3049
|
-
}
|
|
3050
|
-
),
|
|
3051
|
-
/* @__PURE__ */ jsx(reactNative.View, { className: "flex-1" }),
|
|
3052
|
-
summary && /* The demo's "body" face is Inter, which is the library's `font-sans`
|
|
3053
|
-
(the mapping B1 established for PrBadge), not Typography's `font-body`. */
|
|
3054
|
-
/* @__PURE__ */ jsx(
|
|
3055
|
-
Typography,
|
|
3056
|
-
{
|
|
3057
|
-
variant: "caption",
|
|
3058
|
-
color: "secondary",
|
|
3059
|
-
className: "font-sans mr-2 leading-[normal]",
|
|
3060
|
-
testID: "exercise-card-summary",
|
|
3061
|
-
children: formatSummary(summary)
|
|
3062
|
-
}
|
|
3063
|
-
),
|
|
3064
|
-
isPR && /* @__PURE__ */ jsx(reactNative.View, { style: { marginLeft: 4 }, children: /* @__PURE__ */ jsx(PrBadge, { type: "e1rm", compact: true, animate: false }) })
|
|
3065
|
-
] }),
|
|
3066
|
-
(completedSets > 0 || remaining > 0) && /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row", style: { marginTop: 6, gap: 4 }, testID: "exercise-card-strips", children: [
|
|
3067
|
-
setVelocities?.map((velocities, i) => /* @__PURE__ */ jsx(
|
|
3068
|
-
VelocityStrip,
|
|
3069
|
-
{
|
|
3070
|
-
velocities,
|
|
3071
|
-
zones: velocityZones,
|
|
3072
|
-
variant: "compact",
|
|
3073
|
-
height: 8,
|
|
3074
|
-
hideBaseline: true,
|
|
3075
|
-
testID: `exercise-card-velocity-strip-${i}`
|
|
3076
|
-
},
|
|
3077
|
-
i
|
|
3078
|
-
)),
|
|
3079
|
-
Array.from({ length: remaining }, (_, i) => /* @__PURE__ */ jsx(
|
|
3080
|
-
PlaceholderStrip,
|
|
3081
|
-
{
|
|
3082
|
-
testID: `exercise-card-placeholder-${i}`
|
|
3083
|
-
},
|
|
3084
|
-
`placeholder-${i}`
|
|
3085
|
-
))
|
|
3086
|
-
] })
|
|
3087
|
-
]
|
|
3088
|
-
}
|
|
3089
|
-
)
|
|
3222
|
+
...row,
|
|
3223
|
+
sets: summary.sets,
|
|
3224
|
+
reps: summary.reps,
|
|
3225
|
+
load: summary.weight,
|
|
3226
|
+
unit: summary.unit
|
|
3090
3227
|
}
|
|
3091
|
-
);
|
|
3228
|
+
) : /* @__PURE__ */ jsx(ExerciseCardHeading, { ...row });
|
|
3092
3229
|
}
|
|
3093
3230
|
function deriveHeaderSetStates(sets) {
|
|
3094
3231
|
return sets.map((set) => {
|
|
@@ -3113,10 +3250,9 @@ function ExpandedCard({
|
|
|
3113
3250
|
setStates,
|
|
3114
3251
|
stripHeight = 8,
|
|
3115
3252
|
velocityZones,
|
|
3116
|
-
supersetPosition
|
|
3253
|
+
supersetPosition,
|
|
3254
|
+
isLive
|
|
3117
3255
|
}) {
|
|
3118
|
-
const borderRadius = getSupersetBorderRadius(supersetPosition);
|
|
3119
|
-
const supersetMargin = getSupersetMargin(supersetPosition);
|
|
3120
3256
|
const unit = summary?.unit ?? sets?.[0]?.unit ?? "lbs";
|
|
3121
3257
|
const headerStates = setStates ?? (sets ? deriveHeaderSetStates(sets) : []);
|
|
3122
3258
|
const headerIndicator = indicator ?? (isPR ? "pr" : void 0);
|
|
@@ -3124,11 +3260,7 @@ function ExpandedCard({
|
|
|
3124
3260
|
reactNative.View,
|
|
3125
3261
|
{
|
|
3126
3262
|
className: "bg-surface-elevated border-hairline",
|
|
3127
|
-
style: {
|
|
3128
|
-
borderWidth: 1,
|
|
3129
|
-
...borderRadius,
|
|
3130
|
-
...supersetMargin
|
|
3131
|
-
},
|
|
3263
|
+
style: { borderWidth: 1, ...supersetChrome(supersetPosition) },
|
|
3132
3264
|
testID: "exercise-card",
|
|
3133
3265
|
children: [
|
|
3134
3266
|
/* @__PURE__ */ jsx(
|
|
@@ -3143,6 +3275,7 @@ function ExpandedCard({
|
|
|
3143
3275
|
indicator: headerIndicator,
|
|
3144
3276
|
setStates: headerStates,
|
|
3145
3277
|
stripHeight,
|
|
3278
|
+
isLive,
|
|
3146
3279
|
onPress: onToggle,
|
|
3147
3280
|
testID: "exercise-card-heading"
|
|
3148
3281
|
}
|
|
@@ -3170,62 +3303,21 @@ function UpcomingCard({
|
|
|
3170
3303
|
name,
|
|
3171
3304
|
prescription,
|
|
3172
3305
|
previousBest,
|
|
3306
|
+
indicator,
|
|
3173
3307
|
supersetPosition,
|
|
3308
|
+
isSelected,
|
|
3174
3309
|
onToggle
|
|
3175
3310
|
}) {
|
|
3176
|
-
const
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
...supersetMargin
|
|
3187
|
-
},
|
|
3188
|
-
accessibilityLabel: formatAccessibilityLabel(name, void 0, prescription),
|
|
3189
|
-
testID: "exercise-card",
|
|
3190
|
-
children: /* @__PURE__ */ jsxs(reactNative.View, { className: "flex-row items-center", children: [
|
|
3191
|
-
/* @__PURE__ */ jsx(
|
|
3192
|
-
Typography,
|
|
3193
|
-
{
|
|
3194
|
-
variant: "h6",
|
|
3195
|
-
color: "primary",
|
|
3196
|
-
className: "shrink-0 text-sm font-bold leading-[normal]",
|
|
3197
|
-
testID: "exercise-card-name",
|
|
3198
|
-
children: name
|
|
3199
|
-
}
|
|
3200
|
-
),
|
|
3201
|
-
prescription && /* @__PURE__ */ jsx(
|
|
3202
|
-
Typography,
|
|
3203
|
-
{
|
|
3204
|
-
variant: "caption",
|
|
3205
|
-
color: "secondary",
|
|
3206
|
-
maxLines: 1,
|
|
3207
|
-
className: "font-sans shrink ml-2 leading-[normal]",
|
|
3208
|
-
testID: "exercise-card-prescription",
|
|
3209
|
-
children: prescription
|
|
3210
|
-
}
|
|
3211
|
-
),
|
|
3212
|
-
/* @__PURE__ */ jsx(reactNative.View, { className: "flex-1", style: { minWidth: 8 } }),
|
|
3213
|
-
previousBest && /* 11px is off the type scale; `2xs` (10px) is the step below, as B2's
|
|
3214
|
-
WorkoutCard date took for the same size. */
|
|
3215
|
-
/* @__PURE__ */ jsx(
|
|
3216
|
-
Typography,
|
|
3217
|
-
{
|
|
3218
|
-
variant: "caption",
|
|
3219
|
-
color: "tertiary",
|
|
3220
|
-
maxLines: 1,
|
|
3221
|
-
className: "font-sans shrink text-2xs leading-[normal]",
|
|
3222
|
-
testID: "exercise-card-previous-best",
|
|
3223
|
-
children: previousBest
|
|
3224
|
-
}
|
|
3225
|
-
)
|
|
3226
|
-
] })
|
|
3227
|
-
}
|
|
3228
|
-
) });
|
|
3311
|
+
const row = {
|
|
3312
|
+
density: "upcoming",
|
|
3313
|
+
name,
|
|
3314
|
+
previousBest,
|
|
3315
|
+
indicator,
|
|
3316
|
+
isSelected,
|
|
3317
|
+
onPress: onToggle,
|
|
3318
|
+
style: supersetChrome(supersetPosition)
|
|
3319
|
+
};
|
|
3320
|
+
return prescription !== void 0 ? /* @__PURE__ */ jsx(ExerciseCardHeading, { ...row, prescription }) : /* @__PURE__ */ jsx(ExerciseCardHeading, { ...row });
|
|
3229
3321
|
}
|
|
3230
3322
|
function ExerciseCard({
|
|
3231
3323
|
upcoming,
|
|
@@ -3245,7 +3337,9 @@ function ExerciseCard({
|
|
|
3245
3337
|
if (upcoming) return /* @__PURE__ */ jsx(UpcomingCard, { ...rest, onToggle });
|
|
3246
3338
|
return isExpanded ? /* @__PURE__ */ jsx(ExpandedCard, { ...rest, onToggle }) : /* @__PURE__ */ jsx(CollapsedCard, { ...rest, onToggle });
|
|
3247
3339
|
}
|
|
3248
|
-
var
|
|
3340
|
+
var t2 = getSemanticColors("dark");
|
|
3341
|
+
var BRAND_PRIMARY = t2["brand-primary"];
|
|
3342
|
+
var ON_BRAND_PRIMARY = t2["on-brand-primary"];
|
|
3249
3343
|
var INPUT_CLASSNAME = "bg-surface-raised border-hairline-strong text-text-primary";
|
|
3250
3344
|
var inputStyle = {
|
|
3251
3345
|
fontSize: 14,
|
|
@@ -3390,7 +3484,7 @@ function InputBar({
|
|
|
3390
3484
|
fontSize: 13,
|
|
3391
3485
|
fontWeight: "700",
|
|
3392
3486
|
fontFamily: "Inter, sans-serif",
|
|
3393
|
-
color:
|
|
3487
|
+
color: ON_BRAND_PRIMARY
|
|
3394
3488
|
},
|
|
3395
3489
|
children: "Record"
|
|
3396
3490
|
}
|
|
@@ -3617,7 +3711,7 @@ function RestActions({ onAddTime, onSkip }) {
|
|
|
3617
3711
|
{
|
|
3618
3712
|
onPress: onAddTime,
|
|
3619
3713
|
style: {
|
|
3620
|
-
backgroundColor:
|
|
3714
|
+
backgroundColor: alpha(primitiveColors.white, 0.06),
|
|
3621
3715
|
paddingVertical: 8,
|
|
3622
3716
|
paddingHorizontal: 20,
|
|
3623
3717
|
borderRadius: 8
|
|
@@ -3640,7 +3734,7 @@ function RestActions({ onAddTime, onSkip }) {
|
|
|
3640
3734
|
{
|
|
3641
3735
|
onPress: onSkip,
|
|
3642
3736
|
style: {
|
|
3643
|
-
backgroundColor:
|
|
3737
|
+
backgroundColor: alpha(BRAND_PRIMARY2, 0.12),
|
|
3644
3738
|
paddingVertical: 8,
|
|
3645
3739
|
paddingHorizontal: 20,
|
|
3646
3740
|
borderRadius: 8
|
|
@@ -4171,128 +4265,6 @@ function ActiveWorkoutPage({
|
|
|
4171
4265
|
}
|
|
4172
4266
|
);
|
|
4173
4267
|
}
|
|
4174
|
-
var FLOATING_LIFT_MIN = 4;
|
|
4175
|
-
var LIFT_RIM_ALPHA = { dark: 0.12, light: 0.9 };
|
|
4176
|
-
var AMBIENT = {
|
|
4177
|
-
1: [
|
|
4178
|
-
{ y: 1, blur: 2, alpha: 0.35 },
|
|
4179
|
-
{ y: 2, blur: 6, alpha: 0.3 }
|
|
4180
|
-
],
|
|
4181
|
-
2: [
|
|
4182
|
-
{ y: 1, blur: 2, alpha: 0.35 },
|
|
4183
|
-
{ y: 4, blur: 12, alpha: 0.32 }
|
|
4184
|
-
],
|
|
4185
|
-
3: [
|
|
4186
|
-
{ y: 2, blur: 4, alpha: 0.35 },
|
|
4187
|
-
{ y: 8, blur: 22, alpha: 0.35 }
|
|
4188
|
-
],
|
|
4189
|
-
4: [
|
|
4190
|
-
{ y: 1, blur: 2, alpha: 0.35 },
|
|
4191
|
-
{ y: 10, blur: 24, alpha: 0.3 },
|
|
4192
|
-
{ y: 24, blur: 48, alpha: 0.2 }
|
|
4193
|
-
],
|
|
4194
|
-
5: [
|
|
4195
|
-
{ y: 2, blur: 4, alpha: 0.4 },
|
|
4196
|
-
{ y: 16, blur: 32, alpha: 0.35 },
|
|
4197
|
-
{ y: 32, blur: 64, alpha: 0.25 }
|
|
4198
|
-
]
|
|
4199
|
-
};
|
|
4200
|
-
var AMBIENT_ALPHA_SCALE = { dark: 1, light: 0.4 };
|
|
4201
|
-
function ambientLayers(step, mode) {
|
|
4202
|
-
const scale = AMBIENT_ALPHA_SCALE[mode];
|
|
4203
|
-
return AMBIENT[step].map(
|
|
4204
|
-
({ y, blur, alpha: alpha2 }) => `0 ${y}px ${blur}px rgba(0,0,0,${(alpha2 * scale).toFixed(2)})`
|
|
4205
|
-
);
|
|
4206
|
-
}
|
|
4207
|
-
function liftShadow(step, mode = "dark", opts = {}) {
|
|
4208
|
-
const rim = opts.rim ?? LIFT_RIM_ALPHA[mode];
|
|
4209
|
-
const layers = ambientLayers(step, mode);
|
|
4210
|
-
if (rim > 0) layers.unshift(`inset 0 1px 0 rgba(255,255,255,${rim.toFixed(2)})`);
|
|
4211
|
-
return layers.join(", ");
|
|
4212
|
-
}
|
|
4213
|
-
function liftStyle(step, mode = "dark", opts = {}) {
|
|
4214
|
-
const deepest = AMBIENT[step][AMBIENT[step].length - 1];
|
|
4215
|
-
return reactNative.Platform.select({
|
|
4216
|
-
web: { boxShadow: liftShadow(step, mode, opts) },
|
|
4217
|
-
default: {
|
|
4218
|
-
shadowColor: "#000",
|
|
4219
|
-
shadowOffset: { width: 0, height: Math.round(deepest.y / 2) },
|
|
4220
|
-
shadowOpacity: deepest.alpha * AMBIENT_ALPHA_SCALE[mode],
|
|
4221
|
-
shadowRadius: deepest.blur / 2,
|
|
4222
|
-
elevation: step
|
|
4223
|
-
}
|
|
4224
|
-
});
|
|
4225
|
-
}
|
|
4226
|
-
var FLOATING_ELEVATION_MIN = FLOATING_LIFT_MIN;
|
|
4227
|
-
function getPressedRecessShadow(fillColor, _mode = "dark") {
|
|
4228
|
-
const { boxShadow } = insetWell(fillColor);
|
|
4229
|
-
return reactNative.Platform.select({
|
|
4230
|
-
web: { boxShadow },
|
|
4231
|
-
default: {}
|
|
4232
|
-
});
|
|
4233
|
-
}
|
|
4234
|
-
var glowConfig = {
|
|
4235
|
-
tight: { blur: 4, spread: 0, opacity: 0.4 },
|
|
4236
|
-
subtle: { blur: 12, spread: 0, opacity: 0.25 },
|
|
4237
|
-
medium: { blur: 20, spread: 2, opacity: 0.4 },
|
|
4238
|
-
strong: { blur: 30, spread: 4, opacity: 0.55 }
|
|
4239
|
-
};
|
|
4240
|
-
function getGlowShadow(color, intensity = "medium") {
|
|
4241
|
-
const config = glowConfig[intensity];
|
|
4242
|
-
const rgb = hexToRgb(color);
|
|
4243
|
-
if (!rgb) return {};
|
|
4244
|
-
return reactNative.Platform.select({
|
|
4245
|
-
web: {
|
|
4246
|
-
boxShadow: `0 0 ${config.blur}px ${config.spread}px rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${config.opacity})`
|
|
4247
|
-
},
|
|
4248
|
-
default: {
|
|
4249
|
-
shadowColor: color,
|
|
4250
|
-
shadowOffset: { width: 0, height: 0 },
|
|
4251
|
-
shadowOpacity: config.opacity,
|
|
4252
|
-
shadowRadius: config.blur / 2,
|
|
4253
|
-
elevation: 0
|
|
4254
|
-
}
|
|
4255
|
-
});
|
|
4256
|
-
}
|
|
4257
|
-
function recessDepth(inherited, planesDown, mode) {
|
|
4258
|
-
let plane = inherited.level;
|
|
4259
|
-
for (let i = 0; i < planesDown; i++) plane = pressedLevel(plane);
|
|
4260
|
-
const backgroundColor = surfaceBackground(plane, mode);
|
|
4261
|
-
return { plane, backgroundColor, depthStyle: getPressedRecessShadow(backgroundColor, mode) };
|
|
4262
|
-
}
|
|
4263
|
-
function resolveSurfaceDepth(inherited, props) {
|
|
4264
|
-
const mode = props.theme ?? inherited.mode;
|
|
4265
|
-
const elevation = props.elevation ?? 0;
|
|
4266
|
-
if (props.pressed || elevation < 0) {
|
|
4267
|
-
const down = props.pressed ? 1 : -elevation;
|
|
4268
|
-
return { mode, step: 0, lifted: false, ...recessDepth(inherited, down, mode) };
|
|
4269
|
-
}
|
|
4270
|
-
const step = props.level != null ? 0 : props.raise ?? elevation;
|
|
4271
|
-
const floating = step >= FLOATING_ELEVATION_MIN;
|
|
4272
|
-
const plane = props.level ?? (floating ? "overlay" : raisedLevel(inherited.level, step));
|
|
4273
|
-
const lifted = props.lift ?? step > 0;
|
|
4274
|
-
const liftStep = Math.max(1, Math.min(5, step));
|
|
4275
|
-
const depthStyle = lifted ? liftStyle(liftStep, mode, props.liftOptions) : {};
|
|
4276
|
-
return { mode, plane, backgroundColor: surfaceBackground(plane, mode), depthStyle, step, lifted };
|
|
4277
|
-
}
|
|
4278
|
-
function useResolvedSurface(props) {
|
|
4279
|
-
const inherited = useSurface();
|
|
4280
|
-
const { level, raise, elevation, pressed, lift, liftOptions, theme } = props;
|
|
4281
|
-
return react.useMemo(
|
|
4282
|
-
() => resolveSurfaceDepth(inherited, {
|
|
4283
|
-
level,
|
|
4284
|
-
raise,
|
|
4285
|
-
elevation,
|
|
4286
|
-
pressed,
|
|
4287
|
-
lift,
|
|
4288
|
-
liftOptions,
|
|
4289
|
-
theme
|
|
4290
|
-
}),
|
|
4291
|
-
[inherited, level, raise, elevation, pressed, lift, liftOptions, theme]
|
|
4292
|
-
);
|
|
4293
|
-
}
|
|
4294
|
-
|
|
4295
|
-
// src/components/ui/card/Card.tsx
|
|
4296
4268
|
var EDGE_CLASS = {
|
|
4297
4269
|
elevated: "",
|
|
4298
4270
|
accent: "",
|
|
@@ -4572,11 +4544,11 @@ var WARNING = t3["status-warning"];
|
|
|
4572
4544
|
var ERROR = t3["status-error"];
|
|
4573
4545
|
var ACCENT_STOPS = [BRAND_PRIMARY_DARK, BRAND_PRIMARY4, BRAND_PRIMARY_LIGHT];
|
|
4574
4546
|
var CARD_GRADIENT = `linear-gradient(135deg, ${resolveColor("surface-elevated")} 0%, ${resolveColor("surface-raised")} 100%)`;
|
|
4575
|
-
var GAUGE_GRADIENT =
|
|
4547
|
+
var GAUGE_GRADIENT = `linear-gradient(90deg, ${alpha(SUCCESS, 0.25)} 0%, ${alpha(WARNING, 0.25)} 50%, ${alpha(ERROR, 0.25)} 100%)`;
|
|
4576
4548
|
var STATUS_VARIANTS = {
|
|
4577
|
-
success: { bg:
|
|
4578
|
-
warning: { bg:
|
|
4579
|
-
error: { bg:
|
|
4549
|
+
success: { bg: alpha(SUCCESS, 0.15), border: alpha(SUCCESS, 0.3), text: SUCCESS },
|
|
4550
|
+
warning: { bg: alpha(WARNING, 0.15), border: alpha(WARNING, 0.3), text: WARNING },
|
|
4551
|
+
error: { bg: alpha(ERROR, 0.15), border: alpha(ERROR, 0.25), text: ERROR }
|
|
4580
4552
|
};
|
|
4581
4553
|
function clamp01(value) {
|
|
4582
4554
|
if (!Number.isFinite(value)) return 0;
|
|
@@ -4729,7 +4701,7 @@ function Gauge({ gauge }) {
|
|
|
4729
4701
|
bottom: 0,
|
|
4730
4702
|
width: 1,
|
|
4731
4703
|
marginLeft: -0.5,
|
|
4732
|
-
backgroundColor:
|
|
4704
|
+
backgroundColor: alpha(primitiveColors.white, 0.3)
|
|
4733
4705
|
},
|
|
4734
4706
|
testID: "meso-status-card-gauge-center"
|
|
4735
4707
|
}
|
|
@@ -4838,9 +4810,9 @@ function MesoStatusCard({
|
|
|
4838
4810
|
reactNative.View,
|
|
4839
4811
|
{
|
|
4840
4812
|
style: {
|
|
4841
|
-
backgroundColor:
|
|
4813
|
+
backgroundColor: alpha(WARNING, 0.06),
|
|
4842
4814
|
borderWidth: 1,
|
|
4843
|
-
borderColor:
|
|
4815
|
+
borderColor: alpha(WARNING, 0.15),
|
|
4844
4816
|
borderRadius: 8,
|
|
4845
4817
|
paddingVertical: 10,
|
|
4846
4818
|
paddingHorizontal: 12
|
|
@@ -4866,9 +4838,9 @@ function MesoStatusCard({
|
|
|
4866
4838
|
className: "flex-row items-center",
|
|
4867
4839
|
style: {
|
|
4868
4840
|
gap: 8,
|
|
4869
|
-
backgroundColor:
|
|
4841
|
+
backgroundColor: alpha(SUCCESS, 0.06),
|
|
4870
4842
|
borderWidth: 1,
|
|
4871
|
-
borderColor:
|
|
4843
|
+
borderColor: alpha(SUCCESS, 0.2),
|
|
4872
4844
|
borderRadius: 8,
|
|
4873
4845
|
paddingVertical: 10,
|
|
4874
4846
|
paddingHorizontal: 12
|
|
@@ -4903,11 +4875,11 @@ var PROJECTION_LINE_COLOR = resolveColor("text-tertiary");
|
|
|
4903
4875
|
var STATUS_SUCCESS2 = sem["status-success"];
|
|
4904
4876
|
var STATUS_ERROR2 = sem["status-error"];
|
|
4905
4877
|
var STATUS_WARNING2 = sem["status-warning"];
|
|
4906
|
-
var GRID_LINE =
|
|
4907
|
-
var SUCCESS_PILL_BG =
|
|
4908
|
-
var SUCCESS_PILL_BORDER =
|
|
4909
|
-
var ERROR_PILL_BG =
|
|
4910
|
-
var ERROR_PILL_BORDER =
|
|
4878
|
+
var GRID_LINE = alpha(primitiveColors.white, 0.06);
|
|
4879
|
+
var SUCCESS_PILL_BG = alpha(STATUS_SUCCESS2, 0.1);
|
|
4880
|
+
var SUCCESS_PILL_BORDER = alpha(STATUS_SUCCESS2, 0.2);
|
|
4881
|
+
var ERROR_PILL_BG = alpha(STATUS_ERROR2, 0.1);
|
|
4882
|
+
var ERROR_PILL_BORDER = alpha(STATUS_ERROR2, 0.2);
|
|
4911
4883
|
var PLOT_LEFT = 26;
|
|
4912
4884
|
var TOOLTIP_WIDTH = 124;
|
|
4913
4885
|
function timeOf(dateStr) {
|
|
@@ -5152,7 +5124,7 @@ function StrengthTrendChart({
|
|
|
5152
5124
|
height,
|
|
5153
5125
|
borderLeftWidth: 1,
|
|
5154
5126
|
borderStyle: "dashed",
|
|
5155
|
-
borderLeftColor:
|
|
5127
|
+
borderLeftColor: alpha(primitiveColors.white, 0.1)
|
|
5156
5128
|
}
|
|
5157
5129
|
},
|
|
5158
5130
|
`boundary-${i}`
|
|
@@ -5425,9 +5397,9 @@ var STATUS_SUCCESS3 = t4["status-success"];
|
|
|
5425
5397
|
var STATUS_WARNING3 = t4["status-warning"];
|
|
5426
5398
|
var STATUS_INFO = t4["status-info"];
|
|
5427
5399
|
var DOT_BORDER = "#F3F4F6";
|
|
5428
|
-
var BAND_FILL =
|
|
5429
|
-
var BAND_EDGE =
|
|
5430
|
-
var PROJECTION_FILL =
|
|
5400
|
+
var BAND_FILL = alpha(STATUS_SUCCESS3, 0.1);
|
|
5401
|
+
var BAND_EDGE = alpha(STATUS_SUCCESS3, 0.45);
|
|
5402
|
+
var PROJECTION_FILL = alpha(STATUS_SUCCESS3, 0.05);
|
|
5431
5403
|
var PADDING_LEFT = 28;
|
|
5432
5404
|
var PADDING_RIGHT = 10;
|
|
5433
5405
|
var PADDING_TOP = 8;
|
|
@@ -6201,9 +6173,9 @@ function ExerciseDetailPage({
|
|
|
6201
6173
|
paddingVertical: 4,
|
|
6202
6174
|
paddingHorizontal: 10,
|
|
6203
6175
|
borderRadius: 6,
|
|
6204
|
-
backgroundColor:
|
|
6176
|
+
backgroundColor: alpha(BRAND_PRIMARY6, 0.1),
|
|
6205
6177
|
borderWidth: 1,
|
|
6206
|
-
borderColor:
|
|
6178
|
+
borderColor: alpha(BRAND_PRIMARY6, 0.25)
|
|
6207
6179
|
},
|
|
6208
6180
|
testID: "exercise-detail-page-e1rm",
|
|
6209
6181
|
children: [
|
|
@@ -6506,13 +6478,16 @@ var toneStyles = {
|
|
|
6506
6478
|
// host is, and an alpha fill composites by the same amount on all of them.
|
|
6507
6479
|
// A `surface-*` fill would vanish on the plane it names. Borderless like the
|
|
6508
6480
|
// six coloured tones — the fill carries the capsule, not a ring.
|
|
6481
|
+
// Label comes from `on-*-subtle`, not the base tone token: the base is tuned to
|
|
6482
|
+
// carry a white label as a solid fill, which left error and accent unreadable
|
|
6483
|
+
// here (AW-133). The on-subtle tokens level the family at one weight.
|
|
6509
6484
|
neutral: "bg-hairline-subtle border-transparent text-text-secondary",
|
|
6510
|
-
brand: "bg-brand-primary-subtle border-transparent text-brand-primary",
|
|
6511
|
-
"brand-secondary": "bg-brand-secondary-subtle border-transparent text-brand-secondary",
|
|
6512
|
-
success: "bg-status-success-subtle border-transparent text-status-success",
|
|
6513
|
-
warning: "bg-status-warning-subtle border-transparent text-status-warning",
|
|
6514
|
-
error: "bg-status-error-subtle border-transparent text-status-error",
|
|
6515
|
-
info: "bg-status-info-subtle border-transparent text-status-info"
|
|
6485
|
+
brand: "bg-brand-primary-subtle border-transparent text-on-brand-primary-subtle",
|
|
6486
|
+
"brand-secondary": "bg-brand-secondary-subtle border-transparent text-on-brand-secondary-subtle",
|
|
6487
|
+
success: "bg-status-success-subtle border-transparent text-on-status-success-subtle",
|
|
6488
|
+
warning: "bg-status-warning-subtle border-transparent text-on-status-warning-subtle",
|
|
6489
|
+
error: "bg-status-error-subtle border-transparent text-on-status-error-subtle",
|
|
6490
|
+
info: "bg-status-info-subtle border-transparent text-on-status-info-subtle"
|
|
6516
6491
|
},
|
|
6517
6492
|
outline: {
|
|
6518
6493
|
neutral: "border-hairline text-text-secondary",
|
|
@@ -6826,7 +6801,7 @@ function WorkoutPill({
|
|
|
6826
6801
|
var t6 = getSemanticColors("dark");
|
|
6827
6802
|
var TRACK_BG = "#333333";
|
|
6828
6803
|
var LABEL_COLOR = "#6B7280";
|
|
6829
|
-
var TARGET_LINE_COLOR = "
|
|
6804
|
+
var TARGET_LINE_COLOR = alpha(t6["status-info"], 0.5);
|
|
6830
6805
|
var AT_TARGET_GLOW = getGlowShadow(t6["status-info"], "subtle");
|
|
6831
6806
|
var ZONE = {
|
|
6832
6807
|
building: t6["status-success"],
|
|
@@ -7108,7 +7083,7 @@ var ACCENT_STOPS2 = [BRAND_PRIMARY_DARK2, BRAND_PRIMARY7, BRAND_PRIMARY_LIGHT2];
|
|
|
7108
7083
|
function heatmapColor(percentage) {
|
|
7109
7084
|
const clamped = Math.max(0, Math.min(100, percentage));
|
|
7110
7085
|
const opacity = 0.12 + clamped / 100 * 0.78;
|
|
7111
|
-
return
|
|
7086
|
+
return alpha(BRAND_PRIMARY7, opacity);
|
|
7112
7087
|
}
|
|
7113
7088
|
function MesoCard({
|
|
7114
7089
|
name,
|