@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.
- package/README.md +122 -10
- package/dist/client/content/bans.d.ts +2 -0
- package/dist/client/content/bans.js +24 -12
- package/dist/client/content/bans.js.map +1 -1
- package/dist/client/content/comments.d.ts +2 -0
- package/dist/client/content/comments.js.map +1 -1
- package/dist/client/content/polls.d.ts +9 -2
- package/dist/client/content/polls.js.map +1 -1
- package/dist/client/generated/routes.d.ts +28 -2
- package/dist/client/generated/routes.js +40 -0
- package/dist/client/generated/routes.js.map +1 -1
- package/dist/client/generated/wire.d.ts +4 -0
- package/dist/client/generated/wire.js.map +1 -1
- package/dist/client/index.d.ts +3 -3
- package/dist/client/media/queue.d.ts +1 -1
- package/dist/client/media/queue.js +1 -1
- package/dist/client/media/queue.js.map +1 -1
- package/dist/client/taxonomy.d.ts +5 -1
- package/dist/client/taxonomy.js +7 -0
- package/dist/client/taxonomy.js.map +1 -1
- package/dist/client.js +2 -2
- package/dist/components/admin/media-item-panel.d.ts +27 -0
- package/dist/components/admin/media-item-panel.js +397 -0
- package/dist/components/admin/media-item-panel.js.map +1 -0
- package/dist/components/admin/poll-manager.d.ts +28 -0
- package/dist/components/admin/poll-manager.js +297 -0
- package/dist/components/admin/poll-manager.js.map +1 -0
- package/dist/components/admin/post-manager.d.ts +45 -0
- package/dist/components/admin/post-manager.js +602 -0
- package/dist/components/admin/post-manager.js.map +1 -0
- package/dist/components/admin/shell.d.ts +73 -0
- package/dist/components/admin/shell.js +148 -0
- package/dist/components/admin/shell.js.map +1 -0
- package/dist/components/admin/taxonomy-manager.d.ts +54 -0
- package/dist/components/admin/taxonomy-manager.js +976 -0
- package/dist/components/admin/taxonomy-manager.js.map +1 -0
- package/dist/components/admin/upload-queue.d.ts +23 -0
- package/dist/components/admin/upload-queue.js +365 -0
- package/dist/components/admin/upload-queue.js.map +1 -0
- package/dist/components/admin/user-comment-standing.d.ts +25 -0
- package/dist/components/admin/user-comment-standing.js +229 -0
- package/dist/components/admin/user-comment-standing.js.map +1 -0
- package/dist/components/social/bans.d.ts +5 -2
- package/dist/components/social/bans.js +132 -134
- package/dist/components/social/bans.js.map +1 -1
- package/dist/components/social/index.d.ts +1 -1
- package/dist/components/social/moderation.d.ts +11 -13
- package/dist/components/social/moderation.js +299 -218
- package/dist/components/social/moderation.js.map +1 -1
- package/dist/components/social/parts.d.ts +3 -2
- package/dist/components/social/parts.js +74 -48
- package/dist/components/social/parts.js.map +1 -1
- package/dist/components/social/poll-editor.js +1 -0
- package/dist/components/social/poll-editor.js.map +1 -1
- package/dist/editor/index.d.ts +1 -0
- package/dist/editor/rich-text-editor.d.ts +13 -0
- package/dist/editor/rich-text-editor.js +228 -0
- package/dist/editor/rich-text-editor.js.map +1 -0
- package/dist/editor.js +2 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +15 -8
- package/dist/locales/admin/de.d.ts +2 -0
- package/dist/locales/admin/de.js +227 -0
- package/dist/locales/admin/de.js.map +1 -0
- package/dist/locales/admin/en.d.ts +222 -0
- package/dist/locales/admin/en.js +227 -0
- package/dist/locales/admin/en.js.map +1 -0
- package/dist/locales/admin/es.d.ts +2 -0
- package/dist/locales/admin/es.js +227 -0
- package/dist/locales/admin/es.js.map +1 -0
- package/dist/locales/admin/ja.d.ts +2 -0
- package/dist/locales/admin/ja.js +227 -0
- package/dist/locales/admin/ja.js.map +1 -0
- package/dist/locales/admin/ko.d.ts +2 -0
- package/dist/locales/admin/ko.js +227 -0
- package/dist/locales/admin/ko.js.map +1 -0
- package/dist/locales/admin/zh.d.ts +2 -0
- package/dist/locales/admin/zh.js +227 -0
- package/dist/locales/admin/zh.js.map +1 -0
- package/dist/locales/de.js +5 -3
- package/dist/locales/de.js.map +1 -1
- package/dist/locales/en.d.ts +227 -0
- package/dist/locales/en.js +5 -3
- package/dist/locales/en.js.map +1 -1
- package/dist/locales/es.js +5 -3
- package/dist/locales/es.js.map +1 -1
- package/dist/locales/ja.js +5 -3
- package/dist/locales/ja.js.map +1 -1
- package/dist/locales/ko.js +5 -3
- package/dist/locales/ko.js.map +1 -1
- package/dist/locales/social/de.js +8 -1
- package/dist/locales/social/de.js.map +1 -1
- package/dist/locales/social/en.d.ts +7 -0
- package/dist/locales/social/en.js +8 -1
- package/dist/locales/social/en.js.map +1 -1
- package/dist/locales/social/es.js +8 -1
- package/dist/locales/social/es.js.map +1 -1
- package/dist/locales/social/ja.js +8 -1
- package/dist/locales/social/ja.js.map +1 -1
- package/dist/locales/social/ko.js +8 -1
- package/dist/locales/social/ko.js.map +1 -1
- package/dist/locales/social/zh.js +8 -1
- package/dist/locales/social/zh.js.map +1 -1
- package/dist/locales/zh.js +5 -3
- package/dist/locales/zh.js.map +1 -1
- package/dist/provider.d.ts +2 -0
- package/dist/provider.js +23 -19
- package/dist/provider.js.map +1 -1
- package/dist/react/admin.d.ts +55 -0
- package/dist/react/admin.js +97 -0
- package/dist/react/admin.js.map +1 -0
- package/dist/react/comments.d.ts +18 -2
- package/dist/react/comments.js +24 -8
- package/dist/react/comments.js.map +1 -1
- package/dist/react/context.d.ts +7 -1
- package/dist/react/context.js +6 -1
- package/dist/react/context.js.map +1 -1
- package/dist/react/folder.js.map +1 -1
- package/dist/react/index.d.ts +4 -3
- package/dist/react/polls.js +88 -87
- package/dist/react/polls.js.map +1 -1
- package/dist/react/posts.js +123 -122
- package/dist/react/posts.js.map +1 -1
- package/dist/react/resources.js +3 -0
- package/dist/react/resources.js.map +1 -1
- package/dist/react/upload.d.ts +10 -10
- package/dist/react/upload.js +1 -1
- package/dist/react/upload.js.map +1 -1
- package/dist/react/use-resource.d.ts +16 -0
- package/dist/react/use-resource.js +20 -1
- package/dist/react/use-resource.js.map +1 -1
- package/dist/react.js +21 -20
- package/dist/styles.css +1 -1
- 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;
|