@burdenoff/microfe-atheletebridge 2026.705.1 → 2026.706.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 (103) hide show
  1. package/dist/atheletebridge/AthleteBridgeRoot.js +55 -39
  2. package/dist/atheletebridge/AthleteBridgeRoot.js.map +1 -1
  3. package/dist/atheletebridge/AthleteBridgeRoutes.js +18 -6
  4. package/dist/atheletebridge/AthleteBridgeRoutes.js.map +1 -1
  5. package/dist/atheletebridge/components/Crest.js +70 -0
  6. package/dist/atheletebridge/components/Crest.js.map +1 -0
  7. package/dist/atheletebridge/components/FixtureCard.js +8 -72
  8. package/dist/atheletebridge/components/FixtureCard.js.map +1 -1
  9. package/dist/atheletebridge/components/MatchupRow.js +74 -0
  10. package/dist/atheletebridge/components/MatchupRow.js.map +1 -0
  11. package/dist/atheletebridge/components/MetricsCard.js +61 -21
  12. package/dist/atheletebridge/components/MetricsCard.js.map +1 -1
  13. package/dist/atheletebridge/components/ProgramCard.js +75 -43
  14. package/dist/atheletebridge/components/ProgramCard.js.map +1 -1
  15. package/dist/atheletebridge/components/Scoreboard.js +163 -0
  16. package/dist/atheletebridge/components/Scoreboard.js.map +1 -0
  17. package/dist/atheletebridge/components/SessionCard.js +64 -41
  18. package/dist/atheletebridge/components/SessionCard.js.map +1 -1
  19. package/dist/atheletebridge/components/SessionStatusTimeline.js +80 -0
  20. package/dist/atheletebridge/components/SessionStatusTimeline.js.map +1 -0
  21. package/dist/atheletebridge/components/StatusBadge.js +5 -5
  22. package/dist/atheletebridge/components/StatusBadge.js.map +1 -1
  23. package/dist/atheletebridge/components/TeamCard.js +65 -35
  24. package/dist/atheletebridge/components/TeamCard.js.map +1 -1
  25. package/dist/atheletebridge/components/UserAvatar.js +33 -0
  26. package/dist/atheletebridge/components/UserAvatar.js.map +1 -0
  27. package/dist/atheletebridge/components/domain.js +5 -2
  28. package/dist/atheletebridge/components/domain.js.map +1 -1
  29. package/dist/atheletebridge/components/viz/AvatarStack.js +2 -0
  30. package/dist/atheletebridge/components/viz/BarChart.js +83 -0
  31. package/dist/atheletebridge/components/viz/BarChart.js.map +1 -0
  32. package/dist/atheletebridge/components/viz/DonutChart.js +109 -0
  33. package/dist/atheletebridge/components/viz/DonutChart.js.map +1 -0
  34. package/dist/atheletebridge/components/viz/LineChart.js +123 -0
  35. package/dist/atheletebridge/components/viz/LineChart.js.map +1 -0
  36. package/dist/atheletebridge/components/viz/ProgressRing.js +6 -0
  37. package/dist/atheletebridge/components/viz/ProgressRing.js.map +1 -0
  38. package/dist/atheletebridge/components/viz/RatingStars.js +92 -0
  39. package/dist/atheletebridge/components/viz/RatingStars.js.map +1 -0
  40. package/dist/atheletebridge/components/viz/Sparkline.js +74 -0
  41. package/dist/atheletebridge/components/viz/Sparkline.js.map +1 -0
  42. package/dist/atheletebridge/components/viz/StatCard.js +60 -0
  43. package/dist/atheletebridge/components/viz/StatCard.js.map +1 -0
  44. package/dist/atheletebridge/components/viz/StepProgress.js +3 -0
  45. package/dist/atheletebridge/components/viz/Timeline.js +66 -0
  46. package/dist/atheletebridge/components/viz/Timeline.js.map +1 -0
  47. package/dist/atheletebridge/components/viz/index.js +13 -0
  48. package/dist/atheletebridge/components/viz/lib/Avatar.js +1 -0
  49. package/dist/atheletebridge/components/viz/lib/CartesianFrame.js +119 -0
  50. package/dist/atheletebridge/components/viz/lib/CartesianFrame.js.map +1 -0
  51. package/dist/atheletebridge/components/viz/lib/ResponsiveSvg.js +35 -0
  52. package/dist/atheletebridge/components/viz/lib/ResponsiveSvg.js.map +1 -0
  53. package/dist/atheletebridge/components/viz/lib/format.js +17 -0
  54. package/dist/atheletebridge/components/viz/lib/format.js.map +1 -0
  55. package/dist/atheletebridge/components/viz/lib/geometry.js +61 -0
  56. package/dist/atheletebridge/components/viz/lib/geometry.js.map +1 -0
  57. package/dist/atheletebridge/components/viz/lib/hooks.js +39 -0
  58. package/dist/atheletebridge/components/viz/lib/hooks.js.map +1 -0
  59. package/dist/atheletebridge/components/viz/lib/palette.js +27 -0
  60. package/dist/atheletebridge/components/viz/lib/palette.js.map +1 -0
  61. package/dist/atheletebridge/hooks/useAthleteBridgeApi.js +369 -163
  62. package/dist/atheletebridge/hooks/useAthleteBridgeApi.js.map +1 -1
  63. package/dist/atheletebridge/pages/DashboardPage.js +182 -117
  64. package/dist/atheletebridge/pages/DashboardPage.js.map +1 -1
  65. package/dist/atheletebridge/pages/StandingsPage.js +119 -95
  66. package/dist/atheletebridge/pages/StandingsPage.js.map +1 -1
  67. package/dist/atheletebridge/pages/analytics/CoachAnalyticsPage.js +372 -0
  68. package/dist/atheletebridge/pages/analytics/CoachAnalyticsPage.js.map +1 -0
  69. package/dist/atheletebridge/pages/athletes/AthleteProfilePage.js +511 -0
  70. package/dist/atheletebridge/pages/athletes/AthleteProfilePage.js.map +1 -0
  71. package/dist/atheletebridge/pages/fixtures/FixtureDetailPage.js +120 -131
  72. package/dist/atheletebridge/pages/fixtures/FixtureDetailPage.js.map +1 -1
  73. package/dist/atheletebridge/pages/fixtures/FixtureFormPage.js +264 -176
  74. package/dist/atheletebridge/pages/fixtures/FixtureFormPage.js.map +1 -1
  75. package/dist/atheletebridge/pages/fixtures/FixturesListPage.js +84 -47
  76. package/dist/atheletebridge/pages/fixtures/FixturesListPage.js.map +1 -1
  77. package/dist/atheletebridge/pages/performance/PerformancePage.js +435 -284
  78. package/dist/atheletebridge/pages/performance/PerformancePage.js.map +1 -1
  79. package/dist/atheletebridge/pages/programs/ProgramDetailPage.js +188 -124
  80. package/dist/atheletebridge/pages/programs/ProgramDetailPage.js.map +1 -1
  81. package/dist/atheletebridge/pages/programs/ProgramsListPage.js +56 -39
  82. package/dist/atheletebridge/pages/programs/ProgramsListPage.js.map +1 -1
  83. package/dist/atheletebridge/pages/sessions/SessionDetailPage.js +268 -139
  84. package/dist/atheletebridge/pages/sessions/SessionDetailPage.js.map +1 -1
  85. package/dist/atheletebridge/pages/sessions/SessionFormPage.js +254 -162
  86. package/dist/atheletebridge/pages/sessions/SessionFormPage.js.map +1 -1
  87. package/dist/atheletebridge/pages/sessions/SessionsListPage.js +38 -36
  88. package/dist/atheletebridge/pages/sessions/SessionsListPage.js.map +1 -1
  89. package/dist/atheletebridge/pages/teams/TeamDetailPage.js +437 -189
  90. package/dist/atheletebridge/pages/teams/TeamDetailPage.js.map +1 -1
  91. package/dist/atheletebridge/pages/teams/TeamFormPage.js +368 -177
  92. package/dist/atheletebridge/pages/teams/TeamFormPage.js.map +1 -1
  93. package/dist/atheletebridge/pages/teams/TeamsListPage.js +3 -0
  94. package/dist/atheletebridge/pages/teams/TeamsListPage.js.map +1 -1
  95. package/dist/atheletebridge/pages/tournaments/TournamentBracketPage.js +298 -0
  96. package/dist/atheletebridge/pages/tournaments/TournamentBracketPage.js.map +1 -0
  97. package/dist/atheletebridge/utils/identity.js +31 -0
  98. package/dist/atheletebridge/utils/identity.js.map +1 -0
  99. package/dist/atheletebridge/utils/timeAgo.js +20 -0
  100. package/dist/atheletebridge/utils/timeAgo.js.map +1 -0
  101. package/dist/atheletebridge/utils/url.js +17 -0
  102. package/dist/atheletebridge/utils/url.js.map +1 -0
  103. package/package.json +1 -1
@@ -4,102 +4,118 @@ import { useCallback as n, useEffect as r } from "react";
4
4
  import { QueryClient as i, QueryClientProvider as a } from "@tanstack/react-query";
5
5
  import { useI18n as o } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
6
6
  import { FeatureFlagProvider as s } from "@burdenoff/fe-libs/shared/feature-flags";
7
- import { CalendarDays as c, ClipboardCheck as l, Dumbbell as u, Gauge as d, LayoutDashboard as f, Trophy as p, Users as m } from "lucide-react";
8
- import { jsx as h } from "react/jsx-runtime";
7
+ import { BarChart3 as c, CalendarDays as l, ClipboardCheck as u, Dumbbell as d, Gauge as f, LayoutDashboard as p, Swords as m, Trophy as h, Users as g } from "lucide-react";
8
+ import { jsx as _ } from "react/jsx-runtime";
9
9
  //#region src/atheletebridge/AthleteBridgeRoot.tsx
10
- var g = new i({ defaultOptions: { queries: {
10
+ var v = new i({ defaultOptions: { queries: {
11
11
  staleTime: 300 * 1e3,
12
12
  retry: 1
13
- } } }), _ = (i) => {
14
- let { registerNavItems: _, registerFooterItems: v, basePath: y = "/" } = i, { t: b } = o(), x = n((e, t) => {
15
- let n = b(e);
13
+ } } }), y = (i) => {
14
+ let { registerNavItems: y, registerFooterItems: b, basePath: x = "/" } = i, { t: S } = o(), C = n((e, t) => {
15
+ let n = S(e);
16
16
  return n === e ? t : n;
17
- }, [b]), S = (e, t) => (e.endsWith("/") ? e.slice(0, -1) : e) + (t.startsWith("/") ? t : `/${t}`);
17
+ }, [S]), w = (e, t) => (e.endsWith("/") ? e.slice(0, -1) : e) + (t.startsWith("/") ? t : `/${t}`);
18
18
  return r(() => {
19
- if (_) return _([
19
+ if (y) return y([
20
20
  {
21
21
  id: "atheletebridge-dashboard",
22
- label: x("atheletebridge.nav.dashboard", "Dashboard"),
23
- path: S(y, ""),
24
- icon: /* @__PURE__ */ h(f, { size: 20 }),
22
+ label: C("atheletebridge.nav.dashboard", "Dashboard"),
23
+ path: w(x, ""),
24
+ icon: /* @__PURE__ */ _(p, { size: 20 }),
25
25
  order: 1,
26
26
  group: "main"
27
27
  },
28
28
  {
29
29
  id: "atheletebridge-teams",
30
- label: x("atheletebridge.nav.teams", "Teams"),
31
- path: S(y, "teams"),
32
- icon: /* @__PURE__ */ h(m, { size: 20 }),
30
+ label: C("atheletebridge.nav.teams", "Teams"),
31
+ path: w(x, "teams"),
32
+ icon: /* @__PURE__ */ _(g, { size: 20 }),
33
33
  order: 10,
34
34
  group: "roster"
35
35
  },
36
36
  {
37
37
  id: "atheletebridge-fixtures",
38
- label: x("atheletebridge.nav.fixtures", "Fixtures"),
39
- path: S(y, "fixtures"),
40
- icon: /* @__PURE__ */ h(c, { size: 20 }),
38
+ label: C("atheletebridge.nav.fixtures", "Fixtures"),
39
+ path: w(x, "fixtures"),
40
+ icon: /* @__PURE__ */ _(l, { size: 20 }),
41
41
  order: 11,
42
42
  group: "roster"
43
43
  },
44
44
  {
45
45
  id: "atheletebridge-standings",
46
- label: x("atheletebridge.nav.standings", "Standings"),
47
- path: S(y, "standings"),
48
- icon: /* @__PURE__ */ h(p, { size: 20 }),
46
+ label: C("atheletebridge.nav.standings", "Standings"),
47
+ path: w(x, "standings"),
48
+ icon: /* @__PURE__ */ _(h, { size: 20 }),
49
49
  order: 12,
50
50
  group: "roster"
51
51
  },
52
+ {
53
+ id: "atheletebridge-tournaments",
54
+ label: C("atheletebridge.nav.tournaments", "Tournaments"),
55
+ path: w(x, "tournaments"),
56
+ icon: /* @__PURE__ */ _(m, { size: 20 }),
57
+ order: 13,
58
+ group: "roster"
59
+ },
52
60
  {
53
61
  id: "atheletebridge-programs",
54
- label: x("atheletebridge.nav.programs", "Programs"),
55
- path: S(y, "programs"),
56
- icon: /* @__PURE__ */ h(u, { size: 20 }),
62
+ label: C("atheletebridge.nav.programs", "Programs"),
63
+ path: w(x, "programs"),
64
+ icon: /* @__PURE__ */ _(d, { size: 20 }),
57
65
  order: 20,
58
66
  group: "training"
59
67
  },
60
68
  {
61
69
  id: "atheletebridge-sessions",
62
- label: x("atheletebridge.nav.sessions", "Sessions"),
63
- path: S(y, "sessions"),
64
- icon: /* @__PURE__ */ h(l, { size: 20 }),
70
+ label: C("atheletebridge.nav.sessions", "Sessions"),
71
+ path: w(x, "sessions"),
72
+ icon: /* @__PURE__ */ _(u, { size: 20 }),
65
73
  order: 21,
66
74
  group: "training"
67
75
  },
68
76
  {
69
77
  id: "atheletebridge-performance",
70
- label: x("atheletebridge.nav.performance", "Performance"),
71
- path: S(y, "performance"),
72
- icon: /* @__PURE__ */ h(d, { size: 20 }),
78
+ label: C("atheletebridge.nav.performance", "Performance"),
79
+ path: w(x, "performance"),
80
+ icon: /* @__PURE__ */ _(f, { size: 20 }),
73
81
  order: 22,
74
82
  group: "training"
83
+ },
84
+ {
85
+ id: "atheletebridge-analytics",
86
+ label: C("atheletebridge.nav.analytics", "Analytics"),
87
+ path: w(x, "analytics"),
88
+ icon: /* @__PURE__ */ _(c, { size: 20 }),
89
+ order: 23,
90
+ group: "training"
75
91
  }
76
92
  ]);
77
93
  }, [
78
- _,
79
94
  y,
80
- x
95
+ x,
96
+ C
81
97
  ]), r(() => {
82
- if (v) return v([{
98
+ if (b) return b([{
83
99
  id: "atheletebridge-status",
84
- label: x("atheletebridge.footer.ready", "AthleteBridge Ready"),
100
+ label: C("atheletebridge.footer.ready", "AthleteBridge Ready"),
85
101
  type: "status",
86
102
  order: 10,
87
103
  section: "left"
88
104
  }]);
89
- }, [v, x]), /* @__PURE__ */ h(a, {
90
- client: g,
91
- children: /* @__PURE__ */ h(s, {
105
+ }, [b, C]), /* @__PURE__ */ _(a, {
106
+ client: v,
107
+ children: /* @__PURE__ */ _(s, {
92
108
  workspaceId: null,
93
109
  gateway: "global",
94
110
  defaultEnabled: !0,
95
- children: /* @__PURE__ */ h(e, {
111
+ children: /* @__PURE__ */ _(e, {
96
112
  ...i,
97
- children: /* @__PURE__ */ h(t, {})
113
+ children: /* @__PURE__ */ _(t, {})
98
114
  })
99
115
  })
100
116
  });
101
117
  };
102
118
  //#endregion
103
- export { _ as AthleteBridgeRoot };
119
+ export { y as AthleteBridgeRoot };
104
120
 
105
121
  //# sourceMappingURL=AthleteBridgeRoot.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AthleteBridgeRoot.js","names":[],"sources":["../../src/atheletebridge/AthleteBridgeRoot.tsx"],"sourcesContent":["/**\n * AthleteBridge Root Component\n * @module atheletebridge\n *\n * The single Root export consumed by the host app shell. The export name and\n * props (AthleteBridgeRootProps) are the host contract and must not change —\n * only the internal nav config, provider tree, and routes are product-specific.\n */\n\nimport type { FC } from 'react';\nimport { useCallback, useEffect } from 'react';\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { FeatureFlagProvider } from '@burdenoff/fe-libs/shared/feature-flags';\nimport {\n LayoutDashboard,\n Users,\n CalendarDays,\n Trophy,\n Dumbbell,\n ClipboardCheck,\n Gauge,\n} from 'lucide-react';\nimport { AthleteBridgeProvider } from './context/AthleteBridgeContext';\nimport { AthleteBridgeRoutes } from './AthleteBridgeRoutes';\nimport type { AthleteBridgeRootProps, NavItem } from './types';\n\n// Create a query client for this microfrontend\nconst queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 5 * 60 * 1000,\n retry: 1,\n },\n },\n});\n\nexport const AthleteBridgeRoot: FC<AthleteBridgeRootProps> = (props) => {\n const { registerNavItems, registerFooterItems, basePath = '/' } = props;\n const { t: translate } = useI18n();\n const t = useCallback(\n (key: string, fallback: string): string => {\n const value = translate(key);\n return value === key ? fallback : value;\n },\n [translate]\n );\n\n // Helper to join paths correctly\n const joinPath = (base: string, path: string): string => {\n const cleanBase = base.endsWith('/') ? base.slice(0, -1) : base;\n const cleanPath = path.startsWith('/') ? path : `/${path}`;\n return cleanBase + cleanPath;\n };\n\n // Register navigation items with shell on mount\n useEffect(() => {\n if (!registerNavItems) return;\n\n const navItems: NavItem[] = [\n {\n id: 'atheletebridge-dashboard',\n label: t('atheletebridge.nav.dashboard', 'Dashboard'),\n path: joinPath(basePath, ''),\n icon: <LayoutDashboard size={20} />,\n order: 1,\n group: 'main',\n },\n {\n id: 'atheletebridge-teams',\n label: t('atheletebridge.nav.teams', 'Teams'),\n path: joinPath(basePath, 'teams'),\n icon: <Users size={20} />,\n order: 10,\n group: 'roster',\n },\n {\n id: 'atheletebridge-fixtures',\n label: t('atheletebridge.nav.fixtures', 'Fixtures'),\n path: joinPath(basePath, 'fixtures'),\n icon: <CalendarDays size={20} />,\n order: 11,\n group: 'roster',\n },\n {\n id: 'atheletebridge-standings',\n label: t('atheletebridge.nav.standings', 'Standings'),\n path: joinPath(basePath, 'standings'),\n icon: <Trophy size={20} />,\n order: 12,\n group: 'roster',\n },\n {\n id: 'atheletebridge-programs',\n label: t('atheletebridge.nav.programs', 'Programs'),\n path: joinPath(basePath, 'programs'),\n icon: <Dumbbell size={20} />,\n order: 20,\n group: 'training',\n },\n {\n id: 'atheletebridge-sessions',\n label: t('atheletebridge.nav.sessions', 'Sessions'),\n path: joinPath(basePath, 'sessions'),\n icon: <ClipboardCheck size={20} />,\n order: 21,\n group: 'training',\n },\n {\n id: 'atheletebridge-performance',\n label: t('atheletebridge.nav.performance', 'Performance'),\n path: joinPath(basePath, 'performance'),\n icon: <Gauge size={20} />,\n order: 22,\n group: 'training',\n },\n ];\n\n const cleanup = registerNavItems(navItems);\n return cleanup;\n }, [registerNavItems, basePath, t]);\n\n // Register footer items\n useEffect(() => {\n if (!registerFooterItems) return;\n\n const footerItems = [\n {\n id: 'atheletebridge-status',\n label: t('atheletebridge.footer.ready', 'AthleteBridge Ready'),\n type: 'status' as const,\n order: 10,\n section: 'left' as const,\n },\n ];\n\n const cleanup = registerFooterItems(footerItems);\n return cleanup;\n }, [registerFooterItems, t]);\n\n return (\n <QueryClientProvider client={queryClient}>\n <FeatureFlagProvider workspaceId={null} gateway=\"global\" defaultEnabled={true}>\n <AthleteBridgeProvider {...props}>\n <AthleteBridgeRoutes />\n </AthleteBridgeProvider>\n </FeatureFlagProvider>\n </QueryClientProvider>\n );\n};\n"],"mappings":";;;;;;;;;AA4BA,IAAM,IAAc,IAAI,EAAY,EAClC,gBAAgB,EACd,SAAS;CACP,WAAW,MAAS;CACpB,OAAO;CACR,EACF,EACF,CAAC,EAEW,KAAiD,MAAU;CACtE,IAAM,EAAE,qBAAkB,wBAAqB,cAAW,QAAQ,GAC5D,EAAE,GAAG,MAAc,GAAS,EAC5B,IAAI,GACP,GAAa,MAA6B;EACzC,IAAM,IAAQ,EAAU,EAAI;AAC5B,SAAO,MAAU,IAAM,IAAW;IAEpC,CAAC,EAAU,CACZ,EAGK,KAAY,GAAc,OACZ,EAAK,SAAS,IAAI,GAAG,EAAK,MAAM,GAAG,GAAG,GAAG,MACzC,EAAK,WAAW,IAAI,GAAG,IAAO,IAAI;AAyFtD,QApFA,QAAgB;AACT,QA8DL,QADgB,EA3DY;GAC1B;IACE,IAAI;IACJ,OAAO,EAAE,gCAAgC,YAAY;IACrD,MAAM,EAAS,GAAU,GAAG;IAC5B,MAAM,kBAAC,GAAD,EAAiB,MAAM,IAAM,CAAA;IACnC,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,4BAA4B,QAAQ;IAC7C,MAAM,EAAS,GAAU,QAAQ;IACjC,MAAM,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;IACzB,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,+BAA+B,WAAW;IACnD,MAAM,EAAS,GAAU,WAAW;IACpC,MAAM,kBAAC,GAAD,EAAc,MAAM,IAAM,CAAA;IAChC,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,gCAAgC,YAAY;IACrD,MAAM,EAAS,GAAU,YAAY;IACrC,MAAM,kBAAC,GAAD,EAAQ,MAAM,IAAM,CAAA;IAC1B,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,+BAA+B,WAAW;IACnD,MAAM,EAAS,GAAU,WAAW;IACpC,MAAM,kBAAC,GAAD,EAAU,MAAM,IAAM,CAAA;IAC5B,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,+BAA+B,WAAW;IACnD,MAAM,EAAS,GAAU,WAAW;IACpC,MAAM,kBAAC,GAAD,EAAgB,MAAM,IAAM,CAAA;IAClC,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,kCAAkC,cAAc;IACzD,MAAM,EAAS,GAAU,cAAc;IACvC,MAAM,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;IACzB,OAAO;IACP,OAAO;IACR;GACF,CAEyC;IAEzC;EAAC;EAAkB;EAAU;EAAE,CAAC,EAGnC,QAAgB;AACT,QAaL,QADgB,EAVI,CAClB;GACE,IAAI;GACJ,OAAO,EAAE,+BAA+B,sBAAsB;GAC9D,MAAM;GACN,OAAO;GACP,SAAS;GACV,CACF,CAE+C;IAE/C,CAAC,GAAqB,EAAE,CAAC,EAG1B,kBAAC,GAAD;EAAqB,QAAQ;YAC3B,kBAAC,GAAD;GAAqB,aAAa;GAAM,SAAQ;GAAS,gBAAgB;aACvE,kBAAC,GAAD;IAAuB,GAAI;cACzB,kBAAC,GAAD,EAAuB,CAAA;IACD,CAAA;GACJ,CAAA;EACF,CAAA"}
1
+ {"version":3,"file":"AthleteBridgeRoot.js","names":[],"sources":["../../src/atheletebridge/AthleteBridgeRoot.tsx"],"sourcesContent":["/**\n * AthleteBridge Root Component\n * @module atheletebridge\n *\n * The single Root export consumed by the host app shell. The export name and\n * props (AthleteBridgeRootProps) are the host contract and must not change —\n * only the internal nav config, provider tree, and routes are product-specific.\n */\n\nimport type { FC } from 'react';\nimport { useCallback, useEffect } from 'react';\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { FeatureFlagProvider } from '@burdenoff/fe-libs/shared/feature-flags';\nimport {\n LayoutDashboard,\n Users,\n CalendarDays,\n Trophy,\n Dumbbell,\n ClipboardCheck,\n Gauge,\n BarChart3,\n Swords,\n} from 'lucide-react';\nimport { AthleteBridgeProvider } from './context/AthleteBridgeContext';\nimport { AthleteBridgeRoutes } from './AthleteBridgeRoutes';\nimport type { AthleteBridgeRootProps, NavItem } from './types';\n\n// Create a query client for this microfrontend\nconst queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 5 * 60 * 1000,\n retry: 1,\n },\n },\n});\n\nexport const AthleteBridgeRoot: FC<AthleteBridgeRootProps> = (props) => {\n const { registerNavItems, registerFooterItems, basePath = '/' } = props;\n const { t: translate } = useI18n();\n const t = useCallback(\n (key: string, fallback: string): string => {\n const value = translate(key);\n return value === key ? fallback : value;\n },\n [translate]\n );\n\n // Helper to join paths correctly\n const joinPath = (base: string, path: string): string => {\n const cleanBase = base.endsWith('/') ? base.slice(0, -1) : base;\n const cleanPath = path.startsWith('/') ? path : `/${path}`;\n return cleanBase + cleanPath;\n };\n\n // Register navigation items with shell on mount\n useEffect(() => {\n if (!registerNavItems) return;\n\n const navItems: NavItem[] = [\n {\n id: 'atheletebridge-dashboard',\n label: t('atheletebridge.nav.dashboard', 'Dashboard'),\n path: joinPath(basePath, ''),\n icon: <LayoutDashboard size={20} />,\n order: 1,\n group: 'main',\n },\n {\n id: 'atheletebridge-teams',\n label: t('atheletebridge.nav.teams', 'Teams'),\n path: joinPath(basePath, 'teams'),\n icon: <Users size={20} />,\n order: 10,\n group: 'roster',\n },\n {\n id: 'atheletebridge-fixtures',\n label: t('atheletebridge.nav.fixtures', 'Fixtures'),\n path: joinPath(basePath, 'fixtures'),\n icon: <CalendarDays size={20} />,\n order: 11,\n group: 'roster',\n },\n {\n id: 'atheletebridge-standings',\n label: t('atheletebridge.nav.standings', 'Standings'),\n path: joinPath(basePath, 'standings'),\n icon: <Trophy size={20} />,\n order: 12,\n group: 'roster',\n },\n {\n id: 'atheletebridge-tournaments',\n label: t('atheletebridge.nav.tournaments', 'Tournaments'),\n path: joinPath(basePath, 'tournaments'),\n icon: <Swords size={20} />,\n order: 13,\n group: 'roster',\n },\n {\n id: 'atheletebridge-programs',\n label: t('atheletebridge.nav.programs', 'Programs'),\n path: joinPath(basePath, 'programs'),\n icon: <Dumbbell size={20} />,\n order: 20,\n group: 'training',\n },\n {\n id: 'atheletebridge-sessions',\n label: t('atheletebridge.nav.sessions', 'Sessions'),\n path: joinPath(basePath, 'sessions'),\n icon: <ClipboardCheck size={20} />,\n order: 21,\n group: 'training',\n },\n {\n id: 'atheletebridge-performance',\n label: t('atheletebridge.nav.performance', 'Performance'),\n path: joinPath(basePath, 'performance'),\n icon: <Gauge size={20} />,\n order: 22,\n group: 'training',\n },\n {\n id: 'atheletebridge-analytics',\n label: t('atheletebridge.nav.analytics', 'Analytics'),\n path: joinPath(basePath, 'analytics'),\n icon: <BarChart3 size={20} />,\n order: 23,\n group: 'training',\n },\n ];\n\n const cleanup = registerNavItems(navItems);\n return cleanup;\n }, [registerNavItems, basePath, t]);\n\n // Register footer items\n useEffect(() => {\n if (!registerFooterItems) return;\n\n const footerItems = [\n {\n id: 'atheletebridge-status',\n label: t('atheletebridge.footer.ready', 'AthleteBridge Ready'),\n type: 'status' as const,\n order: 10,\n section: 'left' as const,\n },\n ];\n\n const cleanup = registerFooterItems(footerItems);\n return cleanup;\n }, [registerFooterItems, t]);\n\n return (\n <QueryClientProvider client={queryClient}>\n <FeatureFlagProvider workspaceId={null} gateway=\"global\" defaultEnabled={true}>\n <AthleteBridgeProvider {...props}>\n <AthleteBridgeRoutes />\n </AthleteBridgeProvider>\n </FeatureFlagProvider>\n </QueryClientProvider>\n );\n};\n"],"mappings":";;;;;;;;;AA8BA,IAAM,IAAc,IAAI,EAAY,EAClC,gBAAgB,EACd,SAAS;CACP,WAAW,MAAS;CACpB,OAAO;CACR,EACF,EACF,CAAC,EAEW,KAAiD,MAAU;CACtE,IAAM,EAAE,qBAAkB,wBAAqB,cAAW,QAAQ,GAC5D,EAAE,GAAG,MAAc,GAAS,EAC5B,IAAI,GACP,GAAa,MAA6B;EACzC,IAAM,IAAQ,EAAU,EAAI;AAC5B,SAAO,MAAU,IAAM,IAAW;IAEpC,CAAC,EAAU,CACZ,EAGK,KAAY,GAAc,OACZ,EAAK,SAAS,IAAI,GAAG,EAAK,MAAM,GAAG,GAAG,GAAG,MACzC,EAAK,WAAW,IAAI,GAAG,IAAO,IAAI;AAyGtD,QApGA,QAAgB;AACT,QA8EL,QADgB,EA3EY;GAC1B;IACE,IAAI;IACJ,OAAO,EAAE,gCAAgC,YAAY;IACrD,MAAM,EAAS,GAAU,GAAG;IAC5B,MAAM,kBAAC,GAAD,EAAiB,MAAM,IAAM,CAAA;IACnC,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,4BAA4B,QAAQ;IAC7C,MAAM,EAAS,GAAU,QAAQ;IACjC,MAAM,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;IACzB,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,+BAA+B,WAAW;IACnD,MAAM,EAAS,GAAU,WAAW;IACpC,MAAM,kBAAC,GAAD,EAAc,MAAM,IAAM,CAAA;IAChC,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,gCAAgC,YAAY;IACrD,MAAM,EAAS,GAAU,YAAY;IACrC,MAAM,kBAAC,GAAD,EAAQ,MAAM,IAAM,CAAA;IAC1B,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,kCAAkC,cAAc;IACzD,MAAM,EAAS,GAAU,cAAc;IACvC,MAAM,kBAAC,GAAD,EAAQ,MAAM,IAAM,CAAA;IAC1B,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,+BAA+B,WAAW;IACnD,MAAM,EAAS,GAAU,WAAW;IACpC,MAAM,kBAAC,GAAD,EAAU,MAAM,IAAM,CAAA;IAC5B,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,+BAA+B,WAAW;IACnD,MAAM,EAAS,GAAU,WAAW;IACpC,MAAM,kBAAC,GAAD,EAAgB,MAAM,IAAM,CAAA;IAClC,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,kCAAkC,cAAc;IACzD,MAAM,EAAS,GAAU,cAAc;IACvC,MAAM,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;IACzB,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO,EAAE,gCAAgC,YAAY;IACrD,MAAM,EAAS,GAAU,YAAY;IACrC,MAAM,kBAAC,GAAD,EAAW,MAAM,IAAM,CAAA;IAC7B,OAAO;IACP,OAAO;IACR;GACF,CAEyC;IAEzC;EAAC;EAAkB;EAAU;EAAE,CAAC,EAGnC,QAAgB;AACT,QAaL,QADgB,EAVI,CAClB;GACE,IAAI;GACJ,OAAO,EAAE,+BAA+B,sBAAsB;GAC9D,MAAM;GACN,OAAO;GACP,SAAS;GACV,CACF,CAE+C;IAE/C,CAAC,GAAqB,EAAE,CAAC,EAG1B,kBAAC,GAAD;EAAqB,QAAQ;YAC3B,kBAAC,GAAD;GAAqB,aAAa;GAAM,SAAQ;GAAS,gBAAgB;aACvE,kBAAC,GAAD;IAAuB,GAAI;cACzB,kBAAC,GAAD,EAAuB,CAAA;IACD,CAAA;GACJ,CAAA;EACF,CAAA"}
@@ -5,15 +5,15 @@ import { Loader2 as i } from "lucide-react";
5
5
  import { Navigate as a, Route as o, Routes as s, useLocation as c } from "react-router-dom";
6
6
  import { jsx as l, jsxs as u } from "react/jsx-runtime";
7
7
  //#region src/atheletebridge/AthleteBridgeRoutes.tsx
8
- var d = r(() => import("./pages/teams/TeamsListPage.js").then((e) => ({ default: e.TeamsListPage }))), f = r(() => import("./pages/teams/TeamDetailPage.js").then((e) => ({ default: e.TeamDetailPage }))), p = r(() => import("./pages/teams/TeamFormPage.js").then((e) => ({ default: e.TeamFormPage }))), m = r(() => import("./pages/fixtures/FixturesListPage.js").then((e) => ({ default: e.FixturesListPage }))), h = r(() => import("./pages/fixtures/FixtureDetailPage.js").then((e) => ({ default: e.FixtureDetailPage }))), g = r(() => import("./pages/fixtures/FixtureFormPage.js").then((e) => ({ default: e.FixtureFormPage }))), _ = r(() => import("./pages/StandingsPage.js").then((e) => ({ default: e.StandingsPage }))), v = r(() => import("./pages/programs/ProgramsListPage.js").then((e) => ({ default: e.ProgramsListPage }))), y = r(() => import("./pages/programs/ProgramDetailPage.js").then((e) => ({ default: e.ProgramDetailPage }))), b = r(() => import("./pages/programs/ProgramFormPage.js").then((e) => ({ default: e.ProgramFormPage }))), x = r(() => import("./pages/sessions/SessionsListPage.js").then((e) => ({ default: e.SessionsListPage }))), S = r(() => import("./pages/sessions/SessionDetailPage.js").then((e) => ({ default: e.SessionDetailPage }))), C = r(() => import("./pages/sessions/SessionFormPage.js").then((e) => ({ default: e.SessionFormPage }))), w = r(() => import("./pages/performance/PerformancePage.js").then((e) => ({ default: e.PerformancePage }))), T = () => /* @__PURE__ */ l("div", {
8
+ var d = r(() => import("./pages/teams/TeamsListPage.js").then((e) => ({ default: e.TeamsListPage }))), f = r(() => import("./pages/teams/TeamDetailPage.js").then((e) => ({ default: e.TeamDetailPage }))), p = r(() => import("./pages/teams/TeamFormPage.js").then((e) => ({ default: e.TeamFormPage }))), m = r(() => import("./pages/fixtures/FixturesListPage.js").then((e) => ({ default: e.FixturesListPage }))), h = r(() => import("./pages/fixtures/FixtureDetailPage.js").then((e) => ({ default: e.FixtureDetailPage }))), g = r(() => import("./pages/fixtures/FixtureFormPage.js").then((e) => ({ default: e.FixtureFormPage }))), _ = r(() => import("./pages/StandingsPage.js").then((e) => ({ default: e.StandingsPage }))), v = r(() => import("./pages/programs/ProgramsListPage.js").then((e) => ({ default: e.ProgramsListPage }))), y = r(() => import("./pages/programs/ProgramDetailPage.js").then((e) => ({ default: e.ProgramDetailPage }))), b = r(() => import("./pages/programs/ProgramFormPage.js").then((e) => ({ default: e.ProgramFormPage }))), x = r(() => import("./pages/sessions/SessionsListPage.js").then((e) => ({ default: e.SessionsListPage }))), S = r(() => import("./pages/sessions/SessionDetailPage.js").then((e) => ({ default: e.SessionDetailPage }))), C = r(() => import("./pages/sessions/SessionFormPage.js").then((e) => ({ default: e.SessionFormPage }))), w = r(() => import("./pages/performance/PerformancePage.js").then((e) => ({ default: e.PerformancePage }))), T = r(() => import("./pages/athletes/AthleteProfilePage.js").then((e) => ({ default: e.AthleteProfilePage }))), E = r(() => import("./pages/analytics/CoachAnalyticsPage.js").then((e) => ({ default: e.CoachAnalyticsPage }))), D = r(() => import("./pages/tournaments/TournamentBracketPage.js").then((e) => ({ default: e.TournamentBracketPage }))), O = () => /* @__PURE__ */ l("div", {
9
9
  className: "flex min-h-[400px] items-center justify-center",
10
10
  children: /* @__PURE__ */ l(i, { className: "h-8 w-8 animate-spin text-text-secondary" })
11
- }), E = () => {
12
- let { basePath: r, isStandalone: i } = e(), E = c(), D = r === "/" ? "" : (r ?? "").replace(/\/$/, "");
13
- return D && !i && !(E.pathname === D || E.pathname.startsWith(D + "/")) ? null : /* @__PURE__ */ l("div", {
11
+ }), k = () => {
12
+ let { basePath: r, isStandalone: i } = e(), k = c(), A = r === "/" ? "" : (r ?? "").replace(/\/$/, "");
13
+ return A && !i && !(k.pathname === A || k.pathname.startsWith(A + "/")) ? null : /* @__PURE__ */ l("div", {
14
14
  className: "flex min-h-full flex-col",
15
15
  children: /* @__PURE__ */ l(n, {
16
- fallback: /* @__PURE__ */ l(T, {}),
16
+ fallback: /* @__PURE__ */ l(O, {}),
17
17
  children: /* @__PURE__ */ u(s, { children: [
18
18
  /* @__PURE__ */ l(o, {
19
19
  index: !0,
@@ -35,6 +35,10 @@ var d = r(() => import("./pages/teams/TeamsListPage.js").then((e) => ({ default:
35
35
  path: "teams/:id/edit",
36
36
  element: /* @__PURE__ */ l(p, {})
37
37
  }),
38
+ /* @__PURE__ */ l(o, {
39
+ path: "teams/:teamId/athletes/:memberId",
40
+ element: /* @__PURE__ */ l(T, {})
41
+ }),
38
42
  /* @__PURE__ */ l(o, {
39
43
  path: "fixtures",
40
44
  element: /* @__PURE__ */ l(m, {})
@@ -83,6 +87,14 @@ var d = r(() => import("./pages/teams/TeamsListPage.js").then((e) => ({ default:
83
87
  path: "performance",
84
88
  element: /* @__PURE__ */ l(w, {})
85
89
  }),
90
+ /* @__PURE__ */ l(o, {
91
+ path: "analytics",
92
+ element: /* @__PURE__ */ l(E, {})
93
+ }),
94
+ /* @__PURE__ */ l(o, {
95
+ path: "tournaments",
96
+ element: /* @__PURE__ */ l(D, {})
97
+ }),
86
98
  /* @__PURE__ */ l(o, {
87
99
  path: "*",
88
100
  element: /* @__PURE__ */ l(a, {
@@ -95,6 +107,6 @@ var d = r(() => import("./pages/teams/TeamsListPage.js").then((e) => ({ default:
95
107
  });
96
108
  };
97
109
  //#endregion
98
- export { E as AthleteBridgeRoutes };
110
+ export { k as AthleteBridgeRoutes };
99
111
 
100
112
  //# sourceMappingURL=AthleteBridgeRoutes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AthleteBridgeRoutes.js","names":[],"sources":["../../src/atheletebridge/AthleteBridgeRoutes.tsx"],"sourcesContent":["/**\n * AthleteBridge Routes\n * @module atheletebridge\n *\n * Real sports-domain routes wired to the deployed `wspace-atheletebridge-svc`\n * GraphQL contract. Dashboard is eager; entity pages are lazy.\n */\n\nimport { type FC, lazy, Suspense } from 'react';\nimport { Routes, Route, Navigate, useLocation } from 'react-router-dom';\nimport { Loader2 } from 'lucide-react';\nimport { useAthleteBridge } from './context/AthleteBridgeContext';\n\n// Eager — primary landing\nimport { DashboardPage } from './pages/DashboardPage';\n\n// Teams\nconst TeamsListPage = lazy(() =>\n import('./pages/teams/TeamsListPage').then((m) => ({ default: m.TeamsListPage }))\n);\nconst TeamDetailPage = lazy(() =>\n import('./pages/teams/TeamDetailPage').then((m) => ({ default: m.TeamDetailPage }))\n);\nconst TeamFormPage = lazy(() =>\n import('./pages/teams/TeamFormPage').then((m) => ({ default: m.TeamFormPage }))\n);\n\n// Fixtures\nconst FixturesListPage = lazy(() =>\n import('./pages/fixtures/FixturesListPage').then((m) => ({ default: m.FixturesListPage }))\n);\nconst FixtureDetailPage = lazy(() =>\n import('./pages/fixtures/FixtureDetailPage').then((m) => ({ default: m.FixtureDetailPage }))\n);\nconst FixtureFormPage = lazy(() =>\n import('./pages/fixtures/FixtureFormPage').then((m) => ({ default: m.FixtureFormPage }))\n);\n\n// Standings\nconst StandingsPage = lazy(() =>\n import('./pages/StandingsPage').then((m) => ({ default: m.StandingsPage }))\n);\n\n// Programs\nconst ProgramsListPage = lazy(() =>\n import('./pages/programs/ProgramsListPage').then((m) => ({ default: m.ProgramsListPage }))\n);\nconst ProgramDetailPage = lazy(() =>\n import('./pages/programs/ProgramDetailPage').then((m) => ({ default: m.ProgramDetailPage }))\n);\nconst ProgramFormPage = lazy(() =>\n import('./pages/programs/ProgramFormPage').then((m) => ({ default: m.ProgramFormPage }))\n);\n\n// Sessions\nconst SessionsListPage = lazy(() =>\n import('./pages/sessions/SessionsListPage').then((m) => ({ default: m.SessionsListPage }))\n);\nconst SessionDetailPage = lazy(() =>\n import('./pages/sessions/SessionDetailPage').then((m) => ({ default: m.SessionDetailPage }))\n);\nconst SessionFormPage = lazy(() =>\n import('./pages/sessions/SessionFormPage').then((m) => ({ default: m.SessionFormPage }))\n);\n\n// Performance\nconst PerformancePage = lazy(() =>\n import('./pages/performance/PerformancePage').then((m) => ({ default: m.PerformancePage }))\n);\n\nconst PageLoader: FC = () => (\n <div className=\"flex min-h-[400px] items-center justify-center\">\n <Loader2 className=\"h-8 w-8 animate-spin text-text-secondary\" />\n </div>\n);\n\nexport const AthleteBridgeRoutes: FC = () => {\n const { basePath, isStandalone } = useAthleteBridge();\n const location = useLocation();\n\n const normalizedBasePath = basePath === '/' ? '' : (basePath ?? '').replace(/\\/$/, '');\n\n // Guard: only render when the path matches basePath (integrated mode).\n if (normalizedBasePath && !isStandalone) {\n const pathMatches =\n location.pathname === normalizedBasePath ||\n location.pathname.startsWith(normalizedBasePath + '/');\n if (!pathMatches) {\n return null;\n }\n }\n\n return (\n <div className=\"flex min-h-full flex-col\">\n <Suspense fallback={<PageLoader />}>\n <Routes>\n {/* Dashboard */}\n <Route index element={<DashboardPage />} />\n\n {/* Teams */}\n <Route path=\"teams\" element={<TeamsListPage />} />\n <Route path=\"teams/new\" element={<TeamFormPage />} />\n <Route path=\"teams/:id\" element={<TeamDetailPage />} />\n <Route path=\"teams/:id/edit\" element={<TeamFormPage />} />\n\n {/* Fixtures */}\n <Route path=\"fixtures\" element={<FixturesListPage />} />\n <Route path=\"fixtures/new\" element={<FixtureFormPage />} />\n <Route path=\"fixtures/:id\" element={<FixtureDetailPage />} />\n\n {/* Standings */}\n <Route path=\"standings\" element={<StandingsPage />} />\n\n {/* Programs */}\n <Route path=\"programs\" element={<ProgramsListPage />} />\n <Route path=\"programs/new\" element={<ProgramFormPage />} />\n <Route path=\"programs/:id\" element={<ProgramDetailPage />} />\n <Route path=\"programs/:id/edit\" element={<ProgramFormPage />} />\n\n {/* Sessions */}\n <Route path=\"sessions\" element={<SessionsListPage />} />\n <Route path=\"sessions/new\" element={<SessionFormPage />} />\n <Route path=\"sessions/:id\" element={<SessionDetailPage />} />\n\n {/* Performance */}\n <Route path=\"performance\" element={<PerformancePage />} />\n\n {/* Fallback */}\n <Route path=\"*\" element={<Navigate to=\".\" replace />} />\n </Routes>\n </Suspense>\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"AthleteBridgeRoutes.js","names":[],"sources":["../../src/atheletebridge/AthleteBridgeRoutes.tsx"],"sourcesContent":["/**\n * AthleteBridge Routes\n * @module atheletebridge\n *\n * Real sports-domain routes wired to the deployed `wspace-atheletebridge-svc`\n * GraphQL contract. Dashboard is eager; entity pages are lazy.\n */\n\nimport { type FC, lazy, Suspense } from 'react';\nimport { Routes, Route, Navigate, useLocation } from 'react-router-dom';\nimport { Loader2 } from 'lucide-react';\nimport { useAthleteBridge } from './context/AthleteBridgeContext';\n\n// Eager — primary landing\nimport { DashboardPage } from './pages/DashboardPage';\n\n// Teams\nconst TeamsListPage = lazy(() =>\n import('./pages/teams/TeamsListPage').then((m) => ({ default: m.TeamsListPage }))\n);\nconst TeamDetailPage = lazy(() =>\n import('./pages/teams/TeamDetailPage').then((m) => ({ default: m.TeamDetailPage }))\n);\nconst TeamFormPage = lazy(() =>\n import('./pages/teams/TeamFormPage').then((m) => ({ default: m.TeamFormPage }))\n);\n\n// Fixtures\nconst FixturesListPage = lazy(() =>\n import('./pages/fixtures/FixturesListPage').then((m) => ({ default: m.FixturesListPage }))\n);\nconst FixtureDetailPage = lazy(() =>\n import('./pages/fixtures/FixtureDetailPage').then((m) => ({ default: m.FixtureDetailPage }))\n);\nconst FixtureFormPage = lazy(() =>\n import('./pages/fixtures/FixtureFormPage').then((m) => ({ default: m.FixtureFormPage }))\n);\n\n// Standings\nconst StandingsPage = lazy(() =>\n import('./pages/StandingsPage').then((m) => ({ default: m.StandingsPage }))\n);\n\n// Programs\nconst ProgramsListPage = lazy(() =>\n import('./pages/programs/ProgramsListPage').then((m) => ({ default: m.ProgramsListPage }))\n);\nconst ProgramDetailPage = lazy(() =>\n import('./pages/programs/ProgramDetailPage').then((m) => ({ default: m.ProgramDetailPage }))\n);\nconst ProgramFormPage = lazy(() =>\n import('./pages/programs/ProgramFormPage').then((m) => ({ default: m.ProgramFormPage }))\n);\n\n// Sessions\nconst SessionsListPage = lazy(() =>\n import('./pages/sessions/SessionsListPage').then((m) => ({ default: m.SessionsListPage }))\n);\nconst SessionDetailPage = lazy(() =>\n import('./pages/sessions/SessionDetailPage').then((m) => ({ default: m.SessionDetailPage }))\n);\nconst SessionFormPage = lazy(() =>\n import('./pages/sessions/SessionFormPage').then((m) => ({ default: m.SessionFormPage }))\n);\n\n// Performance\nconst PerformancePage = lazy(() =>\n import('./pages/performance/PerformancePage').then((m) => ({ default: m.PerformancePage }))\n);\n\n// Athlete profile\nconst AthleteProfilePage = lazy(() =>\n import('./pages/athletes/AthleteProfilePage').then((m) => ({ default: m.AthleteProfilePage }))\n);\n\n// Coach analytics\nconst CoachAnalyticsPage = lazy(() =>\n import('./pages/analytics/CoachAnalyticsPage').then((m) => ({ default: m.CoachAnalyticsPage }))\n);\n\n// Tournaments (esports bracket)\nconst TournamentBracketPage = lazy(() =>\n import('./pages/tournaments/TournamentBracketPage').then((m) => ({\n default: m.TournamentBracketPage,\n }))\n);\n\nconst PageLoader: FC = () => (\n <div className=\"flex min-h-[400px] items-center justify-center\">\n <Loader2 className=\"h-8 w-8 animate-spin text-text-secondary\" />\n </div>\n);\n\nexport const AthleteBridgeRoutes: FC = () => {\n const { basePath, isStandalone } = useAthleteBridge();\n const location = useLocation();\n\n const normalizedBasePath = basePath === '/' ? '' : (basePath ?? '').replace(/\\/$/, '');\n\n // Guard: only render when the path matches basePath (integrated mode).\n if (normalizedBasePath && !isStandalone) {\n const pathMatches =\n location.pathname === normalizedBasePath ||\n location.pathname.startsWith(normalizedBasePath + '/');\n if (!pathMatches) {\n return null;\n }\n }\n\n return (\n <div className=\"flex min-h-full flex-col\">\n <Suspense fallback={<PageLoader />}>\n <Routes>\n {/* Dashboard */}\n <Route index element={<DashboardPage />} />\n\n {/* Teams */}\n <Route path=\"teams\" element={<TeamsListPage />} />\n <Route path=\"teams/new\" element={<TeamFormPage />} />\n <Route path=\"teams/:id\" element={<TeamDetailPage />} />\n <Route path=\"teams/:id/edit\" element={<TeamFormPage />} />\n\n {/* Athlete profile (reached from a team roster) */}\n <Route path=\"teams/:teamId/athletes/:memberId\" element={<AthleteProfilePage />} />\n\n {/* Fixtures */}\n <Route path=\"fixtures\" element={<FixturesListPage />} />\n <Route path=\"fixtures/new\" element={<FixtureFormPage />} />\n <Route path=\"fixtures/:id\" element={<FixtureDetailPage />} />\n\n {/* Standings */}\n <Route path=\"standings\" element={<StandingsPage />} />\n\n {/* Programs */}\n <Route path=\"programs\" element={<ProgramsListPage />} />\n <Route path=\"programs/new\" element={<ProgramFormPage />} />\n <Route path=\"programs/:id\" element={<ProgramDetailPage />} />\n <Route path=\"programs/:id/edit\" element={<ProgramFormPage />} />\n\n {/* Sessions */}\n <Route path=\"sessions\" element={<SessionsListPage />} />\n <Route path=\"sessions/new\" element={<SessionFormPage />} />\n <Route path=\"sessions/:id\" element={<SessionDetailPage />} />\n\n {/* Performance */}\n <Route path=\"performance\" element={<PerformancePage />} />\n\n {/* Analytics */}\n <Route path=\"analytics\" element={<CoachAnalyticsPage />} />\n\n {/* Tournaments (esports bracket) */}\n <Route path=\"tournaments\" element={<TournamentBracketPage />} />\n\n {/* Fallback */}\n <Route path=\"*\" element={<Navigate to=\".\" replace />} />\n </Routes>\n </Suspense>\n </div>\n );\n};\n"],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ import { cn as e } from "../utils/cn.js";
2
+ import { gradientForSeed as t, initials as n } from "../utils/identity.js";
3
+ import { SPORT_ICONS as r } from "./domain.js";
4
+ import { useId as i } from "react";
5
+ import { jsx as a, jsxs as o } from "react/jsx-runtime";
6
+ //#region src/atheletebridge/components/Crest.tsx
7
+ var s = "M20 1.5 L37 7.5 L37 22 C37 34 29 40.5 20 42.5 C11 40.5 3 34 3 22 L3 7.5 Z", c = ({ name: c, sport: l, size: u = 44, showSportGlyph: d = !0, className: f }) => {
8
+ let [p, m] = t(c || l || "team"), h = n(c, 3), g = `crest-grad-${i().replace(/:/g, "")}`, _ = l ? r[l] : void 0;
9
+ return /* @__PURE__ */ o("span", {
10
+ className: e("relative inline-flex shrink-0 items-center justify-center", f),
11
+ style: {
12
+ width: u,
13
+ height: u * 44 / 40
14
+ },
15
+ role: "img",
16
+ "aria-label": `${c} crest`,
17
+ children: [
18
+ /* @__PURE__ */ o("svg", {
19
+ viewBox: "0 0 40 44",
20
+ width: u,
21
+ height: u * 44 / 40,
22
+ "aria-hidden": "true",
23
+ style: { display: "block" },
24
+ children: [/* @__PURE__ */ a("defs", { children: /* @__PURE__ */ o("linearGradient", {
25
+ id: g,
26
+ x1: "0",
27
+ y1: "0",
28
+ x2: "1",
29
+ y2: "1",
30
+ children: [/* @__PURE__ */ a("stop", {
31
+ offset: "0%",
32
+ style: { stopColor: p }
33
+ }), /* @__PURE__ */ a("stop", {
34
+ offset: "100%",
35
+ style: { stopColor: m }
36
+ })]
37
+ }) }), /* @__PURE__ */ a("path", {
38
+ d: s,
39
+ fill: `url(#${g})`,
40
+ stroke: "var(--color-action-primary-text)",
41
+ strokeOpacity: .22,
42
+ strokeWidth: 1
43
+ })]
44
+ }),
45
+ _ && d ? /* @__PURE__ */ a(_, {
46
+ "aria-hidden": "true",
47
+ className: "pointer-events-none absolute",
48
+ style: {
49
+ width: u * .9,
50
+ height: u * .9,
51
+ color: "var(--color-action-primary-text)",
52
+ opacity: .12
53
+ }
54
+ }) : null,
55
+ /* @__PURE__ */ a("span", {
56
+ "aria-hidden": "true",
57
+ className: "absolute font-bold leading-none tracking-tight text-[var(--color-action-primary-text)]",
58
+ style: {
59
+ fontSize: Math.max(10, u * .34),
60
+ letterSpacing: "-0.02em"
61
+ },
62
+ children: h
63
+ })
64
+ ]
65
+ });
66
+ };
67
+ //#endregion
68
+ export { c as Crest };
69
+
70
+ //# sourceMappingURL=Crest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Crest.js","names":[],"sources":["../../../src/atheletebridge/components/Crest.tsx"],"sourcesContent":["/**\n * Team crest\n * @module atheletebridge/components\n *\n * A deterministic gradient MONOGRAM crest — an honest stand-in for a club logo\n * (the schema has no logo/image field). The gradient + initials are derived\n * stably from the team name, and an optional faint sport glyph reinforces the\n * discipline. Semantic tokens only.\n */\n\nimport { type FC, useId } from 'react';\nimport { cn } from '../utils/cn';\nimport { gradientForSeed, initials } from '../utils/identity';\nimport { SPORT_ICONS } from './domain';\nimport type { AthSport } from '../types';\n\nexport interface CrestProps {\n /** Team name — seeds the gradient and provides the monogram initials. */\n name: string;\n /** Sport — renders a faint watermark glyph and (fallback) seeds the gradient. */\n sport?: AthSport;\n /** Pixel size of the crest (width == height of the shield's bounding box). */\n size?: number;\n /** Show the faint sport glyph watermark (default true when `sport` is set). */\n showSportGlyph?: boolean;\n className?: string;\n}\n\n// Classic shield silhouette in a 40×44 viewBox with a softly-pointed base.\nconst SHIELD_PATH = 'M20 1.5 L37 7.5 L37 22 C37 34 29 40.5 20 42.5 C11 40.5 3 34 3 22 L3 7.5 Z';\n\n/** Deterministic gradient monogram crest for a team (honest logo stand-in). */\nexport const Crest: FC<CrestProps> = ({\n name,\n sport,\n size = 44,\n showSportGlyph = true,\n className,\n}) => {\n const seed = name || sport || 'team';\n const [from, to] = gradientForSeed(seed);\n const mono = initials(name, 3);\n const gradId = `crest-grad-${useId().replace(/:/g, '')}`;\n const SportIcon = sport ? SPORT_ICONS[sport] : undefined;\n\n return (\n <span\n className={cn('relative inline-flex shrink-0 items-center justify-center', className)}\n style={{ width: size, height: (size * 44) / 40 }}\n role=\"img\"\n aria-label={`${name} crest`}\n >\n <svg\n viewBox=\"0 0 40 44\"\n width={size}\n height={(size * 44) / 40}\n aria-hidden=\"true\"\n style={{ display: 'block' }}\n >\n <defs>\n <linearGradient id={gradId} x1=\"0\" y1=\"0\" x2=\"1\" y2=\"1\">\n <stop offset=\"0%\" style={{ stopColor: from }} />\n <stop offset=\"100%\" style={{ stopColor: to }} />\n </linearGradient>\n </defs>\n <path\n d={SHIELD_PATH}\n fill={`url(#${gradId})`}\n stroke=\"var(--color-action-primary-text)\"\n strokeOpacity={0.22}\n strokeWidth={1}\n />\n </svg>\n\n {SportIcon && showSportGlyph ? (\n <SportIcon\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute\"\n style={{\n width: size * 0.9,\n height: size * 0.9,\n color: 'var(--color-action-primary-text)',\n opacity: 0.12,\n }}\n />\n ) : null}\n\n <span\n aria-hidden=\"true\"\n className=\"absolute font-bold leading-none tracking-tight text-[var(--color-action-primary-text)]\"\n style={{ fontSize: Math.max(10, size * 0.34), letterSpacing: '-0.02em' }}\n >\n {mono}\n </span>\n </span>\n );\n};\n"],"mappings":";;;;;;AA6BA,IAAM,IAAc,6EAGP,KAAyB,EACpC,SACA,UACA,UAAO,IACP,oBAAiB,IACjB,mBACI;CAEJ,IAAM,CAAC,GAAM,KAAM,EADN,KAAQ,KAAS,OACU,EAClC,IAAO,EAAS,GAAM,EAAE,EACxB,IAAS,cAAc,GAAO,CAAC,QAAQ,MAAM,GAAG,IAChD,IAAY,IAAQ,EAAY,KAAS,KAAA;AAE/C,QACE,kBAAC,QAAD;EACE,WAAW,EAAG,6DAA6D,EAAU;EACrF,OAAO;GAAE,OAAO;GAAM,QAAS,IAAO,KAAM;GAAI;EAChD,MAAK;EACL,cAAY,GAAG,EAAK;YAJtB;GAME,kBAAC,OAAD;IACE,SAAQ;IACR,OAAO;IACP,QAAS,IAAO,KAAM;IACtB,eAAY;IACZ,OAAO,EAAE,SAAS,SAAS;cAL7B,CAOE,kBAAC,QAAD,EAAA,UACE,kBAAC,kBAAD;KAAgB,IAAI;KAAQ,IAAG;KAAI,IAAG;KAAI,IAAG;KAAI,IAAG;eAApD,CACE,kBAAC,QAAD;MAAM,QAAO;MAAK,OAAO,EAAE,WAAW,GAAM;MAAI,CAAA,EAChD,kBAAC,QAAD;MAAM,QAAO;MAAO,OAAO,EAAE,WAAW,GAAI;MAAI,CAAA,CACjC;QACZ,CAAA,EACP,kBAAC,QAAD;KACE,GAAG;KACH,MAAM,QAAQ,EAAO;KACrB,QAAO;KACP,eAAe;KACf,aAAa;KACb,CAAA,CACE;;GAEL,KAAa,IACZ,kBAAC,GAAD;IACE,eAAY;IACZ,WAAU;IACV,OAAO;KACL,OAAO,IAAO;KACd,QAAQ,IAAO;KACf,OAAO;KACP,SAAS;KACV;IACD,CAAA,GACA;GAEJ,kBAAC,QAAD;IACE,eAAY;IACZ,WAAU;IACV,OAAO;KAAE,UAAU,KAAK,IAAI,IAAI,IAAO,IAAK;KAAE,eAAe;KAAW;cAEvE;IACI,CAAA;GACF"}
@@ -1,76 +1,12 @@
1
- import { cn as e } from "../utils/cn.js";
2
- import { StatusBadge as t } from "./StatusBadge.js";
3
- import { FIXTURE_TYPE_LABELS as n } from "./domain.js";
4
- import { formatDate as r } from "../utils/formatters.js";
5
- import { CalendarClock as i, MapPin as a } from "lucide-react";
6
- import { jsx as o, jsxs as s } from "react/jsx-runtime";
7
- import { GlassCard as c } from "@burdenoff/fe-libs/ui";
1
+ import { Scoreboard as e } from "./Scoreboard.js";
2
+ import { jsx as t } from "react/jsx-runtime";
8
3
  //#region src/atheletebridge/components/FixtureCard.tsx
9
- var l = ({ fixture: l, onClick: u }) => {
10
- let d = l.homeTeam?.name ?? "Home", f = l.awayTeam?.name ?? (l.awayTeamId ? "Away" : "TBD"), p = l.homeScore !== null && l.awayScore !== null;
11
- return /* @__PURE__ */ s(c, {
12
- treatment: "metric",
13
- role: "button",
14
- tabIndex: 0,
15
- onClick: u,
16
- onKeyDown: (e) => {
17
- (e.key === "Enter" || e.key === " ") && (e.preventDefault(), u?.());
18
- },
19
- className: e("cursor-pointer p-5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]"),
20
- children: [
21
- /* @__PURE__ */ s("div", {
22
- className: "flex items-center justify-between gap-3",
23
- children: [/* @__PURE__ */ o("span", {
24
- className: "inline-flex items-center rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary",
25
- children: n[l.type]
26
- }), /* @__PURE__ */ o(t, { status: l.status })]
27
- }),
28
- /* @__PURE__ */ s("div", {
29
- className: "mt-4 flex items-center justify-between gap-3",
30
- children: [
31
- /* @__PURE__ */ o("span", {
32
- className: "flex-1 truncate text-right text-sm font-semibold text-text-primary",
33
- children: d
34
- }),
35
- /* @__PURE__ */ o("span", {
36
- className: "shrink-0 rounded-lg bg-bg-sunken px-3 py-1 text-sm font-bold tabular-nums text-text-primary",
37
- children: p ? `${l.homeScore} : ${l.awayScore}` : "vs"
38
- }),
39
- /* @__PURE__ */ o("span", {
40
- className: "flex-1 truncate text-left text-sm font-semibold text-text-primary",
41
- children: f
42
- })
43
- ]
44
- }),
45
- /* @__PURE__ */ s("div", {
46
- className: "mt-4 flex flex-wrap items-center gap-x-4 gap-y-1.5 text-xs text-text-secondary",
47
- children: [
48
- /* @__PURE__ */ s("span", {
49
- className: "flex items-center gap-1",
50
- children: [
51
- /* @__PURE__ */ o(i, { className: "h-3.5 w-3.5" }),
52
- " ",
53
- r(l.scheduledAt)
54
- ]
55
- }),
56
- l.venue && /* @__PURE__ */ s("span", {
57
- className: "flex items-center gap-1 truncate",
58
- children: [
59
- /* @__PURE__ */ o(a, { className: "h-3.5 w-3.5 shrink-0" }),
60
- " ",
61
- l.venue
62
- ]
63
- }),
64
- l.competition && /* @__PURE__ */ o("span", {
65
- className: "truncate",
66
- children: l.competition
67
- })
68
- ]
69
- })
70
- ]
71
- });
72
- };
4
+ var n = ({ fixture: n, onClick: r }) => /* @__PURE__ */ t(e, {
5
+ fixture: n,
6
+ onClick: r,
7
+ variant: "card"
8
+ });
73
9
  //#endregion
74
- export { l as FixtureCard };
10
+ export { n as FixtureCard };
75
11
 
76
12
  //# sourceMappingURL=FixtureCard.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"FixtureCard.js","names":[],"sources":["../../../src/atheletebridge/components/FixtureCard.tsx"],"sourcesContent":["/**\n * Fixture Card\n * @module atheletebridge/components\n */\n\nimport type { FC } from 'react';\nimport { CalendarClock, MapPin } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { StatusBadge } from './StatusBadge';\nimport { FIXTURE_TYPE_LABELS } from './domain';\nimport { formatDate } from '../utils/formatters';\nimport { cn } from '../utils/cn';\nimport type { AthFixture } from '../types';\n\ninterface FixtureCardProps {\n fixture: AthFixture;\n onClick?: () => void;\n}\n\nexport const FixtureCard: FC<FixtureCardProps> = ({ fixture, onClick }) => {\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\n return (\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 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]'\n )}\n >\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"inline-flex items-center rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary\">\n {FIXTURE_TYPE_LABELS[fixture.type]}\n </span>\n <StatusBadge status={fixture.status} />\n </div>\n\n <div className=\"mt-4 flex items-center justify-between gap-3\">\n <span className=\"flex-1 truncate text-right text-sm font-semibold text-text-primary\">\n {homeName}\n </span>\n <span className=\"shrink-0 rounded-lg bg-bg-sunken px-3 py-1 text-sm font-bold tabular-nums text-text-primary\">\n {hasScore ? `${fixture.homeScore} : ${fixture.awayScore}` : 'vs'}\n </span>\n <span className=\"flex-1 truncate text-left text-sm font-semibold text-text-primary\">\n {awayName}\n </span>\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\" /> {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\" /> {fixture.venue}\n </span>\n )}\n {fixture.competition && <span className=\"truncate\">{fixture.competition}</span>}\n </div>\n </GlassCard>\n );\n};\n"],"mappings":";;;;;;;;AAmBA,IAAa,KAAqC,EAAE,YAAS,iBAAc;CACzE,IAAM,IAAW,EAAQ,UAAU,QAAQ,QACrC,IAAW,EAAQ,UAAU,SAAS,EAAQ,aAAa,SAAS,QACpE,IAAW,EAAQ,cAAc,QAAQ,EAAQ,cAAc;AAErE,QACE,kBAAC,GAAD;EACE,WAAU;EACV,MAAK;EACL,UAAU;EACD;EACT,YAAY,MAAM;AAChB,IAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,SACjC,EAAE,gBAAgB,EAClB,KAAW;;EAGf,WAAW,EACT,kHACD;YAbH;GAeE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,QAAD;KAAM,WAAU;eACb,EAAoB,EAAQ;KACxB,CAAA,EACP,kBAAC,GAAD,EAAa,QAAQ,EAAQ,QAAU,CAAA,CACnC;;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,QAAD;MAAM,WAAU;gBACb;MACI,CAAA;KACP,kBAAC,QAAD;MAAM,WAAU;gBACb,IAAW,GAAG,EAAQ,UAAU,KAAK,EAAQ,cAAc;MACvD,CAAA;KACP,kBAAC,QAAD;MAAM,WAAU;gBACb;MACI,CAAA;KACH;;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,QAAD;MAAM,WAAU;gBAAhB;OACE,kBAAC,GAAD,EAAe,WAAU,eAAgB,CAAA;;OAAE,EAAW,EAAQ,YAAY;OACrE;;KACN,EAAQ,SACP,kBAAC,QAAD;MAAM,WAAU;gBAAhB;OACE,kBAAC,GAAD,EAAQ,WAAU,wBAAyB,CAAA;;OAAE,EAAQ;OAChD;;KAER,EAAQ,eAAe,kBAAC,QAAD;MAAM,WAAU;gBAAY,EAAQ;MAAmB,CAAA;KAC3E;;GACI"}
1
+ {"version":3,"file":"FixtureCard.js","names":[],"sources":["../../../src/atheletebridge/components/FixtureCard.tsx"],"sourcesContent":["/**\n * Fixture Card\n * @module atheletebridge/components\n *\n * A fixture tile rendered as a crest-vs-crest Scoreboard (competition strip →\n * home crest / score-or-vs / away crest → date + venue), replacing the former\n * plain card. Semantic tokens only; winner side tinted from the real score.\n */\n\nimport type { FC } from 'react';\nimport { Scoreboard } from './Scoreboard';\nimport type { AthFixture } from '../types';\n\ninterface FixtureCardProps {\n fixture: AthFixture;\n onClick?: () => void;\n}\n\nexport const FixtureCard: FC<FixtureCardProps> = ({ fixture, onClick }) => (\n <Scoreboard fixture={fixture} onClick={onClick} variant=\"card\" />\n);\n"],"mappings":";;;AAkBA,IAAa,KAAqC,EAAE,YAAS,iBAC3D,kBAAC,GAAD;CAAqB;CAAkB;CAAS,SAAQ;CAAS,CAAA"}
@@ -0,0 +1,74 @@
1
+ import { cn as e } from "../utils/cn.js";
2
+ import { StatusBadge as t } from "./StatusBadge.js";
3
+ import { formatDate as n } from "../utils/formatters.js";
4
+ import { MatchupSide as r, ScoreCenter as i, resolveMatchup as a } from "./Scoreboard.js";
5
+ import { CalendarDays as o, ChevronRight as s, Trophy as c } from "lucide-react";
6
+ import { Fragment as l, jsx as u, jsxs as d } from "react/jsx-runtime";
7
+ import { Badge as f } from "@burdenoff/fe-libs/ui";
8
+ //#region src/atheletebridge/components/MatchupRow.tsx
9
+ var p = ({ fixture: e }) => /* @__PURE__ */ d("div", {
10
+ className: "flex flex-col items-end gap-1 text-right",
11
+ children: [/* @__PURE__ */ d("span", {
12
+ className: "flex items-center gap-1 text-xs text-text-secondary",
13
+ children: [/* @__PURE__ */ u(o, {
14
+ className: "h-3.5 w-3.5 shrink-0",
15
+ "aria-hidden": "true"
16
+ }), n(e.scheduledAt)]
17
+ }), /* @__PURE__ */ d("div", {
18
+ className: "flex items-center gap-1.5",
19
+ children: [e.competition ? /* @__PURE__ */ d(f, {
20
+ variant: "secondary",
21
+ className: "gap-1",
22
+ children: [e.type === "CUP" || e.type === "TOURNAMENT" ? /* @__PURE__ */ u(c, {
23
+ className: "h-3 w-3",
24
+ "aria-hidden": "true"
25
+ }) : null, e.competition]
26
+ }) : null, /* @__PURE__ */ u(t, { status: e.status })]
27
+ })]
28
+ }), m = ({ fixture: t, onClick: o, rail: c, className: f }) => {
29
+ let m = a(t), h = !!o, g = c === !1 ? null : c === void 0 ? /* @__PURE__ */ u(p, { fixture: t }) : c, _ = g == null && !m.hasScore ? n(t.scheduledAt) : null, v = /* @__PURE__ */ d(l, { children: [/* @__PURE__ */ d("div", {
30
+ className: "grid flex-1 grid-cols-[1fr_auto_1fr] items-center gap-2 sm:gap-3",
31
+ children: [
32
+ /* @__PURE__ */ u(r, {
33
+ name: m.homeName,
34
+ sport: m.homeSport,
35
+ align: "end",
36
+ won: m.homeWon,
37
+ dimmed: m.awayWon,
38
+ crestSize: 36
39
+ }),
40
+ /* @__PURE__ */ u(i, {
41
+ matchup: m,
42
+ time: _,
43
+ size: "sm"
44
+ }),
45
+ /* @__PURE__ */ u(r, {
46
+ name: m.awayName,
47
+ sport: m.awaySport,
48
+ align: "start",
49
+ won: m.awayWon,
50
+ dimmed: m.homeWon,
51
+ crestSize: 36
52
+ })
53
+ ]
54
+ }), g ? /* @__PURE__ */ d("div", {
55
+ className: "hidden items-center gap-3 border-l border-border-seam pl-3 sm:flex md:pl-4",
56
+ children: [g, h ? /* @__PURE__ */ u(s, {
57
+ className: "h-4 w-4 shrink-0 text-text-muted",
58
+ "aria-hidden": "true"
59
+ }) : null]
60
+ }) : null] });
61
+ return h ? /* @__PURE__ */ u("button", {
62
+ type: "button",
63
+ onClick: o,
64
+ className: e("flex w-full items-center gap-3 rounded-[var(--radius-card)] px-1 py-3 text-left transition-colors hover:bg-bg-sunken focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] md:gap-4", f),
65
+ children: v
66
+ }) : /* @__PURE__ */ u("div", {
67
+ className: e("flex w-full items-center gap-3 py-3 md:gap-4", f),
68
+ children: v
69
+ });
70
+ };
71
+ //#endregion
72
+ export { m as MatchupRow };
73
+
74
+ //# sourceMappingURL=MatchupRow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MatchupRow.js","names":[],"sources":["../../../src/atheletebridge/components/MatchupRow.tsx"],"sourcesContent":["/**\n * MatchupRow\n * @module atheletebridge/components\n *\n * A compact single-line crest-vs-crest fixture row for the dashboard \"Upcoming\n * fixtures\" feed and team-detail fixture lists. Reuses the Scoreboard building\n * blocks (crest sides + score/vs centerpiece). Semantic tokens only.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { CalendarDays, ChevronRight, Trophy } from 'lucide-react';\nimport { Badge } from '@burdenoff/fe-libs/ui';\nimport { MatchupSide, ScoreCenter, resolveMatchup } from './Scoreboard';\nimport { StatusBadge } from './StatusBadge';\nimport { formatDate } from '../utils/formatters';\nimport { cn } from '../utils/cn';\nimport type { AthFixture } from '../types';\n\nexport interface MatchupRowProps {\n fixture: AthFixture;\n onClick?: () => void;\n /**\n * Right-hand rail content. Defaults to date + competition + status. Pass\n * `false` to hide the rail entirely, or a node to override it.\n */\n rail?: ReactNode | false;\n className?: string;\n}\n\nconst DefaultRail: FC<{ fixture: AthFixture }> = ({ fixture }) => (\n <div className=\"flex flex-col items-end gap-1 text-right\">\n <span className=\"flex items-center gap-1 text-xs text-text-secondary\">\n <CalendarDays className=\"h-3.5 w-3.5 shrink-0\" aria-hidden=\"true\" />\n {formatDate(fixture.scheduledAt)}\n </span>\n <div className=\"flex items-center gap-1.5\">\n {fixture.competition ? (\n <Badge variant=\"secondary\" className=\"gap-1\">\n {fixture.type === 'CUP' || fixture.type === 'TOURNAMENT' ? (\n <Trophy className=\"h-3 w-3\" aria-hidden=\"true\" />\n ) : null}\n {fixture.competition}\n </Badge>\n ) : null}\n <StatusBadge status={fixture.status} />\n </div>\n </div>\n);\n\n/** Compact crest-vs-crest fixture row (dashboard / team-detail feeds). */\nexport const MatchupRow: FC<MatchupRowProps> = ({ fixture, onClick, rail, className }) => {\n const matchup = resolveMatchup(fixture);\n const clickable = Boolean(onClick);\n\n const railNode =\n rail === false ? null : rail !== undefined ? rail : <DefaultRail fixture={fixture} />;\n\n // When there's no rail to carry the date, surface the kickoff under the \"vs\".\n const timeLabel = railNode == null && !matchup.hasScore ? formatDate(fixture.scheduledAt) : null;\n\n const content = (\n <>\n <div className=\"grid flex-1 grid-cols-[1fr_auto_1fr] items-center gap-2 sm:gap-3\">\n <MatchupSide\n name={matchup.homeName}\n sport={matchup.homeSport}\n align=\"end\"\n won={matchup.homeWon}\n dimmed={matchup.awayWon}\n crestSize={36}\n />\n <ScoreCenter matchup={matchup} time={timeLabel} size=\"sm\" />\n <MatchupSide\n name={matchup.awayName}\n sport={matchup.awaySport}\n align=\"start\"\n won={matchup.awayWon}\n dimmed={matchup.homeWon}\n crestSize={36}\n />\n </div>\n {railNode ? (\n <div className=\"hidden items-center gap-3 border-l border-border-seam pl-3 sm:flex md:pl-4\">\n {railNode}\n {clickable ? (\n <ChevronRight className=\"h-4 w-4 shrink-0 text-text-muted\" aria-hidden=\"true\" />\n ) : null}\n </div>\n ) : null}\n </>\n );\n\n if (clickable) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className={cn(\n 'flex w-full items-center gap-3 rounded-[var(--radius-card)] px-1 py-3 text-left transition-colors hover:bg-bg-sunken focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] md:gap-4',\n className\n )}\n >\n {content}\n </button>\n );\n }\n\n return <div className={cn('flex w-full items-center gap-3 py-3 md:gap-4', className)}>{content}</div>;\n};\n"],"mappings":";;;;;;;;AA6BA,IAAM,KAA4C,EAAE,iBAClD,kBAAC,OAAD;CAAK,WAAU;WAAf,CACE,kBAAC,QAAD;EAAM,WAAU;YAAhB,CACE,kBAAC,GAAD;GAAc,WAAU;GAAuB,eAAY;GAAS,CAAA,EACnE,EAAW,EAAQ,YAAY,CAC3B;KACP,kBAAC,OAAD;EAAK,WAAU;YAAf,CACG,EAAQ,cACP,kBAAC,GAAD;GAAO,SAAQ;GAAY,WAAU;aAArC,CACG,EAAQ,SAAS,SAAS,EAAQ,SAAS,eAC1C,kBAAC,GAAD;IAAQ,WAAU;IAAU,eAAY;IAAS,CAAA,GAC/C,MACH,EAAQ,YACH;OACN,MACJ,kBAAC,GAAD,EAAa,QAAQ,EAAQ,QAAU,CAAA,CACnC;IACF;IAIK,KAAmC,EAAE,YAAS,YAAS,SAAM,mBAAgB;CACxF,IAAM,IAAU,EAAe,EAAQ,EACjC,IAAY,EAAQ,GAEpB,IACJ,MAAS,KAAQ,OAAO,MAAS,KAAA,IAAmB,kBAAC,GAAD,EAAsB,YAAW,CAAA,GAAxC,GAGzC,IAAY,KAAY,QAAQ,CAAC,EAAQ,WAAW,EAAW,EAAQ,YAAY,GAAG,MAEtF,IACJ,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,GAAD;IACE,MAAM,EAAQ;IACd,OAAO,EAAQ;IACf,OAAM;IACN,KAAK,EAAQ;IACb,QAAQ,EAAQ;IAChB,WAAW;IACX,CAAA;GACF,kBAAC,GAAD;IAAsB;IAAS,MAAM;IAAW,MAAK;IAAO,CAAA;GAC5D,kBAAC,GAAD;IACE,MAAM,EAAQ;IACd,OAAO,EAAQ;IACf,OAAM;IACN,KAAK,EAAQ;IACb,QAAQ,EAAQ;IAChB,WAAW;IACX,CAAA;GACE;KACL,IACC,kBAAC,OAAD;EAAK,WAAU;YAAf,CACG,GACA,IACC,kBAAC,GAAD;GAAc,WAAU;GAAmC,eAAY;GAAS,CAAA,GAC9E,KACA;MACJ,KACH,EAAA,CAAA;AAkBL,QAfI,IAEA,kBAAC,UAAD;EACE,MAAK;EACI;EACT,WAAW,EACT,8NACA,EACD;YAEA;EACM,CAAA,GAIN,kBAAC,OAAD;EAAK,WAAW,EAAG,gDAAgD,EAAU;YAAG;EAAc,CAAA"}