@burdenoff/microfe-atheletebridge 2026.628.1 → 2026.705.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 (37) hide show
  1. package/dist/atheletebridge/AthleteBridgeRoot.js +45 -37
  2. package/dist/atheletebridge/AthleteBridgeRoot.js.map +1 -1
  3. package/dist/atheletebridge/AthleteBridgeRoutes.js +10 -6
  4. package/dist/atheletebridge/AthleteBridgeRoutes.js.map +1 -1
  5. package/dist/atheletebridge/components/AthleteSelect.js +66 -0
  6. package/dist/atheletebridge/components/AthleteSelect.js.map +1 -0
  7. package/dist/atheletebridge/components/DrillVideoLink.js +28 -0
  8. package/dist/atheletebridge/components/DrillVideoLink.js.map +1 -0
  9. package/dist/atheletebridge/components/FixtureCard.js.map +1 -1
  10. package/dist/atheletebridge/components/LoadingState.js.map +1 -1
  11. package/dist/atheletebridge/components/MetricsCard.js +20 -46
  12. package/dist/atheletebridge/components/MetricsCard.js.map +1 -1
  13. package/dist/atheletebridge/components/UserSearchSelect.js +129 -0
  14. package/dist/atheletebridge/components/UserSearchSelect.js.map +1 -0
  15. package/dist/atheletebridge/components/domain.js +10 -1
  16. package/dist/atheletebridge/components/domain.js.map +1 -1
  17. package/dist/atheletebridge/context/AthleteBridgeContext.js.map +1 -1
  18. package/dist/atheletebridge/hooks/useAthleteBridgeApi.js +313 -180
  19. package/dist/atheletebridge/hooks/useAthleteBridgeApi.js.map +1 -1
  20. package/dist/atheletebridge/pages/DashboardPage.js +77 -69
  21. package/dist/atheletebridge/pages/DashboardPage.js.map +1 -1
  22. package/dist/atheletebridge/pages/StandingsPage.js.map +1 -1
  23. package/dist/atheletebridge/pages/performance/PerformancePage.js +496 -0
  24. package/dist/atheletebridge/pages/performance/PerformancePage.js.map +1 -0
  25. package/dist/atheletebridge/pages/programs/ProgramDetailPage.js +175 -141
  26. package/dist/atheletebridge/pages/programs/ProgramDetailPage.js.map +1 -1
  27. package/dist/atheletebridge/pages/programs/ProgramFormPage.js.map +1 -1
  28. package/dist/atheletebridge/pages/sessions/SessionFormPage.js +91 -98
  29. package/dist/atheletebridge/pages/sessions/SessionFormPage.js.map +1 -1
  30. package/dist/atheletebridge/pages/teams/TeamDetailPage.js +132 -137
  31. package/dist/atheletebridge/pages/teams/TeamDetailPage.js.map +1 -1
  32. package/dist/atheletebridge/pages/teams/TeamFormPage.js.map +1 -1
  33. package/dist/atheletebridge/pages/teams/TeamsListPage.js.map +1 -1
  34. package/dist/atheletebridge/utils/formatters.js +2 -25
  35. package/dist/atheletebridge/utils/formatters.js.map +1 -1
  36. package/dist/index.js +4 -4
  37. package/package.json +5 -5
@@ -4,94 +4,102 @@ 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, LayoutDashboard as d, Trophy as f, Users as p } from "lucide-react";
8
- import { jsx as m } from "react/jsx-runtime";
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";
9
9
  //#region src/atheletebridge/AthleteBridgeRoot.tsx
10
- var h = new i({ defaultOptions: { queries: {
10
+ var g = new i({ defaultOptions: { queries: {
11
11
  staleTime: 300 * 1e3,
12
12
  retry: 1
13
- } } }), g = (i) => {
14
- let { registerNavItems: g, registerFooterItems: _, basePath: v = "/" } = i, { t: y } = o(), b = n((e, t) => {
15
- let n = y(e);
13
+ } } }), _ = (i) => {
14
+ let { registerNavItems: _, registerFooterItems: v, basePath: y = "/" } = i, { t: b } = o(), x = n((e, t) => {
15
+ let n = b(e);
16
16
  return n === e ? t : n;
17
- }, [y]), x = (e, t) => (e.endsWith("/") ? e.slice(0, -1) : e) + (t.startsWith("/") ? t : `/${t}`);
17
+ }, [b]), S = (e, t) => (e.endsWith("/") ? e.slice(0, -1) : e) + (t.startsWith("/") ? t : `/${t}`);
18
18
  return r(() => {
19
- if (g) return g([
19
+ if (_) return _([
20
20
  {
21
21
  id: "atheletebridge-dashboard",
22
- label: b("atheletebridge.nav.dashboard", "Dashboard"),
23
- path: x(v, ""),
24
- icon: /* @__PURE__ */ m(d, { size: 20 }),
22
+ label: x("atheletebridge.nav.dashboard", "Dashboard"),
23
+ path: S(y, ""),
24
+ icon: /* @__PURE__ */ h(f, { size: 20 }),
25
25
  order: 1,
26
26
  group: "main"
27
27
  },
28
28
  {
29
29
  id: "atheletebridge-teams",
30
- label: b("atheletebridge.nav.teams", "Teams"),
31
- path: x(v, "teams"),
32
- icon: /* @__PURE__ */ m(p, { size: 20 }),
30
+ label: x("atheletebridge.nav.teams", "Teams"),
31
+ path: S(y, "teams"),
32
+ icon: /* @__PURE__ */ h(m, { size: 20 }),
33
33
  order: 10,
34
34
  group: "roster"
35
35
  },
36
36
  {
37
37
  id: "atheletebridge-fixtures",
38
- label: b("atheletebridge.nav.fixtures", "Fixtures"),
39
- path: x(v, "fixtures"),
40
- icon: /* @__PURE__ */ m(c, { size: 20 }),
38
+ label: x("atheletebridge.nav.fixtures", "Fixtures"),
39
+ path: S(y, "fixtures"),
40
+ icon: /* @__PURE__ */ h(c, { size: 20 }),
41
41
  order: 11,
42
42
  group: "roster"
43
43
  },
44
44
  {
45
45
  id: "atheletebridge-standings",
46
- label: b("atheletebridge.nav.standings", "Standings"),
47
- path: x(v, "standings"),
48
- icon: /* @__PURE__ */ m(f, { size: 20 }),
46
+ label: x("atheletebridge.nav.standings", "Standings"),
47
+ path: S(y, "standings"),
48
+ icon: /* @__PURE__ */ h(p, { size: 20 }),
49
49
  order: 12,
50
50
  group: "roster"
51
51
  },
52
52
  {
53
53
  id: "atheletebridge-programs",
54
- label: b("atheletebridge.nav.programs", "Programs"),
55
- path: x(v, "programs"),
56
- icon: /* @__PURE__ */ m(u, { size: 20 }),
54
+ label: x("atheletebridge.nav.programs", "Programs"),
55
+ path: S(y, "programs"),
56
+ icon: /* @__PURE__ */ h(u, { size: 20 }),
57
57
  order: 20,
58
58
  group: "training"
59
59
  },
60
60
  {
61
61
  id: "atheletebridge-sessions",
62
- label: b("atheletebridge.nav.sessions", "Sessions"),
63
- path: x(v, "sessions"),
64
- icon: /* @__PURE__ */ m(l, { size: 20 }),
62
+ label: x("atheletebridge.nav.sessions", "Sessions"),
63
+ path: S(y, "sessions"),
64
+ icon: /* @__PURE__ */ h(l, { size: 20 }),
65
65
  order: 21,
66
66
  group: "training"
67
+ },
68
+ {
69
+ id: "atheletebridge-performance",
70
+ label: x("atheletebridge.nav.performance", "Performance"),
71
+ path: S(y, "performance"),
72
+ icon: /* @__PURE__ */ h(d, { size: 20 }),
73
+ order: 22,
74
+ group: "training"
67
75
  }
68
76
  ]);
69
77
  }, [
70
- g,
71
- v,
72
- b
78
+ _,
79
+ y,
80
+ x
73
81
  ]), r(() => {
74
- if (_) return _([{
82
+ if (v) return v([{
75
83
  id: "atheletebridge-status",
76
- label: b("atheletebridge.footer.ready", "AthleteBridge Ready"),
84
+ label: x("atheletebridge.footer.ready", "AthleteBridge Ready"),
77
85
  type: "status",
78
86
  order: 10,
79
87
  section: "left"
80
88
  }]);
81
- }, [_, b]), /* @__PURE__ */ m(a, {
82
- client: h,
83
- children: /* @__PURE__ */ m(s, {
89
+ }, [v, x]), /* @__PURE__ */ h(a, {
90
+ client: g,
91
+ children: /* @__PURE__ */ h(s, {
84
92
  workspaceId: null,
85
93
  gateway: "global",
86
94
  defaultEnabled: !0,
87
- children: /* @__PURE__ */ m(e, {
95
+ children: /* @__PURE__ */ h(e, {
88
96
  ...i,
89
- children: /* @__PURE__ */ m(t, {})
97
+ children: /* @__PURE__ */ h(t, {})
90
98
  })
91
99
  })
92
100
  });
93
101
  };
94
102
  //#endregion
95
- export { g as AthleteBridgeRoot };
103
+ export { _ as AthleteBridgeRoot };
96
104
 
97
105
  //# 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} 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\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":";;;;;;;;;AA2BA,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;AAiFtD,QA5EA,QAAgB;AACT,QAsDL,QADgB,EAnDY;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;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} 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"}
@@ -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 = () => /* @__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 = () => /* @__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
- }), T = () => {
12
- let { basePath: r, isStandalone: i } = e(), T = c(), E = r === "/" ? "" : (r ?? "").replace(/\/$/, "");
13
- return E && !i && !(T.pathname === E || T.pathname.startsWith(E + "/")) ? null : /* @__PURE__ */ l("div", {
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", {
14
14
  className: "flex min-h-full flex-col",
15
15
  children: /* @__PURE__ */ l(n, {
16
- fallback: /* @__PURE__ */ l(w, {}),
16
+ fallback: /* @__PURE__ */ l(T, {}),
17
17
  children: /* @__PURE__ */ u(s, { children: [
18
18
  /* @__PURE__ */ l(o, {
19
19
  index: !0,
@@ -79,6 +79,10 @@ var d = r(() => import("./pages/teams/TeamsListPage.js").then((e) => ({ default:
79
79
  path: "sessions/:id",
80
80
  element: /* @__PURE__ */ l(S, {})
81
81
  }),
82
+ /* @__PURE__ */ l(o, {
83
+ path: "performance",
84
+ element: /* @__PURE__ */ l(w, {})
85
+ }),
82
86
  /* @__PURE__ */ l(o, {
83
87
  path: "*",
84
88
  element: /* @__PURE__ */ l(a, {
@@ -91,6 +95,6 @@ var d = r(() => import("./pages/teams/TeamsListPage.js").then((e) => ({ default:
91
95
  });
92
96
  };
93
97
  //#endregion
94
- export { T as AthleteBridgeRoutes };
98
+ export { E as AthleteBridgeRoutes };
95
99
 
96
100
  //# 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\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 {/* 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\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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"}
@@ -0,0 +1,66 @@
1
+ import { useTeamMembers as e, useTeams as t } from "../hooks/useAthleteBridgeApi.js";
2
+ import { FormField as n, fieldInputClass as r } from "./form.js";
3
+ import { useMemo as i, useState as a } from "react";
4
+ import { jsx as o, jsxs as s } from "react/jsx-runtime";
5
+ //#region src/atheletebridge/components/AthleteSelect.tsx
6
+ function c({ athleteId: c, onSelect: l, required: u = !1, teamLabel: d = "Team", athleteLabel: f = "Athlete", idPrefix: p = "athlete" }) {
7
+ let [m, h] = a(""), g = t({ pagination: { limit: 100 } }), _ = e(m || void 0), v = i(() => g.data?.items ?? [], [g.data]), y = i(() => (_.data ?? []).filter((e) => !!e.userId), [_.data]), b = `${p}-team`, x = `${p}-athlete`, S = m ? _.isLoading ? "Loading roster…" : y.length === 0 ? "This team has no members yet — add them from the team page." : void 0 : "Choose a team to load its roster.";
8
+ return /* @__PURE__ */ s("div", {
9
+ className: "grid grid-cols-1 gap-5 sm:grid-cols-2",
10
+ children: [/* @__PURE__ */ o(n, {
11
+ label: d,
12
+ htmlFor: b,
13
+ required: u,
14
+ children: /* @__PURE__ */ s("select", {
15
+ id: b,
16
+ className: r,
17
+ value: m,
18
+ onChange: (e) => {
19
+ h(e.target.value), l({
20
+ athleteId: "",
21
+ displayName: ""
22
+ });
23
+ },
24
+ children: [/* @__PURE__ */ o("option", {
25
+ value: "",
26
+ children: "Select a team…"
27
+ }), v.map((e) => /* @__PURE__ */ o("option", {
28
+ value: e.id,
29
+ children: e.name
30
+ }, e.id))]
31
+ })
32
+ }), /* @__PURE__ */ o(n, {
33
+ label: f,
34
+ htmlFor: x,
35
+ required: u,
36
+ hint: S,
37
+ children: /* @__PURE__ */ s("select", {
38
+ id: x,
39
+ className: r,
40
+ value: c,
41
+ disabled: !m || y.length === 0,
42
+ onChange: (e) => {
43
+ let t = y.find((t) => t.userId === e.target.value);
44
+ l(t ? {
45
+ athleteId: t.userId,
46
+ displayName: t.displayName
47
+ } : {
48
+ athleteId: "",
49
+ displayName: ""
50
+ });
51
+ },
52
+ children: [/* @__PURE__ */ o("option", {
53
+ value: "",
54
+ children: "Select an athlete…"
55
+ }), y.map((e) => /* @__PURE__ */ s("option", {
56
+ value: e.userId,
57
+ children: [e.displayName, e.jerseyNumber == null ? "" : ` · #${e.jerseyNumber}`]
58
+ }, e.id))]
59
+ })
60
+ })]
61
+ });
62
+ }
63
+ //#endregion
64
+ export { c as AthleteSelect };
65
+
66
+ //# sourceMappingURL=AthleteSelect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AthleteSelect.js","names":[],"sources":["../../../src/atheletebridge/components/AthleteSelect.tsx"],"sourcesContent":["/**\n * Athlete picker\n * @module atheletebridge/components\n *\n * Two coupled selects — pick a team, then pick an athlete from that team's live\n * roster (`athListMembers`). Emits the athlete's user id (used everywhere an\n * `athleteId` is required) plus a display name, so a coach never has to paste a\n * raw UUID. Semantic tokens only.\n */\n\nimport { useMemo, useState } from 'react';\nimport { FormField, fieldInputClass } from './form';\nimport { useTeams, useTeamMembers } from '../hooks/useAthleteBridgeApi';\n\nexport interface AthleteSelectValue {\n athleteId: string;\n displayName: string;\n}\n\ninterface AthleteSelectProps {\n /** Currently selected athlete user id. */\n athleteId: string;\n onSelect: (value: AthleteSelectValue) => void;\n required?: boolean;\n teamLabel?: string;\n athleteLabel?: string;\n /** Prefix for the field ids so multiple instances stay unique/accessible. */\n idPrefix?: string;\n}\n\nexport function AthleteSelect({\n athleteId,\n onSelect,\n required = false,\n teamLabel = 'Team',\n athleteLabel = 'Athlete',\n idPrefix = 'athlete',\n}: AthleteSelectProps) {\n const [teamId, setTeamId] = useState('');\n\n const teams = useTeams({ pagination: { limit: 100 } });\n const members = useTeamMembers(teamId || undefined);\n\n const teamOptions = useMemo(() => teams.data?.items ?? [], [teams.data]);\n const memberOptions = useMemo(\n () => (members.data ?? []).filter((m) => Boolean(m.userId)),\n [members.data]\n );\n\n const teamFieldId = `${idPrefix}-team`;\n const athleteFieldId = `${idPrefix}-athlete`;\n\n const memberHint = teamId\n ? members.isLoading\n ? 'Loading roster…'\n : memberOptions.length === 0\n ? 'This team has no members yet — add them from the team page.'\n : undefined\n : 'Choose a team to load its roster.';\n\n return (\n <div className=\"grid grid-cols-1 gap-5 sm:grid-cols-2\">\n <FormField label={teamLabel} htmlFor={teamFieldId} required={required}>\n <select\n id={teamFieldId}\n className={fieldInputClass}\n value={teamId}\n onChange={(e) => {\n setTeamId(e.target.value);\n // Clear any prior athlete selection when the team changes.\n onSelect({ athleteId: '', displayName: '' });\n }}\n >\n <option value=\"\">Select a team…</option>\n {teamOptions.map((team) => (\n <option key={team.id} value={team.id}>\n {team.name}\n </option>\n ))}\n </select>\n </FormField>\n\n <FormField\n label={athleteLabel}\n htmlFor={athleteFieldId}\n required={required}\n hint={memberHint}\n >\n <select\n id={athleteFieldId}\n className={fieldInputClass}\n value={athleteId}\n disabled={!teamId || memberOptions.length === 0}\n onChange={(e) => {\n const picked = memberOptions.find((m) => m.userId === e.target.value);\n onSelect(\n picked\n ? { athleteId: picked.userId, displayName: picked.displayName }\n : { athleteId: '', displayName: '' }\n );\n }}\n >\n <option value=\"\">Select an athlete…</option>\n {memberOptions.map((member) => (\n <option key={member.id} value={member.userId}>\n {member.displayName}\n {member.jerseyNumber != null ? ` · #${member.jerseyNumber}` : ''}\n </option>\n ))}\n </select>\n </FormField>\n </div>\n );\n}\n"],"mappings":";;;;;AA8BA,SAAgB,EAAc,EAC5B,cACA,aACA,cAAW,IACX,eAAY,QACZ,kBAAe,WACf,cAAW,aACU;CACrB,IAAM,CAAC,GAAQ,KAAa,EAAS,GAAG,EAElC,IAAQ,EAAS,EAAE,YAAY,EAAE,OAAO,KAAK,EAAE,CAAC,EAChD,IAAU,EAAe,KAAU,KAAA,EAAU,EAE7C,IAAc,QAAc,EAAM,MAAM,SAAS,EAAE,EAAE,CAAC,EAAM,KAAK,CAAC,EAClE,IAAgB,SACb,EAAQ,QAAQ,EAAE,EAAE,QAAQ,MAAM,EAAQ,EAAE,OAAQ,EAC3D,CAAC,EAAQ,KAAK,CACf,EAEK,IAAc,GAAG,EAAS,QAC1B,IAAiB,GAAG,EAAS,WAE7B,IAAa,IACf,EAAQ,YACN,oBACA,EAAc,WAAW,IACvB,gEACA,KAAA,IACJ;AAEJ,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,GAAD;GAAW,OAAO;GAAW,SAAS;GAAuB;aAC3D,kBAAC,UAAD;IACE,IAAI;IACJ,WAAW;IACX,OAAO;IACP,WAAW,MAAM;AAGf,KAFA,EAAU,EAAE,OAAO,MAAM,EAEzB,EAAS;MAAE,WAAW;MAAI,aAAa;MAAI,CAAC;;cAPhD,CAUE,kBAAC,UAAD;KAAQ,OAAM;eAAG;KAAuB,CAAA,EACvC,EAAY,KAAK,MAChB,kBAAC,UAAD;KAAsB,OAAO,EAAK;eAC/B,EAAK;KACC,EAFI,EAAK,GAET,CACT,CACK;;GACC,CAAA,EAEZ,kBAAC,GAAD;GACE,OAAO;GACP,SAAS;GACC;GACV,MAAM;aAEN,kBAAC,UAAD;IACE,IAAI;IACJ,WAAW;IACX,OAAO;IACP,UAAU,CAAC,KAAU,EAAc,WAAW;IAC9C,WAAW,MAAM;KACf,IAAM,IAAS,EAAc,MAAM,MAAM,EAAE,WAAW,EAAE,OAAO,MAAM;AACrE,OACE,IACI;MAAE,WAAW,EAAO;MAAQ,aAAa,EAAO;MAAa,GAC7D;MAAE,WAAW;MAAI,aAAa;MAAI,CACvC;;cAXL,CAcE,kBAAC,UAAD;KAAQ,OAAM;eAAG;KAA2B,CAAA,EAC3C,EAAc,KAAK,MAClB,kBAAC,UAAD;KAAwB,OAAO,EAAO;eAAtC,CACG,EAAO,aACP,EAAO,gBAAgB,OAAsC,KAA/B,OAAO,EAAO,eACtC;OAHI,EAAO,GAGX,CACT,CACK;;GACC,CAAA,CACR"}
@@ -0,0 +1,28 @@
1
+ import { useFile as e } from "../hooks/useAthleteBridgeApi.js";
2
+ import { ExternalLink as t, FileVideo as n, Loader2 as r } from "lucide-react";
3
+ import { jsx as i, jsxs as a } from "react/jsx-runtime";
4
+ //#region src/atheletebridge/components/DrillVideoLink.tsx
5
+ function o({ fileId: o }) {
6
+ let s = e(o), c = s.data?.downloadUrl ?? void 0, l = s.data?.name ?? "Demo video";
7
+ return c ? /* @__PURE__ */ a("a", {
8
+ href: c,
9
+ target: "_blank",
10
+ rel: "noreferrer",
11
+ className: "mt-1.5 inline-flex items-center gap-1 text-xs font-medium text-primary hover:underline",
12
+ children: [
13
+ /* @__PURE__ */ i(n, { className: "h-3.5 w-3.5" }),
14
+ /* @__PURE__ */ i("span", {
15
+ className: "max-w-[16rem] truncate",
16
+ children: l
17
+ }),
18
+ /* @__PURE__ */ i(t, { className: "h-3 w-3" })
19
+ ]
20
+ }) : /* @__PURE__ */ a("span", {
21
+ className: "mt-1.5 inline-flex items-center gap-1 text-xs text-text-secondary",
22
+ children: [s.isLoading ? /* @__PURE__ */ i(r, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ i(n, { className: "h-3.5 w-3.5" }), "Demo video"]
23
+ });
24
+ }
25
+ //#endregion
26
+ export { o as DrillVideoLink };
27
+
28
+ //# sourceMappingURL=DrillVideoLink.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DrillVideoLink.js","names":[],"sources":["../../../src/atheletebridge/components/DrillVideoLink.tsx"],"sourcesContent":["/**\n * Drill demo-video reference\n * @module atheletebridge/components\n *\n * A drill's `video` is a reference into wspace-files-svc (blobs live there). We\n * resolve the playable URL lazily and in isolation, so a missing/expired blob\n * degrades to a quiet badge instead of ever breaking the program page.\n */\n\nimport { ExternalLink, FileVideo, Loader2 } from 'lucide-react';\nimport { useFile } from '../hooks/useAthleteBridgeApi';\n\nexport function DrillVideoLink({ fileId }: { fileId: string }) {\n const file = useFile(fileId);\n const url = file.data?.downloadUrl ?? undefined;\n const label = file.data?.name ?? 'Demo video';\n\n if (url) {\n return (\n <a\n href={url}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"mt-1.5 inline-flex items-center gap-1 text-xs font-medium text-primary hover:underline\"\n >\n <FileVideo className=\"h-3.5 w-3.5\" />\n <span className=\"max-w-[16rem] truncate\">{label}</span>\n <ExternalLink className=\"h-3 w-3\" />\n </a>\n );\n }\n\n return (\n <span className=\"mt-1.5 inline-flex items-center gap-1 text-xs text-text-secondary\">\n {file.isLoading ? (\n <Loader2 className=\"h-3.5 w-3.5 animate-spin\" />\n ) : (\n <FileVideo className=\"h-3.5 w-3.5\" />\n )}\n Demo video\n </span>\n );\n}\n"],"mappings":";;;;AAYA,SAAgB,EAAe,EAAE,aAA8B;CAC7D,IAAM,IAAO,EAAQ,EAAO,EACtB,IAAM,EAAK,MAAM,eAAe,KAAA,GAChC,IAAQ,EAAK,MAAM,QAAQ;AAiBjC,QAfI,IAEA,kBAAC,KAAD;EACE,MAAM;EACN,QAAO;EACP,KAAI;EACJ,WAAU;YAJZ;GAME,kBAAC,GAAD,EAAW,WAAU,eAAgB,CAAA;GACrC,kBAAC,QAAD;IAAM,WAAU;cAA0B;IAAa,CAAA;GACvD,kBAAC,GAAD,EAAc,WAAU,WAAY,CAAA;GAClC;MAKN,kBAAC,QAAD;EAAM,WAAU;YAAhB,CACG,EAAK,YACJ,kBAAC,GAAD,EAAS,WAAU,4BAA6B,CAAA,GAEhD,kBAAC,GAAD,EAAW,WAAU,eAAgB,CAAA,EACrC,aAEG"}
@@ -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 && (\n <span className=\"truncate\">{fixture.competition}</span>\n )}\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,eACP,kBAAC,QAAD;MAAM,WAAU;gBAAY,EAAQ;MAAmB,CAAA;KAErD;;GACI"}
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 +1 @@
1
- {"version":3,"file":"LoadingState.js","names":[],"sources":["../../../src/atheletebridge/components/LoadingState.tsx"],"sourcesContent":["/**\n * Loading / Error State Components\n * @module atheletebridge/components\n *\n * Small calm, centered states shared across list and detail pages.\n */\n\nimport type { FC } from 'react';\nimport { AlertCircle, Loader2 } from 'lucide-react';\nimport { cn } from '../utils/cn';\n\ninterface LoadingStateProps {\n label?: string;\n className?: string;\n}\n\nexport const LoadingState: FC<LoadingStateProps> = ({ label = 'Loading…', className }) => (\n <div\n className={cn('flex min-h-[40vh] flex-col items-center justify-center gap-3', className)}\n role=\"status\"\n aria-live=\"polite\"\n >\n <Loader2 className=\"h-8 w-8 animate-spin text-text-secondary\" />\n <p className=\"text-sm text-text-secondary\">{label}</p>\n </div>\n);\n\ninterface ErrorStateProps {\n title?: string;\n message?: string;\n onRetry?: () => void;\n className?: string;\n}\n\nexport const ErrorState: FC<ErrorStateProps> = ({\n title = 'Something went wrong',\n message = 'We could not load this data. Please try again.',\n onRetry,\n className,\n}) => (\n <div\n className={cn('flex min-h-[40vh] flex-col items-center justify-center gap-3 text-center', className)}\n >\n <AlertCircle className=\"h-10 w-10 text-status-error-text\" />\n <h3 className=\"text-lg font-semibold text-text-primary\">{title}</h3>\n <p className=\"max-w-sm text-sm text-text-secondary\">{message}</p>\n {onRetry && (\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"mt-2 rounded-lg border border-border-seam px-4 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n Try again\n </button>\n )}\n </div>\n);\n"],"mappings":";;;;AAgBA,IAAa,KAAuC,EAAE,WAAQ,YAAY,mBACxE,kBAAC,OAAD;CACE,WAAW,EAAG,gEAAgE,EAAU;CACxF,MAAK;CACL,aAAU;WAHZ,CAKE,kBAAC,GAAD,EAAS,WAAU,4CAA6C,CAAA,EAChE,kBAAC,KAAD;EAAG,WAAU;YAA+B;EAAU,CAAA,CAClD;IAUK,KAAmC,EAC9C,WAAQ,wBACR,aAAU,kDACV,YACA,mBAEA,kBAAC,OAAD;CACE,WAAW,EAAG,4EAA4E,EAAU;WADtG;EAGE,kBAAC,GAAD,EAAa,WAAU,oCAAqC,CAAA;EAC5D,kBAAC,MAAD;GAAI,WAAU;aAA2C;GAAW,CAAA;EACpE,kBAAC,KAAD;GAAG,WAAU;aAAwC;GAAY,CAAA;EAChE,KACC,kBAAC,UAAD;GACE,MAAK;GACL,SAAS;GACT,WAAU;aACX;GAEQ,CAAA;EAEP"}
1
+ {"version":3,"file":"LoadingState.js","names":[],"sources":["../../../src/atheletebridge/components/LoadingState.tsx"],"sourcesContent":["/**\n * Loading / Error State Components\n * @module atheletebridge/components\n *\n * Small calm, centered states shared across list and detail pages.\n */\n\nimport type { FC } from 'react';\nimport { AlertCircle, Loader2 } from 'lucide-react';\nimport { cn } from '../utils/cn';\n\ninterface LoadingStateProps {\n label?: string;\n className?: string;\n}\n\nexport const LoadingState: FC<LoadingStateProps> = ({ label = 'Loading…', className }) => (\n <div\n className={cn('flex min-h-[40vh] flex-col items-center justify-center gap-3', className)}\n role=\"status\"\n aria-live=\"polite\"\n >\n <Loader2 className=\"h-8 w-8 animate-spin text-text-secondary\" />\n <p className=\"text-sm text-text-secondary\">{label}</p>\n </div>\n);\n\ninterface ErrorStateProps {\n title?: string;\n message?: string;\n onRetry?: () => void;\n className?: string;\n}\n\nexport const ErrorState: FC<ErrorStateProps> = ({\n title = 'Something went wrong',\n message = 'We could not load this data. Please try again.',\n onRetry,\n className,\n}) => (\n <div\n className={cn(\n 'flex min-h-[40vh] flex-col items-center justify-center gap-3 text-center',\n className\n )}\n >\n <AlertCircle className=\"h-10 w-10 text-status-error-text\" />\n <h3 className=\"text-lg font-semibold text-text-primary\">{title}</h3>\n <p className=\"max-w-sm text-sm text-text-secondary\">{message}</p>\n {onRetry && (\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"mt-2 rounded-lg border border-border-seam px-4 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n Try again\n </button>\n )}\n </div>\n);\n"],"mappings":";;;;AAgBA,IAAa,KAAuC,EAAE,WAAQ,YAAY,mBACxE,kBAAC,OAAD;CACE,WAAW,EAAG,gEAAgE,EAAU;CACxF,MAAK;CACL,aAAU;WAHZ,CAKE,kBAAC,GAAD,EAAS,WAAU,4CAA6C,CAAA,EAChE,kBAAC,KAAD;EAAG,WAAU;YAA+B;EAAU,CAAA,CAClD;IAUK,KAAmC,EAC9C,WAAQ,wBACR,aAAU,kDACV,YACA,mBAEA,kBAAC,OAAD;CACE,WAAW,EACT,4EACA,EACD;WAJH;EAME,kBAAC,GAAD,EAAa,WAAU,oCAAqC,CAAA;EAC5D,kBAAC,MAAD;GAAI,WAAU;aAA2C;GAAW,CAAA;EACpE,kBAAC,KAAD;GAAG,WAAU;aAAwC;GAAY,CAAA;EAChE,KACC,kBAAC,UAAD;GACE,MAAK;GACL,SAAS;GACT,WAAU;aACX;GAEQ,CAAA;EAEP"}
@@ -1,52 +1,26 @@
1
1
  import { cn as e } from "../utils/cn.js";
2
- import { Minus as t, TrendingDown as n, TrendingUp as r } from "lucide-react";
3
- import { jsx as i, jsxs as a } from "react/jsx-runtime";
4
- import { GlassCard as o } from "@burdenoff/fe-libs/ui";
2
+ import { jsx as t, jsxs as n } from "react/jsx-runtime";
3
+ import { GlassCard as r } from "@burdenoff/fe-libs/ui";
5
4
  //#region src/atheletebridge/components/MetricsCard.tsx
6
- var s = {
7
- up: {
8
- icon: r,
9
- color: "text-status-success-text"
10
- },
11
- down: {
12
- icon: n,
13
- color: "text-status-error-text"
14
- },
15
- neutral: {
16
- icon: t,
17
- color: "text-text-secondary"
18
- }
19
- }, c = ({ icon: t, value: n, label: r, trend: c, trendValue: l, featured: u = !1, className: d }) => {
20
- let f = c ? s[c] : null, p = f?.icon;
21
- return /* @__PURE__ */ a(o, {
22
- treatment: u ? "glass" : "metric",
23
- glow: u,
24
- className: e("p-6", d),
25
- children: [/* @__PURE__ */ a("div", {
26
- className: "relative flex items-center justify-between",
27
- children: [/* @__PURE__ */ i("div", {
28
- className: "text-text-secondary",
29
- children: t
30
- }), c && f && p && /* @__PURE__ */ a("div", {
31
- className: e("flex items-center gap-1 text-xs font-medium", f.color),
32
- children: [/* @__PURE__ */ i(p, { className: "h-3.5 w-3.5" }), l && /* @__PURE__ */ i("span", {
33
- className: "tabular-nums",
34
- children: l
35
- })]
36
- })]
37
- }), /* @__PURE__ */ a("div", {
38
- className: "relative mt-3",
39
- children: [/* @__PURE__ */ i("p", {
40
- className: "text-2xl font-bold tabular-nums text-text-primary",
41
- children: n
42
- }), /* @__PURE__ */ i("p", {
43
- className: "mt-1 text-sm text-text-secondary",
44
- children: r
45
- })]
5
+ var i = ({ icon: i, value: a, label: o, featured: s = !1, className: c }) => /* @__PURE__ */ n(r, {
6
+ treatment: s ? "glass" : "metric",
7
+ glow: s,
8
+ className: e("p-6", c),
9
+ children: [/* @__PURE__ */ t("div", {
10
+ className: "relative text-text-secondary",
11
+ children: i
12
+ }), /* @__PURE__ */ n("div", {
13
+ className: "relative mt-3",
14
+ children: [/* @__PURE__ */ t("p", {
15
+ className: "text-2xl font-bold tabular-nums text-text-primary",
16
+ children: a
17
+ }), /* @__PURE__ */ t("p", {
18
+ className: "mt-1 text-sm text-text-secondary",
19
+ children: o
46
20
  })]
47
- });
48
- };
21
+ })]
22
+ });
49
23
  //#endregion
50
- export { c as MetricsCard };
24
+ export { i as MetricsCard };
51
25
 
52
26
  //# sourceMappingURL=MetricsCard.js.map
@@ -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 * Numerals are tabular for clean alignment. No hover movement.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { TrendingUp, TrendingDown, Minus } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\nimport type { TrendDirection } from '../types';\n\ninterface MetricsCardProps {\n icon: ReactNode;\n value: string | number;\n label: string;\n trend?: TrendDirection;\n trendValue?: string;\n /** Render as the single featured hero metric (glass treatment + glow). */\n featured?: boolean;\n className?: string;\n}\n\nconst trendConfig: Record<TrendDirection, { icon: typeof TrendingUp; color: string }> = {\n up: { icon: TrendingUp, color: 'text-status-success-text' },\n down: { icon: TrendingDown, color: 'text-status-error-text' },\n neutral: { icon: Minus, color: 'text-text-secondary' },\n};\n\nexport const MetricsCard: FC<MetricsCardProps> = ({\n icon,\n value,\n label,\n trend,\n trendValue,\n featured = false,\n className,\n}) => {\n const trendInfo = trend ? trendConfig[trend] : null;\n const TrendIcon = trendInfo?.icon;\n\n return (\n <GlassCard\n treatment={featured ? 'glass' : 'metric'}\n glow={featured}\n className={cn('p-6', className)}\n >\n <div className=\"relative flex items-center justify-between\">\n <div className=\"text-text-secondary\">{icon}</div>\n {trend && trendInfo && TrendIcon && (\n <div className={cn('flex items-center gap-1 text-xs font-medium', trendInfo.color)}>\n <TrendIcon className=\"h-3.5 w-3.5\" />\n {trendValue && <span className=\"tabular-nums\">{trendValue}</span>}\n </div>\n )}\n </div>\n <div className=\"relative mt-3\">\n <p className=\"text-2xl font-bold tabular-nums text-text-primary\">{value}</p>\n <p className=\"mt-1 text-sm text-text-secondary\">{label}</p>\n </div>\n </GlassCard>\n );\n};\n"],"mappings":";;;;;AA2BA,IAAM,IAAkF;CACtF,IAAI;EAAE,MAAM;EAAY,OAAO;EAA4B;CAC3D,MAAM;EAAE,MAAM;EAAc,OAAO;EAA0B;CAC7D,SAAS;EAAE,MAAM;EAAO,OAAO;EAAuB;CACvD,EAEY,KAAqC,EAChD,SACA,UACA,UACA,UACA,eACA,cAAW,IACX,mBACI;CACJ,IAAM,IAAY,IAAQ,EAAY,KAAS,MACzC,IAAY,GAAW;AAE7B,QACE,kBAAC,GAAD;EACE,WAAW,IAAW,UAAU;EAChC,MAAM;EACN,WAAW,EAAG,OAAO,EAAU;YAHjC,CAKE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAuB;IAAW,CAAA,EAChD,KAAS,KAAa,KACrB,kBAAC,OAAD;IAAK,WAAW,EAAG,+CAA+C,EAAU,MAAM;cAAlF,CACE,kBAAC,GAAD,EAAW,WAAU,eAAgB,CAAA,EACpC,KAAc,kBAAC,QAAD;KAAM,WAAU;eAAgB;KAAkB,CAAA,CAC7D;MAEJ;MACN,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,KAAD;IAAG,WAAU;cAAqD;IAAU,CAAA,EAC5E,kBAAC,KAAD;IAAG,WAAU;cAAoC;IAAU,CAAA,CACvD;KACI"}
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 * Numerals are tabular for clean alignment. No hover movement.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\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 className?: string;\n}\n\nexport const MetricsCard: FC<MetricsCardProps> = ({\n icon,\n value,\n label,\n featured = false,\n className,\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=\"text-2xl font-bold tabular-nums text-text-primary\">{value}</p>\n <p className=\"mt-1 text-sm text-text-secondary\">{label}</p>\n </div>\n </GlassCard>\n );\n};\n"],"mappings":";;;;AAuBA,IAAa,KAAqC,EAChD,SACA,UACA,UACA,cAAW,IACX,mBAGE,kBAAC,GAAD;CACE,WAAW,IAAW,UAAU;CAChC,MAAM;CACN,WAAW,EAAG,OAAO,EAAU;WAHjC,CAKE,kBAAC,OAAD;EAAK,WAAU;YAAgC;EAAW,CAAA,EAC1D,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,KAAD;GAAG,WAAU;aAAqD;GAAU,CAAA,EAC5E,kBAAC,KAAD;GAAG,WAAU;aAAoC;GAAU,CAAA,CACvD;IACI"}