@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
@@ -1,17 +1,17 @@
1
1
  import { useAthleteBridge as e } from "../../context/AthleteBridgeContext.js";
2
2
  import { PageLayout as t } from "../../components/PageLayout.js";
3
3
  import { StatusBadge as n } from "../../components/StatusBadge.js";
4
- import { PROGRAM_LEVEL_LABELS as r, SPORT_LABELS as i } from "../../components/domain.js";
5
- import { EmptyState as a } from "../../components/EmptyState.js";
6
- import { ErrorState as o, LoadingState as ee } from "../../components/LoadingState.js";
7
- import { useAddDrill as te, useArchiveProgram as ne, useProgram as re, useRemoveDrill as s, useTransitionProgram as c, useUploadFile as l } from "../../hooks/useAthleteBridgeApi.js";
4
+ import { PROGRAM_LEVEL_LABELS as r, SPORT_ICONS as i, SPORT_LABELS as a } from "../../components/domain.js";
5
+ import { EmptyState as o } from "../../components/EmptyState.js";
6
+ import { ErrorState as s, LoadingState as c } from "../../components/LoadingState.js";
7
+ import { useAddDrill as l, useArchiveProgram as ee, useProgram as te, useRemoveDrill as ne, useTransitionProgram as re, useUploadFile as ie } from "../../hooks/useAthleteBridgeApi.js";
8
8
  import { FormField as u, fieldInputClass as d } from "../../components/form.js";
9
9
  import { DrillVideoLink as f } from "../../components/DrillVideoLink.js";
10
10
  import { useMemo as p, useState as m } from "react";
11
- import { Archive as h, ArrowLeft as g, Copy as _, Edit as v, FileVideo as y, Loader2 as b, Plus as x, Send as ie, Trash2 as ae, Undo2 as oe } from "lucide-react";
12
- import { useParams as se } from "react-router-dom";
13
- import { Fragment as ce, jsx as S, jsxs as C } from "react/jsx-runtime";
14
- import { EmphasisPanel as w, GlassCard as T, ResponsiveDialog as E, ResponsiveDialogContent as D, ResponsiveDialogFooter as O, ResponsiveDialogHeader as k, ResponsiveDialogTitle as A } from "@burdenoff/fe-libs/ui";
11
+ import { Archive as h, ArrowLeft as g, Copy as _, Edit as v, FileVideo as y, Loader2 as b, Plus as x, Send as ae, Trash2 as oe, Undo2 as se } from "lucide-react";
12
+ import { useParams as ce } from "react-router-dom";
13
+ import { Fragment as le, jsx as S, jsxs as C } from "react/jsx-runtime";
14
+ import { Accordion as ue, AccordionContent as de, AccordionItem as fe, AccordionTrigger as pe, Badge as w, GlassCard as T, ResponsiveDialog as E, ResponsiveDialogContent as D, ResponsiveDialogFooter as O, ResponsiveDialogHeader as k, ResponsiveDialogTitle as A } from "@burdenoff/fe-libs/ui";
15
15
  //#region src/atheletebridge/pages/programs/ProgramDetailPage.tsx
16
16
  var j = {
17
17
  name: "",
@@ -21,15 +21,18 @@ var j = {
21
21
  reps: "",
22
22
  durationSec: "",
23
23
  restSec: ""
24
- }, M = (e) => {
24
+ }, M = ({ children: e }) => /* @__PURE__ */ S("span", {
25
+ className: "inline-flex items-center rounded-md border border-border-seam bg-bg-sunken px-2 py-0.5 text-xs font-medium tabular-nums text-text-secondary",
26
+ children: e
27
+ }), N = (e) => {
25
28
  let t = e.trim();
26
29
  if (!t) return;
27
30
  let n = Number.parseInt(t, 10);
28
31
  return Number.isNaN(n) ? void 0 : n;
29
32
  };
30
- function N() {
31
- let { id: N } = se(), { navigateTo: P } = e(), F = re(N), I = c(), L = ne(), R = te(), z = s(N), B = l(), [V, H] = m(!1), [U, W] = m(j), [G, K] = m(null), [q, J] = m(!1), [Y, X] = m(null), le = p(() => {
32
- let e = F.data?.drills ?? [], t = /* @__PURE__ */ new Map();
33
+ function P() {
34
+ let { id: P } = ce(), { navigateTo: F } = e(), I = te(P), L = re(), R = ee(), z = l(), B = ne(P), me = ie(), [he, V] = m(!1), [H, U] = m(j), [W, G] = m(null), [K, q] = m(!1), [J, Y] = m(null), X = p(() => {
35
+ let e = I.data?.drills ?? [], t = /* @__PURE__ */ new Map();
33
36
  for (let n of e) {
34
37
  let e = t.get(n.weekNumber) ?? [];
35
38
  e.push(n), t.set(n.weekNumber, e);
@@ -38,52 +41,53 @@ function N() {
38
41
  week: e,
39
42
  drills: [...t].sort((e, t) => e.orderIndex - t.orderIndex)
40
43
  }));
41
- }, [F.data]);
42
- if (F.isLoading) return /* @__PURE__ */ S(t, {
44
+ }, [I.data]);
45
+ if (I.isLoading) return /* @__PURE__ */ S(t, {
43
46
  title: "Program",
44
- children: /* @__PURE__ */ S(ee, { label: "Loading program…" })
47
+ children: /* @__PURE__ */ S(c, { label: "Loading program…" })
45
48
  });
46
- if (F.isError || !F.data) return /* @__PURE__ */ S(t, {
49
+ if (I.isError || !I.data) return /* @__PURE__ */ S(t, {
47
50
  title: "Program",
48
- children: /* @__PURE__ */ S(o, {
51
+ children: /* @__PURE__ */ S(s, {
49
52
  title: "Program not found",
50
53
  message: "This program does not exist or you do not have access to it.",
51
- onRetry: () => P("/programs")
54
+ onRetry: () => F("/programs")
52
55
  })
53
56
  });
54
- let Z = F.data, Q = Z.drills?.length ?? 0, $ = (e) => {
55
- N && I.mutate({
56
- id: N,
57
+ let Z = I.data, Q = Z.drills?.length ?? 0, ge = i[Z.sport], _e = X.map(({ week: e }) => `week-${e}`), $ = (e) => {
58
+ P && L.mutate({
59
+ id: P,
57
60
  status: e
58
61
  });
59
62
  };
60
63
  return /* @__PURE__ */ C(t, {
61
64
  title: Z.name,
62
- description: `${i[Z.sport]} · ${r[Z.level]} · ${Z.weeks} ${Z.weeks === 1 ? "week" : "weeks"}`,
65
+ gradientTitle: !0,
66
+ description: `${a[Z.sport]} · ${r[Z.level]} · ${Z.weeks} ${Z.weeks === 1 ? "week" : "weeks"}`,
63
67
  actions: /* @__PURE__ */ C("div", {
64
68
  className: "flex flex-wrap items-center gap-2",
65
69
  children: [
66
70
  /* @__PURE__ */ C("button", {
67
71
  type: "button",
68
- onClick: () => P("/programs"),
72
+ onClick: () => F("/programs"),
69
73
  className: "inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken",
70
74
  children: [/* @__PURE__ */ S(g, { className: "h-4 w-4" }), " Back"]
71
75
  }),
72
76
  /* @__PURE__ */ C("button", {
73
77
  type: "button",
74
- onClick: () => P(`/programs/${Z.id}/edit`),
78
+ onClick: () => F(`/programs/${Z.id}/edit`),
75
79
  className: "inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken",
76
80
  children: [/* @__PURE__ */ S(v, { className: "h-4 w-4" }), " Edit"]
77
81
  }),
78
82
  Z.status !== "ARCHIVED" && /* @__PURE__ */ C("button", {
79
83
  type: "button",
80
84
  onClick: async () => {
81
- N && (await L.mutateAsync(N), P("/programs"));
85
+ P && (await R.mutateAsync(P), F("/programs"));
82
86
  },
83
- disabled: L.isPending,
87
+ disabled: R.isPending,
84
88
  className: "inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:opacity-60",
85
89
  children: [
86
- L.isPending ? /* @__PURE__ */ S(b, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ S(h, { className: "h-4 w-4" }),
90
+ R.isPending ? /* @__PURE__ */ S(b, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ S(h, { className: "h-4 w-4" }),
87
91
  " ",
88
92
  "Archive"
89
93
  ]
@@ -96,10 +100,44 @@ function N() {
96
100
  className: "mb-8 p-6",
97
101
  children: [
98
102
  /* @__PURE__ */ C("div", {
99
- className: "flex flex-wrap items-center gap-3",
100
- children: [/* @__PURE__ */ S(n, { status: Z.status }), Z.isTemplate && /* @__PURE__ */ C("span", {
101
- className: "inline-flex items-center gap-1 text-sm text-text-secondary",
102
- children: [/* @__PURE__ */ S(_, { className: "h-3.5 w-3.5" }), " Template"]
103
+ className: "flex items-start gap-4",
104
+ children: [/* @__PURE__ */ S("div", {
105
+ className: "flex h-14 w-14 shrink-0 items-center justify-center rounded-2xl bg-[var(--color-accent-soft)] text-text-primary",
106
+ children: /* @__PURE__ */ S(ge, {
107
+ className: "h-7 w-7",
108
+ "aria-hidden": "true"
109
+ })
110
+ }), /* @__PURE__ */ C("div", {
111
+ className: "min-w-0 flex-1",
112
+ children: [/* @__PURE__ */ C("div", {
113
+ className: "flex flex-wrap items-center gap-2",
114
+ children: [
115
+ /* @__PURE__ */ S(w, {
116
+ variant: "secondary",
117
+ children: a[Z.sport]
118
+ }),
119
+ /* @__PURE__ */ S(w, {
120
+ variant: "secondary",
121
+ children: r[Z.level]
122
+ }),
123
+ /* @__PURE__ */ S(n, { status: Z.status }),
124
+ Z.isTemplate && /* @__PURE__ */ C("span", {
125
+ className: "inline-flex items-center gap-1 text-xs text-text-secondary",
126
+ children: [/* @__PURE__ */ S(_, { className: "h-3.5 w-3.5" }), " Template"]
127
+ })
128
+ ]
129
+ }), /* @__PURE__ */ C("p", {
130
+ className: "mt-2 text-sm text-text-secondary",
131
+ children: [
132
+ Z.weeks,
133
+ " ",
134
+ Z.weeks === 1 ? "week" : "weeks",
135
+ " · ",
136
+ Q,
137
+ " ",
138
+ Q === 1 ? "drill" : "drills"
139
+ ]
140
+ })]
103
141
  })]
104
142
  }),
105
143
  Z.summary && /* @__PURE__ */ S("p", {
@@ -123,20 +161,20 @@ function N() {
123
161
  Z.status === "DRAFT" && /* @__PURE__ */ C("button", {
124
162
  type: "button",
125
163
  onClick: () => $("PUBLISHED"),
126
- disabled: I.isPending,
164
+ disabled: L.isPending,
127
165
  className: "inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-3 py-1.5 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-60",
128
- children: [/* @__PURE__ */ S(ie, { className: "h-4 w-4" }), " Publish"]
166
+ children: [/* @__PURE__ */ S(ae, { className: "h-4 w-4" }), " Publish"]
129
167
  }),
130
- Z.status === "PUBLISHED" && /* @__PURE__ */ C(ce, { children: [/* @__PURE__ */ C("button", {
168
+ Z.status === "PUBLISHED" && /* @__PURE__ */ C(le, { children: [/* @__PURE__ */ C("button", {
131
169
  type: "button",
132
170
  onClick: () => $("DRAFT"),
133
- disabled: I.isPending,
171
+ disabled: L.isPending,
134
172
  className: "inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:opacity-60",
135
- children: [/* @__PURE__ */ S(oe, { className: "h-4 w-4" }), " Pull back to draft"]
173
+ children: [/* @__PURE__ */ S(se, { className: "h-4 w-4" }), " Pull back to draft"]
136
174
  }), /* @__PURE__ */ C("button", {
137
175
  type: "button",
138
176
  onClick: () => $("ARCHIVED"),
139
- disabled: I.isPending,
177
+ disabled: L.isPending,
140
178
  className: "inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:opacity-60",
141
179
  children: [/* @__PURE__ */ S(h, { className: "h-4 w-4" }), " Archive"]
142
180
  })] }),
@@ -144,7 +182,7 @@ function N() {
144
182
  className: "text-sm text-text-secondary",
145
183
  children: "This program is archived."
146
184
  }),
147
- I.isPending && /* @__PURE__ */ S(b, { className: "h-4 w-4 animate-spin text-text-secondary" })
185
+ L.isPending && /* @__PURE__ */ S(b, { className: "h-4 w-4 animate-spin text-text-secondary" })
148
186
  ]
149
187
  })
150
188
  ]
@@ -161,94 +199,120 @@ function N() {
161
199
  }), /* @__PURE__ */ C("button", {
162
200
  type: "button",
163
201
  onClick: () => {
164
- X(null), H(!0);
202
+ Y(null), V(!0);
165
203
  },
166
204
  className: "inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-3 py-1.5 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90",
167
205
  children: [/* @__PURE__ */ S(x, { className: "h-4 w-4" }), " Add drill"]
168
206
  })]
169
- }), Q === 0 ? /* @__PURE__ */ S(a, {
207
+ }), Q === 0 ? /* @__PURE__ */ S(o, {
170
208
  illustration: "empty-data",
171
209
  icon: /* @__PURE__ */ S(x, { className: "h-10 w-10" }),
172
210
  title: "No drills yet",
173
211
  description: "Add drills with sets, reps and durations, organized by week."
174
- }) : /* @__PURE__ */ S("div", {
175
- className: "space-y-6",
176
- children: le.map(({ week: e, drills: t }) => /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ C("h3", {
177
- className: "mb-3 text-sm font-semibold uppercase tracking-wide text-text-secondary",
178
- children: ["Week ", e]
179
- }), /* @__PURE__ */ S(w, { children: /* @__PURE__ */ S("div", {
180
- className: "divide-y divide-border-seam",
181
- children: t.map((e) => /* @__PURE__ */ C("div", {
182
- className: "flex items-start gap-4 py-3",
183
- children: [/* @__PURE__ */ C("div", {
184
- className: "min-w-0 flex-1",
185
- children: [
186
- /* @__PURE__ */ S("p", {
187
- className: "text-sm font-medium text-text-primary",
188
- children: e.name
189
- }),
190
- e.description && /* @__PURE__ */ S("p", {
191
- className: "mt-0.5 text-xs text-text-secondary",
192
- children: e.description
193
- }),
194
- /* @__PURE__ */ C("div", {
195
- className: "mt-1.5 flex flex-wrap gap-x-3 gap-y-1 text-xs text-text-secondary",
212
+ }) : /* @__PURE__ */ S(ue, {
213
+ type: "multiple",
214
+ defaultValue: _e,
215
+ className: "flex flex-col gap-3",
216
+ children: X.map(({ week: e, drills: t }) => /* @__PURE__ */ S(T, {
217
+ treatment: "insight",
218
+ className: "overflow-hidden px-4 py-0",
219
+ children: /* @__PURE__ */ C(fe, {
220
+ value: `week-${e}`,
221
+ className: "border-b-0",
222
+ children: [/* @__PURE__ */ S(pe, {
223
+ className: "py-4",
224
+ children: /* @__PURE__ */ C("span", {
225
+ className: "flex items-center gap-2.5",
226
+ children: [/* @__PURE__ */ C("span", {
227
+ className: "text-sm font-semibold text-text-primary",
228
+ children: ["Week ", e]
229
+ }), /* @__PURE__ */ C(w, {
230
+ variant: "secondary",
196
231
  children: [
197
- e.sets !== null && /* @__PURE__ */ C("span", { children: [e.sets, " sets"] }),
198
- e.reps !== null && /* @__PURE__ */ C("span", { children: [e.reps, " reps"] }),
199
- e.durationSec !== null && /* @__PURE__ */ C("span", { children: [e.durationSec, "s work"] }),
200
- e.restSec !== null && /* @__PURE__ */ C("span", { children: [e.restSec, "s rest"] })
232
+ t.length,
233
+ " ",
234
+ t.length === 1 ? "drill" : "drills"
201
235
  ]
202
- }),
203
- e.video?.id && /* @__PURE__ */ S("div", { children: /* @__PURE__ */ S(f, { fileId: e.video.id }) })
204
- ]
205
- }), /* @__PURE__ */ S("button", {
206
- type: "button",
207
- onClick: () => void z.mutate(e.id),
208
- disabled: z.isPending,
209
- "aria-label": `Remove ${e.name}`,
210
- className: "rounded-lg p-2 text-text-secondary transition-colors hover:bg-status-error-bg-subtle hover:text-status-error-text disabled:opacity-60",
211
- children: /* @__PURE__ */ S(ae, { className: "h-4 w-4" })
236
+ })]
237
+ })
238
+ }), /* @__PURE__ */ S(de, {
239
+ className: "pb-2",
240
+ children: /* @__PURE__ */ S("div", {
241
+ className: "divide-y divide-border-seam",
242
+ children: t.map((e) => /* @__PURE__ */ C("div", {
243
+ className: "flex items-start gap-4 py-3",
244
+ children: [/* @__PURE__ */ C("div", {
245
+ className: "min-w-0 flex-1",
246
+ children: [
247
+ /* @__PURE__ */ S("p", {
248
+ className: "text-sm font-medium text-text-primary",
249
+ children: e.name
250
+ }),
251
+ e.description && /* @__PURE__ */ S("p", {
252
+ className: "mt-0.5 text-xs text-text-secondary",
253
+ children: e.description
254
+ }),
255
+ /* @__PURE__ */ C("div", {
256
+ className: "mt-2 flex flex-wrap gap-1.5",
257
+ children: [
258
+ e.sets !== null && /* @__PURE__ */ C(M, { children: [e.sets, " sets"] }),
259
+ e.reps !== null && /* @__PURE__ */ C(M, { children: [e.reps, " reps"] }),
260
+ e.durationSec !== null && /* @__PURE__ */ C(M, { children: [e.durationSec, "s work"] }),
261
+ e.restSec !== null && /* @__PURE__ */ C(M, { children: [e.restSec, "s rest"] })
262
+ ]
263
+ }),
264
+ e.video?.id && /* @__PURE__ */ S("div", { children: /* @__PURE__ */ S(f, { fileId: e.video.id }) })
265
+ ]
266
+ }), /* @__PURE__ */ S("button", {
267
+ type: "button",
268
+ onClick: () => void B.mutate(e.id),
269
+ disabled: B.isPending,
270
+ "aria-label": `Remove ${e.name}`,
271
+ className: "rounded-lg p-2 text-text-secondary transition-colors hover:bg-status-error-bg-subtle hover:text-status-error-text disabled:opacity-60",
272
+ children: /* @__PURE__ */ S(oe, { className: "h-4 w-4" })
273
+ })]
274
+ }, e.id))
275
+ })
212
276
  })]
213
- }, e.id))
214
- }) })] }, e))
277
+ })
278
+ }, e))
215
279
  })] }),
216
280
  /* @__PURE__ */ S(E, {
217
- open: V,
218
- onOpenChange: H,
281
+ open: he,
282
+ onOpenChange: V,
219
283
  children: /* @__PURE__ */ C(D, { children: [/* @__PURE__ */ S(k, { children: /* @__PURE__ */ S(A, { children: "Add drill" }) }), /* @__PURE__ */ C("form", {
220
284
  onSubmit: async (e) => {
221
- if (e.preventDefault(), X(null), !N) return;
222
- if (!U.name.trim()) {
223
- X("Drill name is required.");
285
+ if (e.preventDefault(), Y(null), !P) return;
286
+ if (!H.name.trim()) {
287
+ Y("Drill name is required.");
224
288
  return;
225
289
  }
226
- let t = M(U.weekNumber) ?? 1, n;
227
- if (G) {
228
- J(!0);
290
+ let t = N(H.weekNumber) ?? 1, n;
291
+ if (W) {
292
+ q(!0);
229
293
  try {
230
- n = await B(G);
294
+ n = await me(W);
231
295
  } catch (e) {
232
- X(e instanceof Error ? e.message : "Failed to upload the demo video."), J(!1);
296
+ Y(e instanceof Error ? e.message : "Failed to upload the demo video."), q(!1);
233
297
  return;
234
298
  }
235
- J(!1);
299
+ q(!1);
236
300
  }
237
301
  try {
238
- await R.mutateAsync({
239
- programId: N,
240
- name: U.name.trim(),
241
- description: U.description.trim() || void 0,
302
+ await z.mutateAsync({
303
+ programId: P,
304
+ name: H.name.trim(),
305
+ description: H.description.trim() || void 0,
242
306
  weekNumber: t,
243
- orderIndex: F.data?.drills?.filter((e) => e.weekNumber === t).length ?? 0,
244
- sets: M(U.sets),
245
- reps: M(U.reps),
246
- durationSec: M(U.durationSec),
247
- restSec: M(U.restSec),
307
+ orderIndex: I.data?.drills?.filter((e) => e.weekNumber === t).length ?? 0,
308
+ sets: N(H.sets),
309
+ reps: N(H.reps),
310
+ durationSec: N(H.durationSec),
311
+ restSec: N(H.restSec),
248
312
  videoFileId: n
249
- }), W(j), K(null), H(!1);
313
+ }), U(j), G(null), V(!1);
250
314
  } catch (e) {
251
- X(e instanceof Error ? e.message : "Failed to add drill.");
315
+ Y(e instanceof Error ? e.message : "Failed to add drill.");
252
316
  }
253
317
  },
254
318
  className: "space-y-4 px-1",
@@ -260,8 +324,8 @@ function N() {
260
324
  children: /* @__PURE__ */ S("input", {
261
325
  id: "drillName",
262
326
  className: d,
263
- value: U.name,
264
- onChange: (e) => W((t) => ({
327
+ value: H.name,
328
+ onChange: (e) => U((t) => ({
265
329
  ...t,
266
330
  name: e.target.value
267
331
  })),
@@ -275,8 +339,8 @@ function N() {
275
339
  id: "drillDesc",
276
340
  className: d,
277
341
  rows: 2,
278
- value: U.description,
279
- onChange: (e) => W((t) => ({
342
+ value: H.description,
343
+ onChange: (e) => U((t) => ({
280
344
  ...t,
281
345
  description: e.target.value
282
346
  })),
@@ -284,7 +348,7 @@ function N() {
284
348
  })
285
349
  }),
286
350
  /* @__PURE__ */ C("div", {
287
- className: "grid grid-cols-3 gap-4",
351
+ className: "grid grid-cols-1 gap-4 sm:grid-cols-3",
288
352
  children: [
289
353
  /* @__PURE__ */ S(u, {
290
354
  label: "Week",
@@ -293,8 +357,8 @@ function N() {
293
357
  id: "drillWeek",
294
358
  inputMode: "numeric",
295
359
  className: d,
296
- value: U.weekNumber,
297
- onChange: (e) => W((t) => ({
360
+ value: H.weekNumber,
361
+ onChange: (e) => U((t) => ({
298
362
  ...t,
299
363
  weekNumber: e.target.value
300
364
  }))
@@ -307,8 +371,8 @@ function N() {
307
371
  id: "drillSets",
308
372
  inputMode: "numeric",
309
373
  className: d,
310
- value: U.sets,
311
- onChange: (e) => W((t) => ({
374
+ value: H.sets,
375
+ onChange: (e) => U((t) => ({
312
376
  ...t,
313
377
  sets: e.target.value
314
378
  }))
@@ -321,8 +385,8 @@ function N() {
321
385
  id: "drillReps",
322
386
  inputMode: "numeric",
323
387
  className: d,
324
- value: U.reps,
325
- onChange: (e) => W((t) => ({
388
+ value: H.reps,
389
+ onChange: (e) => U((t) => ({
326
390
  ...t,
327
391
  reps: e.target.value
328
392
  }))
@@ -339,8 +403,8 @@ function N() {
339
403
  id: "drillDuration",
340
404
  inputMode: "numeric",
341
405
  className: d,
342
- value: U.durationSec,
343
- onChange: (e) => W((t) => ({
406
+ value: H.durationSec,
407
+ onChange: (e) => U((t) => ({
344
408
  ...t,
345
409
  durationSec: e.target.value
346
410
  }))
@@ -352,8 +416,8 @@ function N() {
352
416
  id: "drillRest",
353
417
  inputMode: "numeric",
354
418
  className: d,
355
- value: U.restSec,
356
- onChange: (e) => W((t) => ({
419
+ value: H.restSec,
420
+ onChange: (e) => U((t) => ({
357
421
  ...t,
358
422
  restSec: e.target.value
359
423
  }))
@@ -369,32 +433,32 @@ function N() {
369
433
  type: "file",
370
434
  accept: "video/*",
371
435
  className: d,
372
- onChange: (e) => K(e.target.files?.[0] ?? null)
373
- }), G && /* @__PURE__ */ C("p", {
436
+ onChange: (e) => G(e.target.files?.[0] ?? null)
437
+ }), W && /* @__PURE__ */ C("p", {
374
438
  className: "mt-1 inline-flex items-center gap-1 text-xs text-text-secondary",
375
439
  children: [
376
440
  /* @__PURE__ */ S(y, { className: "h-3.5 w-3.5" }),
377
441
  " ",
378
- G.name
442
+ W.name
379
443
  ]
380
444
  })]
381
445
  }),
382
- Y && /* @__PURE__ */ S("p", {
446
+ J && /* @__PURE__ */ S("p", {
383
447
  className: "text-sm text-status-error-text",
384
- children: Y
448
+ children: J
385
449
  }),
386
450
  /* @__PURE__ */ C(O, { children: [/* @__PURE__ */ S("button", {
387
451
  type: "button",
388
452
  onClick: () => {
389
- H(!1), K(null);
453
+ V(!1), G(null);
390
454
  },
391
455
  className: "rounded-lg border border-border-seam px-4 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken",
392
456
  children: "Cancel"
393
457
  }), /* @__PURE__ */ C("button", {
394
458
  type: "submit",
395
- disabled: R.isPending || q,
459
+ disabled: z.isPending || K,
396
460
  className: "inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-60",
397
- children: [(R.isPending || q) && /* @__PURE__ */ S(b, { className: "h-4 w-4 animate-spin" }), q ? "Uploading video…" : "Add drill"]
461
+ children: [(z.isPending || K) && /* @__PURE__ */ S(b, { className: "h-4 w-4 animate-spin" }), K ? "Uploading video…" : "Add drill"]
398
462
  })] })
399
463
  ]
400
464
  })] })
@@ -403,6 +467,6 @@ function N() {
403
467
  });
404
468
  }
405
469
  //#endregion
406
- export { N as ProgramDetailPage };
470
+ export { P as ProgramDetailPage };
407
471
 
408
472
  //# sourceMappingURL=ProgramDetailPage.js.map