@openrails/contentkit-ui 0.103.1 → 0.104.0-rc.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 (145) hide show
  1. package/README.md +105 -43
  2. package/dist/client/beacons.d.ts +3 -13
  3. package/dist/client/beacons.js +4 -45
  4. package/dist/client/beacons.js.map +1 -1
  5. package/dist/client/client.d.ts +3 -0
  6. package/dist/client/client.js +45 -43
  7. package/dist/client/client.js.map +1 -1
  8. package/dist/client/content/favorites.d.ts +2 -0
  9. package/dist/client/content/favorites.js.map +1 -1
  10. package/dist/client/content/types.d.ts +3 -0
  11. package/dist/client/content/types.js.map +1 -1
  12. package/dist/client/discovery.d.ts +28 -3
  13. package/dist/client/discovery.js +22 -1
  14. package/dist/client/discovery.js.map +1 -1
  15. package/dist/client/engagement.d.ts +70 -0
  16. package/dist/client/engagement.js +191 -0
  17. package/dist/client/engagement.js.map +1 -0
  18. package/dist/client/generated/routes.d.ts +35 -9
  19. package/dist/client/generated/routes.js +59 -2
  20. package/dist/client/generated/routes.js.map +1 -1
  21. package/dist/client/generated/wire.d.ts +53 -12
  22. package/dist/client/generated/wire.js.map +1 -1
  23. package/dist/client/guest-reading-history.d.ts +40 -0
  24. package/dist/client/guest-reading-history.js +144 -0
  25. package/dist/client/guest-reading-history.js.map +1 -0
  26. package/dist/client/index.d.ts +4 -2
  27. package/dist/client/stats.d.ts +5 -5
  28. package/dist/client/stats.js.map +1 -1
  29. package/dist/client.js +24 -22
  30. package/dist/components/admin/content-manager.d.ts +1 -1
  31. package/dist/components/admin/content-manager.js +342 -302
  32. package/dist/components/admin/content-manager.js.map +1 -1
  33. package/dist/components/admin/page-review.js +106 -97
  34. package/dist/components/admin/page-review.js.map +1 -1
  35. package/dist/components/admin/quick-search.d.ts +14 -0
  36. package/dist/components/admin/quick-search.js +60 -0
  37. package/dist/components/admin/quick-search.js.map +1 -0
  38. package/dist/components/admin/reader-content-editor.d.ts +6 -0
  39. package/dist/components/admin/reader-content-editor.js +733 -0
  40. package/dist/components/admin/reader-content-editor.js.map +1 -0
  41. package/dist/components/admin/reader-manifest.js +120 -105
  42. package/dist/components/admin/reader-manifest.js.map +1 -1
  43. package/dist/components/admin/stats-dashboard.d.ts +4 -4
  44. package/dist/components/admin/stats-dashboard.js +132 -134
  45. package/dist/components/admin/stats-dashboard.js.map +1 -1
  46. package/dist/components/content/daily-releases.js +143 -191
  47. package/dist/components/content/daily-releases.js.map +1 -1
  48. package/dist/components/content/editor-save.d.ts +32 -0
  49. package/dist/components/content/editor-save.js +51 -0
  50. package/dist/components/content/editor-save.js.map +1 -0
  51. package/dist/components/content/editors.d.ts +17 -2
  52. package/dist/components/content/editors.js +359 -328
  53. package/dist/components/content/editors.js.map +1 -1
  54. package/dist/components/content/favorites.d.ts +6 -0
  55. package/dist/components/content/favorites.js +33 -0
  56. package/dist/components/content/favorites.js.map +1 -0
  57. package/dist/components/content/filter-dialog.js +19 -15
  58. package/dist/components/content/filter-dialog.js.map +1 -1
  59. package/dist/components/content/filters.d.ts +2 -0
  60. package/dist/components/content/filters.js +5 -1
  61. package/dist/components/content/filters.js.map +1 -1
  62. package/dist/components/content/grid.d.ts +34 -13
  63. package/dist/components/content/grid.js +300 -271
  64. package/dist/components/content/grid.js.map +1 -1
  65. package/dist/components/content/history.d.ts +6 -0
  66. package/dist/components/content/history.js +91 -0
  67. package/dist/components/content/history.js.map +1 -0
  68. package/dist/components/content/index.d.ts +1 -0
  69. package/dist/components/content/offer-fields.d.ts +1 -1
  70. package/dist/components/content/offer-fields.js +86 -64
  71. package/dist/components/content/offer-fields.js.map +1 -1
  72. package/dist/components/content/search.d.ts +11 -4
  73. package/dist/components/content/search.js +22 -11
  74. package/dist/components/content/search.js.map +1 -1
  75. package/dist/components/content/summary-tile.d.ts +14 -0
  76. package/dist/components/content/summary-tile.js +63 -0
  77. package/dist/components/content/summary-tile.js.map +1 -0
  78. package/dist/components/groups/memberships.d.ts +11 -1
  79. package/dist/components/groups/memberships.js +1 -1
  80. package/dist/components/groups/memberships.js.map +1 -1
  81. package/dist/components/media-folder-editor.d.ts +4 -0
  82. package/dist/components/media-folder-editor.js +178 -168
  83. package/dist/components/media-folder-editor.js.map +1 -1
  84. package/dist/components/video-mini-player.d.ts +4 -1
  85. package/dist/components/video-mini-player.js +77 -71
  86. package/dist/components/video-mini-player.js.map +1 -1
  87. package/dist/components/video-player.d.ts +4 -1
  88. package/dist/components/video-player.js +280 -276
  89. package/dist/components/video-player.js.map +1 -1
  90. package/dist/index.d.ts +1 -0
  91. package/dist/index.js +17 -14
  92. package/dist/locales/admin/de.js +33 -8
  93. package/dist/locales/admin/de.js.map +1 -1
  94. package/dist/locales/admin/en.d.ts +29 -4
  95. package/dist/locales/admin/en.js +33 -8
  96. package/dist/locales/admin/en.js.map +1 -1
  97. package/dist/locales/admin/es.js +33 -8
  98. package/dist/locales/admin/es.js.map +1 -1
  99. package/dist/locales/admin/ja.js +33 -8
  100. package/dist/locales/admin/ja.js.map +1 -1
  101. package/dist/locales/admin/ko.js +33 -8
  102. package/dist/locales/admin/ko.js.map +1 -1
  103. package/dist/locales/admin/zh.js +33 -8
  104. package/dist/locales/admin/zh.js.map +1 -1
  105. package/dist/locales/discovery/de.js +0 -1
  106. package/dist/locales/discovery/de.js.map +1 -1
  107. package/dist/locales/discovery/en.d.ts +0 -1
  108. package/dist/locales/discovery/en.js +0 -1
  109. package/dist/locales/discovery/en.js.map +1 -1
  110. package/dist/locales/discovery/es.js +0 -1
  111. package/dist/locales/discovery/es.js.map +1 -1
  112. package/dist/locales/discovery/ja.js +0 -1
  113. package/dist/locales/discovery/ja.js.map +1 -1
  114. package/dist/locales/discovery/ko.js +0 -1
  115. package/dist/locales/discovery/ko.js.map +1 -1
  116. package/dist/locales/discovery/zh.js +0 -1
  117. package/dist/locales/discovery/zh.js.map +1 -1
  118. package/dist/locales/en.d.ts +29 -5
  119. package/dist/react/discovery.d.ts +20 -17
  120. package/dist/react/discovery.js +273 -221
  121. package/dist/react/discovery.js.map +1 -1
  122. package/dist/react/index.d.ts +2 -1
  123. package/dist/react/page-review.d.ts +1 -1
  124. package/dist/react/page-review.js +6 -5
  125. package/dist/react/page-review.js.map +1 -1
  126. package/dist/react/resources.d.ts +3 -1
  127. package/dist/react/resources.js +4 -0
  128. package/dist/react/resources.js.map +1 -1
  129. package/dist/react/stats.d.ts +2 -2
  130. package/dist/react/stats.js.map +1 -1
  131. package/dist/react/use-draft.d.ts +8 -0
  132. package/dist/react/use-draft.js +35 -0
  133. package/dist/react/use-draft.js.map +1 -0
  134. package/dist/react/use-engagement.d.ts +26 -0
  135. package/dist/react/use-engagement.js +221 -0
  136. package/dist/react/use-engagement.js.map +1 -0
  137. package/dist/react/use-resource.d.ts +4 -3
  138. package/dist/react/use-resource.js +2 -1
  139. package/dist/react/use-resource.js.map +1 -1
  140. package/dist/react.js +12 -11
  141. package/dist/styles.css +1 -1
  142. package/dist/ui/dialog.d.ts +2 -1
  143. package/dist/ui/dialog.js +23 -20
  144. package/dist/ui/dialog.js.map +1 -1
  145. package/package.json +1 -1
@@ -0,0 +1,733 @@
1
+ import { toContentKitError as e } from "../../client/errors.js";
2
+ import { stem as t } from "../../client/media/client.js";
3
+ import { useMessages as n } from "../../i18n/context.js";
4
+ import { useErrorReporter as r, useGuarded as i } from "../../react/context.js";
5
+ import { useContentScope as ee } from "../../react/use-resource.js";
6
+ import { useContentGroups as te } from "../../react/groups.js";
7
+ import { isProcessing as ne } from "../../client/media/windows.js";
8
+ import { Button as a } from "../../ui/button.js";
9
+ import { useMediaFolder as re } from "../../react/folder.js";
10
+ import { MediaFolderEditor as ie } from "../media-folder-editor.js";
11
+ import { Badge as ae } from "../../ui/badge.js";
12
+ import { Input as o } from "../../ui/input.js";
13
+ import { Label as s } from "../../ui/label.js";
14
+ import { Select as c, SelectContent as l, SelectItem as u, SelectTrigger as oe, SelectValue as se } from "../../ui/select.js";
15
+ import { Textarea as ce } from "../../ui/textarea.js";
16
+ import { ErrorLine as d, contentError as le, useAction as ue } from "../social/parts.js";
17
+ import { LoadFailed as de, Rows as fe, useConfirm as pe } from "./shell.js";
18
+ import { localInput as me } from "../social/bans.js";
19
+ import { imageRefs as he } from "../../client/contents.js";
20
+ import { parseAttributes as ge } from "../../client/group-fields.js";
21
+ import { GroupPicker as _e, labelOf as ve } from "../groups/parts.js";
22
+ import { useDraft as f } from "../../react/use-draft.js";
23
+ import { EditorSaveContext as ye, readerMediaReady as be, useEditorSaveCoordinator as xe } from "../content/editor-save.js";
24
+ import { OfferFields as Se } from "../content/offer-fields.js";
25
+ import { AttributeFields as Ce, formOf as we } from "../groups/fields.js";
26
+ import { MembershipRow as Te } from "../groups/memberships.js";
27
+ import { ReaderManifestEditor as Ee } from "./reader-manifest.js";
28
+ import { usePageReview as De } from "../../react/page-review.js";
29
+ import { PageReview as Oe } from "./page-review.js";
30
+ import { RuleFields as ke, VersionsEditor as Ae, cleanRule as je, complete as Me, versionLabel as Ne } from "../content/editors.js";
31
+ import { useContent as Pe } from "../../react/contents.js";
32
+ import { contentStatus as Fe } from "./content-manager.js";
33
+ import { useEffect as p, useId as Ie, useMemo as m, useRef as h, useState as g } from "react";
34
+ import { jsx as _, jsxs as v } from "react/jsx-runtime";
35
+ import { StarIcon as Le } from "@hugeicons/core-free-icons";
36
+ import { HugeiconsIcon as Re } from "@hugeicons/react";
37
+ //#region src/components/admin/reader-content-editor.tsx
38
+ var y = () => ({
39
+ title: "",
40
+ slug: "",
41
+ description: "",
42
+ body: ""
43
+ }), ze = (e, t) => e?.text?.[t] ?? (e?.language === t ? {
44
+ title: e.title,
45
+ slug: e.slug,
46
+ description: e.description,
47
+ body: e.body
48
+ } : y()), Be = (e) => e.replace(/\.[^.]+$/, "").replace(/[_-]+/g, " ").trim().slice(0, 300), Ve = (e) => ({
49
+ ...e,
50
+ title: e.title.trim(),
51
+ slug: e.slug?.trim() || void 0,
52
+ description: e.description?.trim()
53
+ }), b = class extends Error {};
54
+ function x({ title: e, children: t, className: n = "" }) {
55
+ return /* @__PURE__ */ v("section", {
56
+ className: `grid min-w-0 content-start gap-4 rounded-xl border border-border bg-card p-4 ${n}`,
57
+ children: [/* @__PURE__ */ _("h2", {
58
+ className: "text-base font-semibold",
59
+ children: e
60
+ }), t]
61
+ });
62
+ }
63
+ function S(S) {
64
+ let { client: C, scope: He } = ee(S.client), Ue = n(), { t: w } = Ue, T = Ie(), We = i(), Ge = r(S.onError), E = S.model, D = E.kinds[S.kind], Ke = S.languages?.map((e) => typeof e == "string" ? {
65
+ value: e,
66
+ label: e
67
+ } : e), O = Ke?.length ? Ke : E.languages.map((e) => ({
68
+ value: e,
69
+ label: e
70
+ })), qe = O.map((e) => e.value).join("|"), [k, Je] = g(O[0]?.value ?? "en"), [Ye, Xe] = g(""), A = Pe(S.id, S.kind, k, {
71
+ client: C,
72
+ version: Ye || void 0
73
+ }), [Ze, Qe] = g(null), j = A.content ?? Ze, M = h({
74
+ item: j,
75
+ scope: He,
76
+ alive: !0
77
+ });
78
+ M.current.item = j, p(() => {
79
+ let e = M.current;
80
+ return e.alive = !0, () => {
81
+ e.alive = !1;
82
+ };
83
+ }, []);
84
+ let N = () => M.current.alive && M.current.scope === He, P = h(null), [$e, et] = g(!1), [F, tt] = g(!1), [nt, I] = g(), [rt, it] = g(""), at = f(m(() => ({ at: j?.publish_at ? me(new Date(j.publish_at)) : "" }), [j?.publish_at])), ot = at.value.at, st = (e) => at.edit({ at: e }), [ct, lt] = g(!1), [ut, dt] = g([]), [ft, pt] = g(!1), [mt, ht] = g(!1), L = m(() => [...j?.versions ?? []].sort((e, t) => e.position - t.position), [j?.versions]), R = L.find((e) => e.id === Ye) ?? L[0];
85
+ p(() => {
86
+ ft && R && dt((e) => e.includes(R.id) ? e : [...e, R.id]);
87
+ }, [ft, R]);
88
+ let z = te(j?.id, {
89
+ language: k,
90
+ client: C
91
+ }), gt = m(() => new Map(z.entities), [z.entities]), [_t, vt] = g(/* @__PURE__ */ new Map()), yt = m(() => new Map([..._t, ...gt]), [gt, _t]), B = m(() => D.entities ?? [], [D.entities]), V = f(m(() => Object.fromEntries(qe.split("|").map((e) => [e, ze(j, e)])), [j, qe])), H = f(m(() => ({
92
+ listing: j?.listing ?? "listed",
93
+ comments: j?.comments ?? "open",
94
+ attributes: we(D.attributes ?? {}, j?.attributes ?? {}),
95
+ access: j?.access ?? { level: "public" }
96
+ }), [
97
+ j?.listing,
98
+ j?.comments,
99
+ j?.attributes,
100
+ j?.access,
101
+ D.attributes
102
+ ])), U = f(m(() => ({ memberships: z.memberships.filter((e) => B.includes(z.entities.get(e.group_id ?? "")?.kind ?? "")) }), [
103
+ z.memberships,
104
+ z.entities,
105
+ B
106
+ ])), W = xe(), G = h({
107
+ texts: V,
108
+ details: H,
109
+ associations: U,
110
+ language: k
111
+ });
112
+ G.current = {
113
+ texts: V,
114
+ details: H,
115
+ associations: U,
116
+ language: k
117
+ };
118
+ let K = V.value[k] ?? y(), bt = (K.body ?? "").replace(he(), (e, t) => A.imageSrc(t) ?? e), q = (e) => V.edit((t) => ({
119
+ ...t,
120
+ [k]: {
121
+ ...t[k] ?? y(),
122
+ ...e
123
+ }
124
+ })), xt = (t) => {
125
+ N() && (I(t instanceof b ? t.message : t), t instanceof b || Ge(e(t), "content.save"));
126
+ }, St = async (e) => {
127
+ if (M.current.item) return M.current.item;
128
+ if (P.current) return P.current;
129
+ et(!0);
130
+ let t = G.current.language, n = G.current.texts.get()[t] ?? y(), r = n.title.trim() || Be(e ?? "") || w("readerEditor.untitled");
131
+ n.title.trim() || G.current.texts.edit((e) => ({
132
+ ...e,
133
+ [t]: {
134
+ ...e[t] ?? y(),
135
+ title: r
136
+ }
137
+ }));
138
+ let i = {
139
+ kind: S.kind,
140
+ text: { [t]: {
141
+ ...n,
142
+ title: r
143
+ } },
144
+ owner_group_id: S.ownerGroup
145
+ };
146
+ return P.current = A.create(i).then((e) => (M.current.item = e, N() && (Qe(e), S.onCreated?.(e)), e)).finally(() => {
147
+ P.current = null, N() && et(!1);
148
+ }), P.current;
149
+ }, J = m(() => j && R ? {
150
+ kind: S.kind,
151
+ id: j.id,
152
+ version: R.id
153
+ } : null, [
154
+ S.kind,
155
+ j,
156
+ R
157
+ ]), Y = ue("content.save", S.onError), X = ue("offer.save", S.onError), Z = ue("content.save", S.onError), Q = re(J, {
158
+ commit: R?.live ? "manual" : "auto",
159
+ client: C,
160
+ onError: S.onError
161
+ }), Ct = h(Q);
162
+ Ct.current = Q;
163
+ let wt = Q.read.read?.files ?? [], $ = De(j?.id, R?.id, { client: C }), Tt = $.reload, Et = J && Q.read.read ? JSON.stringify([
164
+ J.id,
165
+ J.version,
166
+ wt.filter((e) => e.upload).map((e) => [
167
+ e.path,
168
+ e.size,
169
+ e.staged,
170
+ e.pending,
171
+ e.failed
172
+ ])
173
+ ]) : null;
174
+ p(() => {
175
+ Et && Tt();
176
+ }, [Et, Tt]);
177
+ let Dt = !!Q.error || Q.queue.items.some((e) => e.status === "failed") || wt.some((e) => e.failed), Ot = wt.some(ne), kt = $.review?.selected ?? 0, At = Q.busy || $e || Ot || Q.read.loading || $.loading || Y.pending, jt = At || Dt || !!Q.read.error || !!$.error || kt === 0 || W.pending || X.pending, Mt = (e) => {
178
+ let t = [...e];
179
+ t.length && (Q.add(t), St(t.find((e) => /\.zip$/i.test(e.name))?.name ?? t[0]?.name).catch(xt));
180
+ }, Nt = at.dirty.length > 0 || V.dirty.length > 0 || H.dirty.length > 0 || U.dirty.length > 0 || W.dirty;
181
+ p(() => {
182
+ if (!Nt && !Q.busy) return;
183
+ let e = (e) => {
184
+ e.preventDefault(), e.returnValue = "";
185
+ };
186
+ return addEventListener("beforeunload", e), () => removeEventListener("beforeunload", e);
187
+ }, [Nt, Q.busy]);
188
+ let Pt = async (e) => {
189
+ if (F) return;
190
+ I(void 0), it("");
191
+ let t = G.current;
192
+ if (!t.texts.get()[t.language]?.title.trim()) return I(w("contentManager.titleRequired"));
193
+ let n = W.problem();
194
+ if (n) return I(w("readerEditor.fixSection", { section: n }));
195
+ if (!Me(t.details.get().access) || t.details.get().access.level === "tier" && !t.details.get().access.tiers?.length) return I(w("readerEditor.accessRequired"));
196
+ let r;
197
+ try {
198
+ r = ge(D.attributes ?? {}, t.details.get().attributes);
199
+ } catch (e) {
200
+ return xt(e);
201
+ }
202
+ if (e && jt) return I(w("readerEditor.filesNotReady"));
203
+ tt(!0);
204
+ let i = t.texts.checkpoint(), ee = t.details.checkpoint(), te = t.associations.checkpoint(), ne = t.texts.dirty.slice(), a = { ...t.texts.get() }, re = t.details.get(), ie = t.associations.get().memberships.slice(), ae = !0;
205
+ try {
206
+ let n = await St();
207
+ if (!N()) return;
208
+ if (z.error) throw z.error;
209
+ if (await We(async () => {
210
+ for (let e of ne) {
211
+ let t = String(e), r = a[t];
212
+ if (!r?.title.trim()) throw new b(w("contentManager.titleRequired"));
213
+ if (n = await C.contents.putText(n.id, t, Ve(r)), !N()) return;
214
+ }
215
+ if (n = await C.contents.get(n.id, k), N() && (n = await C.contents.update(n.id, {
216
+ listing: re.listing,
217
+ comments: re.comments,
218
+ attributes: r,
219
+ access: je(re.access),
220
+ revision: n.revision
221
+ }), N() && t.associations.dirty.length)) {
222
+ let e = n.versions.find((e) => e.id === R?.id) ?? n.versions[0], t = ie.map((t) => {
223
+ let n = yt.get(t.group_id ?? "")?.kind;
224
+ return n && E.entity_kinds[n]?.version_level && !t.version_id ? {
225
+ ...t,
226
+ version_id: e?.id
227
+ } : t;
228
+ }), r = await C.entities.setOfContent(n.id, {
229
+ kinds: [...B],
230
+ memberships: t
231
+ }, k);
232
+ ae = te({ memberships: r.memberships.filter((e) => B.includes(r.entities.find((t) => t.id === e.group_id)?.kind ?? "")) });
233
+ }
234
+ }), !N()) return;
235
+ let o = Ct.current;
236
+ !o.busy && (o.pending.length || o.queue.items.some((e) => e.status === "uploaded")) && await o.commit();
237
+ let s = await W.save(N);
238
+ if (s) throw new b(w("readerEditor.fixSection", { section: s }));
239
+ if (!N()) return;
240
+ let c = i(Object.fromEntries(O.map((e) => [e.value, n.text?.[e.value] ?? a[e.value] ?? y()]))), l = ee({
241
+ listing: n.listing,
242
+ comments: n.comments,
243
+ attributes: we(D.attributes ?? {}, n.attributes),
244
+ access: n.access
245
+ });
246
+ if (e) {
247
+ if (!c || !l || !ae) throw new b(w("readerEditor.changedDuringSave"));
248
+ let e = Ct.current;
249
+ if (!J || e.busy || e.error || e.queue.items.some((e) => e.status === "failed") || !await be(C, J)) throw new b(w("readerEditor.filesNotReady"));
250
+ if ((R ? await C.contents.version(n.id, R.id, k) : null)?.state !== "published") throw new b(w("readerEditor.versionDraft"));
251
+ if (!N()) return;
252
+ let t = at.checkpoint(), r = await We(() => C.contents.publish(n.id, ot ? new Date(ot).toISOString() : void 0));
253
+ t({ at: r.publish_at ? me(new Date(r.publish_at)) : "" }), it(w("contentManager.publishedNotice"));
254
+ } else it(w("pollEditor.saved"));
255
+ } catch (e) {
256
+ xt(e);
257
+ } finally {
258
+ N() && tt(!1);
259
+ }
260
+ }, Ft = async (e) => {
261
+ let t = await St(e.name), n = t.versions.find((e) => e.id === R?.id) ?? t.versions[0];
262
+ if (!n || !N()) return;
263
+ let r = {
264
+ kind: S.kind,
265
+ id: t.id,
266
+ version: n.id
267
+ }, i = await C.media.uploadNamed(r, e, { path: await C.media.presetPath(S.kind, "cover", e) });
268
+ N() && await C.contents.setCover(t.id, n.id, i.name);
269
+ }, It = async (e) => {
270
+ if (!J || !j || !R) return;
271
+ let n = await C.media.presetPath(S.kind, "cover", new File([], e.path.split("/").at(-1) ?? "cover", { type: e.type }));
272
+ await C.media.commit(J, [{
273
+ op: "copy",
274
+ from: {
275
+ id: j.id,
276
+ version: R.id,
277
+ path: e.path
278
+ },
279
+ to: n
280
+ }]), N() && await C.contents.setCover(j.id, R.id, t(n).split("/").at(-1));
281
+ }, { confirm: Lt, dialog: Rt } = pe(), zt = async () => {
282
+ j && await Lt({
283
+ title: w("contentManager.deleteTitle", { title: j.title }),
284
+ description: w("contentManager.deleteBody"),
285
+ confirm: w("contentManager.delete")
286
+ }) && await Z.run(async () => {
287
+ Q.discard(), await C.contents.remove(j.id), N() && S.onDeleted?.(j);
288
+ });
289
+ };
290
+ if (S.id && !j) return A.error ? /* @__PURE__ */ _(de, {
291
+ error: A.error,
292
+ message: w("contentManager.loadFailed"),
293
+ retry: A.reload
294
+ }) : /* @__PURE__ */ _(fe, {});
295
+ let Bt = j ? Fe(j) : "draft", Vt = R?.id, Ht = (e) => H.edit((t) => ({
296
+ ...t,
297
+ ...e
298
+ })), Ut = L.map((e) => ({
299
+ id: e.id,
300
+ label: Ne(e, (e) => O.find((t) => t.value === e)?.label ?? e, S.labels)
301
+ }));
302
+ return /* @__PURE__ */ _(ye.Provider, {
303
+ value: W.context,
304
+ children: /* @__PURE__ */ v("div", {
305
+ className: "grid gap-5 text-base",
306
+ "data-ckui": "reader-content-editor",
307
+ children: [
308
+ /* @__PURE__ */ v("div", {
309
+ className: "sticky top-0 z-10 flex flex-wrap items-center gap-3 rounded-xl border border-border bg-background/95 p-4 shadow-sm",
310
+ children: [
311
+ /* @__PURE__ */ v("div", {
312
+ className: "min-w-0 flex-1",
313
+ children: [/* @__PURE__ */ _("h1", {
314
+ className: "truncate text-xl font-semibold",
315
+ children: K.title || w("readerEditor.new")
316
+ }), /* @__PURE__ */ v("div", {
317
+ className: "mt-1 flex items-center gap-2 text-sm text-muted-foreground",
318
+ children: [
319
+ /* @__PURE__ */ _(ae, {
320
+ variant: j?.live ? "default" : "outline",
321
+ children: w(`contentManager.${Bt}`)
322
+ }),
323
+ R && /* @__PURE__ */ _("span", { children: w("contentEditor.pageCount", { count: $.review ? kt : R.pages ?? 0 }) }),
324
+ $e && /* @__PURE__ */ _("span", {
325
+ role: "status",
326
+ children: w("common.saving")
327
+ })
328
+ ]
329
+ })]
330
+ }),
331
+ j?.live && S.contentHref?.(j) && /* @__PURE__ */ _("a", {
332
+ href: S.contentHref(j),
333
+ className: "text-sm underline",
334
+ children: w("contentManager.view")
335
+ }),
336
+ /* @__PURE__ */ _(a, {
337
+ disabled: F || $e,
338
+ onClick: () => void Pt(!1),
339
+ children: w(F ? "common.saving" : j?.live ? "common.save" : "readerEditor.saveDraft")
340
+ }),
341
+ !j?.live && /* @__PURE__ */ _(a, {
342
+ variant: "outline",
343
+ disabled: F || jt,
344
+ onClick: () => void Pt(!0),
345
+ children: w(ot ? "readerEditor.schedule" : "contentManager.publish")
346
+ })
347
+ ]
348
+ }),
349
+ nt != null && /* @__PURE__ */ _(d, { children: typeof nt == "string" ? nt : le(Ue, e(nt)) }),
350
+ rt && /* @__PURE__ */ _("p", {
351
+ role: "status",
352
+ className: "text-sm text-muted-foreground",
353
+ children: rt
354
+ }),
355
+ /* @__PURE__ */ v("fieldset", {
356
+ disabled: F,
357
+ className: "grid min-w-0 items-start gap-5 xl:grid-cols-[minmax(0,1fr)_minmax(18rem,24rem)]",
358
+ children: [/* @__PURE__ */ v("div", {
359
+ className: "grid min-w-0 gap-5",
360
+ children: [
361
+ /* @__PURE__ */ v(x, {
362
+ title: w("readerEditor.details"),
363
+ children: [
364
+ /* @__PURE__ */ v("div", {
365
+ className: "grid gap-4 sm:grid-cols-[minmax(0,1fr)_10rem]",
366
+ children: [/* @__PURE__ */ v("div", {
367
+ className: "grid gap-1.5",
368
+ children: [/* @__PURE__ */ _(s, {
369
+ htmlFor: `${T}-title`,
370
+ children: w("contentManager.itemTitle")
371
+ }), /* @__PURE__ */ _(o, {
372
+ id: `${T}-title`,
373
+ required: !0,
374
+ maxLength: 300,
375
+ value: K.title,
376
+ onChange: (e) => q({ title: e.target.value })
377
+ })]
378
+ }), /* @__PURE__ */ v("div", {
379
+ className: "grid gap-1.5",
380
+ children: [/* @__PURE__ */ _(s, {
381
+ htmlFor: `${T}-language`,
382
+ children: w("contentManager.language")
383
+ }), /* @__PURE__ */ v(c, {
384
+ value: k,
385
+ onValueChange: (e) => e && Je(e),
386
+ children: [/* @__PURE__ */ _(oe, {
387
+ id: `${T}-language`,
388
+ children: /* @__PURE__ */ _(se, { children: O.find((e) => e.value === k)?.label ?? k })
389
+ }), /* @__PURE__ */ _(l, { children: O.map((e) => /* @__PURE__ */ _(u, {
390
+ value: e.value,
391
+ children: e.label
392
+ }, e.value)) })]
393
+ })]
394
+ })]
395
+ }),
396
+ /* @__PURE__ */ v("div", {
397
+ className: "grid gap-1.5",
398
+ children: [/* @__PURE__ */ _(s, {
399
+ htmlFor: `${T}-description`,
400
+ children: w("contentManager.description")
401
+ }), /* @__PURE__ */ _(ce, {
402
+ id: `${T}-description`,
403
+ rows: 3,
404
+ value: K.description ?? "",
405
+ onChange: (e) => q({ description: e.target.value })
406
+ })]
407
+ }),
408
+ /* @__PURE__ */ _(Ce, {
409
+ declared: D.attributes ?? {},
410
+ form: H.value.attributes,
411
+ onChange: (e, t) => Ht({ attributes: {
412
+ ...H.value.attributes,
413
+ [e]: t
414
+ } }),
415
+ labels: S.labels
416
+ }),
417
+ /* @__PURE__ */ v("details", {
418
+ className: "grid gap-3",
419
+ children: [/* @__PURE__ */ _("summary", {
420
+ className: "cursor-pointer text-sm text-muted-foreground",
421
+ children: w("readerEditor.additionalText")
422
+ }), /* @__PURE__ */ v("div", {
423
+ className: "mt-3 grid gap-3",
424
+ children: [
425
+ /* @__PURE__ */ v("div", {
426
+ className: "grid gap-1.5",
427
+ children: [/* @__PURE__ */ _(s, {
428
+ htmlFor: `${T}-slug`,
429
+ children: w("contentManager.slug")
430
+ }), /* @__PURE__ */ _(o, {
431
+ id: `${T}-slug`,
432
+ value: K.slug ?? "",
433
+ placeholder: w("contentManager.slugAuto"),
434
+ onChange: (e) => q({ slug: e.target.value })
435
+ })]
436
+ }),
437
+ /* @__PURE__ */ _(s, {
438
+ htmlFor: `${T}-body`,
439
+ children: w("contentManager.body")
440
+ }),
441
+ S.renderEditor ? S.renderEditor({
442
+ value: bt,
443
+ onChange: (e) => q({ body: A.storedBody(e) }),
444
+ uploadImage: j ? (e) => A.uploadImage(e) : void 0,
445
+ disabled: F,
446
+ "aria-label": w("contentManager.body")
447
+ }) : /* @__PURE__ */ _(ce, {
448
+ id: `${T}-body`,
449
+ value: K.body ?? "",
450
+ onChange: (e) => q({ body: e.target.value })
451
+ })
452
+ ]
453
+ })]
454
+ })
455
+ ]
456
+ }),
457
+ /* @__PURE__ */ v(x, {
458
+ title: w("readerEditor.files"),
459
+ children: [
460
+ L.length > 1 && /* @__PURE__ */ v(c, {
461
+ value: Vt ?? "",
462
+ onValueChange: (e) => e && Xe(e),
463
+ disabled: Q.busy || Q.pending.length > 0,
464
+ children: [/* @__PURE__ */ _(oe, {
465
+ "aria-label": w("contentEditor.versions"),
466
+ children: /* @__PURE__ */ _(se, { children: Ut.find((e) => e.id === Vt)?.label })
467
+ }), /* @__PURE__ */ _(l, { children: Ut.map((e) => /* @__PURE__ */ _(u, {
468
+ value: e.id,
469
+ children: e.label
470
+ }, e.id)) })]
471
+ }),
472
+ /* @__PURE__ */ _("p", {
473
+ className: "text-sm text-muted-foreground",
474
+ children: w("readerEditor.fileHelp")
475
+ }),
476
+ /* @__PURE__ */ _(ie, {
477
+ folder: {
478
+ ...Q,
479
+ add: Mt
480
+ },
481
+ label: !1,
482
+ layout: "grid",
483
+ disabled: F,
484
+ inputLabel: w("readerEditor.files"),
485
+ rowActions: (e) => e.type.startsWith("image/") && Q.groups.some((t) => t.rule?.page && t.files.some((t) => t.path === e.path)) ? /* @__PURE__ */ _(a, {
486
+ size: "icon-sm",
487
+ variant: "ghost",
488
+ title: w("readerEditor.useCover"),
489
+ "aria-label": w("readerEditor.useCoverFor", { name: e.path.split("/").at(-1) ?? e.path }),
490
+ disabled: Y.pending || F,
491
+ onClick: () => void Y.run(() => It(e)),
492
+ children: /* @__PURE__ */ _(Re, { icon: Le })
493
+ }) : null
494
+ }),
495
+ Q.read.error && /* @__PURE__ */ _(de, {
496
+ error: Q.read.error,
497
+ message: w("contentManager.loadFailed"),
498
+ retry: Q.read.reload
499
+ }),
500
+ $.error && /* @__PURE__ */ _(de, {
501
+ error: $.error,
502
+ message: w("pageReview.loadFailed"),
503
+ retry: $.reload
504
+ }),
505
+ (Dt || At || !$.error && !Q.read.error && kt === 0) && /* @__PURE__ */ _("p", {
506
+ role: "status",
507
+ className: "text-sm text-muted-foreground",
508
+ children: w(Dt ? "readerEditor.filesFailed" : At ? "readerEditor.processing" : "readerEditor.addPages")
509
+ }),
510
+ j && R && /* @__PURE__ */ v("details", {
511
+ onToggle: (e) => e.currentTarget.open && ht(!0),
512
+ children: [/* @__PURE__ */ _("summary", {
513
+ className: "cursor-pointer font-medium",
514
+ children: w("pageReview.title")
515
+ }), mt && /* @__PURE__ */ _(Oe, {
516
+ content: j.id,
517
+ version: R.id,
518
+ client: C,
519
+ onError: S.onError
520
+ }, R.id)]
521
+ })
522
+ ]
523
+ }),
524
+ j && /* @__PURE__ */ v("details", {
525
+ className: "rounded-xl border border-border bg-card p-4",
526
+ onToggle: (e) => e.currentTarget.open && lt(!0),
527
+ children: [/* @__PURE__ */ _("summary", {
528
+ className: "cursor-pointer font-medium",
529
+ children: w("readerEditor.versions")
530
+ }), ct && /* @__PURE__ */ _(Ae, {
531
+ content: j,
532
+ media: !1,
533
+ activeVersion: Vt,
534
+ client: C,
535
+ labels: S.labels,
536
+ onError: S.onError
537
+ })]
538
+ }),
539
+ j && R && /* @__PURE__ */ v("details", {
540
+ className: "rounded-xl border border-border bg-card p-4",
541
+ onToggle: (e) => pt(e.currentTarget.open),
542
+ children: [/* @__PURE__ */ _("summary", {
543
+ className: "cursor-pointer font-medium",
544
+ children: w("readerEditor.readerTools")
545
+ }), ut.filter((e) => L.some((t) => t.id === e)).map((e) => /* @__PURE__ */ _("div", {
546
+ hidden: e !== R.id,
547
+ children: /* @__PURE__ */ _(Ee, {
548
+ content: j.id,
549
+ version: e,
550
+ client: C,
551
+ onError: S.onError
552
+ })
553
+ }, e))]
554
+ })
555
+ ]
556
+ }), /* @__PURE__ */ v("aside", {
557
+ className: "grid min-w-0 gap-5",
558
+ children: [
559
+ /* @__PURE__ */ v(x, {
560
+ title: w("readerEditor.entities"),
561
+ children: [z.error && /* @__PURE__ */ _(d, { error: z.error }), B.map((e) => {
562
+ let t = U.value.memberships.map((e, t) => ({
563
+ a: e,
564
+ index: t
565
+ })).filter(({ a: t }) => yt.get(t.group_id ?? "")?.kind === e);
566
+ return /* @__PURE__ */ v("fieldset", {
567
+ disabled: !!j && z.loading,
568
+ className: "grid min-w-0 gap-2",
569
+ children: [
570
+ /* @__PURE__ */ _("legend", {
571
+ className: "mb-2 font-semibold",
572
+ children: ve(S.labels, e)
573
+ }),
574
+ t.map(({ a: t, index: n }) => /* @__PURE__ */ _(Te, {
575
+ m: t,
576
+ card: yt.get(t.group_id ?? ""),
577
+ spec: E.entity_kinds[e] ?? {},
578
+ labels: S.labels,
579
+ versions: Ut,
580
+ versionLabel: (e) => Ut.find((t) => t.id === e)?.label ?? e,
581
+ onChange: (e) => U.edit((t) => ({ memberships: t.memberships.map((t, r) => r === n ? {
582
+ ...t,
583
+ ...e
584
+ } : t) })),
585
+ onRemove: () => U.edit((e) => ({ memberships: e.memberships.filter((e, t) => t !== n) }))
586
+ }, `${t.group_id}:${n}`)),
587
+ /* @__PURE__ */ _(_e, {
588
+ kind: e,
589
+ management: S.management,
590
+ language: k,
591
+ exclude: t.filter(({ a: e }) => !e.version_id && !e.role).map(({ a: e }) => e.group_id),
592
+ label: w("memberships.add", { kind: ve(S.labels, e) }),
593
+ client: C,
594
+ onPick: (t) => {
595
+ vt((e) => new Map(e).set(t.id, t)), U.edit((n) => ({ memberships: [...n.memberships, {
596
+ group_id: t.id,
597
+ ...E.entity_kinds[e]?.version_level && R ? { version_id: R.id } : {}
598
+ }] }));
599
+ }
600
+ })
601
+ ]
602
+ }, e);
603
+ })]
604
+ }),
605
+ /* @__PURE__ */ v(x, {
606
+ title: w("contentManager.cover"),
607
+ children: [
608
+ R?.cover?.url ? /* @__PURE__ */ _("img", {
609
+ src: R.cover.url,
610
+ alt: "",
611
+ className: "mx-auto max-h-64 rounded-lg object-contain"
612
+ }) : /* @__PURE__ */ _("p", {
613
+ className: "text-sm text-muted-foreground",
614
+ children: w("readerEditor.firstPageCover")
615
+ }),
616
+ /* @__PURE__ */ v("label", {
617
+ className: "inline-flex cursor-pointer justify-center rounded-md border border-border px-3 py-2 text-sm font-medium hover:bg-muted",
618
+ children: [w("contentManager.addCover"), /* @__PURE__ */ _("input", {
619
+ type: "file",
620
+ accept: "image/*",
621
+ className: "sr-only",
622
+ "aria-label": w("contentManager.cover"),
623
+ disabled: Y.pending || F,
624
+ onChange: (e) => {
625
+ let t = e.target.files?.[0];
626
+ e.target.value = "", t && Y.run(() => Ft(t));
627
+ }
628
+ })]
629
+ }),
630
+ /* @__PURE__ */ _(d, { error: Y.error })
631
+ ]
632
+ }),
633
+ /* @__PURE__ */ v(x, {
634
+ title: w("contentEditor.accessTitle"),
635
+ children: [
636
+ /* @__PURE__ */ _(ke, {
637
+ value: H.value.access,
638
+ onChange: (e) => Ht({ access: e }),
639
+ model: E,
640
+ kind: S.kind,
641
+ owner: j?.owner_group_id ?? S.ownerGroup,
642
+ labels: S.labels,
643
+ client: C
644
+ }),
645
+ j && (H.value.access.level === "ppv" || H.value.access.level === "group_ppv" || j.offer) && /* @__PURE__ */ _(Se, {
646
+ offer: j.offer,
647
+ pending: X.pending,
648
+ onSell: (e) => X.run(() => C.offers.sell({ content: j.id }, e)),
649
+ onWithdraw: () => void X.run(() => C.offers.withdraw({ content: j.id }))
650
+ }),
651
+ /* @__PURE__ */ _(d, { error: X.error })
652
+ ]
653
+ }),
654
+ /* @__PURE__ */ v(x, {
655
+ title: w("readerEditor.publication"),
656
+ children: [
657
+ !j?.live && /* @__PURE__ */ v("div", {
658
+ className: "grid gap-1.5",
659
+ children: [/* @__PURE__ */ _(s, {
660
+ htmlFor: `${T}-publish`,
661
+ children: w("contentManager.publishAt")
662
+ }), /* @__PURE__ */ _(o, {
663
+ id: `${T}-publish`,
664
+ type: "datetime-local",
665
+ value: ot,
666
+ onChange: (e) => st(e.target.value)
667
+ })]
668
+ }),
669
+ /* @__PURE__ */ _(s, {
670
+ htmlFor: `${T}-listing`,
671
+ children: w("contentEditor.listing")
672
+ }),
673
+ /* @__PURE__ */ v(c, {
674
+ value: H.value.listing,
675
+ onValueChange: (e) => e && Ht({ listing: e }),
676
+ children: [/* @__PURE__ */ _(oe, {
677
+ id: `${T}-listing`,
678
+ children: /* @__PURE__ */ _(se, { children: w(`contentEditor.listing_${H.value.listing}`) })
679
+ }), /* @__PURE__ */ _(l, { children: [
680
+ "listed",
681
+ "members",
682
+ "unlisted"
683
+ ].map((e) => /* @__PURE__ */ _(u, {
684
+ value: e,
685
+ children: w(`contentEditor.listing_${e}`)
686
+ }, e)) })]
687
+ }),
688
+ /* @__PURE__ */ _(s, {
689
+ htmlFor: `${T}-comments`,
690
+ children: w("contentEditor.comments")
691
+ }),
692
+ /* @__PURE__ */ v(c, {
693
+ value: H.value.comments,
694
+ onValueChange: (e) => e && Ht({ comments: e }),
695
+ children: [/* @__PURE__ */ _(oe, {
696
+ id: `${T}-comments`,
697
+ children: /* @__PURE__ */ _(se, { children: w(`contentEditor.comments_${H.value.comments}`) })
698
+ }), /* @__PURE__ */ _(l, { children: [
699
+ "open",
700
+ "closed",
701
+ "hidden"
702
+ ].map((e) => /* @__PURE__ */ _(u, {
703
+ value: e,
704
+ children: w(`contentEditor.comments_${e}`)
705
+ }, e)) })]
706
+ }),
707
+ j?.state === "published" && /* @__PURE__ */ _(a, {
708
+ variant: "outline",
709
+ disabled: Z.pending,
710
+ onClick: () => void Z.run(() => C.contents.unpublish(j.id)),
711
+ children: w("contentManager.unpublish")
712
+ }),
713
+ j && /* @__PURE__ */ _(a, {
714
+ variant: "destructive",
715
+ disabled: Z.pending,
716
+ onClick: () => void zt(),
717
+ children: w("contentManager.delete")
718
+ }),
719
+ /* @__PURE__ */ _(d, { error: Z.error })
720
+ ]
721
+ })
722
+ ]
723
+ })]
724
+ }),
725
+ Rt
726
+ ]
727
+ })
728
+ });
729
+ }
730
+ //#endregion
731
+ export { S as ReaderContentEditor };
732
+
733
+ //# sourceMappingURL=reader-content-editor.js.map