@burdenoff/microfe-hookmovies 2026.706.3 → 2026.706.4

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 (33) hide show
  1. package/dist/hookmovies/pages/HomePage.js +211 -139
  2. package/dist/hookmovies/pages/HomePage.js.map +1 -1
  3. package/dist/hookmovies/pages/ai/ConciergePage.js +3 -3
  4. package/dist/hookmovies/pages/auditions/AuditionDetailPage.js +223 -140
  5. package/dist/hookmovies/pages/auditions/AuditionDetailPage.js.map +1 -1
  6. package/dist/hookmovies/pages/auditions/AuditionsPage.js +159 -81
  7. package/dist/hookmovies/pages/auditions/AuditionsPage.js.map +1 -1
  8. package/dist/hookmovies/pages/catalog/PeoplePage.js +175 -101
  9. package/dist/hookmovies/pages/catalog/PeoplePage.js.map +1 -1
  10. package/dist/hookmovies/pages/catalog/StudiosPage.js +189 -106
  11. package/dist/hookmovies/pages/catalog/StudiosPage.js.map +1 -1
  12. package/dist/hookmovies/pages/catalog/TitleDetailPage.js +745 -623
  13. package/dist/hookmovies/pages/catalog/TitleDetailPage.js.map +1 -1
  14. package/dist/hookmovies/pages/catalog/TitlesPage.js +218 -138
  15. package/dist/hookmovies/pages/catalog/TitlesPage.js.map +1 -1
  16. package/dist/hookmovies/pages/commerce/CheckoutPage.js +8 -8
  17. package/dist/hookmovies/pages/consumer/DiscoveryPage.js +14 -14
  18. package/dist/hookmovies/pages/consumer/TitleViewPage.js +6 -6
  19. package/dist/hookmovies/pages/distribution/RightsWindowsPage.js +235 -162
  20. package/dist/hookmovies/pages/distribution/RightsWindowsPage.js.map +1 -1
  21. package/dist/hookmovies/pages/library/EntitlementsPage.js +447 -221
  22. package/dist/hookmovies/pages/library/EntitlementsPage.js.map +1 -1
  23. package/dist/hookmovies/pages/library/ListsPage.js +242 -166
  24. package/dist/hookmovies/pages/library/ListsPage.js.map +1 -1
  25. package/dist/hookmovies/pages/live/LivePage.js +12 -12
  26. package/dist/hookmovies/pages/localization/LocalizationPage.js +10 -10
  27. package/dist/hookmovies/pages/productions/ProductionDetailPage.js +265 -179
  28. package/dist/hookmovies/pages/productions/ProductionDetailPage.js.map +1 -1
  29. package/dist/hookmovies/pages/productions/ProductionsPage.js +264 -71
  30. package/dist/hookmovies/pages/productions/ProductionsPage.js.map +1 -1
  31. package/dist/hookmovies/pages/social/WatchPartyRoomPage.js +205 -205
  32. package/dist/hookmovies/pages/social/WatchPartyRoomPage.js.map +1 -1
  33. package/package.json +1 -1
@@ -4,158 +4,199 @@ import { PageLayout as n } from "../components/PageLayout.js";
4
4
  import { MetricsCard as r } from "../components/MetricsCard.js";
5
5
  import { StatusBadge as i } from "../components/StatusBadge.js";
6
6
  import { useAuditions as a, useMyWatchProgress as o, usePeople as s, useProductions as c, useReviews as l, useStudios as u, useTitles as d } from "../hooks/useHookMoviesApi.js";
7
- import { formatEnumLabel as f, formatRelativeTime as p } from "../utils/formatters.js";
8
- import { useMemo as m } from "react";
9
- import { ArrowRight as h, Building2 as g, Clapperboard as _, Film as v, Megaphone as y, PlayCircle as b, Plus as x, ScrollText as S, Star as C, Users as w } from "lucide-react";
10
- import { jsx as T, jsxs as E } from "react/jsx-runtime";
11
- import { GlassCard as D } from "@burdenoff/fe-libs/ui";
7
+ import { useFileUrl as f } from "../hooks/useFiles.js";
8
+ import { formatEnumLabel as p, formatRelativeTime as m } from "../utils/formatters.js";
9
+ import { useMemo as h, useState as g } from "react";
10
+ import { ArrowRight as _, Building2 as v, Clapperboard as y, Film as b, Megaphone as x, PlayCircle as S, Plus as C, ScrollText as w, Star as T, Users as E } from "lucide-react";
11
+ import { jsx as D, jsxs as O } from "react/jsx-runtime";
12
+ import { GlassCard as k } from "@burdenoff/fe-libs/ui";
12
13
  //#region src/hookmovies/pages/HomePage.tsx
13
- var O = {
14
+ var A = ({ fileId: e, alt: n }) => {
15
+ let { data: r, isLoading: i } = f(e), [a, o] = g(!1);
16
+ return /* @__PURE__ */ D("div", {
17
+ className: "relative h-16 w-11 shrink-0 overflow-hidden rounded-md border border-border-seam bg-bg-sunken",
18
+ children: e && r && !a ? /* @__PURE__ */ D("img", {
19
+ src: r ?? void 0,
20
+ alt: n,
21
+ loading: "lazy",
22
+ onError: () => o(!0),
23
+ className: "h-full w-full object-cover"
24
+ }) : /* @__PURE__ */ D("div", {
25
+ className: t("flex h-full w-full items-center justify-center text-text-muted", i && !!e && "motion-safe:animate-pulse"),
26
+ "aria-hidden": "true",
27
+ children: /* @__PURE__ */ D(b, { className: "h-4 w-4" })
28
+ })
29
+ });
30
+ }, j = {
14
31
  limit: 5,
15
32
  offset: 0
16
- }, k = {
33
+ }, M = {
17
34
  limit: 1,
18
35
  offset: 0
19
- }, A = () => {
20
- let { navigateTo: A, currentUser: j } = e(), M = d({}, k), N = c({}, k), P = a({ status: "OPEN" }, k), F = l({}, k), I = u(k), L = s(k), R = d({}, O), z = o(), B = M.data?.totalCount ?? 0, V = N.data?.totalCount ?? 0, H = P.data?.totalCount ?? 0, U = F.data?.totalCount ?? 0, W = I.data?.totalCount ?? 0, G = L.data?.totalCount ?? 0, K = m(() => (z.data ?? []).filter((e) => !e.completed).slice(0, 4), [z.data]), q = [
36
+ }, N = () => {
37
+ let { navigateTo: f, currentUser: g } = e(), N = d({}, M), P = c({}, M), F = a({ status: "OPEN" }, M), I = l({}, M), L = u(M), R = s(M), z = d({}, j), B = o(), V = N.data?.totalCount ?? 0, H = P.data?.totalCount ?? 0, U = F.data?.totalCount ?? 0, W = I.data?.totalCount ?? 0, G = L.data?.totalCount ?? 0, K = R.data?.totalCount ?? 0, q = h(() => (B.data ?? []).filter((e) => !e.completed).slice(0, 4), [B.data]), J = [
38
+ {
39
+ id: "titles",
40
+ icon: /* @__PURE__ */ D(b, { className: "h-5 w-5" }),
41
+ value: V,
42
+ label: "Titles",
43
+ path: "catalog/titles",
44
+ featured: !0
45
+ },
46
+ {
47
+ id: "productions",
48
+ icon: /* @__PURE__ */ D(y, { className: "h-5 w-5" }),
49
+ value: H,
50
+ label: "Productions",
51
+ path: "productions"
52
+ },
53
+ {
54
+ id: "auditions",
55
+ icon: /* @__PURE__ */ D(x, { className: "h-5 w-5" }),
56
+ value: U,
57
+ label: "Open Auditions",
58
+ path: "auditions"
59
+ },
60
+ {
61
+ id: "reviews",
62
+ icon: /* @__PURE__ */ D(T, { className: "h-5 w-5" }),
63
+ value: W,
64
+ label: "Reviews",
65
+ path: "engagement/reviews"
66
+ },
67
+ {
68
+ id: "studios",
69
+ icon: /* @__PURE__ */ D(v, { className: "h-5 w-5" }),
70
+ value: G,
71
+ label: "Studios",
72
+ path: "catalog/studios"
73
+ },
74
+ {
75
+ id: "people",
76
+ icon: /* @__PURE__ */ D(E, { className: "h-5 w-5" }),
77
+ value: K,
78
+ label: "People",
79
+ path: "catalog/people"
80
+ }
81
+ ], Y = [
21
82
  {
22
83
  id: "catalog",
23
84
  label: "Catalog",
24
85
  description: "Movies, series, anime & more",
25
- icon: v,
86
+ icon: b,
26
87
  path: "catalog/titles"
27
88
  },
28
89
  {
29
90
  id: "studios",
30
91
  label: "Studios",
31
92
  description: "Studios, channels & networks",
32
- icon: g,
93
+ icon: v,
33
94
  path: "catalog/studios"
34
95
  },
35
96
  {
36
97
  id: "people",
37
98
  label: "People",
38
99
  description: "Cast & crew directory",
39
- icon: w,
100
+ icon: E,
40
101
  path: "catalog/people"
41
102
  },
42
103
  {
43
104
  id: "productions",
44
105
  label: "Productions",
45
106
  description: "Development → release pipeline",
46
- icon: _,
107
+ icon: y,
47
108
  path: "productions"
48
109
  },
49
110
  {
50
111
  id: "auditions",
51
112
  label: "Auditions",
52
113
  description: "Casting & talent marketplace",
53
- icon: y,
114
+ icon: x,
54
115
  path: "auditions"
55
116
  },
56
117
  {
57
118
  id: "reviews",
58
119
  label: "Reviews",
59
120
  description: "Ratings & audience reviews",
60
- icon: C,
121
+ icon: T,
61
122
  path: "engagement/reviews"
62
123
  },
63
124
  {
64
125
  id: "rights",
65
126
  label: "Rights & Distribution",
66
127
  description: "Licensing windows & territories",
67
- icon: S,
128
+ icon: w,
68
129
  path: "distribution/rights"
69
130
  },
70
131
  {
71
132
  id: "library",
72
133
  label: "My Library",
73
134
  description: "Watchlists, playlists & history",
74
- icon: b,
135
+ icon: S,
75
136
  path: "library/lists"
76
137
  }
77
138
  ];
78
- return /* @__PURE__ */ E(n, {
139
+ return /* @__PURE__ */ O(n, {
79
140
  hero: !0,
80
141
  title: "HookMovies",
81
- description: j?.name ? `Welcome back, ${j.name}` : "The global creative-media network",
142
+ description: g?.name ? `Welcome back, ${g.name}` : "The global creative-media network",
82
143
  purpose: "Discover and stream titles, run productions and casting, and manage rights & distribution — your workspace's whole creative-media operation in one place.",
83
- actions: /* @__PURE__ */ E("button", {
144
+ actions: /* @__PURE__ */ O("button", {
84
145
  type: "button",
85
- onClick: () => A("catalog/titles/new"),
146
+ onClick: () => f("catalog/titles/new"),
86
147
  className: "inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90 transition-opacity",
87
- children: [/* @__PURE__ */ T(x, { className: "h-4 w-4" }), "New Title"]
148
+ children: [/* @__PURE__ */ D(C, { className: "h-4 w-4" }), "New Title"]
88
149
  }),
89
150
  children: [
90
- /* @__PURE__ */ E("div", {
91
- className: "grid grid-cols-2 gap-4 lg:grid-cols-3 xl:grid-cols-6",
92
- children: [
93
- /* @__PURE__ */ T(r, {
94
- featured: !0,
95
- icon: /* @__PURE__ */ T(v, { className: "h-5 w-5" }),
96
- value: B,
97
- label: "Titles"
98
- }),
99
- /* @__PURE__ */ T(r, {
100
- icon: /* @__PURE__ */ T(_, { className: "h-5 w-5" }),
101
- value: V,
102
- label: "Productions"
103
- }),
104
- /* @__PURE__ */ T(r, {
105
- icon: /* @__PURE__ */ T(y, { className: "h-5 w-5" }),
106
- value: H,
107
- label: "Open Auditions"
108
- }),
109
- /* @__PURE__ */ T(r, {
110
- icon: /* @__PURE__ */ T(C, { className: "h-5 w-5" }),
111
- value: U,
112
- label: "Reviews"
113
- }),
114
- /* @__PURE__ */ T(r, {
115
- icon: /* @__PURE__ */ T(g, { className: "h-5 w-5" }),
116
- value: W,
117
- label: "Studios"
118
- }),
119
- /* @__PURE__ */ T(r, {
120
- icon: /* @__PURE__ */ T(w, { className: "h-5 w-5" }),
121
- value: G,
122
- label: "People"
151
+ /* @__PURE__ */ D("div", {
152
+ className: "grid grid-cols-2 gap-3 sm:gap-4 lg:grid-cols-3 xl:grid-cols-6",
153
+ children: J.map((e) => /* @__PURE__ */ D("button", {
154
+ type: "button",
155
+ onClick: () => f(e.path),
156
+ "aria-label": `${e.label}: ${e.value}. Open ${e.label}`,
157
+ className: t("group rounded-2xl text-left focus:outline-none", "focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]"),
158
+ children: /* @__PURE__ */ D(r, {
159
+ featured: e.featured,
160
+ icon: e.icon,
161
+ value: e.value,
162
+ label: e.label,
163
+ className: t("h-full !p-4 transition-[transform,border-color,box-shadow] duration-200", "group-hover:border-border-strong group-hover:shadow-elevation-2", "motion-safe:group-hover:-translate-y-0.5 motion-reduce:transform-none")
123
164
  })
124
- ]
165
+ }, e.id))
125
166
  }),
126
- K.length > 0 && /* @__PURE__ */ E("section", {
167
+ q.length > 0 && /* @__PURE__ */ O("section", {
127
168
  className: "mt-8",
128
- children: [/* @__PURE__ */ T("h2", {
169
+ children: [/* @__PURE__ */ D("h2", {
129
170
  className: "mb-3 text-lg font-semibold text-text-primary",
130
171
  children: "Continue Watching"
131
- }), /* @__PURE__ */ T("div", {
172
+ }), /* @__PURE__ */ D("div", {
132
173
  className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
133
- children: K.map((e) => /* @__PURE__ */ T("button", {
174
+ children: q.map((e) => /* @__PURE__ */ D("button", {
134
175
  type: "button",
135
- onClick: () => e.title && A(`catalog/titles/${e.title.id}`),
176
+ onClick: () => e.title && f(`catalog/titles/${e.title.id}`),
136
177
  className: "text-left",
137
- children: /* @__PURE__ */ E(D, {
178
+ children: /* @__PURE__ */ O(k, {
138
179
  treatment: "metric",
139
180
  className: "h-full border-border-seam p-4",
140
181
  children: [
141
- /* @__PURE__ */ E("div", {
182
+ /* @__PURE__ */ O("div", {
142
183
  className: "flex items-center gap-2 text-action-primary-bg",
143
- children: [/* @__PURE__ */ T(b, { className: "h-5 w-5" }), e.title && /* @__PURE__ */ T("span", {
184
+ children: [/* @__PURE__ */ D(S, { className: "h-5 w-5" }), e.title && /* @__PURE__ */ D("span", {
144
185
  className: "text-xs font-medium uppercase tracking-wide text-text-secondary",
145
- children: f(e.title.type)
186
+ children: p(e.title.type)
146
187
  })]
147
188
  }),
148
- /* @__PURE__ */ T("p", {
189
+ /* @__PURE__ */ D("p", {
149
190
  className: "mt-2 line-clamp-1 text-sm font-semibold text-text-primary",
150
191
  children: e.title?.title ?? "Untitled"
151
192
  }),
152
- /* @__PURE__ */ E("p", {
193
+ /* @__PURE__ */ O("p", {
153
194
  className: "mt-1 text-xs text-text-secondary",
154
195
  children: [
155
196
  Math.round(e.positionSeconds / 60),
156
197
  " min in ·",
157
198
  " ",
158
- p(e.updatedAt)
199
+ m(e.updatedAt)
159
200
  ]
160
201
  })
161
202
  ]
@@ -163,91 +204,122 @@ var O = {
163
204
  }, e.id))
164
205
  })]
165
206
  }),
166
- /* @__PURE__ */ E("section", {
167
- className: "mt-8",
168
- children: [/* @__PURE__ */ T("h2", {
169
- className: "mb-3 text-lg font-semibold text-text-primary",
170
- children: "Modules"
171
- }), /* @__PURE__ */ T("div", {
172
- className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
173
- children: q.map((e) => {
174
- let t = e.icon;
175
- return /* @__PURE__ */ T("button", {
207
+ /* @__PURE__ */ O("div", {
208
+ className: "mt-8 grid grid-cols-1 gap-6 xl:grid-cols-12",
209
+ children: [/* @__PURE__ */ O("section", {
210
+ className: "xl:col-span-5",
211
+ children: [/* @__PURE__ */ O("div", {
212
+ className: "mb-3 flex items-center justify-between gap-3",
213
+ children: [/* @__PURE__ */ O("div", {
214
+ className: "min-w-0",
215
+ children: [/* @__PURE__ */ D("h2", {
216
+ className: "text-lg font-semibold text-text-primary",
217
+ children: "Recently Added"
218
+ }), /* @__PURE__ */ D("p", {
219
+ className: "mt-0.5 text-xs text-text-secondary",
220
+ children: "Latest titles in your catalog"
221
+ })]
222
+ }), /* @__PURE__ */ O("button", {
176
223
  type: "button",
177
- onClick: () => A(e.path),
178
- className: "group text-left",
179
- children: /* @__PURE__ */ E(D, {
180
- treatment: "metric",
181
- className: "flex h-full flex-col border-border-seam p-5",
224
+ onClick: () => f("catalog/titles"),
225
+ className: "inline-flex shrink-0 items-center gap-1 text-sm font-medium text-action-primary-bg hover:opacity-80",
226
+ children: ["View all", /* @__PURE__ */ D(_, { className: "h-3.5 w-3.5" })]
227
+ })]
228
+ }), /* @__PURE__ */ D(k, {
229
+ treatment: "metric",
230
+ className: "overflow-hidden border-border-seam p-0",
231
+ children: /* @__PURE__ */ O("ul", {
232
+ className: "divide-y divide-border-seam",
233
+ children: [(z.data?.items ?? []).map((e) => /* @__PURE__ */ D("li", { children: /* @__PURE__ */ O("button", {
234
+ type: "button",
235
+ onClick: () => f(`catalog/titles/${e.id}`),
236
+ className: t("flex w-full items-center gap-3 px-4 py-3 text-left", "transition-colors hover:bg-bg-sunken", "focus:outline-none focus-visible:bg-bg-sunken"),
182
237
  children: [
183
- /* @__PURE__ */ E("div", {
184
- className: "flex items-center justify-between",
185
- children: [/* @__PURE__ */ T("span", {
186
- className: "inline-flex h-10 w-10 items-center justify-center rounded-lg bg-bg-sunken text-action-primary-bg",
187
- children: /* @__PURE__ */ T(t, { className: "h-5 w-5" })
188
- }), /* @__PURE__ */ T(h, { className: "h-4 w-4 text-text-secondary transition-colors group-hover:text-text-primary" })]
238
+ /* @__PURE__ */ D(A, {
239
+ fileId: e.posterFileId,
240
+ alt: `${e.title} poster`
189
241
  }),
190
- /* @__PURE__ */ T("p", {
191
- className: "mt-3 text-sm font-semibold text-text-primary",
192
- children: e.label
242
+ /* @__PURE__ */ O("div", {
243
+ className: "min-w-0 flex-1",
244
+ children: [
245
+ /* @__PURE__ */ D("p", {
246
+ className: "truncate text-sm font-semibold text-text-primary",
247
+ children: e.title
248
+ }),
249
+ /* @__PURE__ */ O("p", {
250
+ className: "mt-0.5 truncate text-xs text-text-secondary",
251
+ children: [
252
+ p(e.type),
253
+ e.releaseYear ? ` · ${e.releaseYear}` : "",
254
+ e.originalLanguage ? ` · ${e.originalLanguage.toUpperCase()}` : ""
255
+ ]
256
+ }),
257
+ /* @__PURE__ */ O("p", {
258
+ className: "mt-1 text-[11px] text-text-muted",
259
+ children: ["Added ", m(e.createdAt)]
260
+ })
261
+ ]
193
262
  }),
194
- /* @__PURE__ */ T("p", {
195
- className: "mt-1 text-xs text-text-secondary",
196
- children: e.description
263
+ /* @__PURE__ */ D(i, {
264
+ status: e.status,
265
+ className: "shrink-0"
197
266
  })
198
267
  ]
199
- })
200
- }, e.id);
201
- })
202
- })]
203
- }),
204
- /* @__PURE__ */ E("section", {
205
- className: "mt-8",
206
- children: [/* @__PURE__ */ E("div", {
207
- className: "mb-3 flex items-center justify-between",
208
- children: [/* @__PURE__ */ T("h2", {
209
- className: "text-lg font-semibold text-text-primary",
210
- children: "Recently Added"
211
- }), /* @__PURE__ */ E("button", {
212
- type: "button",
213
- onClick: () => A("catalog/titles"),
214
- className: "inline-flex items-center gap-1 text-sm font-medium text-action-primary-bg hover:opacity-80",
215
- children: ["View all", /* @__PURE__ */ T(h, { className: "h-3.5 w-3.5" })]
268
+ }) }, e.id)), z.data && z.data.items.length === 0 && /* @__PURE__ */ O("li", {
269
+ className: "flex flex-col items-center gap-2 px-4 py-10 text-center",
270
+ children: [/* @__PURE__ */ D("span", {
271
+ className: "inline-flex h-10 w-10 items-center justify-center rounded-full bg-bg-sunken text-text-muted",
272
+ children: /* @__PURE__ */ D(b, { className: "h-5 w-5" })
273
+ }), /* @__PURE__ */ D("p", {
274
+ className: "text-sm text-text-secondary",
275
+ children: "No titles yet — create your first title to get started."
276
+ })]
277
+ })]
278
+ })
216
279
  })]
217
- }), /* @__PURE__ */ T(D, {
218
- treatment: "metric",
219
- className: "border-border-seam",
220
- children: /* @__PURE__ */ E("ul", {
221
- className: "divide-y divide-border-seam",
222
- children: [(R.data?.items ?? []).map((e) => /* @__PURE__ */ T("li", { children: /* @__PURE__ */ E("button", {
223
- type: "button",
224
- onClick: () => A(`catalog/titles/${e.id}`),
225
- className: t("flex w-full items-center justify-between gap-3 px-4 py-3 text-left", "hover:bg-bg-sunken transition-colors"),
226
- children: [/* @__PURE__ */ E("div", {
227
- className: "min-w-0",
228
- children: [/* @__PURE__ */ T("p", {
229
- className: "truncate text-sm font-medium text-text-primary",
230
- children: e.title
231
- }), /* @__PURE__ */ E("p", {
232
- className: "text-xs text-text-secondary",
280
+ }), /* @__PURE__ */ O("section", {
281
+ className: "xl:col-span-7",
282
+ children: [/* @__PURE__ */ D("h2", {
283
+ className: "mb-3 text-lg font-semibold text-text-primary",
284
+ children: "Explore Modules"
285
+ }), /* @__PURE__ */ D("div", {
286
+ className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-2 2xl:grid-cols-3",
287
+ children: Y.map((e) => {
288
+ let n = e.icon;
289
+ return /* @__PURE__ */ D("button", {
290
+ type: "button",
291
+ onClick: () => f(e.path),
292
+ className: t("group rounded-2xl text-left focus:outline-none", "focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]"),
293
+ children: /* @__PURE__ */ O(k, {
294
+ treatment: "metric",
295
+ className: t("flex h-full flex-col border-border-seam p-5", "transition-[transform,border-color,box-shadow] duration-200", "group-hover:border-border-strong group-hover:shadow-elevation-2", "motion-safe:group-hover:-translate-y-0.5 motion-reduce:transform-none"),
233
296
  children: [
234
- f(e.type),
235
- e.releaseYear ? ` · ${e.releaseYear}` : "",
236
- e.originalLanguage ? ` · ${e.originalLanguage}` : ""
297
+ /* @__PURE__ */ O("div", {
298
+ className: "flex items-center justify-between",
299
+ children: [/* @__PURE__ */ D("span", {
300
+ className: "inline-flex h-10 w-10 items-center justify-center rounded-lg bg-bg-sunken text-action-primary-bg transition-colors group-hover:bg-action-primary-bg group-hover:text-action-primary-text",
301
+ children: /* @__PURE__ */ D(n, { className: "h-5 w-5" })
302
+ }), /* @__PURE__ */ D(_, { className: "h-4 w-4 text-text-muted transition-all group-hover:translate-x-0.5 group-hover:text-text-primary" })]
303
+ }),
304
+ /* @__PURE__ */ D("p", {
305
+ className: "mt-3 text-sm font-semibold text-text-primary",
306
+ children: e.label
307
+ }),
308
+ /* @__PURE__ */ D("p", {
309
+ className: "mt-1 text-xs text-text-secondary",
310
+ children: e.description
311
+ })
237
312
  ]
238
- })]
239
- }), /* @__PURE__ */ T(i, { status: e.status })]
240
- }) }, e.id)), R.data && R.data.items.length === 0 && /* @__PURE__ */ T("li", {
241
- className: "px-4 py-6 text-center text-sm text-text-secondary",
242
- children: "No titles yet — create your first title to get started."
243
- })]
244
- })
313
+ })
314
+ }, e.id);
315
+ })
316
+ })]
245
317
  })]
246
318
  })
247
319
  ]
248
320
  });
249
321
  };
250
322
  //#endregion
251
- export { A as HomePage };
323
+ export { N as HomePage };
252
324
 
253
325
  //# sourceMappingURL=HomePage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"HomePage.js","names":[],"sources":["../../../src/hookmovies/pages/HomePage.tsx"],"sourcesContent":["/**\n * HookMovies Overview / Dashboard\n * @module hookmovies/pages\n *\n * The MFE's primary landing surface. Summarizes the workspace's catalog,\n * production pipeline, casting activity, and audience engagement using the live\n * HookMovies subgraph (counts derived from the real list ops), plus quick\n * links into each module. No mocks.\n */\n\nimport { type FC, useMemo } from 'react';\nimport {\n Film,\n Clapperboard,\n Megaphone,\n Star,\n Building2,\n Users,\n ScrollText,\n PlayCircle,\n ArrowRight,\n Plus,\n} from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { MetricsCard } from '../components/MetricsCard';\nimport { StatusBadge } from '../components/StatusBadge';\nimport { useHookMovies } from '../context/HookMoviesContext';\nimport {\n useTitles,\n useProductions,\n useAuditions,\n useReviews,\n useStudios,\n usePeople,\n useMyWatchProgress,\n} from '../hooks/useHookMoviesApi';\nimport { cn } from '../utils/cn';\nimport { formatEnumLabel, formatRelativeTime } from '../utils/formatters';\n\nconst SMALL_PAGE = { limit: 5, offset: 0 };\n// Count-only queries: we read `totalCount` off the connection, so fetch a\n// minimal page of rows (the items are discarded here).\nconst COUNT_PAGE = { limit: 1, offset: 0 };\n\nexport const HomePage: FC = () => {\n const { navigateTo, currentUser } = useHookMovies();\n\n const titles = useTitles({}, COUNT_PAGE);\n const productions = useProductions({}, COUNT_PAGE);\n const openAuditions = useAuditions({ status: 'OPEN' }, COUNT_PAGE);\n const reviews = useReviews({}, COUNT_PAGE);\n const studios = useStudios(COUNT_PAGE);\n const people = usePeople(COUNT_PAGE);\n const recentTitles = useTitles({}, SMALL_PAGE);\n const watchProgress = useMyWatchProgress();\n\n const titleCount = titles.data?.totalCount ?? 0;\n const productionCount = productions.data?.totalCount ?? 0;\n const auditionCount = openAuditions.data?.totalCount ?? 0;\n const reviewCount = reviews.data?.totalCount ?? 0;\n const studioCount = studios.data?.totalCount ?? 0;\n const personCount = people.data?.totalCount ?? 0;\n\n const continueWatching = useMemo(\n () => (watchProgress.data ?? []).filter((p) => !p.completed).slice(0, 4),\n [watchProgress.data]\n );\n\n const modules: Array<{\n id: string;\n label: string;\n description: string;\n icon: typeof Film;\n path: string;\n }> = [\n {\n id: 'catalog',\n label: 'Catalog',\n description: 'Movies, series, anime & more',\n icon: Film,\n path: 'catalog/titles',\n },\n {\n id: 'studios',\n label: 'Studios',\n description: 'Studios, channels & networks',\n icon: Building2,\n path: 'catalog/studios',\n },\n {\n id: 'people',\n label: 'People',\n description: 'Cast & crew directory',\n icon: Users,\n path: 'catalog/people',\n },\n {\n id: 'productions',\n label: 'Productions',\n description: 'Development → release pipeline',\n icon: Clapperboard,\n path: 'productions',\n },\n {\n id: 'auditions',\n label: 'Auditions',\n description: 'Casting & talent marketplace',\n icon: Megaphone,\n path: 'auditions',\n },\n {\n id: 'reviews',\n label: 'Reviews',\n description: 'Ratings & audience reviews',\n icon: Star,\n path: 'engagement/reviews',\n },\n {\n id: 'rights',\n label: 'Rights & Distribution',\n description: 'Licensing windows & territories',\n icon: ScrollText,\n path: 'distribution/rights',\n },\n {\n id: 'library',\n label: 'My Library',\n description: 'Watchlists, playlists & history',\n icon: PlayCircle,\n path: 'library/lists',\n },\n ];\n\n return (\n <PageLayout\n hero\n title=\"HookMovies\"\n description={\n currentUser?.name\n ? `Welcome back, ${currentUser.name}`\n : 'The global creative-media network'\n }\n purpose=\"Discover and stream titles, run productions and casting, and manage rights & distribution — your workspace's whole creative-media operation in one place.\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('catalog/titles/new')}\n className=\"inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90 transition-opacity\"\n >\n <Plus className=\"h-4 w-4\" />\n New Title\n </button>\n }\n >\n {/* Key metrics */}\n <div className=\"grid grid-cols-2 gap-4 lg:grid-cols-3 xl:grid-cols-6\">\n <MetricsCard\n featured\n icon={<Film className=\"h-5 w-5\" />}\n value={titleCount}\n label=\"Titles\"\n />\n <MetricsCard\n icon={<Clapperboard className=\"h-5 w-5\" />}\n value={productionCount}\n label=\"Productions\"\n />\n <MetricsCard\n icon={<Megaphone className=\"h-5 w-5\" />}\n value={auditionCount}\n label=\"Open Auditions\"\n />\n <MetricsCard icon={<Star className=\"h-5 w-5\" />} value={reviewCount} label=\"Reviews\" />\n <MetricsCard icon={<Building2 className=\"h-5 w-5\" />} value={studioCount} label=\"Studios\" />\n <MetricsCard icon={<Users className=\"h-5 w-5\" />} value={personCount} label=\"People\" />\n </div>\n\n {/* Continue watching */}\n {continueWatching.length > 0 && (\n <section className=\"mt-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-text-primary\">Continue Watching</h2>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {continueWatching.map((entry) => (\n <button\n key={entry.id}\n type=\"button\"\n onClick={() => entry.title && navigateTo(`catalog/titles/${entry.title.id}`)}\n className=\"text-left\"\n >\n <GlassCard treatment=\"metric\" className=\"h-full border-border-seam p-4\">\n <div className=\"flex items-center gap-2 text-action-primary-bg\">\n <PlayCircle className=\"h-5 w-5\" />\n {entry.title && (\n <span className=\"text-xs font-medium uppercase tracking-wide text-text-secondary\">\n {formatEnumLabel(entry.title.type)}\n </span>\n )}\n </div>\n <p className=\"mt-2 line-clamp-1 text-sm font-semibold text-text-primary\">\n {entry.title?.title ?? 'Untitled'}\n </p>\n <p className=\"mt-1 text-xs text-text-secondary\">\n {Math.round(entry.positionSeconds / 60)} min in ·{' '}\n {formatRelativeTime(entry.updatedAt)}\n </p>\n </GlassCard>\n </button>\n ))}\n </div>\n </section>\n )}\n\n {/* Modules */}\n <section className=\"mt-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-text-primary\">Modules</h2>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {modules.map((mod) => {\n const Icon = mod.icon;\n return (\n <button\n key={mod.id}\n type=\"button\"\n onClick={() => navigateTo(mod.path)}\n className=\"group text-left\"\n >\n <GlassCard\n treatment=\"metric\"\n className=\"flex h-full flex-col border-border-seam p-5\"\n >\n <div className=\"flex items-center justify-between\">\n <span className=\"inline-flex h-10 w-10 items-center justify-center rounded-lg bg-bg-sunken text-action-primary-bg\">\n <Icon className=\"h-5 w-5\" />\n </span>\n <ArrowRight className=\"h-4 w-4 text-text-secondary transition-colors group-hover:text-text-primary\" />\n </div>\n <p className=\"mt-3 text-sm font-semibold text-text-primary\">{mod.label}</p>\n <p className=\"mt-1 text-xs text-text-secondary\">{mod.description}</p>\n </GlassCard>\n </button>\n );\n })}\n </div>\n </section>\n\n {/* Recently added titles */}\n <section className=\"mt-8\">\n <div className=\"mb-3 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Recently Added</h2>\n <button\n type=\"button\"\n onClick={() => navigateTo('catalog/titles')}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-action-primary-bg hover:opacity-80\"\n >\n View all\n <ArrowRight className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <ul className=\"divide-y divide-border-seam\">\n {(recentTitles.data?.items ?? []).map((title) => (\n <li key={title.id}>\n <button\n type=\"button\"\n onClick={() => navigateTo(`catalog/titles/${title.id}`)}\n className={cn(\n 'flex w-full items-center justify-between gap-3 px-4 py-3 text-left',\n 'hover:bg-bg-sunken transition-colors'\n )}\n >\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{title.title}</p>\n <p className=\"text-xs text-text-secondary\">\n {formatEnumLabel(title.type)}\n {title.releaseYear ? ` · ${title.releaseYear}` : ''}\n {title.originalLanguage ? ` · ${title.originalLanguage}` : ''}\n </p>\n </div>\n <StatusBadge status={title.status} />\n </button>\n </li>\n ))}\n {recentTitles.data && recentTitles.data.items.length === 0 && (\n <li className=\"px-4 py-6 text-center text-sm text-text-secondary\">\n No titles yet — create your first title to get started.\n </li>\n )}\n </ul>\n </GlassCard>\n </section>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"HomePage.js","names":[],"sources":["../../../src/hookmovies/pages/HomePage.tsx"],"sourcesContent":["/**\n * HookMovies Overview / Dashboard\n * @module hookmovies/pages\n *\n * The MFE's primary landing surface. Summarizes the workspace's catalog,\n * production pipeline, casting activity, and audience engagement using the live\n * HookMovies subgraph (counts derived from the real list ops), plus quick\n * links into each module. No mocks.\n */\n\nimport { type FC, type ReactNode, useMemo, useState } from 'react';\nimport {\n Film,\n Clapperboard,\n Megaphone,\n Star,\n Building2,\n Users,\n ScrollText,\n PlayCircle,\n ArrowRight,\n Plus,\n} from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { MetricsCard } from '../components/MetricsCard';\nimport { StatusBadge } from '../components/StatusBadge';\nimport { useHookMovies } from '../context/HookMoviesContext';\nimport {\n useTitles,\n useProductions,\n useAuditions,\n useReviews,\n useStudios,\n usePeople,\n useMyWatchProgress,\n} from '../hooks/useHookMoviesApi';\nimport { useFileUrl } from '../hooks/useFiles';\nimport { cn } from '../utils/cn';\nimport { formatEnumLabel, formatRelativeTime } from '../utils/formatters';\n\n/**\n * Small portrait poster thumbnail for the \"Recently Added\" list. Resolves a\n * wspace-files id to a presigned URL via {@link useFileUrl} and falls back to a\n * calm tokenized tile (never a broken image) when the id is absent or fails.\n */\nconst PosterThumb: FC<{ fileId: string | null; alt: string }> = ({ fileId, alt }) => {\n const { data: url, isLoading } = useFileUrl(fileId);\n const [errored, setErrored] = useState(false);\n const showImage = Boolean(fileId) && Boolean(url) && !errored;\n\n return (\n <div className=\"relative h-16 w-11 shrink-0 overflow-hidden rounded-md border border-border-seam bg-bg-sunken\">\n {showImage ? (\n <img\n src={url ?? undefined}\n alt={alt}\n loading=\"lazy\"\n onError={() => setErrored(true)}\n className=\"h-full w-full object-cover\"\n />\n ) : (\n <div\n className={cn(\n 'flex h-full w-full items-center justify-center text-text-muted',\n isLoading && Boolean(fileId) && 'motion-safe:animate-pulse'\n )}\n aria-hidden=\"true\"\n >\n <Film className=\"h-4 w-4\" />\n </div>\n )}\n </div>\n );\n};\n\nconst SMALL_PAGE = { limit: 5, offset: 0 };\n// Count-only queries: we read `totalCount` off the connection, so fetch a\n// minimal page of rows (the items are discarded here).\nconst COUNT_PAGE = { limit: 1, offset: 0 };\n\nexport const HomePage: FC = () => {\n const { navigateTo, currentUser } = useHookMovies();\n\n const titles = useTitles({}, COUNT_PAGE);\n const productions = useProductions({}, COUNT_PAGE);\n const openAuditions = useAuditions({ status: 'OPEN' }, COUNT_PAGE);\n const reviews = useReviews({}, COUNT_PAGE);\n const studios = useStudios(COUNT_PAGE);\n const people = usePeople(COUNT_PAGE);\n const recentTitles = useTitles({}, SMALL_PAGE);\n const watchProgress = useMyWatchProgress();\n\n const titleCount = titles.data?.totalCount ?? 0;\n const productionCount = productions.data?.totalCount ?? 0;\n const auditionCount = openAuditions.data?.totalCount ?? 0;\n const reviewCount = reviews.data?.totalCount ?? 0;\n const studioCount = studios.data?.totalCount ?? 0;\n const personCount = people.data?.totalCount ?? 0;\n\n const continueWatching = useMemo(\n () => (watchProgress.data ?? []).filter((p) => !p.completed).slice(0, 4),\n [watchProgress.data]\n );\n\n const metrics: Array<{\n id: string;\n icon: ReactNode;\n value: number;\n label: string;\n path: string;\n featured?: boolean;\n }> = [\n {\n id: 'titles',\n icon: <Film className=\"h-5 w-5\" />,\n value: titleCount,\n label: 'Titles',\n path: 'catalog/titles',\n featured: true,\n },\n {\n id: 'productions',\n icon: <Clapperboard className=\"h-5 w-5\" />,\n value: productionCount,\n label: 'Productions',\n path: 'productions',\n },\n {\n id: 'auditions',\n icon: <Megaphone className=\"h-5 w-5\" />,\n value: auditionCount,\n label: 'Open Auditions',\n path: 'auditions',\n },\n {\n id: 'reviews',\n icon: <Star className=\"h-5 w-5\" />,\n value: reviewCount,\n label: 'Reviews',\n path: 'engagement/reviews',\n },\n {\n id: 'studios',\n icon: <Building2 className=\"h-5 w-5\" />,\n value: studioCount,\n label: 'Studios',\n path: 'catalog/studios',\n },\n {\n id: 'people',\n icon: <Users className=\"h-5 w-5\" />,\n value: personCount,\n label: 'People',\n path: 'catalog/people',\n },\n ];\n\n const modules: Array<{\n id: string;\n label: string;\n description: string;\n icon: typeof Film;\n path: string;\n }> = [\n {\n id: 'catalog',\n label: 'Catalog',\n description: 'Movies, series, anime & more',\n icon: Film,\n path: 'catalog/titles',\n },\n {\n id: 'studios',\n label: 'Studios',\n description: 'Studios, channels & networks',\n icon: Building2,\n path: 'catalog/studios',\n },\n {\n id: 'people',\n label: 'People',\n description: 'Cast & crew directory',\n icon: Users,\n path: 'catalog/people',\n },\n {\n id: 'productions',\n label: 'Productions',\n description: 'Development → release pipeline',\n icon: Clapperboard,\n path: 'productions',\n },\n {\n id: 'auditions',\n label: 'Auditions',\n description: 'Casting & talent marketplace',\n icon: Megaphone,\n path: 'auditions',\n },\n {\n id: 'reviews',\n label: 'Reviews',\n description: 'Ratings & audience reviews',\n icon: Star,\n path: 'engagement/reviews',\n },\n {\n id: 'rights',\n label: 'Rights & Distribution',\n description: 'Licensing windows & territories',\n icon: ScrollText,\n path: 'distribution/rights',\n },\n {\n id: 'library',\n label: 'My Library',\n description: 'Watchlists, playlists & history',\n icon: PlayCircle,\n path: 'library/lists',\n },\n ];\n\n return (\n <PageLayout\n hero\n title=\"HookMovies\"\n description={\n currentUser?.name\n ? `Welcome back, ${currentUser.name}`\n : 'The global creative-media network'\n }\n purpose=\"Discover and stream titles, run productions and casting, and manage rights & distribution — your workspace's whole creative-media operation in one place.\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('catalog/titles/new')}\n className=\"inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90 transition-opacity\"\n >\n <Plus className=\"h-4 w-4\" />\n New Title\n </button>\n }\n >\n {/* Key metrics — each card jumps to its module */}\n <div className=\"grid grid-cols-2 gap-3 sm:gap-4 lg:grid-cols-3 xl:grid-cols-6\">\n {metrics.map((metric) => (\n <button\n key={metric.id}\n type=\"button\"\n onClick={() => navigateTo(metric.path)}\n aria-label={`${metric.label}: ${metric.value}. Open ${metric.label}`}\n className={cn(\n 'group rounded-2xl text-left focus:outline-none',\n 'focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]'\n )}\n >\n <MetricsCard\n featured={metric.featured}\n icon={metric.icon}\n value={metric.value}\n label={metric.label}\n className={cn(\n 'h-full !p-4 transition-[transform,border-color,box-shadow] duration-200',\n 'group-hover:border-border-strong group-hover:shadow-elevation-2',\n 'motion-safe:group-hover:-translate-y-0.5 motion-reduce:transform-none'\n )}\n />\n </button>\n ))}\n </div>\n\n {/* Continue watching */}\n {continueWatching.length > 0 && (\n <section className=\"mt-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-text-primary\">Continue Watching</h2>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {continueWatching.map((entry) => (\n <button\n key={entry.id}\n type=\"button\"\n onClick={() => entry.title && navigateTo(`catalog/titles/${entry.title.id}`)}\n className=\"text-left\"\n >\n <GlassCard treatment=\"metric\" className=\"h-full border-border-seam p-4\">\n <div className=\"flex items-center gap-2 text-action-primary-bg\">\n <PlayCircle className=\"h-5 w-5\" />\n {entry.title && (\n <span className=\"text-xs font-medium uppercase tracking-wide text-text-secondary\">\n {formatEnumLabel(entry.title.type)}\n </span>\n )}\n </div>\n <p className=\"mt-2 line-clamp-1 text-sm font-semibold text-text-primary\">\n {entry.title?.title ?? 'Untitled'}\n </p>\n <p className=\"mt-1 text-xs text-text-secondary\">\n {Math.round(entry.positionSeconds / 60)} min in ·{' '}\n {formatRelativeTime(entry.updatedAt)}\n </p>\n </GlassCard>\n </button>\n ))}\n </div>\n </section>\n )}\n\n {/* Recently Added + module quick-links, side-by-side on wide screens */}\n <div className=\"mt-8 grid grid-cols-1 gap-6 xl:grid-cols-12\">\n {/* Recently added titles */}\n <section className=\"xl:col-span-5\">\n <div className=\"mb-3 flex items-center justify-between gap-3\">\n <div className=\"min-w-0\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Recently Added</h2>\n <p className=\"mt-0.5 text-xs text-text-secondary\">Latest titles in your catalog</p>\n </div>\n <button\n type=\"button\"\n onClick={() => navigateTo('catalog/titles')}\n className=\"inline-flex shrink-0 items-center gap-1 text-sm font-medium text-action-primary-bg hover:opacity-80\"\n >\n View all\n <ArrowRight className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n <GlassCard treatment=\"metric\" className=\"overflow-hidden border-border-seam p-0\">\n <ul className=\"divide-y divide-border-seam\">\n {(recentTitles.data?.items ?? []).map((title) => (\n <li key={title.id}>\n <button\n type=\"button\"\n onClick={() => navigateTo(`catalog/titles/${title.id}`)}\n className={cn(\n 'flex w-full items-center gap-3 px-4 py-3 text-left',\n 'transition-colors hover:bg-bg-sunken',\n 'focus:outline-none focus-visible:bg-bg-sunken'\n )}\n >\n <PosterThumb fileId={title.posterFileId} alt={`${title.title} poster`} />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-semibold text-text-primary\">\n {title.title}\n </p>\n <p className=\"mt-0.5 truncate text-xs text-text-secondary\">\n {formatEnumLabel(title.type)}\n {title.releaseYear ? ` · ${title.releaseYear}` : ''}\n {title.originalLanguage ? ` · ${title.originalLanguage.toUpperCase()}` : ''}\n </p>\n <p className=\"mt-1 text-[11px] text-text-muted\">\n Added {formatRelativeTime(title.createdAt)}\n </p>\n </div>\n <StatusBadge status={title.status} className=\"shrink-0\" />\n </button>\n </li>\n ))}\n {recentTitles.data && recentTitles.data.items.length === 0 && (\n <li className=\"flex flex-col items-center gap-2 px-4 py-10 text-center\">\n <span className=\"inline-flex h-10 w-10 items-center justify-center rounded-full bg-bg-sunken text-text-muted\">\n <Film className=\"h-5 w-5\" />\n </span>\n <p className=\"text-sm text-text-secondary\">\n No titles yet — create your first title to get started.\n </p>\n </li>\n )}\n </ul>\n </GlassCard>\n </section>\n\n {/* Module quick-links */}\n <section className=\"xl:col-span-7\">\n <h2 className=\"mb-3 text-lg font-semibold text-text-primary\">Explore Modules</h2>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-2 2xl:grid-cols-3\">\n {modules.map((mod) => {\n const Icon = mod.icon;\n return (\n <button\n key={mod.id}\n type=\"button\"\n onClick={() => navigateTo(mod.path)}\n className={cn(\n 'group rounded-2xl text-left focus:outline-none',\n 'focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]'\n )}\n >\n <GlassCard\n treatment=\"metric\"\n className={cn(\n 'flex h-full flex-col border-border-seam p-5',\n 'transition-[transform,border-color,box-shadow] duration-200',\n 'group-hover:border-border-strong group-hover:shadow-elevation-2',\n 'motion-safe:group-hover:-translate-y-0.5 motion-reduce:transform-none'\n )}\n >\n <div className=\"flex items-center justify-between\">\n <span className=\"inline-flex h-10 w-10 items-center justify-center rounded-lg bg-bg-sunken text-action-primary-bg transition-colors group-hover:bg-action-primary-bg group-hover:text-action-primary-text\">\n <Icon className=\"h-5 w-5\" />\n </span>\n <ArrowRight className=\"h-4 w-4 text-text-muted transition-all group-hover:translate-x-0.5 group-hover:text-text-primary\" />\n </div>\n <p className=\"mt-3 text-sm font-semibold text-text-primary\">{mod.label}</p>\n <p className=\"mt-1 text-xs text-text-secondary\">{mod.description}</p>\n </GlassCard>\n </button>\n );\n })}\n </div>\n </section>\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
@@ -2,8 +2,8 @@ import { useHookMovies as e } from "../../context/HookMoviesContext.js";
2
2
  import { cn as t } from "../../utils/cn.js";
3
3
  import { PageLayout as n } from "../../components/PageLayout.js";
4
4
  import { useTitles as r } from "../../hooks/useHookMoviesApi.js";
5
- import { formatEnumLabel as i } from "../../utils/formatters.js";
6
- import { useFileUrl as a } from "../../hooks/useFiles.js";
5
+ import { useFileUrl as i } from "../../hooks/useFiles.js";
6
+ import { formatEnumLabel as a } from "../../utils/formatters.js";
7
7
  import { useCallback as o, useEffect as s, useMemo as c, useRef as l, useState as u } from "react";
8
8
  import { AlertCircle as d, Film as f, Info as p, MessageSquareText as m, RotateCcw as h, Send as g, Sparkles as _, Wand2 as v } from "lucide-react";
9
9
  import { jsx as y, jsxs as b } from "react/jsx-runtime";
@@ -60,7 +60,7 @@ var A = [
60
60
  })]
61
61
  });
62
62
  }, M = ({ title: e, onOpen: n }) => {
63
- let { data: r, isLoading: o } = a(e.posterFileId), [s, c] = u(!1), l = !!e.posterFileId && !!r && !s, d = [i(e.type), e.releaseYear ? String(e.releaseYear) : null].filter(Boolean).join(" · ");
63
+ let { data: r, isLoading: o } = i(e.posterFileId), [s, c] = u(!1), l = !!e.posterFileId && !!r && !s, d = [a(e.type), e.releaseYear ? String(e.releaseYear) : null].filter(Boolean).join(" · ");
64
64
  return /* @__PURE__ */ b("button", {
65
65
  type: "button",
66
66
  onClick: () => n(e.id),