@burdenoff/microfe-atheletebridge 2026.706.1 → 2026.710.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. package/dist/atheletebridge/AthleteBridgeRoot.d.ts +5 -0
  2. package/dist/atheletebridge/AthleteBridgeRoot.d.ts.map +1 -0
  3. package/dist/atheletebridge/AthleteBridgeRoutes.d.ts +4 -0
  4. package/dist/atheletebridge/AthleteBridgeRoutes.d.ts.map +1 -0
  5. package/dist/atheletebridge/AthleteBridgeRoutes.js +135 -57
  6. package/dist/atheletebridge/AthleteBridgeRoutes.js.map +1 -1
  7. package/dist/atheletebridge/components/AthleteSelect.d.ts +26 -0
  8. package/dist/atheletebridge/components/AthleteSelect.d.ts.map +1 -0
  9. package/dist/atheletebridge/components/Crest.d.ts +17 -0
  10. package/dist/atheletebridge/components/Crest.d.ts.map +1 -0
  11. package/dist/atheletebridge/components/CursorPager.d.ts +12 -0
  12. package/dist/atheletebridge/components/CursorPager.d.ts.map +1 -0
  13. package/dist/atheletebridge/components/DrillVideoLink.d.ts +12 -0
  14. package/dist/atheletebridge/components/DrillVideoLink.d.ts.map +1 -0
  15. package/dist/atheletebridge/components/EmptyState.d.ts +14 -0
  16. package/dist/atheletebridge/components/EmptyState.d.ts.map +1 -0
  17. package/dist/atheletebridge/components/FilterSelect.d.ts +23 -0
  18. package/dist/atheletebridge/components/FilterSelect.d.ts.map +1 -0
  19. package/dist/atheletebridge/components/FixtureCard.d.ts +10 -0
  20. package/dist/atheletebridge/components/FixtureCard.d.ts.map +1 -0
  21. package/dist/atheletebridge/components/LoadingState.d.ts +16 -0
  22. package/dist/atheletebridge/components/LoadingState.d.ts.map +1 -0
  23. package/dist/atheletebridge/components/MatchupRow.d.ts +16 -0
  24. package/dist/atheletebridge/components/MatchupRow.d.ts.map +1 -0
  25. package/dist/atheletebridge/components/MatchupRow.js.map +1 -1
  26. package/dist/atheletebridge/components/MetricsCard.d.ts +26 -0
  27. package/dist/atheletebridge/components/MetricsCard.d.ts.map +1 -0
  28. package/dist/atheletebridge/components/MetricsCard.js.map +1 -1
  29. package/dist/atheletebridge/components/PageLayout.d.ts +22 -0
  30. package/dist/atheletebridge/components/PageLayout.d.ts.map +1 -0
  31. package/dist/atheletebridge/components/ProgramCard.d.ts +15 -0
  32. package/dist/atheletebridge/components/ProgramCard.d.ts.map +1 -0
  33. package/dist/atheletebridge/components/RouteAnalytics.d.ts +9 -0
  34. package/dist/atheletebridge/components/RouteAnalytics.d.ts.map +1 -0
  35. package/dist/atheletebridge/components/RouteAnalytics.js +30 -0
  36. package/dist/atheletebridge/components/RouteAnalytics.js.map +1 -0
  37. package/dist/atheletebridge/components/Scoreboard.d.ts +47 -0
  38. package/dist/atheletebridge/components/Scoreboard.d.ts.map +1 -0
  39. package/dist/atheletebridge/components/Scoreboard.js.map +1 -1
  40. package/dist/atheletebridge/components/SessionCard.d.ts +14 -0
  41. package/dist/atheletebridge/components/SessionCard.d.ts.map +1 -0
  42. package/dist/atheletebridge/components/SessionCard.js.map +1 -1
  43. package/dist/atheletebridge/components/SessionStatusTimeline.d.ts +14 -0
  44. package/dist/atheletebridge/components/SessionStatusTimeline.d.ts.map +1 -0
  45. package/dist/atheletebridge/components/SessionStatusTimeline.js.map +1 -1
  46. package/dist/atheletebridge/components/StatusBadge.d.ts +16 -0
  47. package/dist/atheletebridge/components/StatusBadge.d.ts.map +1 -0
  48. package/dist/atheletebridge/components/StatusBadge.js.map +1 -1
  49. package/dist/atheletebridge/components/TeamCard.d.ts +16 -0
  50. package/dist/atheletebridge/components/TeamCard.d.ts.map +1 -0
  51. package/dist/atheletebridge/components/UserAvatar.d.ts +27 -0
  52. package/dist/atheletebridge/components/UserAvatar.d.ts.map +1 -0
  53. package/dist/atheletebridge/components/UserSearchSelect.d.ts +24 -0
  54. package/dist/atheletebridge/components/UserSearchSelect.d.ts.map +1 -0
  55. package/dist/atheletebridge/components/domain.d.ts +18 -0
  56. package/dist/atheletebridge/components/domain.d.ts.map +1 -0
  57. package/dist/atheletebridge/components/form.d.ts +15 -0
  58. package/dist/atheletebridge/components/form.d.ts.map +1 -0
  59. package/dist/atheletebridge/components/index.d.ts +30 -0
  60. package/dist/atheletebridge/components/index.d.ts.map +1 -0
  61. package/dist/atheletebridge/components/viz/AvatarStack.d.ts +13 -0
  62. package/dist/atheletebridge/components/viz/AvatarStack.d.ts.map +1 -0
  63. package/dist/atheletebridge/components/viz/BarChart.d.ts +17 -0
  64. package/dist/atheletebridge/components/viz/BarChart.d.ts.map +1 -0
  65. package/dist/atheletebridge/components/viz/DonutChart.d.ts +20 -0
  66. package/dist/atheletebridge/components/viz/DonutChart.d.ts.map +1 -0
  67. package/dist/atheletebridge/components/viz/LineChart.d.ts +20 -0
  68. package/dist/atheletebridge/components/viz/LineChart.d.ts.map +1 -0
  69. package/dist/atheletebridge/components/viz/ProgressRing.d.ts +20 -0
  70. package/dist/atheletebridge/components/viz/ProgressRing.d.ts.map +1 -0
  71. package/dist/atheletebridge/components/viz/RatingStars.d.ts +28 -0
  72. package/dist/atheletebridge/components/viz/RatingStars.d.ts.map +1 -0
  73. package/dist/atheletebridge/components/viz/Sparkline.d.ts +16 -0
  74. package/dist/atheletebridge/components/viz/Sparkline.d.ts.map +1 -0
  75. package/dist/atheletebridge/components/viz/StatCard.d.ts +22 -0
  76. package/dist/atheletebridge/components/viz/StatCard.d.ts.map +1 -0
  77. package/dist/atheletebridge/components/viz/StepProgress.d.ts +17 -0
  78. package/dist/atheletebridge/components/viz/StepProgress.d.ts.map +1 -0
  79. package/dist/atheletebridge/components/viz/Timeline.d.ts +21 -0
  80. package/dist/atheletebridge/components/viz/Timeline.d.ts.map +1 -0
  81. package/dist/atheletebridge/components/viz/index.d.ts +25 -0
  82. package/dist/atheletebridge/components/viz/index.d.ts.map +1 -0
  83. package/dist/atheletebridge/components/viz/lib/Avatar.d.ts +15 -0
  84. package/dist/atheletebridge/components/viz/lib/Avatar.d.ts.map +1 -0
  85. package/dist/atheletebridge/components/viz/lib/CartesianFrame.d.ts +44 -0
  86. package/dist/atheletebridge/components/viz/lib/CartesianFrame.d.ts.map +1 -0
  87. package/dist/atheletebridge/components/viz/lib/ResponsiveSvg.d.ts +27 -0
  88. package/dist/atheletebridge/components/viz/lib/ResponsiveSvg.d.ts.map +1 -0
  89. package/dist/atheletebridge/components/viz/lib/format.d.ts +10 -0
  90. package/dist/atheletebridge/components/viz/lib/format.d.ts.map +1 -0
  91. package/dist/atheletebridge/components/viz/lib/geometry.d.ts +41 -0
  92. package/dist/atheletebridge/components/viz/lib/geometry.d.ts.map +1 -0
  93. package/dist/atheletebridge/components/viz/lib/hooks.d.ts +18 -0
  94. package/dist/atheletebridge/components/viz/lib/hooks.d.ts.map +1 -0
  95. package/dist/atheletebridge/components/viz/lib/palette.d.ts +31 -0
  96. package/dist/atheletebridge/components/viz/lib/palette.d.ts.map +1 -0
  97. package/dist/atheletebridge/components/viz/lib/types.d.ts +27 -0
  98. package/dist/atheletebridge/components/viz/lib/types.d.ts.map +1 -0
  99. package/dist/atheletebridge/context/AthleteBridgeContext.d.ts +16 -0
  100. package/dist/atheletebridge/context/AthleteBridgeContext.d.ts.map +1 -0
  101. package/dist/atheletebridge/context/index.d.ts +6 -0
  102. package/dist/atheletebridge/context/index.d.ts.map +1 -0
  103. package/dist/atheletebridge/hooks/index.d.ts +3 -0
  104. package/dist/atheletebridge/hooks/index.d.ts.map +1 -0
  105. package/dist/atheletebridge/hooks/useAthleteBridgeAnalytics.d.ts +26 -0
  106. package/dist/atheletebridge/hooks/useAthleteBridgeAnalytics.d.ts.map +1 -0
  107. package/dist/atheletebridge/hooks/useAthleteBridgeApi.d.ts +215 -0
  108. package/dist/atheletebridge/hooks/useAthleteBridgeApi.d.ts.map +1 -0
  109. package/dist/atheletebridge/hooks/useAthleteBridgeApi.js.map +1 -1
  110. package/dist/atheletebridge/hooks/useAthleteBridgePageView.d.ts +16 -0
  111. package/dist/atheletebridge/hooks/useAthleteBridgePageView.d.ts.map +1 -0
  112. package/dist/atheletebridge/index.d.ts +11 -0
  113. package/dist/atheletebridge/index.d.ts.map +1 -0
  114. package/dist/atheletebridge/pages/DashboardPage.d.ts +12 -0
  115. package/dist/atheletebridge/pages/DashboardPage.d.ts.map +1 -0
  116. package/dist/atheletebridge/pages/DashboardPage.js.map +1 -1
  117. package/dist/atheletebridge/pages/StandingsPage.d.ts +10 -0
  118. package/dist/atheletebridge/pages/StandingsPage.d.ts.map +1 -0
  119. package/dist/atheletebridge/pages/analytics/CoachAnalyticsPage.d.ts +18 -0
  120. package/dist/atheletebridge/pages/analytics/CoachAnalyticsPage.d.ts.map +1 -0
  121. package/dist/atheletebridge/pages/athletes/AthleteProfilePage.d.ts +16 -0
  122. package/dist/atheletebridge/pages/athletes/AthleteProfilePage.d.ts.map +1 -0
  123. package/dist/atheletebridge/pages/fixtures/FixtureDetailPage.d.ts +12 -0
  124. package/dist/atheletebridge/pages/fixtures/FixtureDetailPage.d.ts.map +1 -0
  125. package/dist/atheletebridge/pages/fixtures/FixtureFormPage.d.ts +12 -0
  126. package/dist/atheletebridge/pages/fixtures/FixtureFormPage.d.ts.map +1 -0
  127. package/dist/atheletebridge/pages/fixtures/FixtureFormPage.js.map +1 -1
  128. package/dist/atheletebridge/pages/fixtures/FixturesListPage.d.ts +11 -0
  129. package/dist/atheletebridge/pages/fixtures/FixturesListPage.d.ts.map +1 -0
  130. package/dist/atheletebridge/pages/performance/PerformancePage.d.ts +18 -0
  131. package/dist/atheletebridge/pages/performance/PerformancePage.d.ts.map +1 -0
  132. package/dist/atheletebridge/pages/performance/PerformancePage.js.map +1 -1
  133. package/dist/atheletebridge/pages/programs/ProgramDetailPage.d.ts +10 -0
  134. package/dist/atheletebridge/pages/programs/ProgramDetailPage.d.ts.map +1 -0
  135. package/dist/atheletebridge/pages/programs/ProgramFormPage.d.ts +6 -0
  136. package/dist/atheletebridge/pages/programs/ProgramFormPage.d.ts.map +1 -0
  137. package/dist/atheletebridge/pages/programs/ProgramsListPage.d.ts +6 -0
  138. package/dist/atheletebridge/pages/programs/ProgramsListPage.d.ts.map +1 -0
  139. package/dist/atheletebridge/pages/sessions/SessionDetailPage.d.ts +16 -0
  140. package/dist/atheletebridge/pages/sessions/SessionDetailPage.d.ts.map +1 -0
  141. package/dist/atheletebridge/pages/sessions/SessionFormPage.d.ts +11 -0
  142. package/dist/atheletebridge/pages/sessions/SessionFormPage.d.ts.map +1 -0
  143. package/dist/atheletebridge/pages/sessions/SessionsListPage.d.ts +6 -0
  144. package/dist/atheletebridge/pages/sessions/SessionsListPage.d.ts.map +1 -0
  145. package/dist/atheletebridge/pages/teams/TeamDetailPage.d.ts +13 -0
  146. package/dist/atheletebridge/pages/teams/TeamDetailPage.d.ts.map +1 -0
  147. package/dist/atheletebridge/pages/teams/TeamFormPage.d.ts +6 -0
  148. package/dist/atheletebridge/pages/teams/TeamFormPage.d.ts.map +1 -0
  149. package/dist/atheletebridge/pages/teams/TeamsListPage.d.ts +6 -0
  150. package/dist/atheletebridge/pages/teams/TeamsListPage.d.ts.map +1 -0
  151. package/dist/atheletebridge/pages/tournaments/TournamentBracketPage.d.ts +18 -0
  152. package/dist/atheletebridge/pages/tournaments/TournamentBracketPage.d.ts.map +1 -0
  153. package/dist/atheletebridge/store/atheletebridgeStore.d.ts +50 -0
  154. package/dist/atheletebridge/store/atheletebridgeStore.d.ts.map +1 -0
  155. package/dist/atheletebridge/store/index.d.ts +6 -0
  156. package/dist/atheletebridge/store/index.d.ts.map +1 -0
  157. package/dist/atheletebridge/types/assistant.d.ts +62 -0
  158. package/dist/atheletebridge/types/assistant.d.ts.map +1 -0
  159. package/dist/atheletebridge/types/index.d.ts +411 -0
  160. package/dist/atheletebridge/types/index.d.ts.map +1 -0
  161. package/dist/atheletebridge/utils/cn.d.ts +4 -0
  162. package/dist/atheletebridge/utils/cn.d.ts.map +1 -0
  163. package/dist/atheletebridge/utils/datetime.d.ts +16 -0
  164. package/dist/atheletebridge/utils/datetime.d.ts.map +1 -0
  165. package/dist/atheletebridge/utils/formatters.d.ts +30 -0
  166. package/dist/atheletebridge/utils/formatters.d.ts.map +1 -0
  167. package/dist/atheletebridge/utils/identity.d.ts +24 -0
  168. package/dist/atheletebridge/utils/identity.d.ts.map +1 -0
  169. package/dist/atheletebridge/utils/index.d.ts +12 -0
  170. package/dist/atheletebridge/utils/index.d.ts.map +1 -0
  171. package/dist/atheletebridge/utils/navigation.d.ts +20 -0
  172. package/dist/atheletebridge/utils/navigation.d.ts.map +1 -0
  173. package/dist/atheletebridge/utils/pageContext.d.ts +25 -0
  174. package/dist/atheletebridge/utils/pageContext.d.ts.map +1 -0
  175. package/dist/atheletebridge/utils/pageContext.js +48 -0
  176. package/dist/atheletebridge/utils/pageContext.js.map +1 -0
  177. package/dist/atheletebridge/utils/timeAgo.d.ts +16 -0
  178. package/dist/atheletebridge/utils/timeAgo.d.ts.map +1 -0
  179. package/dist/atheletebridge/utils/url.d.ts +22 -0
  180. package/dist/atheletebridge/utils/url.d.ts.map +1 -0
  181. package/dist/generated/global-operations.d.ts +2 -0
  182. package/dist/generated/global-operations.d.ts.map +1 -0
  183. package/dist/generated/global-types.d.ts +23527 -0
  184. package/dist/generated/global-types.d.ts.map +1 -0
  185. package/dist/generated/wspace-operations.d.ts +208 -0
  186. package/dist/generated/wspace-operations.d.ts.map +1 -0
  187. package/dist/generated/wspace-operations.js +59 -0
  188. package/dist/generated/wspace-operations.js.map +1 -0
  189. package/dist/generated/wspace-types.d.ts +57851 -0
  190. package/dist/generated/wspace-types.d.ts.map +1 -0
  191. package/dist/index.d.ts +7 -0
  192. package/dist/index.d.ts.map +1 -0
  193. package/dist/index.js +2 -1
  194. package/dist/services/assistantApi.d.ts +70 -0
  195. package/dist/services/assistantApi.d.ts.map +1 -0
  196. package/dist/services/assistantApi.js +202 -0
  197. package/dist/services/assistantApi.js.map +1 -0
  198. package/dist/services/createSandboxAssistantTransport.d.ts +23 -0
  199. package/dist/services/createSandboxAssistantTransport.d.ts.map +1 -0
  200. package/dist/services/createSandboxAssistantTransport.js +120 -0
  201. package/dist/services/createSandboxAssistantTransport.js.map +1 -0
  202. package/package.json +5 -1
@@ -1 +1 @@
1
- {"version":3,"file":"MetricsCard.js","names":[],"sources":["../../../src/atheletebridge/components/MetricsCard.tsx"],"sourcesContent":["/**\n * Metrics Card Component\n * @module atheletebridge/components\n *\n * Boff UI 2.0: KPI tiles use the glassmorphic `GlassCard` \"metric\" treatment\n * (accent wash + seam border + soft pop-lift). The hero metric per page can\n * opt into the brighter `glass` treatment with an accent glow via `featured`.\n *\n * The original API (`icon`, `value`, `label`, `featured`, `className`) is\n * unchanged. Optional props enrich the tile toward the mock's KPI style: a teal\n * `tone`, a signed `delta` pill, and a footer `sparkline` trend — all opt-in, so\n * existing call sites render exactly as before. Numerals are tabular.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { ArrowDownRight, ArrowUpRight } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { Sparkline } from './viz';\nimport { cn } from '../utils/cn';\n\ntype MetricTone = 'default' | 'accent' | 'success';\n\ninterface MetricsCardProps {\n icon: ReactNode;\n value: string | number;\n label: string;\n /** Render as the single featured hero metric (glass treatment + glow). */\n featured?: boolean;\n /** Value color: `default` (primary), `accent` (teal), or `success` (green). */\n tone?: MetricTone;\n /** Signed change; positive is good unless `invertDelta`. Renders a pill. */\n delta?: number;\n /** Unit appended to the delta (default \"%\"). */\n deltaSuffix?: string;\n /** Context line beside the delta, e.g. \"vs last month\". */\n deltaLabel?: string;\n /** When true (e.g. injuries), a negative delta is the good outcome. */\n invertDelta?: boolean;\n /** Optional trend rendered as a footer sparkline. */\n sparkline?: number[];\n className?: string;\n}\n\nconst TONE_CLASS: Record<MetricTone, string> = {\n default: 'text-text-primary',\n accent: 'text-[var(--color-accent-teal)]',\n success: 'text-status-success-text',\n};\n\nexport const MetricsCard: FC<MetricsCardProps> = ({\n icon,\n value,\n label,\n featured = false,\n tone = 'default',\n delta,\n deltaSuffix = '%',\n deltaLabel,\n invertDelta = false,\n sparkline,\n className,\n}) => {\n const hasDelta = typeof delta === 'number';\n const isNeutral = (delta ?? 0) === 0;\n const positiveIsGood = invertDelta ? (delta ?? 0) < 0 : (delta ?? 0) > 0;\n const rising = (delta ?? 0) > 0;\n const deltaTone = isNeutral\n ? 'text-text-muted'\n : positiveIsGood\n ? 'text-status-success-text'\n : 'text-status-error-text';\n\n return (\n <GlassCard\n treatment={featured ? 'glass' : 'metric'}\n glow={featured}\n className={cn('p-6', className)}\n >\n <div className=\"relative text-text-secondary\">{icon}</div>\n <div className=\"relative mt-3\">\n <p className={cn('text-2xl font-bold tabular-nums', TONE_CLASS[tone])}>{value}</p>\n <p className=\"mt-1 text-sm text-text-secondary\">{label}</p>\n </div>\n\n {hasDelta ? (\n <div className=\"relative mt-2 flex items-center gap-1.5 text-sm\">\n <span className={cn('inline-flex items-center gap-0.5 font-medium tabular-nums', deltaTone)}>\n {isNeutral ? null : rising ? (\n <ArrowUpRight aria-hidden=\"true\" className=\"h-4 w-4\" />\n ) : (\n <ArrowDownRight aria-hidden=\"true\" className=\"h-4 w-4\" />\n )}\n {rising ? '+' : ''}\n {delta}\n {deltaSuffix}\n </span>\n {deltaLabel ? <span className=\"text-text-muted\">{deltaLabel}</span> : null}\n </div>\n ) : null}\n\n {sparkline && sparkline.length > 1 ? (\n <div className=\"relative mt-3\">\n <Sparkline data={sparkline} variant=\"area\" label={`${label} trend`} height={32} />\n </div>\n ) : null}\n </GlassCard>\n );\n};\n"],"mappings":";;;;;;;AA2CA,IAAM,IAAyC;CAC7C,SAAS;CACT,QAAQ;CACR,SAAS;CACV,EAEY,KAAqC,EAChD,SACA,UACA,UACA,cAAW,IACX,UAAO,WACP,UACA,iBAAc,KACd,eACA,iBAAc,IACd,cACA,mBACI;CACJ,IAAM,IAAW,OAAO,KAAU,UAC5B,KAAa,KAAS,OAAO,GAC7B,IAAiB,KAAe,KAAS,KAAK,KAAK,KAAS,KAAK,GACjE,KAAU,KAAS,KAAK,GACxB,IAAY,IACd,oBACA,IACE,6BACA;AAEN,QACE,kBAAC,GAAD;EACE,WAAW,IAAW,UAAU;EAChC,MAAM;EACN,WAAW,EAAG,OAAO,EAAU;YAHjC;GAKE,kBAAC,OAAD;IAAK,WAAU;cAAgC;IAAW,CAAA;GAC1D,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,KAAD;KAAG,WAAW,EAAG,mCAAmC,EAAW,GAAM;eAAG;KAAU,CAAA,EAClF,kBAAC,KAAD;KAAG,WAAU;eAAoC;KAAU,CAAA,CACvD;;GAEL,IACC,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,QAAD;KAAM,WAAW,EAAG,6DAA6D,EAAU;eAA3F;MACG,IAAY,OACX,EADkB,IACjB,IAEA,GAFD;OAAc,eAAY;OAAO,WAAU;OAAY,CAEE;MAE1D,IAAS,MAAM;MACf;MACA;MACI;QACN,IAAa,kBAAC,QAAD;KAAM,WAAU;eAAmB;KAAkB,CAAA,GAAG,KAClE;QACJ;GAEH,KAAa,EAAU,SAAS,IAC/B,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD;KAAW,MAAM;KAAW,SAAQ;KAAO,OAAO,GAAG,EAAM;KAAS,QAAQ;KAAM,CAAA;IAC9E,CAAA,GACJ;GACM"}
1
+ {"version":3,"file":"MetricsCard.js","names":[],"sources":["../../../src/atheletebridge/components/MetricsCard.tsx"],"sourcesContent":["/**\n * Metrics Card Component\n * @module atheletebridge/components\n *\n * Boff UI 2.0: KPI tiles use the glassmorphic `GlassCard` \"metric\" treatment\n * (accent wash + seam border + soft pop-lift). The hero metric per page can\n * opt into the brighter `glass` treatment with an accent glow via `featured`.\n *\n * The original API (`icon`, `value`, `label`, `featured`, `className`) is\n * unchanged. Optional props enrich the tile toward the mock's KPI style: a teal\n * `tone`, a signed `delta` pill, and a footer `sparkline` trend — all opt-in, so\n * existing call sites render exactly as before. Numerals are tabular.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { ArrowDownRight, ArrowUpRight } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { Sparkline } from './viz';\nimport { cn } from '../utils/cn';\n\ntype MetricTone = 'default' | 'accent' | 'success';\n\ninterface MetricsCardProps {\n icon: ReactNode;\n value: string | number;\n label: string;\n /** Render as the single featured hero metric (glass treatment + glow). */\n featured?: boolean;\n /** Value color: `default` (primary), `accent` (teal), or `success` (green). */\n tone?: MetricTone;\n /** Signed change; positive is good unless `invertDelta`. Renders a pill. */\n delta?: number;\n /** Unit appended to the delta (default \"%\"). */\n deltaSuffix?: string;\n /** Context line beside the delta, e.g. \"vs last month\". */\n deltaLabel?: string;\n /** When true (e.g. injuries), a negative delta is the good outcome. */\n invertDelta?: boolean;\n /** Optional trend rendered as a footer sparkline. */\n sparkline?: number[];\n className?: string;\n}\n\nconst TONE_CLASS: Record<MetricTone, string> = {\n default: 'text-text-primary',\n accent: 'text-[var(--color-accent-teal)]',\n success: 'text-status-success-text',\n};\n\nexport const MetricsCard: FC<MetricsCardProps> = ({\n icon,\n value,\n label,\n featured = false,\n tone = 'default',\n delta,\n deltaSuffix = '%',\n deltaLabel,\n invertDelta = false,\n sparkline,\n className,\n}) => {\n const hasDelta = typeof delta === 'number';\n const isNeutral = (delta ?? 0) === 0;\n const positiveIsGood = invertDelta ? (delta ?? 0) < 0 : (delta ?? 0) > 0;\n const rising = (delta ?? 0) > 0;\n const deltaTone = isNeutral\n ? 'text-text-muted'\n : positiveIsGood\n ? 'text-status-success-text'\n : 'text-status-error-text';\n\n return (\n <GlassCard\n treatment={featured ? 'glass' : 'metric'}\n glow={featured}\n className={cn('p-6', className)}\n >\n <div className=\"relative text-text-secondary\">{icon}</div>\n <div className=\"relative mt-3\">\n <p className={cn('text-2xl font-bold tabular-nums', TONE_CLASS[tone])}>{value}</p>\n <p className=\"mt-1 text-sm text-text-secondary\">{label}</p>\n </div>\n\n {hasDelta ? (\n <div className=\"relative mt-2 flex items-center gap-1.5 text-sm\">\n <span\n className={cn('inline-flex items-center gap-0.5 font-medium tabular-nums', deltaTone)}\n >\n {isNeutral ? null : rising ? (\n <ArrowUpRight aria-hidden=\"true\" className=\"h-4 w-4\" />\n ) : (\n <ArrowDownRight aria-hidden=\"true\" className=\"h-4 w-4\" />\n )}\n {rising ? '+' : ''}\n {delta}\n {deltaSuffix}\n </span>\n {deltaLabel ? <span className=\"text-text-muted\">{deltaLabel}</span> : null}\n </div>\n ) : null}\n\n {sparkline && sparkline.length > 1 ? (\n <div className=\"relative mt-3\">\n <Sparkline data={sparkline} variant=\"area\" label={`${label} trend`} height={32} />\n </div>\n ) : null}\n </GlassCard>\n );\n};\n"],"mappings":";;;;;;;AA2CA,IAAM,IAAyC;CAC7C,SAAS;CACT,QAAQ;CACR,SAAS;CACV,EAEY,KAAqC,EAChD,SACA,UACA,UACA,cAAW,IACX,UAAO,WACP,UACA,iBAAc,KACd,eACA,iBAAc,IACd,cACA,mBACI;CACJ,IAAM,IAAW,OAAO,KAAU,UAC5B,KAAa,KAAS,OAAO,GAC7B,IAAiB,KAAe,KAAS,KAAK,KAAK,KAAS,KAAK,GACjE,KAAU,KAAS,KAAK,GACxB,IAAY,IACd,oBACA,IACE,6BACA;AAEN,QACE,kBAAC,GAAD;EACE,WAAW,IAAW,UAAU;EAChC,MAAM;EACN,WAAW,EAAG,OAAO,EAAU;YAHjC;GAKE,kBAAC,OAAD;IAAK,WAAU;cAAgC;IAAW,CAAA;GAC1D,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,KAAD;KAAG,WAAW,EAAG,mCAAmC,EAAW,GAAM;eAAG;KAAU,CAAA,EAClF,kBAAC,KAAD;KAAG,WAAU;eAAoC;KAAU,CAAA,CACvD;;GAEL,IACC,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,QAAD;KACE,WAAW,EAAG,6DAA6D,EAAU;eADvF;MAGG,IAAY,OACX,EADkB,IACjB,IAEA,GAFD;OAAc,eAAY;OAAO,WAAU;OAAY,CAEE;MAE1D,IAAS,MAAM;MACf;MACA;MACI;QACN,IAAa,kBAAC,QAAD;KAAM,WAAU;eAAmB;KAAkB,CAAA,GAAG,KAClE;QACJ;GAEH,KAAa,EAAU,SAAS,IAC/B,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD;KAAW,MAAM;KAAW,SAAQ;KAAO,OAAO,GAAG,EAAM;KAAS,QAAQ;KAAM,CAAA;IAC9E,CAAA,GACJ;GACM"}
@@ -0,0 +1,22 @@
1
+ import { FC, ReactNode } from 'react';
2
+
3
+ interface PageLayoutProps {
4
+ title: ReactNode;
5
+ description?: string;
6
+ actions?: ReactNode;
7
+ children: ReactNode;
8
+ className?: string;
9
+ /**
10
+ * Render the living aurora backdrop behind the header. Use on exactly ONE
11
+ * primary page per MFE (the root dashboard).
12
+ */
13
+ hero?: boolean;
14
+ /**
15
+ * When `title` is a string, wrap it in a subtle brand gradient (the ONE
16
+ * hero heading per page). Ignored when `title` is a node.
17
+ */
18
+ gradientTitle?: boolean;
19
+ }
20
+ export declare const PageLayout: FC<PageLayoutProps>;
21
+ export {};
22
+ //# sourceMappingURL=PageLayout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PageLayout.d.ts","sourceRoot":"","sources":["../../../src/atheletebridge/components/PageLayout.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAI3C,UAAU,eAAe;IACvB,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,eAAO,MAAM,UAAU,EAAE,EAAE,CAAC,eAAe,CAmC1C,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { FC } from 'react';
2
+ import { AthProgram } from '../types';
3
+
4
+ interface ProgramCardProps {
5
+ program: AthProgram;
6
+ onClick?: () => void;
7
+ /**
8
+ * Drill count for the footer chip. Falls back to `program.drills?.length`
9
+ * when the query selected drills; omit the chip if neither is available.
10
+ */
11
+ drillCount?: number;
12
+ }
13
+ export declare const ProgramCard: FC<ProgramCardProps>;
14
+ export {};
15
+ //# sourceMappingURL=ProgramCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProgramCard.d.ts","sourceRoot":"","sources":["../../../src/atheletebridge/components/ProgramCard.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAMhC,OAAO,KAAK,EAAE,UAAU,EAAmB,MAAM,UAAU,CAAC;AAE5D,UAAU,gBAAgB;IACxB,OAAO,EAAE,UAAU,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AASD,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CA6D5C,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * RouteAnalytics
3
+ *
4
+ * Listens to route changes inside the AthleteBridge microfrontend and emits
5
+ * `atheletebridge.page.viewed` events to the shared event bus. The host shell
6
+ * forwards these to OtelBrowserSink / BackendAuditSink / RybbitSink.
7
+ */
8
+ export declare function RouteAnalytics(): null;
9
+ //# sourceMappingURL=RouteAnalytics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RouteAnalytics.d.ts","sourceRoot":"","sources":["../../../src/atheletebridge/components/RouteAnalytics.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAeH,wBAAgB,cAAc,SAmB7B"}
@@ -0,0 +1,30 @@
1
+ import { useEffect as e, useRef as t } from "react";
2
+ import { useLocation as n } from "react-router-dom";
3
+ import { useEventBus as r } from "@burdenoff/fe-libs/shared/events";
4
+ //#region src/atheletebridge/components/RouteAnalytics.tsx
5
+ function i(e) {
6
+ let t = e.split("/").filter(Boolean), n = t.findIndex((e) => e === "atheletebridge"), r = n >= 0 ? t.slice(n + 1) : t;
7
+ return r.length === 0 ? "dashboard" : r.join("/");
8
+ }
9
+ function a() {
10
+ let a = n(), o = r(), s = t(null);
11
+ return e(() => {
12
+ let e = `${a.pathname}${a.search}`;
13
+ if (s.current === e) return;
14
+ s.current = e;
15
+ let t = i(a.pathname);
16
+ o.emitCustom("atheletebridge.page.viewed", {
17
+ page: t,
18
+ route: a.pathname,
19
+ product: "atheletebridge"
20
+ });
21
+ }, [
22
+ o,
23
+ a.pathname,
24
+ a.search
25
+ ]), null;
26
+ }
27
+ //#endregion
28
+ export { a as RouteAnalytics };
29
+
30
+ //# sourceMappingURL=RouteAnalytics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RouteAnalytics.js","names":[],"sources":["../../../src/atheletebridge/components/RouteAnalytics.tsx"],"sourcesContent":["/**\n * RouteAnalytics\n *\n * Listens to route changes inside the AthleteBridge microfrontend and emits\n * `atheletebridge.page.viewed` events to the shared event bus. The host shell\n * forwards these to OtelBrowserSink / BackendAuditSink / RybbitSink.\n */\n\nimport { useEffect, useRef } from 'react';\nimport { useLocation } from 'react-router-dom';\nimport { useEventBus } from '@burdenoff/fe-libs/shared/events';\n\nfunction resolvePageName(pathname: string): string {\n const segments = pathname.split('/').filter(Boolean);\n // When mounted under /atheletebridge, the first segment is the product slug.\n const productIndex = segments.findIndex((s) => s === 'atheletebridge');\n const relevant = productIndex >= 0 ? segments.slice(productIndex + 1) : segments;\n if (relevant.length === 0) return 'dashboard';\n return relevant.join('/');\n}\n\nexport function RouteAnalytics() {\n const location = useLocation();\n const bus = useEventBus();\n const lastEmittedRef = useRef<string | null>(null);\n\n useEffect(() => {\n const route = `${location.pathname}${location.search}`;\n if (lastEmittedRef.current === route) return;\n lastEmittedRef.current = route;\n\n const page = resolvePageName(location.pathname);\n bus.emitCustom('atheletebridge.page.viewed', {\n page,\n route: location.pathname,\n product: 'atheletebridge',\n });\n }, [bus, location.pathname, location.search]);\n\n return null;\n}\n"],"mappings":";;;;AAYA,SAAS,EAAgB,GAA0B;CACjD,IAAM,IAAW,EAAS,MAAM,IAAI,CAAC,OAAO,QAAQ,EAE9C,IAAe,EAAS,WAAW,MAAM,MAAM,iBAAiB,EAChE,IAAW,KAAgB,IAAI,EAAS,MAAM,IAAe,EAAE,GAAG;AAExE,QADI,EAAS,WAAW,IAAU,cAC3B,EAAS,KAAK,IAAI;;AAG3B,SAAgB,IAAiB;CAC/B,IAAM,IAAW,GAAa,EACxB,IAAM,GAAa,EACnB,IAAiB,EAAsB,KAAK;AAelD,QAbA,QAAgB;EACd,IAAM,IAAQ,GAAG,EAAS,WAAW,EAAS;AAC9C,MAAI,EAAe,YAAY,EAAO;AACtC,IAAe,UAAU;EAEzB,IAAM,IAAO,EAAgB,EAAS,SAAS;AAC/C,IAAI,WAAW,8BAA8B;GAC3C;GACA,OAAO,EAAS;GAChB,SAAS;GACV,CAAC;IACD;EAAC;EAAK,EAAS;EAAU,EAAS;EAAO,CAAC,EAEtC"}
@@ -0,0 +1,47 @@
1
+ import { FC, ReactNode } from 'react';
2
+ import { AthFixture, AthSport } from '../types';
3
+
4
+ export interface Matchup {
5
+ homeName: string;
6
+ awayName: string;
7
+ homeSport?: AthSport;
8
+ awaySport?: AthSport;
9
+ homeScore: number | null;
10
+ awayScore: number | null;
11
+ hasScore: boolean;
12
+ homeWon: boolean;
13
+ awayWon: boolean;
14
+ }
15
+ /** Derive the display matchup (names, scores, winner) from a fixture. */
16
+ export declare function resolveMatchup(fixture: AthFixture): Matchup;
17
+ export interface MatchupSideProps {
18
+ name: string;
19
+ sport?: AthSport;
20
+ align?: 'start' | 'end';
21
+ /** Winner emphasis — brightens the name. */
22
+ won?: boolean;
23
+ /** Loser de-emphasis when the fixture has a score. */
24
+ dimmed?: boolean;
25
+ crestSize?: number;
26
+ /** Stack crest above name (hero/card) instead of inline (row). */
27
+ stacked?: boolean;
28
+ className?: string;
29
+ }
30
+ export declare const MatchupSide: FC<MatchupSideProps>;
31
+ export interface ScoreCenterProps {
32
+ matchup: Matchup;
33
+ time?: ReactNode;
34
+ size?: 'sm' | 'md' | 'lg';
35
+ className?: string;
36
+ }
37
+ export declare const ScoreCenter: FC<ScoreCenterProps>;
38
+ export interface ScoreboardProps {
39
+ fixture: AthFixture;
40
+ onClick?: () => void;
41
+ /** `card` = fixtures-list tile; `hero` = large fixture-detail header. */
42
+ variant?: 'card' | 'hero';
43
+ className?: string;
44
+ }
45
+ /** Full crest-vs-crest match card (list tile or detail hero). */
46
+ export declare const Scoreboard: FC<ScoreboardProps>;
47
+ //# sourceMappingURL=Scoreboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Scoreboard.d.ts","sourceRoot":"","sources":["../../../src/atheletebridge/components/Scoreboard.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAQ3C,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAIrD,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,QAAQ,CAAC;IACrB,SAAS,CAAC,EAAE,QAAQ,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,yEAAyE;AACzE,wBAAgB,cAAc,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAmB3D;AAID,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC;IACxB,4CAA4C;IAC5C,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,sDAAsD;IACtD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CAgC5C,CAAC;AAIF,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAQD,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CA8B5C,CAAC;AAyBF,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,UAAU,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,yEAAyE;IACzE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,iEAAiE;AACjE,eAAO,MAAM,UAAU,EAAE,EAAE,CAAC,eAAe,CA6F1C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Scoreboard.js","names":[],"sources":["../../../src/atheletebridge/components/Scoreboard.tsx"],"sourcesContent":["/**\n * Scoreboard\n * @module atheletebridge/components\n *\n * Crest-vs-crest fixture presentation. `Scoreboard` renders the full match card\n * (competition strip → crest / score / crest → venue) used by the fixtures list\n * and fixture detail; the compact single-line `MatchupRow` (separate file)\n * reuses the same building blocks for the dashboard + team-detail feeds.\n *\n * All colors are semantic tokens. Winner side is tinted with\n * status-success-text, loser muted — driven purely by the real score.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { CalendarClock, MapPin, Trophy } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { StatusBadge } from './StatusBadge';\nimport { Crest } from './Crest';\nimport { SPORT_ICONS, FIXTURE_TYPE_LABELS } from './domain';\nimport { formatDate } from '../utils/formatters';\nimport { cn } from '../utils/cn';\nimport type { AthFixture, AthSport } from '../types';\n\n// ── Shared matchup model ─────────────────────────────────────────────────────\n\nexport interface Matchup {\n homeName: string;\n awayName: string;\n homeSport?: AthSport;\n awaySport?: AthSport;\n homeScore: number | null;\n awayScore: number | null;\n hasScore: boolean;\n homeWon: boolean;\n awayWon: boolean;\n}\n\n/** Derive the display matchup (names, scores, winner) from a fixture. */\nexport function resolveMatchup(fixture: AthFixture): Matchup {\n const homeName = fixture.homeTeam?.name ?? 'Home';\n const awayName = fixture.awayTeam?.name ?? (fixture.awayTeamId ? 'Away' : 'TBD');\n const hasScore = fixture.homeScore !== null && fixture.awayScore !== null;\n const homeScore = fixture.homeScore;\n const awayScore = fixture.awayScore;\n const homeWon = hasScore && (homeScore ?? 0) > (awayScore ?? 0);\n const awayWon = hasScore && (awayScore ?? 0) > (homeScore ?? 0);\n return {\n homeName,\n awayName,\n homeSport: fixture.homeTeam?.sport,\n awaySport: fixture.awayTeam?.sport,\n homeScore,\n awayScore,\n hasScore,\n homeWon,\n awayWon,\n };\n}\n\n// ── One team flank (crest + name) ────────────────────────────────────────────\n\nexport interface MatchupSideProps {\n name: string;\n sport?: AthSport;\n align?: 'start' | 'end';\n /** Winner emphasis — brightens the name. */\n won?: boolean;\n /** Loser de-emphasis when the fixture has a score. */\n dimmed?: boolean;\n crestSize?: number;\n /** Stack crest above name (hero/card) instead of inline (row). */\n stacked?: boolean;\n className?: string;\n}\n\nexport const MatchupSide: FC<MatchupSideProps> = ({\n name,\n sport,\n align = 'start',\n won = false,\n dimmed = false,\n crestSize = 40,\n stacked = false,\n className,\n}) => (\n <div\n className={cn(\n 'flex min-w-0 items-center gap-3',\n stacked ? 'flex-col text-center' : align === 'end' ? 'flex-row-reverse text-right' : 'text-left',\n className\n )}\n >\n <Crest name={name} sport={sport} size={crestSize} />\n <span\n className={cn(\n 'min-w-0 truncate font-semibold',\n stacked ? 'max-w-[10rem] text-sm' : 'text-sm',\n won ? 'text-status-success-text' : dimmed ? 'text-text-muted' : 'text-text-primary'\n )}\n >\n {name}\n </span>\n </div>\n);\n\n// ── Centerpiece (score or vs + kickoff) ──────────────────────────────────────\n\nexport interface ScoreCenterProps {\n matchup: Matchup;\n time?: ReactNode;\n size?: 'sm' | 'md' | 'lg';\n className?: string;\n}\n\nconst SCORE_SIZE = {\n sm: 'text-lg',\n md: 'text-2xl',\n lg: 'text-4xl sm:text-5xl',\n} as const;\n\nexport const ScoreCenter: FC<ScoreCenterProps> = ({ matchup, time, size = 'md', className }) => {\n if (!matchup.hasScore) {\n return (\n <div className={cn('flex flex-col items-center gap-0.5', className)}>\n <span className=\"rounded-lg bg-bg-sunken px-3 py-1 text-xs font-bold uppercase tracking-wide text-text-secondary\">\n vs\n </span>\n {time ? <span className=\"text-xs text-text-secondary\">{time}</span> : null}\n </div>\n );\n }\n return (\n <div className={cn('flex flex-col items-center gap-0.5', className)}>\n <span\n className={cn(\n 'flex items-center gap-2 font-bold leading-none tabular-nums',\n SCORE_SIZE[size]\n )}\n >\n <span className={matchup.homeWon ? 'text-status-success-text' : 'text-text-primary'}>\n {matchup.homeScore}\n </span>\n <span className=\"text-text-muted\">–</span>\n <span className={matchup.awayWon ? 'text-status-success-text' : 'text-text-primary'}>\n {matchup.awayScore}\n </span>\n </span>\n {time ? <span className=\"text-xs text-text-secondary\">{time}</span> : null}\n </div>\n );\n};\n\n// ── Competition eyebrow ──────────────────────────────────────────────────────\n\nconst CompetitionStrip: FC<{ fixture: AthFixture; center?: boolean }> = ({\n fixture,\n center = false,\n}) => {\n const SportIcon = fixture.homeTeam?.sport ? SPORT_ICONS[fixture.homeTeam.sport] : Trophy;\n const parts = [fixture.competition, fixture.round].filter(Boolean).join(' · ');\n return (\n <span\n className={cn(\n 'inline-flex items-center gap-1.5 text-xs font-medium text-text-secondary',\n center && 'justify-center'\n )}\n >\n <SportIcon className=\"h-3.5 w-3.5 shrink-0 text-text-muted\" aria-hidden=\"true\" />\n <span className=\"truncate\">{parts || FIXTURE_TYPE_LABELS[fixture.type]}</span>\n </span>\n );\n};\n\n// ── Full match card / hero ───────────────────────────────────────────────────\n\nexport interface ScoreboardProps {\n fixture: AthFixture;\n onClick?: () => void;\n /** `card` = fixtures-list tile; `hero` = large fixture-detail header. */\n variant?: 'card' | 'hero';\n className?: string;\n}\n\n/** Full crest-vs-crest match card (list tile or detail hero). */\nexport const Scoreboard: FC<ScoreboardProps> = ({\n fixture,\n onClick,\n variant = 'card',\n className,\n}) => {\n const matchup = resolveMatchup(fixture);\n const isHero = variant === 'hero';\n const timeLabel = matchup.hasScore ? null : formatDate(fixture.scheduledAt);\n\n const clickable = Boolean(onClick);\n\n return (\n <GlassCard\n treatment={isHero ? 'glass' : 'metric'}\n glow={isHero}\n role={clickable ? 'button' : undefined}\n tabIndex={clickable ? 0 : undefined}\n onClick={onClick}\n onKeyDown={\n clickable\n ? (e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onClick?.();\n }\n }\n : undefined\n }\n className={cn(\n isHero ? 'p-6 sm:p-8' : 'p-5',\n clickable &&\n 'cursor-pointer transition-transform duration-200 hover:-translate-y-0.5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]',\n className\n )}\n >\n <div className={cn('flex items-center justify-between gap-3', isHero && 'justify-center')}>\n <CompetitionStrip fixture={fixture} center={isHero} />\n {!isHero ? <StatusBadge status={fixture.status} /> : null}\n </div>\n\n <div\n className={cn(\n 'mt-4 grid items-center gap-3',\n 'grid-cols-[1fr_auto_1fr]',\n isHero && 'mt-6 gap-4 sm:gap-8'\n )}\n >\n <MatchupSide\n name={matchup.homeName}\n sport={matchup.homeSport}\n align={isHero ? undefined : 'end'}\n stacked={isHero}\n won={matchup.homeWon}\n dimmed={matchup.awayWon}\n crestSize={isHero ? 72 : 40}\n />\n <ScoreCenter matchup={matchup} time={timeLabel} size={isHero ? 'lg' : 'md'} />\n <MatchupSide\n name={matchup.awayName}\n sport={matchup.awaySport}\n align={isHero ? undefined : 'start'}\n stacked={isHero}\n won={matchup.awayWon}\n dimmed={matchup.homeWon}\n crestSize={isHero ? 72 : 40}\n />\n </div>\n\n {isHero ? (\n <div className=\"mt-5 flex justify-center\">\n <StatusBadge status={fixture.status} />\n </div>\n ) : null}\n\n <div\n className={cn(\n 'mt-4 flex flex-wrap items-center gap-x-4 gap-y-1.5 text-xs text-text-secondary',\n isHero && 'mt-6 justify-center'\n )}\n >\n <span className=\"flex items-center gap-1\">\n <CalendarClock className=\"h-3.5 w-3.5\" aria-hidden=\"true\" /> {formatDate(fixture.scheduledAt)}\n </span>\n {fixture.venue ? (\n <span className=\"flex items-center gap-1 truncate\">\n <MapPin className=\"h-3.5 w-3.5 shrink-0\" aria-hidden=\"true\" /> {fixture.venue}\n </span>\n ) : null}\n </div>\n </GlassCard>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"Scoreboard.js","names":[],"sources":["../../../src/atheletebridge/components/Scoreboard.tsx"],"sourcesContent":["/**\n * Scoreboard\n * @module atheletebridge/components\n *\n * Crest-vs-crest fixture presentation. `Scoreboard` renders the full match card\n * (competition strip → crest / score / crest → venue) used by the fixtures list\n * and fixture detail; the compact single-line `MatchupRow` (separate file)\n * reuses the same building blocks for the dashboard + team-detail feeds.\n *\n * All colors are semantic tokens. Winner side is tinted with\n * status-success-text, loser muted — driven purely by the real score.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { CalendarClock, MapPin, Trophy } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { StatusBadge } from './StatusBadge';\nimport { Crest } from './Crest';\nimport { SPORT_ICONS, FIXTURE_TYPE_LABELS } from './domain';\nimport { formatDate } from '../utils/formatters';\nimport { cn } from '../utils/cn';\nimport type { AthFixture, AthSport } from '../types';\n\n// ── Shared matchup model ─────────────────────────────────────────────────────\n\nexport interface Matchup {\n homeName: string;\n awayName: string;\n homeSport?: AthSport;\n awaySport?: AthSport;\n homeScore: number | null;\n awayScore: number | null;\n hasScore: boolean;\n homeWon: boolean;\n awayWon: boolean;\n}\n\n/** Derive the display matchup (names, scores, winner) from a fixture. */\nexport function resolveMatchup(fixture: AthFixture): Matchup {\n const homeName = fixture.homeTeam?.name ?? 'Home';\n const awayName = fixture.awayTeam?.name ?? (fixture.awayTeamId ? 'Away' : 'TBD');\n const hasScore = fixture.homeScore !== null && fixture.awayScore !== null;\n const homeScore = fixture.homeScore;\n const awayScore = fixture.awayScore;\n const homeWon = hasScore && (homeScore ?? 0) > (awayScore ?? 0);\n const awayWon = hasScore && (awayScore ?? 0) > (homeScore ?? 0);\n return {\n homeName,\n awayName,\n homeSport: fixture.homeTeam?.sport,\n awaySport: fixture.awayTeam?.sport,\n homeScore,\n awayScore,\n hasScore,\n homeWon,\n awayWon,\n };\n}\n\n// ── One team flank (crest + name) ────────────────────────────────────────────\n\nexport interface MatchupSideProps {\n name: string;\n sport?: AthSport;\n align?: 'start' | 'end';\n /** Winner emphasis — brightens the name. */\n won?: boolean;\n /** Loser de-emphasis when the fixture has a score. */\n dimmed?: boolean;\n crestSize?: number;\n /** Stack crest above name (hero/card) instead of inline (row). */\n stacked?: boolean;\n className?: string;\n}\n\nexport const MatchupSide: FC<MatchupSideProps> = ({\n name,\n sport,\n align = 'start',\n won = false,\n dimmed = false,\n crestSize = 40,\n stacked = false,\n className,\n}) => (\n <div\n className={cn(\n 'flex min-w-0 items-center gap-3',\n stacked\n ? 'flex-col text-center'\n : align === 'end'\n ? 'flex-row-reverse text-right'\n : 'text-left',\n className\n )}\n >\n <Crest name={name} sport={sport} size={crestSize} />\n <span\n className={cn(\n 'min-w-0 truncate font-semibold',\n stacked ? 'max-w-[10rem] text-sm' : 'text-sm',\n won ? 'text-status-success-text' : dimmed ? 'text-text-muted' : 'text-text-primary'\n )}\n >\n {name}\n </span>\n </div>\n);\n\n// ── Centerpiece (score or vs + kickoff) ──────────────────────────────────────\n\nexport interface ScoreCenterProps {\n matchup: Matchup;\n time?: ReactNode;\n size?: 'sm' | 'md' | 'lg';\n className?: string;\n}\n\nconst SCORE_SIZE = {\n sm: 'text-lg',\n md: 'text-2xl',\n lg: 'text-4xl sm:text-5xl',\n} as const;\n\nexport const ScoreCenter: FC<ScoreCenterProps> = ({ matchup, time, size = 'md', className }) => {\n if (!matchup.hasScore) {\n return (\n <div className={cn('flex flex-col items-center gap-0.5', className)}>\n <span className=\"rounded-lg bg-bg-sunken px-3 py-1 text-xs font-bold uppercase tracking-wide text-text-secondary\">\n vs\n </span>\n {time ? <span className=\"text-xs text-text-secondary\">{time}</span> : null}\n </div>\n );\n }\n return (\n <div className={cn('flex flex-col items-center gap-0.5', className)}>\n <span\n className={cn(\n 'flex items-center gap-2 font-bold leading-none tabular-nums',\n SCORE_SIZE[size]\n )}\n >\n <span className={matchup.homeWon ? 'text-status-success-text' : 'text-text-primary'}>\n {matchup.homeScore}\n </span>\n <span className=\"text-text-muted\">–</span>\n <span className={matchup.awayWon ? 'text-status-success-text' : 'text-text-primary'}>\n {matchup.awayScore}\n </span>\n </span>\n {time ? <span className=\"text-xs text-text-secondary\">{time}</span> : null}\n </div>\n );\n};\n\n// ── Competition eyebrow ──────────────────────────────────────────────────────\n\nconst CompetitionStrip: FC<{ fixture: AthFixture; center?: boolean }> = ({\n fixture,\n center = false,\n}) => {\n const SportIcon = fixture.homeTeam?.sport ? SPORT_ICONS[fixture.homeTeam.sport] : Trophy;\n const parts = [fixture.competition, fixture.round].filter(Boolean).join(' · ');\n return (\n <span\n className={cn(\n 'inline-flex items-center gap-1.5 text-xs font-medium text-text-secondary',\n center && 'justify-center'\n )}\n >\n <SportIcon className=\"h-3.5 w-3.5 shrink-0 text-text-muted\" aria-hidden=\"true\" />\n <span className=\"truncate\">{parts || FIXTURE_TYPE_LABELS[fixture.type]}</span>\n </span>\n );\n};\n\n// ── Full match card / hero ───────────────────────────────────────────────────\n\nexport interface ScoreboardProps {\n fixture: AthFixture;\n onClick?: () => void;\n /** `card` = fixtures-list tile; `hero` = large fixture-detail header. */\n variant?: 'card' | 'hero';\n className?: string;\n}\n\n/** Full crest-vs-crest match card (list tile or detail hero). */\nexport const Scoreboard: FC<ScoreboardProps> = ({\n fixture,\n onClick,\n variant = 'card',\n className,\n}) => {\n const matchup = resolveMatchup(fixture);\n const isHero = variant === 'hero';\n const timeLabel = matchup.hasScore ? null : formatDate(fixture.scheduledAt);\n\n const clickable = Boolean(onClick);\n\n return (\n <GlassCard\n treatment={isHero ? 'glass' : 'metric'}\n glow={isHero}\n role={clickable ? 'button' : undefined}\n tabIndex={clickable ? 0 : undefined}\n onClick={onClick}\n onKeyDown={\n clickable\n ? (e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onClick?.();\n }\n }\n : undefined\n }\n className={cn(\n isHero ? 'p-6 sm:p-8' : 'p-5',\n clickable &&\n 'cursor-pointer transition-transform duration-200 hover:-translate-y-0.5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]',\n className\n )}\n >\n <div className={cn('flex items-center justify-between gap-3', isHero && 'justify-center')}>\n <CompetitionStrip fixture={fixture} center={isHero} />\n {!isHero ? <StatusBadge status={fixture.status} /> : null}\n </div>\n\n <div\n className={cn(\n 'mt-4 grid items-center gap-3',\n 'grid-cols-[1fr_auto_1fr]',\n isHero && 'mt-6 gap-4 sm:gap-8'\n )}\n >\n <MatchupSide\n name={matchup.homeName}\n sport={matchup.homeSport}\n align={isHero ? undefined : 'end'}\n stacked={isHero}\n won={matchup.homeWon}\n dimmed={matchup.awayWon}\n crestSize={isHero ? 72 : 40}\n />\n <ScoreCenter matchup={matchup} time={timeLabel} size={isHero ? 'lg' : 'md'} />\n <MatchupSide\n name={matchup.awayName}\n sport={matchup.awaySport}\n align={isHero ? undefined : 'start'}\n stacked={isHero}\n won={matchup.awayWon}\n dimmed={matchup.homeWon}\n crestSize={isHero ? 72 : 40}\n />\n </div>\n\n {isHero ? (\n <div className=\"mt-5 flex justify-center\">\n <StatusBadge status={fixture.status} />\n </div>\n ) : null}\n\n <div\n className={cn(\n 'mt-4 flex flex-wrap items-center gap-x-4 gap-y-1.5 text-xs text-text-secondary',\n isHero && 'mt-6 justify-center'\n )}\n >\n <span className=\"flex items-center gap-1\">\n <CalendarClock className=\"h-3.5 w-3.5\" aria-hidden=\"true\" />{' '}\n {formatDate(fixture.scheduledAt)}\n </span>\n {fixture.venue ? (\n <span className=\"flex items-center gap-1 truncate\">\n <MapPin className=\"h-3.5 w-3.5 shrink-0\" aria-hidden=\"true\" /> {fixture.venue}\n </span>\n ) : null}\n </div>\n </GlassCard>\n );\n};\n"],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { FC } from 'react';
2
+ import { AthSession } from '../types';
3
+
4
+ interface SessionCardProps {
5
+ session: AthSession;
6
+ onClick?: () => void;
7
+ /** Resolved athlete display name (else a monogram from the id is shown). */
8
+ athleteName?: string | null;
9
+ /** Resolved coach display name (optional sub-label). */
10
+ coachName?: string | null;
11
+ }
12
+ export declare const SessionCard: FC<SessionCardProps>;
13
+ export {};
14
+ //# sourceMappingURL=SessionCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionCard.d.ts","sourceRoot":"","sources":["../../../src/atheletebridge/components/SessionCard.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAShC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C,UAAU,gBAAgB;IACxB,OAAO,EAAE,UAAU,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CAmD5C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"SessionCard.js","names":[],"sources":["../../../src/atheletebridge/components/SessionCard.tsx"],"sourcesContent":["/**\n * Session Card\n * @module atheletebridge/components\n *\n * A coaching-session tile showing the athlete identity (monogram avatar +\n * resolved name when available), session type, schedule, and a colored status\n * badge (Requested amber / Confirmed blue / Completed green / Cancelled grey).\n * A stored rating renders as read-only stars. Semantic tokens only.\n */\n\nimport type { FC } from 'react';\nimport { CalendarClock, Clock, Video, MapPin } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { StatusBadge } from './StatusBadge';\nimport { UserAvatar } from './UserAvatar';\nimport { RatingStars } from './viz';\nimport { SESSION_TYPE_LABELS } from './domain';\nimport { formatDate, formatDuration } from '../utils/formatters';\nimport { cn } from '../utils/cn';\nimport type { AthSession } from '../types';\n\ninterface SessionCardProps {\n session: AthSession;\n onClick?: () => void;\n /** Resolved athlete display name (else a monogram from the id is shown). */\n athleteName?: string | null;\n /** Resolved coach display name (optional sub-label). */\n coachName?: string | null;\n}\n\nexport const SessionCard: FC<SessionCardProps> = ({\n session,\n onClick,\n athleteName,\n coachName,\n}) => (\n <GlassCard\n treatment=\"metric\"\n role=\"button\"\n tabIndex={0}\n onClick={onClick}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onClick?.();\n }\n }}\n className={cn(\n 'cursor-pointer p-5 transition-transform duration-200 hover:-translate-y-0.5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]'\n )}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex min-w-0 items-center gap-3\">\n <UserAvatar name={athleteName} id={session.athleteId} size=\"md\" />\n <div className=\"min-w-0\">\n <h3 className=\"truncate text-base font-semibold text-text-primary\">{session.title}</h3>\n <p className=\"truncate text-sm text-text-secondary\">\n {athleteName?.trim() || 'Athlete'} · {SESSION_TYPE_LABELS[session.type]}\n {coachName?.trim() ? ` · ${coachName.trim()}` : ''}\n </p>\n </div>\n </div>\n <StatusBadge status={session.status} />\n </div>\n\n <div className=\"mt-4 flex flex-wrap items-center gap-x-4 gap-y-1.5 text-xs text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <CalendarClock className=\"h-3.5 w-3.5\" aria-hidden=\"true\" /> {formatDate(session.scheduledAt)}\n </span>\n <span className=\"flex items-center gap-1\">\n <Clock className=\"h-3.5 w-3.5\" aria-hidden=\"true\" /> {formatDuration(session.durationMin)}\n </span>\n {session.type === 'IN_PERSON' && session.location && (\n <span className=\"flex items-center gap-1 truncate\">\n <MapPin className=\"h-3.5 w-3.5 shrink-0\" aria-hidden=\"true\" /> {session.location}\n </span>\n )}\n {session.type !== 'IN_PERSON' && session.meetingUrl && (\n <span className=\"flex items-center gap-1\">\n <Video className=\"h-3.5 w-3.5\" aria-hidden=\"true\" /> Online\n </span>\n )}\n {session.rating !== null && (\n <RatingStars value={session.rating} size={14} showValue />\n )}\n </div>\n </GlassCard>\n);\n"],"mappings":";;;;;;;;;;;AA8BA,IAAa,KAAqC,EAChD,YACA,YACA,gBACA,mBAEA,kBAAC,GAAD;CACE,WAAU;CACV,MAAK;CACL,UAAU;CACD;CACT,YAAY,MAAM;AAChB,GAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,SACjC,EAAE,gBAAgB,EAClB,KAAW;;CAGf,WAAW,EACT,2KACD;WAbH,CAeE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,GAAD;IAAY,MAAM;IAAa,IAAI,EAAQ;IAAW,MAAK;IAAO,CAAA,EAClE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,MAAD;KAAI,WAAU;eAAsD,EAAQ;KAAW,CAAA,EACvF,kBAAC,KAAD;KAAG,WAAU;eAAb;MACG,GAAa,MAAM,IAAI;MAAU;MAAI,EAAoB,EAAQ;MACjE,GAAW,MAAM,GAAG,MAAM,EAAU,MAAM,KAAK;MAC9C;OACA;MACF;MACN,kBAAC,GAAD,EAAa,QAAQ,EAAQ,QAAU,CAAA,CACnC;KAEN,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,QAAD;IAAM,WAAU;cAAhB;KACE,kBAAC,GAAD;MAAe,WAAU;MAAc,eAAY;MAAS,CAAA;;KAAE,EAAW,EAAQ,YAAY;KACxF;;GACP,kBAAC,QAAD;IAAM,WAAU;cAAhB;KACE,kBAAC,GAAD;MAAO,WAAU;MAAc,eAAY;MAAS,CAAA;;KAAE,EAAe,EAAQ,YAAY;KACpF;;GACN,EAAQ,SAAS,eAAe,EAAQ,YACvC,kBAAC,QAAD;IAAM,WAAU;cAAhB;KACE,kBAAC,GAAD;MAAQ,WAAU;MAAuB,eAAY;MAAS,CAAA;;KAAE,EAAQ;KACnE;;GAER,EAAQ,SAAS,eAAe,EAAQ,cACvC,kBAAC,QAAD;IAAM,WAAU;cAAhB,CACE,kBAAC,GAAD;KAAO,WAAU;KAAc,eAAY;KAAS,CAAA,EAAA,UAC/C;;GAER,EAAQ,WAAW,QAClB,kBAAC,GAAD;IAAa,OAAO,EAAQ;IAAQ,MAAM;IAAI,WAAA;IAAY,CAAA;GAExD;IACI"}
1
+ {"version":3,"file":"SessionCard.js","names":[],"sources":["../../../src/atheletebridge/components/SessionCard.tsx"],"sourcesContent":["/**\n * Session Card\n * @module atheletebridge/components\n *\n * A coaching-session tile showing the athlete identity (monogram avatar +\n * resolved name when available), session type, schedule, and a colored status\n * badge (Requested amber / Confirmed blue / Completed green / Cancelled grey).\n * A stored rating renders as read-only stars. Semantic tokens only.\n */\n\nimport type { FC } from 'react';\nimport { CalendarClock, Clock, Video, MapPin } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { StatusBadge } from './StatusBadge';\nimport { UserAvatar } from './UserAvatar';\nimport { RatingStars } from './viz';\nimport { SESSION_TYPE_LABELS } from './domain';\nimport { formatDate, formatDuration } from '../utils/formatters';\nimport { cn } from '../utils/cn';\nimport type { AthSession } from '../types';\n\ninterface SessionCardProps {\n session: AthSession;\n onClick?: () => void;\n /** Resolved athlete display name (else a monogram from the id is shown). */\n athleteName?: string | null;\n /** Resolved coach display name (optional sub-label). */\n coachName?: string | null;\n}\n\nexport const SessionCard: FC<SessionCardProps> = ({ session, onClick, athleteName, coachName }) => (\n <GlassCard\n treatment=\"metric\"\n role=\"button\"\n tabIndex={0}\n onClick={onClick}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onClick?.();\n }\n }}\n className={cn(\n 'cursor-pointer p-5 transition-transform duration-200 hover:-translate-y-0.5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]'\n )}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex min-w-0 items-center gap-3\">\n <UserAvatar name={athleteName} id={session.athleteId} size=\"md\" />\n <div className=\"min-w-0\">\n <h3 className=\"truncate text-base font-semibold text-text-primary\">{session.title}</h3>\n <p className=\"truncate text-sm text-text-secondary\">\n {athleteName?.trim() || 'Athlete'} · {SESSION_TYPE_LABELS[session.type]}\n {coachName?.trim() ? ` · ${coachName.trim()}` : ''}\n </p>\n </div>\n </div>\n <StatusBadge status={session.status} />\n </div>\n\n <div className=\"mt-4 flex flex-wrap items-center gap-x-4 gap-y-1.5 text-xs text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <CalendarClock className=\"h-3.5 w-3.5\" aria-hidden=\"true\" />{' '}\n {formatDate(session.scheduledAt)}\n </span>\n <span className=\"flex items-center gap-1\">\n <Clock className=\"h-3.5 w-3.5\" aria-hidden=\"true\" /> {formatDuration(session.durationMin)}\n </span>\n {session.type === 'IN_PERSON' && session.location && (\n <span className=\"flex items-center gap-1 truncate\">\n <MapPin className=\"h-3.5 w-3.5 shrink-0\" aria-hidden=\"true\" /> {session.location}\n </span>\n )}\n {session.type !== 'IN_PERSON' && session.meetingUrl && (\n <span className=\"flex items-center gap-1\">\n <Video className=\"h-3.5 w-3.5\" aria-hidden=\"true\" /> Online\n </span>\n )}\n {session.rating !== null && <RatingStars value={session.rating} size={14} showValue />}\n </div>\n </GlassCard>\n);\n"],"mappings":";;;;;;;;;;;AA8BA,IAAa,KAAqC,EAAE,YAAS,YAAS,gBAAa,mBACjF,kBAAC,GAAD;CACE,WAAU;CACV,MAAK;CACL,UAAU;CACD;CACT,YAAY,MAAM;AAChB,GAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,SACjC,EAAE,gBAAgB,EAClB,KAAW;;CAGf,WAAW,EACT,2KACD;WAbH,CAeE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,GAAD;IAAY,MAAM;IAAa,IAAI,EAAQ;IAAW,MAAK;IAAO,CAAA,EAClE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,MAAD;KAAI,WAAU;eAAsD,EAAQ;KAAW,CAAA,EACvF,kBAAC,KAAD;KAAG,WAAU;eAAb;MACG,GAAa,MAAM,IAAI;MAAU;MAAI,EAAoB,EAAQ;MACjE,GAAW,MAAM,GAAG,MAAM,EAAU,MAAM,KAAK;MAC9C;OACA;MACF;MACN,kBAAC,GAAD,EAAa,QAAQ,EAAQ,QAAU,CAAA,CACnC;KAEN,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,QAAD;IAAM,WAAU;cAAhB;KACE,kBAAC,GAAD;MAAe,WAAU;MAAc,eAAY;MAAS,CAAA;KAAC;KAC5D,EAAW,EAAQ,YAAY;KAC3B;;GACP,kBAAC,QAAD;IAAM,WAAU;cAAhB;KACE,kBAAC,GAAD;MAAO,WAAU;MAAc,eAAY;MAAS,CAAA;;KAAE,EAAe,EAAQ,YAAY;KACpF;;GACN,EAAQ,SAAS,eAAe,EAAQ,YACvC,kBAAC,QAAD;IAAM,WAAU;cAAhB;KACE,kBAAC,GAAD;MAAQ,WAAU;MAAuB,eAAY;MAAS,CAAA;;KAAE,EAAQ;KACnE;;GAER,EAAQ,SAAS,eAAe,EAAQ,cACvC,kBAAC,QAAD;IAAM,WAAU;cAAhB,CACE,kBAAC,GAAD;KAAO,WAAU;KAAc,eAAY;KAAS,CAAA,EAAA,UAC/C;;GAER,EAAQ,WAAW,QAAQ,kBAAC,GAAD;IAAa,OAAO,EAAQ;IAAQ,MAAM;IAAI,WAAA;IAAY,CAAA;GAClF;IACI"}
@@ -0,0 +1,14 @@
1
+ import { FC } from 'react';
2
+ import { AthSessionStatus } from '../types';
3
+
4
+ export interface SessionStatusTimelineProps {
5
+ status: AthSessionStatus;
6
+ /** Requested-at timestamp (session.createdAt). */
7
+ createdAt?: string | null;
8
+ /** Completed-at timestamp (session.completedAt). */
9
+ completedAt?: string | null;
10
+ className?: string;
11
+ }
12
+ /** Lifecycle stepper for a coaching session (with cancelled/no-show terminal). */
13
+ export declare const SessionStatusTimeline: FC<SessionStatusTimelineProps>;
14
+ //# sourceMappingURL=SessionStatusTimeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionStatusTimeline.d.ts","sourceRoot":"","sources":["../../../src/atheletebridge/components/SessionStatusTimeline.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAKhC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAEjD,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,gBAAgB,CAAC;IACzB,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,oDAAoD;IACpD,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAOD,kFAAkF;AAClF,eAAO,MAAM,qBAAqB,EAAE,EAAE,CAAC,0BAA0B,CAkDhE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"SessionStatusTimeline.js","names":[],"sources":["../../../src/atheletebridge/components/SessionStatusTimeline.tsx"],"sourcesContent":["/**\n * SessionStatusTimeline\n * @module atheletebridge/components\n *\n * A horizontal lifecycle stepper for a coaching session:\n * Requested → Confirmed → Completed\n * with a distinct terminal variant when the session was Cancelled / No-show.\n * The happy path reuses the fe-libs Stepper; timestamps are shown ONLY where the\n * schema actually has them (createdAt for Requested, completedAt for Completed)\n * — Confirmed has no dedicated timestamp field, so none is fabricated.\n * Semantic tokens only.\n */\n\nimport type { FC } from 'react';\nimport { Check, X } from 'lucide-react';\nimport { Stepper, type StepperStep } from '@burdenoff/fe-libs/ui';\nimport { formatDate } from '../utils/formatters';\nimport { cn } from '../utils/cn';\nimport type { AthSessionStatus } from '../types';\n\nexport interface SessionStatusTimelineProps {\n status: AthSessionStatus;\n /** Requested-at timestamp (session.createdAt). */\n createdAt?: string | null;\n /** Completed-at timestamp (session.completedAt). */\n completedAt?: string | null;\n className?: string;\n}\n\nconst shortWhen = (iso: string | null | undefined): string | undefined => {\n if (!iso) return undefined;\n return formatDate(iso, { weekday: 'short', year: undefined });\n};\n\n/** Lifecycle stepper for a coaching session (with cancelled/no-show terminal). */\nexport const SessionStatusTimeline: FC<SessionStatusTimelineProps> = ({\n status,\n createdAt,\n completedAt,\n className,\n}) => {\n // ── Terminal (cancelled / no-show) ─────────────────────────────────────────\n if (status === 'CANCELLED' || status === 'NO_SHOW') {\n const terminalLabel = status === 'CANCELLED' ? 'Cancelled' : 'No-show';\n return (\n <ol\n className={cn('flex items-start gap-2', className)}\n aria-label=\"Session lifecycle\"\n >\n <li className=\"flex flex-1 items-center gap-3\">\n <span\n aria-hidden=\"true\"\n className=\"inline-flex size-7 shrink-0 items-center justify-center rounded-full border border-action-primary-bg bg-action-primary-bg text-action-primary-text\"\n >\n <Check className=\"size-4\" />\n </span>\n <span className=\"min-w-0\">\n <span className=\"block text-sm font-medium text-text-primary\">Requested</span>\n {shortWhen(createdAt) ? (\n <span className=\"block text-xs text-text-muted\">{shortWhen(createdAt)}</span>\n ) : null}\n </span>\n <span\n aria-hidden=\"true\"\n className=\"h-px flex-1 bg-status-error-border\"\n />\n </li>\n <li className=\"flex items-center gap-3\" aria-current=\"step\">\n <span\n aria-hidden=\"true\"\n className=\"inline-flex size-7 shrink-0 items-center justify-center rounded-full border border-status-error-border bg-status-error-bg-subtle text-status-error-text\"\n >\n <X className=\"size-4\" />\n </span>\n <span className=\"text-sm font-medium text-status-error-text\">{terminalLabel}</span>\n </li>\n </ol>\n );\n }\n\n // ── Happy path ─────────────────────────────────────────────────────────────\n const steps: StepperStep[] = [\n { key: 'requested', label: 'Requested', description: shortWhen(createdAt) },\n { key: 'confirmed', label: 'Confirmed' },\n { key: 'completed', label: 'Completed', description: shortWhen(completedAt) },\n ];\n\n // active = index of the in-progress step; past `steps.length` marks all done.\n const active = status === 'REQUESTED' ? 0 : status === 'CONFIRMED' ? 1 : steps.length;\n\n return <Stepper steps={steps} active={active} className={className} />;\n};\n"],"mappings":";;;;;;AA6BA,IAAM,KAAa,MAAuD;AACnE,OACL,QAAO,EAAW,GAAK;EAAE,SAAS;EAAS,MAAM,KAAA;EAAW,CAAC;GAIlD,KAAyD,EACpE,WACA,cACA,gBACA,mBACI;AAEJ,KAAI,MAAW,eAAe,MAAW,WAAW;EAClD,IAAM,IAAgB,MAAW,cAAc,cAAc;AAC7D,SACE,kBAAC,MAAD;GACE,WAAW,EAAG,0BAA0B,EAAU;GAClD,cAAW;aAFb,CAIE,kBAAC,MAAD;IAAI,WAAU;cAAd;KACE,kBAAC,QAAD;MACE,eAAY;MACZ,WAAU;gBAEV,kBAAC,GAAD,EAAO,WAAU,UAAW,CAAA;MACvB,CAAA;KACP,kBAAC,QAAD;MAAM,WAAU;gBAAhB,CACE,kBAAC,QAAD;OAAM,WAAU;iBAA8C;OAAgB,CAAA,EAC7E,EAAU,EAAU,GACnB,kBAAC,QAAD;OAAM,WAAU;iBAAiC,EAAU,EAAU;OAAQ,CAAA,GAC3E,KACC;;KACP,kBAAC,QAAD;MACE,eAAY;MACZ,WAAU;MACV,CAAA;KACC;OACL,kBAAC,MAAD;IAAI,WAAU;IAA0B,gBAAa;cAArD,CACE,kBAAC,QAAD;KACE,eAAY;KACZ,WAAU;eAEV,kBAAC,GAAD,EAAG,WAAU,UAAW,CAAA;KACnB,CAAA,EACP,kBAAC,QAAD;KAAM,WAAU;eAA8C;KAAqB,CAAA,CAChF;MACF;;;CAKT,IAAM,IAAuB;EAC3B;GAAE,KAAK;GAAa,OAAO;GAAa,aAAa,EAAU,EAAU;GAAE;EAC3E;GAAE,KAAK;GAAa,OAAO;GAAa;EACxC;GAAE,KAAK;GAAa,OAAO;GAAa,aAAa,EAAU,EAAY;GAAE;EAC9E;AAKD,QAAO,kBAAC,GAAD;EAAgB;EAAe,QAFvB,MAAW,cAAc,IAAI,MAAW,cAAc,IAAI,EAAM;EAEtB;EAAa,CAAA"}
1
+ {"version":3,"file":"SessionStatusTimeline.js","names":[],"sources":["../../../src/atheletebridge/components/SessionStatusTimeline.tsx"],"sourcesContent":["/**\n * SessionStatusTimeline\n * @module atheletebridge/components\n *\n * A horizontal lifecycle stepper for a coaching session:\n * Requested → Confirmed → Completed\n * with a distinct terminal variant when the session was Cancelled / No-show.\n * The happy path reuses the fe-libs Stepper; timestamps are shown ONLY where the\n * schema actually has them (createdAt for Requested, completedAt for Completed)\n * — Confirmed has no dedicated timestamp field, so none is fabricated.\n * Semantic tokens only.\n */\n\nimport type { FC } from 'react';\nimport { Check, X } from 'lucide-react';\nimport { Stepper, type StepperStep } from '@burdenoff/fe-libs/ui';\nimport { formatDate } from '../utils/formatters';\nimport { cn } from '../utils/cn';\nimport type { AthSessionStatus } from '../types';\n\nexport interface SessionStatusTimelineProps {\n status: AthSessionStatus;\n /** Requested-at timestamp (session.createdAt). */\n createdAt?: string | null;\n /** Completed-at timestamp (session.completedAt). */\n completedAt?: string | null;\n className?: string;\n}\n\nconst shortWhen = (iso: string | null | undefined): string | undefined => {\n if (!iso) return undefined;\n return formatDate(iso, { weekday: 'short', year: undefined });\n};\n\n/** Lifecycle stepper for a coaching session (with cancelled/no-show terminal). */\nexport const SessionStatusTimeline: FC<SessionStatusTimelineProps> = ({\n status,\n createdAt,\n completedAt,\n className,\n}) => {\n // ── Terminal (cancelled / no-show) ─────────────────────────────────────────\n if (status === 'CANCELLED' || status === 'NO_SHOW') {\n const terminalLabel = status === 'CANCELLED' ? 'Cancelled' : 'No-show';\n return (\n <ol className={cn('flex items-start gap-2', className)} aria-label=\"Session lifecycle\">\n <li className=\"flex flex-1 items-center gap-3\">\n <span\n aria-hidden=\"true\"\n className=\"inline-flex size-7 shrink-0 items-center justify-center rounded-full border border-action-primary-bg bg-action-primary-bg text-action-primary-text\"\n >\n <Check className=\"size-4\" />\n </span>\n <span className=\"min-w-0\">\n <span className=\"block text-sm font-medium text-text-primary\">Requested</span>\n {shortWhen(createdAt) ? (\n <span className=\"block text-xs text-text-muted\">{shortWhen(createdAt)}</span>\n ) : null}\n </span>\n <span aria-hidden=\"true\" className=\"h-px flex-1 bg-status-error-border\" />\n </li>\n <li className=\"flex items-center gap-3\" aria-current=\"step\">\n <span\n aria-hidden=\"true\"\n className=\"inline-flex size-7 shrink-0 items-center justify-center rounded-full border border-status-error-border bg-status-error-bg-subtle text-status-error-text\"\n >\n <X className=\"size-4\" />\n </span>\n <span className=\"text-sm font-medium text-status-error-text\">{terminalLabel}</span>\n </li>\n </ol>\n );\n }\n\n // ── Happy path ─────────────────────────────────────────────────────────────\n const steps: StepperStep[] = [\n { key: 'requested', label: 'Requested', description: shortWhen(createdAt) },\n { key: 'confirmed', label: 'Confirmed' },\n { key: 'completed', label: 'Completed', description: shortWhen(completedAt) },\n ];\n\n // active = index of the in-progress step; past `steps.length` marks all done.\n const active = status === 'REQUESTED' ? 0 : status === 'CONFIRMED' ? 1 : steps.length;\n\n return <Stepper steps={steps} active={active} className={className} />;\n};\n"],"mappings":";;;;;;AA6BA,IAAM,KAAa,MAAuD;AACnE,OACL,QAAO,EAAW,GAAK;EAAE,SAAS;EAAS,MAAM,KAAA;EAAW,CAAC;GAIlD,KAAyD,EACpE,WACA,cACA,gBACA,mBACI;AAEJ,KAAI,MAAW,eAAe,MAAW,WAAW;EAClD,IAAM,IAAgB,MAAW,cAAc,cAAc;AAC7D,SACE,kBAAC,MAAD;GAAI,WAAW,EAAG,0BAA0B,EAAU;GAAE,cAAW;aAAnE,CACE,kBAAC,MAAD;IAAI,WAAU;cAAd;KACE,kBAAC,QAAD;MACE,eAAY;MACZ,WAAU;gBAEV,kBAAC,GAAD,EAAO,WAAU,UAAW,CAAA;MACvB,CAAA;KACP,kBAAC,QAAD;MAAM,WAAU;gBAAhB,CACE,kBAAC,QAAD;OAAM,WAAU;iBAA8C;OAAgB,CAAA,EAC7E,EAAU,EAAU,GACnB,kBAAC,QAAD;OAAM,WAAU;iBAAiC,EAAU,EAAU;OAAQ,CAAA,GAC3E,KACC;;KACP,kBAAC,QAAD;MAAM,eAAY;MAAO,WAAU;MAAuC,CAAA;KACvE;OACL,kBAAC,MAAD;IAAI,WAAU;IAA0B,gBAAa;cAArD,CACE,kBAAC,QAAD;KACE,eAAY;KACZ,WAAU;eAEV,kBAAC,GAAD,EAAG,WAAU,UAAW,CAAA;KACnB,CAAA,EACP,kBAAC,QAAD;KAAM,WAAU;eAA8C;KAAqB,CAAA,CAChF;MACF;;;CAKT,IAAM,IAAuB;EAC3B;GAAE,KAAK;GAAa,OAAO;GAAa,aAAa,EAAU,EAAU;GAAE;EAC3E;GAAE,KAAK;GAAa,OAAO;GAAa;EACxC;GAAE,KAAK;GAAa,OAAO;GAAa,aAAa,EAAU,EAAY;GAAE;EAC9E;AAKD,QAAO,kBAAC,GAAD;EAAgB;EAAe,QAFvB,MAAW,cAAc,IAAI,MAAW,cAAc,IAAI,EAAM;EAEtB;EAAa,CAAA"}
@@ -0,0 +1,16 @@
1
+ import { FC } from 'react';
2
+
3
+ type BadgeVariant = 'success' | 'warning' | 'destructive' | 'secondary' | 'info' | 'outline';
4
+ interface StatusBadgeProps {
5
+ status: string;
6
+ /**
7
+ * Force a specific variant, overriding the auto status→color mapping. Useful
8
+ * where the same status string reads differently by context (e.g. a cancelled
9
+ * coaching session shown grey rather than the default destructive red).
10
+ */
11
+ variant?: BadgeVariant;
12
+ className?: string;
13
+ }
14
+ export declare const StatusBadge: FC<StatusBadgeProps>;
15
+ export {};
16
+ //# sourceMappingURL=StatusBadge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatusBadge.d.ts","sourceRoot":"","sources":["../../../src/atheletebridge/components/StatusBadge.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAGhC,KAAK,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,GAAG,WAAW,GAAG,MAAM,GAAG,SAAS,CAAC;AAE7F,UAAU,gBAAgB;IACxB,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAwDD,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CA0B5C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"StatusBadge.js","names":[],"sources":["../../../src/atheletebridge/components/StatusBadge.tsx"],"sourcesContent":["/**\n * Status Badge Component\n * @module atheletebridge/components\n *\n * A colored badge based on a domain status value, with semantic-token color\n * mapping for the AthleteBridge lifecycle states (teams, members, fixtures,\n * programs, sessions, workouts). Uses semantic tokens only — never raw colors.\n */\n\nimport type { FC } from 'react';\nimport { cn } from '../utils/cn';\n\ntype BadgeVariant = 'success' | 'warning' | 'destructive' | 'secondary' | 'info' | 'outline';\n\ninterface StatusBadgeProps {\n status: string;\n /**\n * Force a specific variant, overriding the auto status→color mapping. Useful\n * where the same status string reads differently by context (e.g. a cancelled\n * coaching session shown grey rather than the default destructive red).\n */\n variant?: BadgeVariant;\n className?: string;\n}\n\nconst variantStyles: Record<BadgeVariant, string> = {\n success: 'bg-status-success-bg-subtle text-status-success-text',\n warning: 'bg-status-warning-bg-subtle text-status-warning-text',\n destructive: 'bg-status-error-bg-subtle text-status-error-text',\n secondary: 'bg-bg-sunken text-text-secondary',\n info: 'bg-[var(--color-accent-soft)] text-text-primary',\n outline: 'border border-border-seam text-text-primary',\n};\n\n// Statuses that represent a \"live\" / in-progress condition get a subtle,\n// opacity-only glow pulse (reduced-motion safe via motion-safe:).\nconst liveStatuses = new Set(['live', 'active', 'confirmed', 'in_progress']);\n\nconst statusVariantMap: Record<string, BadgeVariant> = {\n // Team status\n forming: 'warning',\n active: 'success',\n inactive: 'secondary',\n archived: 'secondary',\n\n // Member status\n trial: 'info',\n injured: 'warning',\n suspended: 'destructive',\n released: 'secondary',\n\n // Fixture status\n scheduled: 'info',\n live: 'success',\n completed: 'success',\n postponed: 'warning',\n cancelled: 'destructive',\n\n // Program status\n draft: 'secondary',\n published: 'success',\n\n // Session status\n requested: 'warning',\n confirmed: 'info',\n no_show: 'destructive',\n\n // Workout status\n planned: 'info',\n skipped: 'secondary',\n};\n\nfunction formatStatusLabel(status: string): string {\n return status\n .replace(/_/g, ' ')\n .toLowerCase()\n .replace(/\\b\\w/g, (char) => char.toUpperCase());\n}\n\nexport const StatusBadge: FC<StatusBadgeProps> = ({ status, variant: variantOverride, className }) => {\n const key = status.toLowerCase();\n const variant = variantOverride ?? statusVariantMap[key] ?? 'secondary';\n const isLive = liveStatuses.has(key);\n\n return (\n <span\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-xs font-medium',\n variantStyles[variant],\n className\n )}\n >\n {isLive && (\n <span\n aria-hidden=\"true\"\n className=\"size-1.5 rounded-full bg-current motion-safe:animate-vc-glow-pulse\"\n />\n )}\n {formatStatusLabel(status)}\n </span>\n );\n};\n"],"mappings":";;;AAyBA,IAAM,IAA8C;CAClD,SAAS;CACT,SAAS;CACT,aAAa;CACb,WAAW;CACX,MAAM;CACN,SAAS;CACV,EAIK,IAAe,IAAI,IAAI;CAAC;CAAQ;CAAU;CAAa;CAAc,CAAC,EAEtE,IAAiD;CAErD,SAAS;CACT,QAAQ;CACR,UAAU;CACV,UAAU;CAGV,OAAO;CACP,SAAS;CACT,WAAW;CACX,UAAU;CAGV,WAAW;CACX,MAAM;CACN,WAAW;CACX,WAAW;CACX,WAAW;CAGX,OAAO;CACP,WAAW;CAGX,WAAW;CACX,WAAW;CACX,SAAS;CAGT,SAAS;CACT,SAAS;CACV;AAED,SAAS,EAAkB,GAAwB;AACjD,QAAO,EACJ,QAAQ,MAAM,IAAI,CAClB,aAAa,CACb,QAAQ,UAAU,MAAS,EAAK,aAAa,CAAC;;AAGnD,IAAa,KAAqC,EAAE,WAAQ,SAAS,GAAiB,mBAAgB;CACpG,IAAM,IAAM,EAAO,aAAa,EAC1B,IAAU,KAAmB,EAAiB,MAAQ,aACtD,IAAS,EAAa,IAAI,EAAI;AAEpC,QACE,kBAAC,QAAD;EACE,WAAW,EACT,mFACA,EAAc,IACd,EACD;YALH,CAOG,KACC,kBAAC,QAAD;GACE,eAAY;GACZ,WAAU;GACV,CAAA,EAEH,EAAkB,EAAO,CACrB"}
1
+ {"version":3,"file":"StatusBadge.js","names":[],"sources":["../../../src/atheletebridge/components/StatusBadge.tsx"],"sourcesContent":["/**\n * Status Badge Component\n * @module atheletebridge/components\n *\n * A colored badge based on a domain status value, with semantic-token color\n * mapping for the AthleteBridge lifecycle states (teams, members, fixtures,\n * programs, sessions, workouts). Uses semantic tokens only — never raw colors.\n */\n\nimport type { FC } from 'react';\nimport { cn } from '../utils/cn';\n\ntype BadgeVariant = 'success' | 'warning' | 'destructive' | 'secondary' | 'info' | 'outline';\n\ninterface StatusBadgeProps {\n status: string;\n /**\n * Force a specific variant, overriding the auto status→color mapping. Useful\n * where the same status string reads differently by context (e.g. a cancelled\n * coaching session shown grey rather than the default destructive red).\n */\n variant?: BadgeVariant;\n className?: string;\n}\n\nconst variantStyles: Record<BadgeVariant, string> = {\n success: 'bg-status-success-bg-subtle text-status-success-text',\n warning: 'bg-status-warning-bg-subtle text-status-warning-text',\n destructive: 'bg-status-error-bg-subtle text-status-error-text',\n secondary: 'bg-bg-sunken text-text-secondary',\n info: 'bg-[var(--color-accent-soft)] text-text-primary',\n outline: 'border border-border-seam text-text-primary',\n};\n\n// Statuses that represent a \"live\" / in-progress condition get a subtle,\n// opacity-only glow pulse (reduced-motion safe via motion-safe:).\nconst liveStatuses = new Set(['live', 'active', 'confirmed', 'in_progress']);\n\nconst statusVariantMap: Record<string, BadgeVariant> = {\n // Team status\n forming: 'warning',\n active: 'success',\n inactive: 'secondary',\n archived: 'secondary',\n\n // Member status\n trial: 'info',\n injured: 'warning',\n suspended: 'destructive',\n released: 'secondary',\n\n // Fixture status\n scheduled: 'info',\n live: 'success',\n completed: 'success',\n postponed: 'warning',\n cancelled: 'destructive',\n\n // Program status\n draft: 'secondary',\n published: 'success',\n\n // Session status\n requested: 'warning',\n confirmed: 'info',\n no_show: 'destructive',\n\n // Workout status\n planned: 'info',\n skipped: 'secondary',\n};\n\nfunction formatStatusLabel(status: string): string {\n return status\n .replace(/_/g, ' ')\n .toLowerCase()\n .replace(/\\b\\w/g, (char) => char.toUpperCase());\n}\n\nexport const StatusBadge: FC<StatusBadgeProps> = ({\n status,\n variant: variantOverride,\n className,\n}) => {\n const key = status.toLowerCase();\n const variant = variantOverride ?? statusVariantMap[key] ?? 'secondary';\n const isLive = liveStatuses.has(key);\n\n return (\n <span\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-xs font-medium',\n variantStyles[variant],\n className\n )}\n >\n {isLive && (\n <span\n aria-hidden=\"true\"\n className=\"size-1.5 rounded-full bg-current motion-safe:animate-vc-glow-pulse\"\n />\n )}\n {formatStatusLabel(status)}\n </span>\n );\n};\n"],"mappings":";;;AAyBA,IAAM,IAA8C;CAClD,SAAS;CACT,SAAS;CACT,aAAa;CACb,WAAW;CACX,MAAM;CACN,SAAS;CACV,EAIK,IAAe,IAAI,IAAI;CAAC;CAAQ;CAAU;CAAa;CAAc,CAAC,EAEtE,IAAiD;CAErD,SAAS;CACT,QAAQ;CACR,UAAU;CACV,UAAU;CAGV,OAAO;CACP,SAAS;CACT,WAAW;CACX,UAAU;CAGV,WAAW;CACX,MAAM;CACN,WAAW;CACX,WAAW;CACX,WAAW;CAGX,OAAO;CACP,WAAW;CAGX,WAAW;CACX,WAAW;CACX,SAAS;CAGT,SAAS;CACT,SAAS;CACV;AAED,SAAS,EAAkB,GAAwB;AACjD,QAAO,EACJ,QAAQ,MAAM,IAAI,CAClB,aAAa,CACb,QAAQ,UAAU,MAAS,EAAK,aAAa,CAAC;;AAGnD,IAAa,KAAqC,EAChD,WACA,SAAS,GACT,mBACI;CACJ,IAAM,IAAM,EAAO,aAAa,EAC1B,IAAU,KAAmB,EAAiB,MAAQ,aACtD,IAAS,EAAa,IAAI,EAAI;AAEpC,QACE,kBAAC,QAAD;EACE,WAAW,EACT,mFACA,EAAc,IACd,EACD;YALH,CAOG,KACC,kBAAC,QAAD;GACE,eAAY;GACZ,WAAU;GACV,CAAA,EAEH,EAAkB,EAAO,CACrB"}
@@ -0,0 +1,16 @@
1
+ import { FC } from 'react';
2
+ import { AthTeam } from '../types';
3
+
4
+ interface TeamCardProps {
5
+ team: AthTeam;
6
+ onClick?: () => void;
7
+ /**
8
+ * Member count for the footer chip. Falls back to `team.members?.length`
9
+ * when the list query selected members; omit the chip entirely if neither is
10
+ * available (never guess).
11
+ */
12
+ memberCount?: number;
13
+ }
14
+ export declare const TeamCard: FC<TeamCardProps>;
15
+ export {};
16
+ //# sourceMappingURL=TeamCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TeamCard.d.ts","sourceRoot":"","sources":["../../../src/atheletebridge/components/TeamCard.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAOhC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC,UAAU,aAAa;IACrB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,QAAQ,EAAE,EAAE,CAAC,aAAa,CA2EtC,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { FC } from 'react';
2
+
3
+ declare const SIZE_MAP: {
4
+ readonly xs: 24;
5
+ readonly sm: 32;
6
+ readonly md: 40;
7
+ readonly lg: 56;
8
+ readonly xl: 72;
9
+ };
10
+ export type UserAvatarSize = keyof typeof SIZE_MAP | number;
11
+ export interface UserAvatarProps {
12
+ /** Resolved display name (drives initials + gradient seed). */
13
+ name?: string | null;
14
+ /** Stable id — used as the gradient seed and initials fallback when no name. */
15
+ id?: string | null;
16
+ /** Optional jersey number rendered instead of initials (roster context). */
17
+ jersey?: number | null;
18
+ /** Named size token or explicit pixel diameter. */
19
+ size?: UserAvatarSize;
20
+ /** Extra ring (used inside overlapping stacks / on colored surfaces). */
21
+ ring?: boolean;
22
+ className?: string;
23
+ }
24
+ /** Circular monogram avatar for a user/athlete/coach (initials or jersey #). */
25
+ export declare const UserAvatar: FC<UserAvatarProps>;
26
+ export {};
27
+ //# sourceMappingURL=UserAvatar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UserAvatar.d.ts","sourceRoot":"","sources":["../../../src/atheletebridge/components/UserAvatar.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAIhC,QAAA,MAAM,QAAQ;;;;;;CAAsD,CAAC;AAErE,MAAM,MAAM,cAAc,GAAG,MAAM,OAAO,QAAQ,GAAG,MAAM,CAAC;AAE5D,MAAM,WAAW,eAAe;IAC9B,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,gFAAgF;IAChF,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,4EAA4E;IAC5E,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,mDAAmD;IACnD,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,yEAAyE;IACzE,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,gFAAgF;AAChF,eAAO,MAAM,UAAU,EAAE,EAAE,CAAC,eAAe,CAkC1C,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * User picker
3
+ * @module atheletebridge/components
4
+ *
5
+ * Resolves a real workspace/tenant user by name or email (global user
6
+ * directory) so a coach can add a team member without knowing a raw UUID.
7
+ * Degrades gracefully: if the directory is unavailable the coach can still paste
8
+ * a user id manually. Semantic tokens only.
9
+ */
10
+ export interface UserSelectValue {
11
+ userId: string;
12
+ displayName: string;
13
+ }
14
+ interface UserSearchSelectProps {
15
+ /** Currently selected user id. */
16
+ userId: string;
17
+ /** Display name currently chosen (echoed back so the parent can prefill). */
18
+ displayName: string;
19
+ onSelect: (value: UserSelectValue) => void;
20
+ required?: boolean;
21
+ }
22
+ export declare function UserSearchSelect({ userId, displayName, onSelect, required, }: UserSearchSelectProps): import("react").JSX.Element;
23
+ export {};
24
+ //# sourceMappingURL=UserSearchSelect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UserSearchSelect.d.ts","sourceRoot":"","sources":["../../../src/atheletebridge/components/UserSearchSelect.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAQH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,qBAAqB;IAC7B,kCAAkC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,MAAM,EACN,WAAW,EACX,QAAQ,EACR,QAAgB,GACjB,EAAE,qBAAqB,+BAgIvB"}
@@ -0,0 +1,18 @@
1
+ import { LucideIcon } from 'lucide-react';
2
+ import { AthFixtureType, AthMemberRole, AthMetricType, AthProgramLevel, AthSessionType, AthSport } from '../types';
3
+
4
+ export declare const SPORT_ICONS: Record<AthSport, LucideIcon>;
5
+ export declare const SPORT_LABELS: Record<AthSport, string>;
6
+ export declare const PROGRAM_LEVEL_LABELS: Record<AthProgramLevel, string>;
7
+ export declare const MEMBER_ROLE_LABELS: Record<AthMemberRole, string>;
8
+ export declare const FIXTURE_TYPE_LABELS: Record<AthFixtureType, string>;
9
+ export declare const SESSION_TYPE_LABELS: Record<AthSessionType, string>;
10
+ export declare const METRIC_TYPE_LABELS: Record<AthMetricType, string>;
11
+ export declare const SPORT_OPTIONS: AthSport[];
12
+ export declare const PROGRAM_LEVEL_OPTIONS: AthProgramLevel[];
13
+ export declare const MEMBER_ROLE_OPTIONS: AthMemberRole[];
14
+ export declare const FIXTURE_TYPE_OPTIONS: AthFixtureType[];
15
+ export declare const SESSION_TYPE_OPTIONS: AthSessionType[];
16
+ /** Humanize an enum value for display (fallback when no explicit label exists). */
17
+ export declare function humanizeEnum(value: string): string;
18
+ //# sourceMappingURL=domain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domain.d.ts","sourceRoot":"","sources":["../../../src/atheletebridge/components/domain.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAQL,KAAK,UAAU,EAChB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EACb,aAAa,EACb,eAAe,EACf,cAAc,EACd,QAAQ,EACT,MAAM,UAAU,CAAC;AAElB,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,QAAQ,EAAE,UAAU,CASpD,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CASjD,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,eAAe,EAAE,MAAM,CAKhE,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAO5D,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,cAAc,EAAE,MAAM,CAM9D,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,cAAc,EAAE,MAAM,CAI9D,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAS5D,CAAC;AAEF,eAAO,MAAM,aAAa,EAAgC,QAAQ,EAAE,CAAC;AACrE,eAAO,MAAM,qBAAqB,EAAwC,eAAe,EAAE,CAAC;AAC5F,eAAO,MAAM,mBAAmB,EAAsC,aAAa,EAAE,CAAC;AACtF,eAAO,MAAM,oBAAoB,EAAuC,cAAc,EAAE,CAAC;AACzF,eAAO,MAAM,oBAAoB,EAAuC,cAAc,EAAE,CAAC;AAEzF,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKlD"}
@@ -0,0 +1,15 @@
1
+ import { FC, ReactNode } from 'react';
2
+
3
+ interface FormFieldProps {
4
+ label: string;
5
+ htmlFor?: string;
6
+ required?: boolean;
7
+ hint?: string;
8
+ error?: string;
9
+ children: ReactNode;
10
+ className?: string;
11
+ }
12
+ export declare const FormField: FC<FormFieldProps>;
13
+ export declare const fieldInputClass: string;
14
+ export {};
15
+ //# sourceMappingURL=form.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../../../src/atheletebridge/components/form.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAG3C,UAAU,cAAc;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,SAAS,EAAE,EAAE,CAAC,cAAc,CAkBxC,CAAC;AAEF,eAAO,MAAM,eAAe,QAG3B,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Components Index
3
+ * @module atheletebridge/components
4
+ */
5
+ export { PageLayout } from './PageLayout';
6
+ export { MetricsCard } from './MetricsCard';
7
+ export { StatusBadge } from './StatusBadge';
8
+ export { EmptyState } from './EmptyState';
9
+ export { LoadingState, ErrorState } from './LoadingState';
10
+ export { TeamCard } from './TeamCard';
11
+ export { FixtureCard } from './FixtureCard';
12
+ export { ProgramCard } from './ProgramCard';
13
+ export { SessionCard } from './SessionCard';
14
+ export { Crest, type CrestProps } from './Crest';
15
+ export { UserAvatar, type UserAvatarProps, type UserAvatarSize } from './UserAvatar';
16
+ export { Scoreboard, type ScoreboardProps, MatchupSide, type MatchupSideProps, ScoreCenter, type ScoreCenterProps, resolveMatchup, type Matchup, } from './Scoreboard';
17
+ export { MatchupRow, type MatchupRowProps } from './MatchupRow';
18
+ export { SessionStatusTimeline, type SessionStatusTimelineProps } from './SessionStatusTimeline';
19
+ export { FilterSelect } from './FilterSelect';
20
+ export type { FilterOption } from './FilterSelect';
21
+ export { CursorPager } from './CursorPager';
22
+ export { FormField, fieldInputClass } from './form';
23
+ export { AthleteSelect } from './AthleteSelect';
24
+ export type { AthleteSelectValue } from './AthleteSelect';
25
+ export { UserSearchSelect } from './UserSearchSelect';
26
+ export type { UserSelectValue } from './UserSearchSelect';
27
+ export { DrillVideoLink } from './DrillVideoLink';
28
+ export * from './viz';
29
+ export { SPORT_ICONS, SPORT_LABELS, PROGRAM_LEVEL_LABELS, MEMBER_ROLE_LABELS, FIXTURE_TYPE_LABELS, SESSION_TYPE_LABELS, METRIC_TYPE_LABELS, SPORT_OPTIONS, PROGRAM_LEVEL_OPTIONS, MEMBER_ROLE_OPTIONS, FIXTURE_TYPE_OPTIONS, SESSION_TYPE_OPTIONS, humanizeEnum, } from './domain';
30
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/atheletebridge/components/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AACrF,OAAO,EACL,UAAU,EACV,KAAK,eAAe,EACpB,WAAW,EACX,KAAK,gBAAgB,EACrB,WAAW,EACX,KAAK,gBAAgB,EACrB,cAAc,EACd,KAAK,OAAO,GACb,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,KAAK,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AACjG,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,cAAc,OAAO,CAAC;AACtB,OAAO,EACL,WAAW,EACX,YAAY,EACZ,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,EACb,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,YAAY,GACb,MAAM,UAAU,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { Person } from './lib/types';
2
+
3
+ export interface AvatarStackProps {
4
+ people: Person[];
5
+ /** Maximum avatars shown before collapsing into a "+N" chip. */
6
+ max?: number;
7
+ /** Pixel diameter of each avatar. */
8
+ size?: number;
9
+ className?: string;
10
+ }
11
+ /** Overlapping avatars with a "+N" overflow chip. */
12
+ export declare function AvatarStack({ people, max, size, className }: AvatarStackProps): import("react").JSX.Element | null;
13
+ //# sourceMappingURL=AvatarStack.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AvatarStack.d.ts","sourceRoot":"","sources":["../../../../src/atheletebridge/components/viz/AvatarStack.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,gEAAgE;IAChE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qDAAqD;AACrD,wBAAgB,WAAW,CAAC,EAAE,MAAM,EAAE,GAAO,EAAE,IAAS,EAAE,SAAS,EAAE,EAAE,gBAAgB,sCAmCtF"}
@@ -0,0 +1,17 @@
1
+ import { Segment } from './lib/types';
2
+
3
+ export interface BarChartProps {
4
+ /** Bars to render. A `color` on a datum overrides the palette. */
5
+ series: Segment[];
6
+ height?: number;
7
+ valueFormatter?: (value: number) => string;
8
+ /** Color each bar from the categorical palette instead of a single accent. */
9
+ colorful?: boolean;
10
+ /** Hide the value label above each bar. */
11
+ hideValues?: boolean;
12
+ title?: string;
13
+ className?: string;
14
+ }
15
+ /** Vertical bar chart with value labels and an animated grow-in. */
16
+ export declare function BarChart({ series, height, valueFormatter, colorful, hideValues, title, className, }: BarChartProps): import("react").JSX.Element | null;
17
+ //# sourceMappingURL=BarChart.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BarChart.d.ts","sourceRoot":"","sources":["../../../../src/atheletebridge/components/viz/BarChart.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,aAAa;IAC5B,kEAAkE;IAClE,MAAM,EAAE,OAAO,EAAE,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAC3C,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,2CAA2C;IAC3C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAID,oEAAoE;AACpE,wBAAgB,QAAQ,CAAC,EACvB,MAAM,EACN,MAAY,EACZ,cAA8B,EAC9B,QAAgB,EAChB,UAAkB,EAClB,KAAK,EACL,SAAS,GACV,EAAE,aAAa,sCAoGf"}