@burdenoff/microfe-mybodyshield 2026.705.1 → 2026.705.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mybodyshield/components/DataTable.js +8 -4
- package/dist/mybodyshield/components/DataTable.js.map +1 -1
- package/dist/mybodyshield/components/EvidenceUpload.js +92 -4
- package/dist/mybodyshield/components/EvidenceUpload.js.map +1 -0
- package/dist/mybodyshield/components/FileLink.js +35 -2
- package/dist/mybodyshield/components/FileLink.js.map +1 -0
- package/dist/mybodyshield/components/MybDiscussion.js +107 -6
- package/dist/mybodyshield/components/MybDiscussion.js.map +1 -0
- package/dist/mybodyshield/components/MybTags.js +148 -4
- package/dist/mybodyshield/components/MybTags.js.map +1 -0
- package/dist/mybodyshield/components/Pagination.js.map +1 -1
- package/dist/mybodyshield/components/UserSearchSelect.js +148 -0
- package/dist/mybodyshield/components/UserSearchSelect.js.map +1 -0
- package/dist/mybodyshield/components/index.js +1 -0
- package/dist/mybodyshield/hooks/index.js +1 -0
- package/dist/mybodyshield/hooks/useMyBodyShieldApi.js +47 -27
- package/dist/mybodyshield/hooks/useMyBodyShieldApi.js.map +1 -1
- package/dist/mybodyshield/hooks/useMybComments.js +44 -2
- package/dist/mybodyshield/hooks/useMybComments.js.map +1 -0
- package/dist/mybodyshield/hooks/useMybFiles.js +80 -3
- package/dist/mybodyshield/hooks/useMybFiles.js.map +1 -0
- package/dist/mybodyshield/hooks/useMybTags.js +88 -2
- package/dist/mybodyshield/hooks/useMybTags.js.map +1 -0
- package/dist/mybodyshield/hooks/useMybUsers.js +36 -0
- package/dist/mybodyshield/hooks/useMybUsers.js.map +1 -0
- package/dist/mybodyshield/pages/DashboardPage.js +41 -36
- package/dist/mybodyshield/pages/DashboardPage.js.map +1 -1
- package/dist/mybodyshield/pages/_shared/visuals.js +15 -9
- package/dist/mybodyshield/pages/_shared/visuals.js.map +1 -1
- package/dist/mybodyshield/pages/coaching/CoachingPage.js +171 -147
- package/dist/mybodyshield/pages/coaching/CoachingPage.js.map +1 -1
- package/dist/mybodyshield/pages/goals/GoalsPage.js +0 -8
- package/dist/mybodyshield/pages/goals/GoalsPage.js.map +1 -1
- package/dist/mybodyshield/pages/nutrition/NutritionPage.js +352 -278
- package/dist/mybodyshield/pages/nutrition/NutritionPage.js.map +1 -1
- package/dist/mybodyshield/pages/programs/ProgramDetailPage.js +600 -296
- package/dist/mybodyshield/pages/programs/ProgramDetailPage.js.map +1 -1
- package/dist/mybodyshield/pages/progress/ProgressPage.js +88 -51
- package/dist/mybodyshield/pages/progress/ProgressPage.js.map +1 -1
- package/dist/mybodyshield/pages/train/SessionDetailPage.js +146 -126
- package/dist/mybodyshield/pages/train/SessionDetailPage.js.map +1 -1
- package/dist/mybodyshield/pages/train/SessionsPage.js +1 -4
- package/dist/mybodyshield/pages/train/SessionsPage.js.map +1 -1
- package/package.json +2 -2
|
@@ -95,7 +95,13 @@ var S = ({ value: t, color: n = "var(--color-accent-teal)", height: r = 8, class
|
|
|
95
95
|
children: e
|
|
96
96
|
})]
|
|
97
97
|
}, e))
|
|
98
|
-
})
|
|
98
|
+
});
|
|
99
|
+
function D(e, t) {
|
|
100
|
+
return new Proxy(e, { get(e, n) {
|
|
101
|
+
return e[n] ?? e[t];
|
|
102
|
+
} });
|
|
103
|
+
}
|
|
104
|
+
var O = D({
|
|
99
105
|
STRENGTH: {
|
|
100
106
|
icon: i,
|
|
101
107
|
tint: "var(--color-accent-primary)"
|
|
@@ -120,7 +126,7 @@ var S = ({ value: t, color: n = "var(--color-accent-teal)", height: r = 8, class
|
|
|
120
126
|
icon: l,
|
|
121
127
|
tint: "var(--color-status-success-text)"
|
|
122
128
|
}
|
|
123
|
-
},
|
|
129
|
+
}, "STRENGTH"), k = D({
|
|
124
130
|
CHEST: { tint: "var(--color-accent-primary)" },
|
|
125
131
|
BACK: { tint: "var(--color-accent-teal)" },
|
|
126
132
|
LEGS: { tint: "var(--color-status-warning-text)" },
|
|
@@ -128,7 +134,7 @@ var S = ({ value: t, color: n = "var(--color-accent-teal)", height: r = 8, class
|
|
|
128
134
|
ARMS: { tint: "var(--color-accent-primary)" },
|
|
129
135
|
CORE: { tint: "var(--color-status-success-text)" },
|
|
130
136
|
FULL_BODY: { tint: "var(--color-text-secondary)" }
|
|
131
|
-
},
|
|
137
|
+
}, "FULL_BODY"), A = D({
|
|
132
138
|
WEIGHT_LOSS: {
|
|
133
139
|
icon: h,
|
|
134
140
|
tint: "var(--color-accent-teal)"
|
|
@@ -153,7 +159,7 @@ var S = ({ value: t, color: n = "var(--color-accent-teal)", height: r = 8, class
|
|
|
153
159
|
icon: p,
|
|
154
160
|
tint: "var(--color-text-secondary)"
|
|
155
161
|
}
|
|
156
|
-
},
|
|
162
|
+
}, "GENERAL_FITNESS"), j = D({
|
|
157
163
|
WEIGHT: {
|
|
158
164
|
icon: v,
|
|
159
165
|
tint: "var(--color-accent-primary)",
|
|
@@ -194,7 +200,7 @@ var S = ({ value: t, color: n = "var(--color-accent-teal)", height: r = 8, class
|
|
|
194
200
|
tint: "var(--color-accent-teal)",
|
|
195
201
|
unit: "cm"
|
|
196
202
|
}
|
|
197
|
-
},
|
|
203
|
+
}, "WEIGHT"), M = D({
|
|
198
204
|
SLEEP: {
|
|
199
205
|
icon: n,
|
|
200
206
|
tint: "var(--color-accent-primary)",
|
|
@@ -220,14 +226,14 @@ var S = ({ value: t, color: n = "var(--color-accent-teal)", height: r = 8, class
|
|
|
220
226
|
tint: "var(--color-accent-teal)",
|
|
221
227
|
label: "Mood"
|
|
222
228
|
}
|
|
223
|
-
},
|
|
229
|
+
}, "READINESS"), N = ({ icon: t, tint: n = "var(--color-accent-teal)", className: r }) => /* @__PURE__ */ b("span", {
|
|
224
230
|
className: e("flex size-9 shrink-0 items-center justify-center rounded-lg", r),
|
|
225
231
|
style: {
|
|
226
232
|
backgroundColor: `color-mix(in srgb, ${n} 16%, transparent)`,
|
|
227
233
|
color: n
|
|
228
234
|
},
|
|
229
235
|
children: t
|
|
230
|
-
}),
|
|
236
|
+
}), P = ({ delta: t, unit: n = "", goodDirection: r = "up" }) => {
|
|
231
237
|
if (!Number.isFinite(t) || t === 0) return /* @__PURE__ */ x("span", {
|
|
232
238
|
className: "text-xs text-text-tertiary",
|
|
233
239
|
children: ["±0", n]
|
|
@@ -243,13 +249,13 @@ var S = ({ value: t, color: n = "var(--color-accent-teal)", height: r = 8, class
|
|
|
243
249
|
]
|
|
244
250
|
});
|
|
245
251
|
};
|
|
246
|
-
function
|
|
252
|
+
function F(e) {
|
|
247
253
|
let t = e.targetValue - e.baselineValue;
|
|
248
254
|
if (t === 0) return e.currentValue >= e.targetValue ? 100 : 0;
|
|
249
255
|
let n = (e.currentValue - e.baselineValue) / t * 100;
|
|
250
256
|
return Math.max(0, Math.min(100, n));
|
|
251
257
|
}
|
|
252
258
|
//#endregion
|
|
253
|
-
export {
|
|
259
|
+
export { A as GOAL_TYPE_META, N as IconChip, j as METRIC_META, k as MUSCLE_META, T as MacroBar, E as MacroLegend, S as Meter, C as ProgressRing, M as RECOVERY_META, P as TrendPill, O as WORKOUT_TYPE_META, F as computeGoalProgress };
|
|
254
260
|
|
|
255
261
|
//# sourceMappingURL=visuals.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"visuals.js","names":[],"sources":["../../../../src/mybodyshield/pages/_shared/visuals.tsx"],"sourcesContent":["/**\n * Shared fitness-domain visual helpers.\n * @module mybodyshield/pages/_shared\n *\n * Token-driven (no raw colors) SVG/CSS visual primitives + domain icon/tint\n * maps reused across the MyBodyShield pages. Everything reads fe-libs semantic\n * tokens so light/dark themes and custom themes work automatically.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport {\n Dumbbell,\n HeartPulse,\n Timer,\n Activity,\n StretchHorizontal,\n Flower2,\n Moon,\n Weight,\n Ruler,\n Percent,\n Heart,\n TrendingDown,\n TrendingUp,\n Zap,\n Waves,\n Target,\n Sparkles,\n Brain,\n BedDouble,\n Gauge,\n Smile,\n} from 'lucide-react';\nimport { cn } from '../../utils/cn';\nimport type {\n MybBodyMetricType,\n MybGoalType,\n MybMuscleGroup,\n MybRecoveryMetric,\n MybWorkoutType,\n} from '../../types';\n\n// ============================================================================\n// Meter — a horizontal progress bar with a token-driven fill\n// ============================================================================\n\nexport const Meter: FC<{\n /** 0–100 percentage. */\n value: number;\n /** CSS color for the fill (default: accent-teal). */\n color?: string;\n height?: number;\n className?: string;\n}> = ({ value, color = 'var(--color-accent-teal)', height = 8, className }) => {\n const pct = Math.max(0, Math.min(100, value));\n return (\n <div\n className={cn('w-full overflow-hidden rounded-full bg-bg-sunken', className)}\n style={{ height }}\n role=\"progressbar\"\n aria-valuenow={Math.round(pct)}\n aria-valuemin={0}\n aria-valuemax={100}\n >\n <div\n className=\"h-full rounded-full transition-[width] duration-500 ease-out\"\n style={{ width: `${pct}%`, backgroundColor: color }}\n />\n </div>\n );\n};\n\n// ============================================================================\n// ProgressRing — a circular progress indicator (goal progress, readiness)\n// ============================================================================\n\nexport const ProgressRing: FC<{\n value: number;\n size?: number;\n stroke?: number;\n color?: string;\n trackColor?: string;\n children?: ReactNode;\n className?: string;\n}> = ({\n value,\n size = 96,\n stroke = 9,\n color = 'var(--color-accent-teal)',\n trackColor = 'var(--color-bg-sunken)',\n children,\n className,\n}) => {\n const pct = Math.max(0, Math.min(100, value));\n const r = (size - stroke) / 2;\n const c = 2 * Math.PI * r;\n const offset = c - (pct / 100) * c;\n return (\n <div\n className={cn('relative inline-flex items-center justify-center', className)}\n style={{ width: size, height: size }}\n >\n <svg width={size} height={size} className=\"-rotate-90\">\n <circle\n cx={size / 2}\n cy={size / 2}\n r={r}\n fill=\"none\"\n stroke={trackColor}\n strokeWidth={stroke}\n />\n <circle\n cx={size / 2}\n cy={size / 2}\n r={r}\n fill=\"none\"\n stroke={color}\n strokeWidth={stroke}\n strokeLinecap=\"round\"\n strokeDasharray={c}\n strokeDashoffset={offset}\n className=\"transition-[stroke-dashoffset] duration-700 ease-out\"\n />\n </svg>\n {children != null && (\n <div className=\"absolute inset-0 flex flex-col items-center justify-center\">{children}</div>\n )}\n </div>\n );\n};\n\n// ============================================================================\n// MacroBar — a stacked protein/carbs/fat bar (grams → proportion)\n// ============================================================================\n\nexport const MACRO_HUE = {\n protein: 'var(--color-accent-teal)',\n carbs: 'var(--color-status-warning-text)',\n fat: 'var(--color-accent-primary)',\n} as const;\n\nexport const MacroBar: FC<{\n proteinG: number;\n carbsG: number;\n fatG: number;\n height?: number;\n className?: string;\n}> = ({ proteinG, carbsG, fatG, height = 8, className }) => {\n const total = Math.max(1, proteinG + carbsG + fatG);\n const seg = (g: number) => `${(g / total) * 100}%`;\n return (\n <div\n className={cn('flex w-full overflow-hidden rounded-full bg-bg-sunken', className)}\n style={{ height }}\n >\n <div style={{ width: seg(proteinG), backgroundColor: MACRO_HUE.protein }} />\n <div style={{ width: seg(carbsG), backgroundColor: MACRO_HUE.carbs }} />\n <div style={{ width: seg(fatG), backgroundColor: MACRO_HUE.fat }} />\n </div>\n );\n};\n\nexport const MacroLegend: FC<{ className?: string }> = ({ className }) => (\n <div className={cn('flex flex-wrap items-center gap-3 text-xs text-text-tertiary', className)}>\n {(['protein', 'carbs', 'fat'] as const).map((k) => (\n <span key={k} className=\"inline-flex items-center gap-1.5\">\n <span className=\"size-2 rounded-full\" style={{ backgroundColor: MACRO_HUE[k] }} />\n <span className=\"capitalize\">{k}</span>\n </span>\n ))}\n </div>\n);\n\n// ============================================================================\n// Domain icon + tint maps (semantic tokens only)\n// ============================================================================\n\nexport const WORKOUT_TYPE_META: Record<MybWorkoutType, { icon: typeof Dumbbell; tint: string }> = {\n STRENGTH: { icon: Dumbbell, tint: 'var(--color-accent-primary)' },\n CARDIO: { icon: HeartPulse, tint: 'var(--color-status-warning-text)' },\n HIIT: { icon: Zap, tint: 'var(--color-status-error-text)' },\n MOBILITY: { icon: StretchHorizontal, tint: 'var(--color-accent-teal)' },\n YOGA: { icon: Flower2, tint: 'var(--color-accent-teal)' },\n RECOVERY: { icon: Moon, tint: 'var(--color-status-success-text)' },\n};\n\nexport const MUSCLE_META: Record<MybMuscleGroup, { tint: string }> = {\n CHEST: { tint: 'var(--color-accent-primary)' },\n BACK: { tint: 'var(--color-accent-teal)' },\n LEGS: { tint: 'var(--color-status-warning-text)' },\n SHOULDERS: { tint: 'var(--color-status-error-text)' },\n ARMS: { tint: 'var(--color-accent-primary)' },\n CORE: { tint: 'var(--color-status-success-text)' },\n FULL_BODY: { tint: 'var(--color-text-secondary)' },\n};\n\nexport const GOAL_TYPE_META: Record<MybGoalType, { icon: typeof Target; tint: string }> = {\n WEIGHT_LOSS: { icon: TrendingDown, tint: 'var(--color-accent-teal)' },\n MUSCLE_GAIN: { icon: Dumbbell, tint: 'var(--color-accent-primary)' },\n STRENGTH: { icon: Weight, tint: 'var(--color-status-error-text)' },\n ENDURANCE: { icon: Activity, tint: 'var(--color-status-warning-text)' },\n MOBILITY: { icon: StretchHorizontal, tint: 'var(--color-accent-teal)' },\n GENERAL_FITNESS: { icon: Sparkles, tint: 'var(--color-text-secondary)' },\n};\n\nexport const METRIC_META: Record<\n MybBodyMetricType,\n { icon: typeof Weight; tint: string; unit: string }\n> = {\n WEIGHT: { icon: Weight, tint: 'var(--color-accent-primary)', unit: 'kg' },\n BODY_FAT: { icon: Percent, tint: 'var(--color-status-warning-text)', unit: '%' },\n RESTING_HEART_RATE: { icon: Heart, tint: 'var(--color-status-error-text)', unit: 'bpm' },\n WAIST: { icon: Ruler, tint: 'var(--color-accent-teal)', unit: 'cm' },\n CHEST: { icon: Ruler, tint: 'var(--color-accent-teal)', unit: 'cm' },\n HIPS: { icon: Ruler, tint: 'var(--color-accent-teal)', unit: 'cm' },\n ARM: { icon: Ruler, tint: 'var(--color-accent-teal)', unit: 'cm' },\n THIGH: { icon: Ruler, tint: 'var(--color-accent-teal)', unit: 'cm' },\n};\n\nexport const RECOVERY_META: Record<\n MybRecoveryMetric,\n { icon: typeof Gauge; tint: string; label: string }\n> = {\n SLEEP: { icon: BedDouble, tint: 'var(--color-accent-primary)', label: 'Sleep' },\n READINESS: { icon: Gauge, tint: 'var(--color-status-success-text)', label: 'Readiness' },\n SORENESS: { icon: Waves, tint: 'var(--color-status-warning-text)', label: 'Soreness' },\n STRESS: { icon: Brain, tint: 'var(--color-status-error-text)', label: 'Stress' },\n MOOD: { icon: Smile, tint: 'var(--color-accent-teal)', label: 'Mood' },\n};\n\n// ============================================================================\n// Small helpers\n// ============================================================================\n\n/** Circular icon chip with a soft tinted background. */\nexport const IconChip: FC<{ icon: ReactNode; tint?: string; className?: string }> = ({\n icon,\n tint = 'var(--color-accent-teal)',\n className,\n}) => (\n <span\n className={cn('flex size-9 shrink-0 items-center justify-center rounded-lg', className)}\n style={{ backgroundColor: `color-mix(in srgb, ${tint} 16%, transparent)`, color: tint }}\n >\n {icon}\n </span>\n);\n\n/** A small trend delta pill (up/down/flat) with semantic color. */\nexport const TrendPill: FC<{ delta: number; unit?: string; goodDirection?: 'up' | 'down' }> = ({\n delta,\n unit = '',\n goodDirection = 'up',\n}) => {\n if (!Number.isFinite(delta) || delta === 0) {\n return <span className=\"text-xs text-text-tertiary\">±0{unit}</span>;\n }\n const up = delta > 0;\n const good = goodDirection === 'up' ? up : !up;\n const Icon = up ? TrendingUp : TrendingDown;\n return (\n <span\n className={cn(\n 'inline-flex items-center gap-1 text-xs font-medium tabular-nums',\n good ? 'text-status-success-text' : 'text-status-error-text'\n )}\n >\n <Icon className=\"h-3.5 w-3.5\" />\n {up ? '+' : ''}\n {delta.toFixed(1)}\n {unit}\n </span>\n );\n};\n\n/** Compute a goal's completion percentage from baseline → target → current. */\nexport function computeGoalProgress(goal: {\n baselineValue: number;\n targetValue: number;\n currentValue: number;\n}): number {\n const span = goal.targetValue - goal.baselineValue;\n if (span === 0) return goal.currentValue >= goal.targetValue ? 100 : 0;\n const done = ((goal.currentValue - goal.baselineValue) / span) * 100;\n return Math.max(0, Math.min(100, done));\n}\n\nexport { Timer };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"visuals.js","names":[],"sources":["../../../../src/mybodyshield/pages/_shared/visuals.tsx"],"sourcesContent":["/**\n * Shared fitness-domain visual helpers.\n * @module mybodyshield/pages/_shared\n *\n * Token-driven (no raw colors) SVG/CSS visual primitives + domain icon/tint\n * maps reused across the MyBodyShield pages. Everything reads fe-libs semantic\n * tokens so light/dark themes and custom themes work automatically.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport {\n Dumbbell,\n HeartPulse,\n Timer,\n Activity,\n StretchHorizontal,\n Flower2,\n Moon,\n Weight,\n Ruler,\n Percent,\n Heart,\n TrendingDown,\n TrendingUp,\n Zap,\n Waves,\n Target,\n Sparkles,\n Brain,\n BedDouble,\n Gauge,\n Smile,\n} from 'lucide-react';\nimport { cn } from '../../utils/cn';\nimport type {\n MybBodyMetricType,\n MybGoalType,\n MybMuscleGroup,\n MybRecoveryMetric,\n MybWorkoutType,\n} from '../../types';\n\n// ============================================================================\n// Meter — a horizontal progress bar with a token-driven fill\n// ============================================================================\n\nexport const Meter: FC<{\n /** 0–100 percentage. */\n value: number;\n /** CSS color for the fill (default: accent-teal). */\n color?: string;\n height?: number;\n className?: string;\n}> = ({ value, color = 'var(--color-accent-teal)', height = 8, className }) => {\n const pct = Math.max(0, Math.min(100, value));\n return (\n <div\n className={cn('w-full overflow-hidden rounded-full bg-bg-sunken', className)}\n style={{ height }}\n role=\"progressbar\"\n aria-valuenow={Math.round(pct)}\n aria-valuemin={0}\n aria-valuemax={100}\n >\n <div\n className=\"h-full rounded-full transition-[width] duration-500 ease-out\"\n style={{ width: `${pct}%`, backgroundColor: color }}\n />\n </div>\n );\n};\n\n// ============================================================================\n// ProgressRing — a circular progress indicator (goal progress, readiness)\n// ============================================================================\n\nexport const ProgressRing: FC<{\n value: number;\n size?: number;\n stroke?: number;\n color?: string;\n trackColor?: string;\n children?: ReactNode;\n className?: string;\n}> = ({\n value,\n size = 96,\n stroke = 9,\n color = 'var(--color-accent-teal)',\n trackColor = 'var(--color-bg-sunken)',\n children,\n className,\n}) => {\n const pct = Math.max(0, Math.min(100, value));\n const r = (size - stroke) / 2;\n const c = 2 * Math.PI * r;\n const offset = c - (pct / 100) * c;\n return (\n <div\n className={cn('relative inline-flex items-center justify-center', className)}\n style={{ width: size, height: size }}\n >\n <svg width={size} height={size} className=\"-rotate-90\">\n <circle\n cx={size / 2}\n cy={size / 2}\n r={r}\n fill=\"none\"\n stroke={trackColor}\n strokeWidth={stroke}\n />\n <circle\n cx={size / 2}\n cy={size / 2}\n r={r}\n fill=\"none\"\n stroke={color}\n strokeWidth={stroke}\n strokeLinecap=\"round\"\n strokeDasharray={c}\n strokeDashoffset={offset}\n className=\"transition-[stroke-dashoffset] duration-700 ease-out\"\n />\n </svg>\n {children != null && (\n <div className=\"absolute inset-0 flex flex-col items-center justify-center\">{children}</div>\n )}\n </div>\n );\n};\n\n// ============================================================================\n// MacroBar — a stacked protein/carbs/fat bar (grams → proportion)\n// ============================================================================\n\nexport const MACRO_HUE = {\n protein: 'var(--color-accent-teal)',\n carbs: 'var(--color-status-warning-text)',\n fat: 'var(--color-accent-primary)',\n} as const;\n\nexport const MacroBar: FC<{\n proteinG: number;\n carbsG: number;\n fatG: number;\n height?: number;\n className?: string;\n}> = ({ proteinG, carbsG, fatG, height = 8, className }) => {\n const total = Math.max(1, proteinG + carbsG + fatG);\n const seg = (g: number) => `${(g / total) * 100}%`;\n return (\n <div\n className={cn('flex w-full overflow-hidden rounded-full bg-bg-sunken', className)}\n style={{ height }}\n >\n <div style={{ width: seg(proteinG), backgroundColor: MACRO_HUE.protein }} />\n <div style={{ width: seg(carbsG), backgroundColor: MACRO_HUE.carbs }} />\n <div style={{ width: seg(fatG), backgroundColor: MACRO_HUE.fat }} />\n </div>\n );\n};\n\nexport const MacroLegend: FC<{ className?: string }> = ({ className }) => (\n <div className={cn('flex flex-wrap items-center gap-3 text-xs text-text-tertiary', className)}>\n {(['protein', 'carbs', 'fat'] as const).map((k) => (\n <span key={k} className=\"inline-flex items-center gap-1.5\">\n <span className=\"size-2 rounded-full\" style={{ backgroundColor: MACRO_HUE[k] }} />\n <span className=\"capitalize\">{k}</span>\n </span>\n ))}\n </div>\n);\n\n// ============================================================================\n// Domain icon + tint maps (semantic tokens only)\n// ============================================================================\n\n/**\n * Wrap an enum→meta map so an unknown server enum value (svc stores enums as\n * TEXT, so a value outside the client union is plausible) resolves to a safe\n * fallback entry instead of `undefined` — accessing `.icon`/`.tint`/`.label` on\n * `undefined` would otherwise crash the whole page.\n */\nfunction metaWithFallback<K extends string, V>(\n source: Record<K, V>,\n fallback: NoInfer<K>\n): Record<K, V> {\n return new Proxy(source, {\n get(target, prop: string) {\n return (target as Record<string, V>)[prop] ?? target[fallback];\n },\n }) as Record<K, V>;\n}\n\nconst WORKOUT_TYPE_META_SOURCE: Record<MybWorkoutType, { icon: typeof Dumbbell; tint: string }> = {\n STRENGTH: { icon: Dumbbell, tint: 'var(--color-accent-primary)' },\n CARDIO: { icon: HeartPulse, tint: 'var(--color-status-warning-text)' },\n HIIT: { icon: Zap, tint: 'var(--color-status-error-text)' },\n MOBILITY: { icon: StretchHorizontal, tint: 'var(--color-accent-teal)' },\n YOGA: { icon: Flower2, tint: 'var(--color-accent-teal)' },\n RECOVERY: { icon: Moon, tint: 'var(--color-status-success-text)' },\n};\nexport const WORKOUT_TYPE_META = metaWithFallback(WORKOUT_TYPE_META_SOURCE, 'STRENGTH');\n\nconst MUSCLE_META_SOURCE: Record<MybMuscleGroup, { tint: string }> = {\n CHEST: { tint: 'var(--color-accent-primary)' },\n BACK: { tint: 'var(--color-accent-teal)' },\n LEGS: { tint: 'var(--color-status-warning-text)' },\n SHOULDERS: { tint: 'var(--color-status-error-text)' },\n ARMS: { tint: 'var(--color-accent-primary)' },\n CORE: { tint: 'var(--color-status-success-text)' },\n FULL_BODY: { tint: 'var(--color-text-secondary)' },\n};\nexport const MUSCLE_META = metaWithFallback(MUSCLE_META_SOURCE, 'FULL_BODY');\n\nconst GOAL_TYPE_META_SOURCE: Record<MybGoalType, { icon: typeof Target; tint: string }> = {\n WEIGHT_LOSS: { icon: TrendingDown, tint: 'var(--color-accent-teal)' },\n MUSCLE_GAIN: { icon: Dumbbell, tint: 'var(--color-accent-primary)' },\n STRENGTH: { icon: Weight, tint: 'var(--color-status-error-text)' },\n ENDURANCE: { icon: Activity, tint: 'var(--color-status-warning-text)' },\n MOBILITY: { icon: StretchHorizontal, tint: 'var(--color-accent-teal)' },\n GENERAL_FITNESS: { icon: Sparkles, tint: 'var(--color-text-secondary)' },\n};\nexport const GOAL_TYPE_META = metaWithFallback(GOAL_TYPE_META_SOURCE, 'GENERAL_FITNESS');\n\nconst METRIC_META_SOURCE: Record<\n MybBodyMetricType,\n { icon: typeof Weight; tint: string; unit: string }\n> = {\n WEIGHT: { icon: Weight, tint: 'var(--color-accent-primary)', unit: 'kg' },\n BODY_FAT: { icon: Percent, tint: 'var(--color-status-warning-text)', unit: '%' },\n RESTING_HEART_RATE: { icon: Heart, tint: 'var(--color-status-error-text)', unit: 'bpm' },\n WAIST: { icon: Ruler, tint: 'var(--color-accent-teal)', unit: 'cm' },\n CHEST: { icon: Ruler, tint: 'var(--color-accent-teal)', unit: 'cm' },\n HIPS: { icon: Ruler, tint: 'var(--color-accent-teal)', unit: 'cm' },\n ARM: { icon: Ruler, tint: 'var(--color-accent-teal)', unit: 'cm' },\n THIGH: { icon: Ruler, tint: 'var(--color-accent-teal)', unit: 'cm' },\n};\nexport const METRIC_META = metaWithFallback(METRIC_META_SOURCE, 'WEIGHT');\n\nconst RECOVERY_META_SOURCE: Record<\n MybRecoveryMetric,\n { icon: typeof Gauge; tint: string; label: string }\n> = {\n SLEEP: { icon: BedDouble, tint: 'var(--color-accent-primary)', label: 'Sleep' },\n READINESS: { icon: Gauge, tint: 'var(--color-status-success-text)', label: 'Readiness' },\n SORENESS: { icon: Waves, tint: 'var(--color-status-warning-text)', label: 'Soreness' },\n STRESS: { icon: Brain, tint: 'var(--color-status-error-text)', label: 'Stress' },\n MOOD: { icon: Smile, tint: 'var(--color-accent-teal)', label: 'Mood' },\n};\nexport const RECOVERY_META = metaWithFallback(RECOVERY_META_SOURCE, 'READINESS');\n\n// ============================================================================\n// Small helpers\n// ============================================================================\n\n/** Circular icon chip with a soft tinted background. */\nexport const IconChip: FC<{ icon: ReactNode; tint?: string; className?: string }> = ({\n icon,\n tint = 'var(--color-accent-teal)',\n className,\n}) => (\n <span\n className={cn('flex size-9 shrink-0 items-center justify-center rounded-lg', className)}\n style={{ backgroundColor: `color-mix(in srgb, ${tint} 16%, transparent)`, color: tint }}\n >\n {icon}\n </span>\n);\n\n/** A small trend delta pill (up/down/flat) with semantic color. */\nexport const TrendPill: FC<{ delta: number; unit?: string; goodDirection?: 'up' | 'down' }> = ({\n delta,\n unit = '',\n goodDirection = 'up',\n}) => {\n if (!Number.isFinite(delta) || delta === 0) {\n return <span className=\"text-xs text-text-tertiary\">±0{unit}</span>;\n }\n const up = delta > 0;\n const good = goodDirection === 'up' ? up : !up;\n const Icon = up ? TrendingUp : TrendingDown;\n return (\n <span\n className={cn(\n 'inline-flex items-center gap-1 text-xs font-medium tabular-nums',\n good ? 'text-status-success-text' : 'text-status-error-text'\n )}\n >\n <Icon className=\"h-3.5 w-3.5\" />\n {up ? '+' : ''}\n {delta.toFixed(1)}\n {unit}\n </span>\n );\n};\n\n/** Compute a goal's completion percentage from baseline → target → current. */\nexport function computeGoalProgress(goal: {\n baselineValue: number;\n targetValue: number;\n currentValue: number;\n}): number {\n const span = goal.targetValue - goal.baselineValue;\n if (span === 0) return goal.currentValue >= goal.targetValue ? 100 : 0;\n const done = ((goal.currentValue - goal.baselineValue) / span) * 100;\n return Math.max(0, Math.min(100, done));\n}\n\nexport { Timer };\n"],"mappings":"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"}
|