@openrails/contentkit-ui 0.71.0 → 0.73.0

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 (134) hide show
  1. package/README.md +122 -10
  2. package/dist/client/content/bans.d.ts +2 -0
  3. package/dist/client/content/bans.js +24 -12
  4. package/dist/client/content/bans.js.map +1 -1
  5. package/dist/client/content/comments.d.ts +2 -0
  6. package/dist/client/content/comments.js.map +1 -1
  7. package/dist/client/content/polls.d.ts +9 -2
  8. package/dist/client/content/polls.js.map +1 -1
  9. package/dist/client/generated/routes.d.ts +28 -2
  10. package/dist/client/generated/routes.js +40 -0
  11. package/dist/client/generated/routes.js.map +1 -1
  12. package/dist/client/generated/wire.d.ts +4 -0
  13. package/dist/client/generated/wire.js.map +1 -1
  14. package/dist/client/index.d.ts +3 -3
  15. package/dist/client/media/queue.d.ts +1 -1
  16. package/dist/client/media/queue.js +1 -1
  17. package/dist/client/media/queue.js.map +1 -1
  18. package/dist/client/taxonomy.d.ts +5 -1
  19. package/dist/client/taxonomy.js +7 -0
  20. package/dist/client/taxonomy.js.map +1 -1
  21. package/dist/client.js +2 -2
  22. package/dist/components/admin/media-item-panel.d.ts +27 -0
  23. package/dist/components/admin/media-item-panel.js +397 -0
  24. package/dist/components/admin/media-item-panel.js.map +1 -0
  25. package/dist/components/admin/poll-manager.d.ts +28 -0
  26. package/dist/components/admin/poll-manager.js +297 -0
  27. package/dist/components/admin/poll-manager.js.map +1 -0
  28. package/dist/components/admin/post-manager.d.ts +45 -0
  29. package/dist/components/admin/post-manager.js +602 -0
  30. package/dist/components/admin/post-manager.js.map +1 -0
  31. package/dist/components/admin/shell.d.ts +73 -0
  32. package/dist/components/admin/shell.js +148 -0
  33. package/dist/components/admin/shell.js.map +1 -0
  34. package/dist/components/admin/taxonomy-manager.d.ts +54 -0
  35. package/dist/components/admin/taxonomy-manager.js +976 -0
  36. package/dist/components/admin/taxonomy-manager.js.map +1 -0
  37. package/dist/components/admin/upload-queue.d.ts +23 -0
  38. package/dist/components/admin/upload-queue.js +365 -0
  39. package/dist/components/admin/upload-queue.js.map +1 -0
  40. package/dist/components/admin/user-comment-standing.d.ts +25 -0
  41. package/dist/components/admin/user-comment-standing.js +229 -0
  42. package/dist/components/admin/user-comment-standing.js.map +1 -0
  43. package/dist/components/social/bans.d.ts +5 -2
  44. package/dist/components/social/bans.js +132 -134
  45. package/dist/components/social/bans.js.map +1 -1
  46. package/dist/components/social/index.d.ts +1 -1
  47. package/dist/components/social/moderation.d.ts +11 -13
  48. package/dist/components/social/moderation.js +299 -218
  49. package/dist/components/social/moderation.js.map +1 -1
  50. package/dist/components/social/parts.d.ts +3 -2
  51. package/dist/components/social/parts.js +74 -48
  52. package/dist/components/social/parts.js.map +1 -1
  53. package/dist/components/social/poll-editor.js +1 -0
  54. package/dist/components/social/poll-editor.js.map +1 -1
  55. package/dist/editor/index.d.ts +1 -0
  56. package/dist/editor/rich-text-editor.d.ts +13 -0
  57. package/dist/editor/rich-text-editor.js +228 -0
  58. package/dist/editor/rich-text-editor.js.map +1 -0
  59. package/dist/editor.js +2 -0
  60. package/dist/index.d.ts +8 -0
  61. package/dist/index.js +15 -8
  62. package/dist/locales/admin/de.d.ts +2 -0
  63. package/dist/locales/admin/de.js +227 -0
  64. package/dist/locales/admin/de.js.map +1 -0
  65. package/dist/locales/admin/en.d.ts +222 -0
  66. package/dist/locales/admin/en.js +227 -0
  67. package/dist/locales/admin/en.js.map +1 -0
  68. package/dist/locales/admin/es.d.ts +2 -0
  69. package/dist/locales/admin/es.js +227 -0
  70. package/dist/locales/admin/es.js.map +1 -0
  71. package/dist/locales/admin/ja.d.ts +2 -0
  72. package/dist/locales/admin/ja.js +227 -0
  73. package/dist/locales/admin/ja.js.map +1 -0
  74. package/dist/locales/admin/ko.d.ts +2 -0
  75. package/dist/locales/admin/ko.js +227 -0
  76. package/dist/locales/admin/ko.js.map +1 -0
  77. package/dist/locales/admin/zh.d.ts +2 -0
  78. package/dist/locales/admin/zh.js +227 -0
  79. package/dist/locales/admin/zh.js.map +1 -0
  80. package/dist/locales/de.js +5 -3
  81. package/dist/locales/de.js.map +1 -1
  82. package/dist/locales/en.d.ts +227 -0
  83. package/dist/locales/en.js +5 -3
  84. package/dist/locales/en.js.map +1 -1
  85. package/dist/locales/es.js +5 -3
  86. package/dist/locales/es.js.map +1 -1
  87. package/dist/locales/ja.js +5 -3
  88. package/dist/locales/ja.js.map +1 -1
  89. package/dist/locales/ko.js +5 -3
  90. package/dist/locales/ko.js.map +1 -1
  91. package/dist/locales/social/de.js +8 -1
  92. package/dist/locales/social/de.js.map +1 -1
  93. package/dist/locales/social/en.d.ts +7 -0
  94. package/dist/locales/social/en.js +8 -1
  95. package/dist/locales/social/en.js.map +1 -1
  96. package/dist/locales/social/es.js +8 -1
  97. package/dist/locales/social/es.js.map +1 -1
  98. package/dist/locales/social/ja.js +8 -1
  99. package/dist/locales/social/ja.js.map +1 -1
  100. package/dist/locales/social/ko.js +8 -1
  101. package/dist/locales/social/ko.js.map +1 -1
  102. package/dist/locales/social/zh.js +8 -1
  103. package/dist/locales/social/zh.js.map +1 -1
  104. package/dist/locales/zh.js +5 -3
  105. package/dist/locales/zh.js.map +1 -1
  106. package/dist/provider.d.ts +2 -0
  107. package/dist/provider.js +23 -19
  108. package/dist/provider.js.map +1 -1
  109. package/dist/react/admin.d.ts +55 -0
  110. package/dist/react/admin.js +97 -0
  111. package/dist/react/admin.js.map +1 -0
  112. package/dist/react/comments.d.ts +18 -2
  113. package/dist/react/comments.js +24 -8
  114. package/dist/react/comments.js.map +1 -1
  115. package/dist/react/context.d.ts +7 -1
  116. package/dist/react/context.js +6 -1
  117. package/dist/react/context.js.map +1 -1
  118. package/dist/react/folder.js.map +1 -1
  119. package/dist/react/index.d.ts +4 -3
  120. package/dist/react/polls.js +88 -87
  121. package/dist/react/polls.js.map +1 -1
  122. package/dist/react/posts.js +123 -122
  123. package/dist/react/posts.js.map +1 -1
  124. package/dist/react/resources.js +3 -0
  125. package/dist/react/resources.js.map +1 -1
  126. package/dist/react/upload.d.ts +10 -10
  127. package/dist/react/upload.js +1 -1
  128. package/dist/react/upload.js.map +1 -1
  129. package/dist/react/use-resource.d.ts +16 -0
  130. package/dist/react/use-resource.js +20 -1
  131. package/dist/react/use-resource.js.map +1 -1
  132. package/dist/react.js +21 -20
  133. package/dist/styles.css +1 -1
  134. package/package.json +37 -2
@@ -0,0 +1,229 @@
1
+ import { useMessages as e } from "../../i18n/context.js";
2
+ import { Button as t } from "../../ui/button.js";
3
+ import { useAdminComments as n, useGlobalCommentBan as r } from "../../react/comments.js";
4
+ import { Badge as i } from "../../ui/badge.js";
5
+ import { Skeleton as a } from "../../ui/skeleton.js";
6
+ import { ConfirmDialog as o, ErrorLine as s, RelativeTime as c, formatDate as l, useAction as u } from "../social/parts.js";
7
+ import { AdminRoot as d, LoadFailed as f, NoAccess as p, Rows as m } from "./shell.js";
8
+ import { CommentBanDialog as h } from "../social/bans.js";
9
+ import { useFlowClient as g, useStaffAccess as _ } from "../../react/admin.js";
10
+ import { useState as v } from "react";
11
+ import { Fragment as y, jsx as b, jsxs as x } from "react/jsx-runtime";
12
+ import { cn as S } from "cn";
13
+ //#region src/components/admin/user-comment-standing.tsx
14
+ var C = ["bans", "comments"];
15
+ function w(e = {}) {
16
+ return _(C, e);
17
+ }
18
+ function T({ client: e, baseUrl: t, auth: n, guard: r, appearance: i, className: a, language: o, messages: s, ...c }) {
19
+ let l = g({
20
+ client: e,
21
+ baseUrl: t,
22
+ auth: n
23
+ });
24
+ return /* @__PURE__ */ b(d, {
25
+ flow: "user-comment-standing",
26
+ appearance: i,
27
+ className: a,
28
+ language: o,
29
+ messages: s,
30
+ guard: r,
31
+ children: /* @__PURE__ */ b(E, {
32
+ ...c,
33
+ client: l
34
+ })
35
+ });
36
+ }
37
+ function E(t) {
38
+ let { t: n } = e(), r = w({ client: t.client }), i = /* @__PURE__ */ b("h3", {
39
+ className: "text-base font-semibold",
40
+ children: n("standing.title")
41
+ });
42
+ return r.loading ? /* @__PURE__ */ x(y, { children: [i, /* @__PURE__ */ b(m, { count: 2 })] }) : r.any ? /* @__PURE__ */ x(y, { children: [
43
+ i,
44
+ r.allowed.bans && /* @__PURE__ */ b(D, { ...t }),
45
+ r.allowed.comments && /* @__PURE__ */ b(k, { ...t })
46
+ ] }) : /* @__PURE__ */ x(y, { children: [i, /* @__PURE__ */ b(p, { children: n("standing.noAccess") })] });
47
+ }
48
+ function D({ user: n, name: c, client: d, onError: p }) {
49
+ let m = e(), { t: g } = m, _ = r(n, { client: d }), [y, S] = v(!1), [C, w] = v(!1), T = u("ban.lift", p), E = c ?? _.ban?.user?.username ?? n, D = _.ban;
50
+ return /* @__PURE__ */ x("section", {
51
+ className: "grid gap-2 rounded-lg border border-border p-3",
52
+ "data-ckui": "standing-ban",
53
+ "aria-busy": _.loading,
54
+ children: [
55
+ /* @__PURE__ */ b("h4", {
56
+ className: "font-medium",
57
+ children: g("standing.ban")
58
+ }),
59
+ _.loading && !D ? /* @__PURE__ */ b(a, { className: "h-10 w-full" }) : _.error ? /* @__PURE__ */ b(f, {
60
+ error: _.error,
61
+ message: g("standing.banLoadFailed"),
62
+ retry: _.reload
63
+ }) : D ? /* @__PURE__ */ x("div", {
64
+ className: "flex flex-wrap items-start justify-between gap-3",
65
+ children: [/* @__PURE__ */ x("div", {
66
+ className: "grid min-w-0 gap-0.5",
67
+ children: [
68
+ /* @__PURE__ */ b("div", { children: /* @__PURE__ */ b(i, {
69
+ variant: D.expired ? "outline" : "destructive",
70
+ children: g(D.expired ? "bans.expired" : "bans.active")
71
+ }) }),
72
+ D.reason && /* @__PURE__ */ b("p", {
73
+ className: "break-words",
74
+ children: g("bans.reason", { reason: D.reason })
75
+ }),
76
+ /* @__PURE__ */ x("p", {
77
+ className: "text-muted-foreground",
78
+ children: [
79
+ D.until ? g("bans.until", { date: l(m, D.until) }) : g("bans.untilLifted"),
80
+ " · ",
81
+ g("bans.bannedAt", { date: l(m, D.banned_at, !1) })
82
+ ]
83
+ })
84
+ ]
85
+ }), /* @__PURE__ */ x("div", {
86
+ className: "flex gap-2",
87
+ children: [/* @__PURE__ */ b(t, {
88
+ size: "sm",
89
+ variant: "outline",
90
+ onClick: () => S(!0),
91
+ children: g("bans.update")
92
+ }), /* @__PURE__ */ b(t, {
93
+ size: "sm",
94
+ variant: "destructive",
95
+ onClick: () => w(!0),
96
+ children: g("bans.lift")
97
+ })]
98
+ })]
99
+ }) : /* @__PURE__ */ x("div", {
100
+ className: "flex flex-wrap items-center justify-between gap-2",
101
+ children: [/* @__PURE__ */ b("p", {
102
+ className: "text-muted-foreground",
103
+ children: g("standing.notBanned")
104
+ }), /* @__PURE__ */ b(t, {
105
+ size: "sm",
106
+ variant: "destructive",
107
+ onClick: () => S(!0),
108
+ children: g("comments.ban")
109
+ })]
110
+ }),
111
+ /* @__PURE__ */ b(s, { error: T.error }),
112
+ y && /* @__PURE__ */ b(h, {
113
+ open: !0,
114
+ onOpenChange: S,
115
+ user: {
116
+ id: n,
117
+ name: E
118
+ },
119
+ scopes: ["global"],
120
+ ban: D,
121
+ client: d,
122
+ onError: p
123
+ }),
124
+ /* @__PURE__ */ b(o, {
125
+ open: C,
126
+ onOpenChange: w,
127
+ title: g("bans.liftTitle", { name: E }),
128
+ description: g("bans.liftBody"),
129
+ confirm: g("bans.lift"),
130
+ onConfirm: () => void T.run(_.lift)
131
+ })
132
+ ]
133
+ });
134
+ }
135
+ function O(e) {
136
+ return e.deleted ? "deleted" : e.moderation === "held" ? "held" : e.moderation === "rejected" ? "rejected" : "published";
137
+ }
138
+ function k({ user: r, client: a, itemHref: o, pageSize: l = 10, onError: d }) {
139
+ let { t: p } = e(), h = n({
140
+ author: r,
141
+ pageSize: l,
142
+ client: a
143
+ }), g = u("comment.delete", d), _ = u("comment.restore", d);
144
+ return /* @__PURE__ */ x("section", {
145
+ className: "grid gap-2",
146
+ "data-ckui": "standing-comments",
147
+ children: [
148
+ /* @__PURE__ */ b("h4", {
149
+ className: "font-medium",
150
+ children: p("standing.comments")
151
+ }),
152
+ /* @__PURE__ */ b(s, { error: g.error ?? _.error }),
153
+ h.loading && !h.items.length ? /* @__PURE__ */ b(m, { count: 2 }) : h.error && !h.items.length ? /* @__PURE__ */ b(f, {
154
+ error: h.error,
155
+ message: p("moderation.loadFailed"),
156
+ retry: h.reload
157
+ }) : h.items.length ? /* @__PURE__ */ b("ul", {
158
+ className: "grid divide-y divide-border rounded-lg border border-border",
159
+ children: h.items.map((e) => {
160
+ let n = O(e), r = o?.({
161
+ kind: e.content_kind,
162
+ id: e.content_id
163
+ });
164
+ return /* @__PURE__ */ x("li", {
165
+ className: "grid gap-1.5 p-3",
166
+ "data-ckui": "admin-comment",
167
+ "data-status": n,
168
+ children: [
169
+ /* @__PURE__ */ x("div", {
170
+ className: "flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted-foreground",
171
+ children: [
172
+ /* @__PURE__ */ b(c, { at: e.created_at }),
173
+ /* @__PURE__ */ b(i, {
174
+ variant: n === "published" ? "outline" : n === "held" ? "secondary" : "destructive",
175
+ children: p(`moderation.${n}`)
176
+ }),
177
+ /* @__PURE__ */ x("span", { children: [
178
+ p("moderation.on"),
179
+ " ",
180
+ r ? /* @__PURE__ */ x("a", {
181
+ className: "hover:underline",
182
+ href: r,
183
+ children: [
184
+ e.content_kind,
185
+ "/",
186
+ e.content_id
187
+ ]
188
+ }) : `${e.content_kind}/${e.content_id}`
189
+ ] })
190
+ ]
191
+ }),
192
+ /* @__PURE__ */ b("p", {
193
+ className: S("line-clamp-3 break-words whitespace-pre-wrap", e.deleted && "text-muted-foreground line-through"),
194
+ children: e.body
195
+ }),
196
+ /* @__PURE__ */ b("div", { children: e.deleted ? /* @__PURE__ */ b(t, {
197
+ size: "sm",
198
+ variant: "outline",
199
+ disabled: _.pending,
200
+ onClick: () => void _.run(() => a.comments.restore(e.id)),
201
+ children: p("moderation.restore")
202
+ }) : /* @__PURE__ */ b(t, {
203
+ size: "sm",
204
+ variant: "destructive",
205
+ disabled: g.pending,
206
+ onClick: () => void g.run(() => a.comments.delete(e.id)),
207
+ children: p("moderation.delete")
208
+ }) })
209
+ ]
210
+ }, e.id);
211
+ })
212
+ }) : /* @__PURE__ */ b("p", {
213
+ className: "text-muted-foreground",
214
+ children: p("standing.noComments")
215
+ }),
216
+ h.hasMore && /* @__PURE__ */ b(t, {
217
+ variant: "outline",
218
+ className: "justify-self-center",
219
+ disabled: h.loadingMore,
220
+ onClick: () => void h.loadMore(),
221
+ children: p("moderation.loadMore")
222
+ })
223
+ ]
224
+ });
225
+ }
226
+ //#endregion
227
+ export { T as UserCommentStanding, w as useUserCommentStandingAccess };
228
+
229
+ //# sourceMappingURL=user-comment-standing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-comment-standing.js","names":[],"sources":["../../../src/components/admin/user-comment-standing.tsx"],"sourcesContent":["import { cn } from \"cn\";\nimport { useState } from \"react\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport type { AdminComment } from \"../../client/generated/wire.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport { useFlowClient, useStaffAccess, type FlowClientOptions, type StaffAccess } from \"../../react/admin.js\";\nimport { useAdminComments, useGlobalCommentBan } from \"../../react/comments.js\";\nimport { Badge } from \"#ckui/ui/badge\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Skeleton } from \"#ckui/ui/skeleton\";\nimport { CommentBanDialog } from \"../social/bans.js\";\nimport { ConfirmDialog, ErrorLine, formatDate, RelativeTime, useAction } from \"../social/parts.js\";\nimport { AdminRoot, LoadFailed, NoAccess, Rows, type AdminFlowProps } from \"./shell.js\";\n\nexport interface UserCommentStandingProps extends AdminFlowProps {\n /** The user's id. */\n user: string;\n /** Their name in headings and dialogs; else their username once known. */\n name?: string;\n /** A link to a commented item. */\n itemHref?: (item: { kind: string; id: string }) => string | undefined;\n /** Comments per page. Default 10. */\n pageSize?: number;\n}\n\ntype StandingArea = \"bans\" | \"comments\";\nconst AREAS: readonly StandingArea[] = [\"bans\", \"comments\"];\n\n/** Whether the caller may manage site-wide comment bans and moderate comments: what UserCommentStanding shows. */\nexport function useUserCommentStandingAccess(o: FlowClientOptions = {}): StaffAccess<StandingArea> {\n return useStaffAccess(AREAS, o);\n}\n\n/**\n * A user page's comment panel: the person's site-wide comment ban (ban,\n * replace, lift) and their recent comments (delete, restore), each as the\n * caller's permissions allow.\n */\nexport function UserCommentStanding({ client: own, baseUrl, auth, guard, appearance, className, language, messages, ...p }: UserCommentStandingProps) {\n const client = useFlowClient({ client: own, baseUrl, auth });\n return (\n <AdminRoot flow=\"user-comment-standing\" appearance={appearance} className={className} language={language} messages={messages} guard={guard}>\n <Standing {...p} client={client} />\n </AdminRoot>\n );\n}\n\ntype Inner = Omit<UserCommentStandingProps, \"client\" | \"baseUrl\" | \"auth\" | \"guard\" | \"appearance\" | \"className\" | \"language\" | \"messages\"> & { client: ContentKitClient };\n\nfunction Standing(p: Inner) {\n const { t } = useMessages();\n const access = useUserCommentStandingAccess({ client: p.client });\n const title = <h3 className=\"text-base font-semibold\">{t(\"standing.title\")}</h3>;\n if (access.loading)\n return (\n <>\n {title}\n <Rows count={2} />\n </>\n );\n if (!access.any)\n return (\n <>\n {title}\n <NoAccess>{t(\"standing.noAccess\")}</NoAccess>\n </>\n );\n return (\n <>\n {title}\n {access.allowed.bans && <BanCard {...p} />}\n {access.allowed.comments && <Recent {...p} />}\n </>\n );\n}\n\nfunction BanCard({ user, name, client, onError }: Inner) {\n const m = useMessages();\n const { t } = m;\n const g = useGlobalCommentBan(user, { client });\n const [editing, setEditing] = useState(false);\n const [lifting, setLifting] = useState(false);\n const lift = useAction(\"ban.lift\", onError);\n const who = name ?? g.ban?.user?.username ?? user;\n const ban = g.ban;\n return (\n <section className=\"grid gap-2 rounded-lg border border-border p-3\" data-ckui=\"standing-ban\" aria-busy={g.loading}>\n <h4 className=\"font-medium\">{t(\"standing.ban\")}</h4>\n {g.loading && !ban ? (\n <Skeleton className=\"h-10 w-full\" />\n ) : g.error ? (\n <LoadFailed error={g.error} message={t(\"standing.banLoadFailed\")} retry={g.reload} />\n ) : !ban ? (\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <p className=\"text-muted-foreground\">{t(\"standing.notBanned\")}</p>\n <Button size=\"sm\" variant=\"destructive\" onClick={() => setEditing(true)}>\n {t(\"comments.ban\")}\n </Button>\n </div>\n ) : (\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"grid min-w-0 gap-0.5\">\n <div>\n <Badge variant={ban.expired ? \"outline\" : \"destructive\"}>{t(ban.expired ? \"bans.expired\" : \"bans.active\")}</Badge>\n </div>\n {ban.reason && <p className=\"break-words\">{t(\"bans.reason\", { reason: ban.reason })}</p>}\n <p className=\"text-muted-foreground\">\n {ban.until ? t(\"bans.until\", { date: formatDate(m, ban.until) }) : t(\"bans.untilLifted\")} · {t(\"bans.bannedAt\", { date: formatDate(m, ban.banned_at, false) })}\n </p>\n </div>\n <div className=\"flex gap-2\">\n <Button size=\"sm\" variant=\"outline\" onClick={() => setEditing(true)}>\n {t(\"bans.update\")}\n </Button>\n <Button size=\"sm\" variant=\"destructive\" onClick={() => setLifting(true)}>\n {t(\"bans.lift\")}\n </Button>\n </div>\n </div>\n )}\n <ErrorLine error={lift.error} />\n {editing && <CommentBanDialog open onOpenChange={setEditing} user={{ id: user, name: who }} scopes={[\"global\"]} ban={ban} client={client} onError={onError} />}\n <ConfirmDialog\n open={lifting}\n onOpenChange={setLifting}\n title={t(\"bans.liftTitle\", { name: who })}\n description={t(\"bans.liftBody\")}\n confirm={t(\"bans.lift\")}\n onConfirm={() => void lift.run(g.lift)}\n />\n </section>\n );\n}\n\nfunction status(c: AdminComment): \"deleted\" | \"held\" | \"rejected\" | \"published\" {\n if (c.deleted) return \"deleted\";\n return c.moderation === \"held\" ? \"held\" : c.moderation === \"rejected\" ? \"rejected\" : \"published\";\n}\n\nfunction Recent({ user, client, itemHref, pageSize = 10, onError }: Inner) {\n const { t } = useMessages();\n const list = useAdminComments({ author: user, pageSize, client });\n const del = useAction(\"comment.delete\", onError);\n const restore = useAction(\"comment.restore\", onError);\n return (\n <section className=\"grid gap-2\" data-ckui=\"standing-comments\">\n <h4 className=\"font-medium\">{t(\"standing.comments\")}</h4>\n <ErrorLine error={del.error ?? restore.error} />\n {list.loading && !list.items.length ? (\n <Rows count={2} />\n ) : list.error && !list.items.length ? (\n <LoadFailed error={list.error} message={t(\"moderation.loadFailed\")} retry={list.reload} />\n ) : !list.items.length ? (\n <p className=\"text-muted-foreground\">{t(\"standing.noComments\")}</p>\n ) : (\n <ul className=\"grid divide-y divide-border rounded-lg border border-border\">\n {list.items.map((c) => {\n const s = status(c);\n const href = itemHref?.({ kind: c.content_kind, id: c.content_id });\n return (\n <li key={c.id} className=\"grid gap-1.5 p-3\" data-ckui=\"admin-comment\" data-status={s}>\n <div className=\"flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted-foreground\">\n <RelativeTime at={c.created_at} />\n <Badge variant={s === \"published\" ? \"outline\" : s === \"held\" ? \"secondary\" : \"destructive\"}>{t(`moderation.${s}`)}</Badge>\n <span>\n {t(\"moderation.on\")}{\" \"}\n {href ? (\n <a className=\"hover:underline\" href={href}>\n {c.content_kind}/{c.content_id}\n </a>\n ) : (\n `${c.content_kind}/${c.content_id}`\n )}\n </span>\n </div>\n <p className={cn(\"line-clamp-3 break-words whitespace-pre-wrap\", c.deleted && \"text-muted-foreground line-through\")}>{c.body}</p>\n <div>\n {c.deleted ? (\n <Button size=\"sm\" variant=\"outline\" disabled={restore.pending} onClick={() => void restore.run(() => client.comments.restore(c.id))}>\n {t(\"moderation.restore\")}\n </Button>\n ) : (\n <Button size=\"sm\" variant=\"destructive\" disabled={del.pending} onClick={() => void del.run(() => client.comments.delete(c.id))}>\n {t(\"moderation.delete\")}\n </Button>\n )}\n </div>\n </li>\n );\n })}\n </ul>\n )}\n {list.hasMore && (\n <Button variant=\"outline\" className=\"justify-self-center\" disabled={list.loadingMore} onClick={() => void list.loadMore()}>\n {t(\"moderation.loadMore\")}\n </Button>\n )}\n </section>\n );\n}\n\n"],"mappings":"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"}
@@ -32,11 +32,14 @@ export interface CommentBansProps {
32
32
  /** "global": the site's bans (CommentBan); "owner": the caller's own. Default "global". */
33
33
  scope?: BanScope;
34
34
  pageSize?: number;
35
+ /** The page shown (from 1), when the host keeps it, e.g. in the URL; with onPageChange. */
36
+ page?: number;
37
+ onPageChange?: (page: number) => void;
35
38
  userHref?: (user: PublicUser) => string | undefined;
36
39
  client?: ContentKitClient;
37
40
  onError?: ContentKitErrorHandler;
38
41
  className?: string;
39
42
  appearance?: ContentKitUiAppearance;
40
43
  }
41
- /** A scope's comment bans, newest first: who, why, until when; ban a user by id, update or lift a ban. */
42
- export declare function CommentBans({ scope, pageSize, userHref, client, onError, className, appearance }: CommentBansProps): import('react').JSX.Element;
44
+ /** A scope's comment bans, newest first, a page at a time: who, why, until when; ban a user by id, update or lift a ban. */
45
+ export declare function CommentBans({ scope, pageSize, page: shown, onPageChange, userHref, client: own, onError, className, appearance }: CommentBansProps): import('react').JSX.Element;