@openrails/contentkit-ui 0.0.0-stage → 0.68.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.
- package/README.md +470 -2
- package/dist/appearance.d.ts +38 -0
- package/dist/appearance.js +15 -0
- package/dist/appearance.js.map +1 -0
- package/dist/assets/hash.worker-BYfo-7MQ.js.map +1 -0
- package/dist/client/aspect.d.ts +6 -0
- package/dist/client/aspect.js +17 -0
- package/dist/client/aspect.js.map +1 -0
- package/dist/client/client.d.ts +53 -0
- package/dist/client/client.js +36 -0
- package/dist/client/client.js.map +1 -0
- package/dist/client/codes.d.ts +12 -0
- package/dist/client/codes.js +19 -0
- package/dist/client/codes.js.map +1 -0
- package/dist/client/content/bans.d.ts +15 -0
- package/dist/client/content/bans.js +40 -0
- package/dist/client/content/bans.js.map +1 -0
- package/dist/client/content/comments.d.ts +36 -0
- package/dist/client/content/comments.js +95 -0
- package/dist/client/content/comments.js.map +1 -0
- package/dist/client/content/favorites.d.ts +14 -0
- package/dist/client/content/favorites.js +42 -0
- package/dist/client/content/favorites.js.map +1 -0
- package/dist/client/content/moderation.d.ts +18 -0
- package/dist/client/content/moderation.js +37 -0
- package/dist/client/content/moderation.js.map +1 -0
- package/dist/client/content/polls.d.ts +47 -0
- package/dist/client/content/polls.js +151 -0
- package/dist/client/content/polls.js.map +1 -0
- package/dist/client/content/posts.d.ts +44 -0
- package/dist/client/content/posts.js +92 -0
- package/dist/client/content/posts.js.map +1 -0
- package/dist/client/content/reactions.d.ts +12 -0
- package/dist/client/content/reactions.js +36 -0
- package/dist/client/content/reactions.js.map +1 -0
- package/dist/client/content/types.d.ts +91 -0
- package/dist/client/content/types.js +8 -0
- package/dist/client/content/types.js.map +1 -0
- package/dist/client/crop.d.ts +32 -0
- package/dist/client/crop.js +103 -0
- package/dist/client/crop.js.map +1 -0
- package/dist/client/errors.d.ts +54 -0
- package/dist/client/errors.js +80 -0
- package/dist/client/errors.js.map +1 -0
- package/dist/client/gallery.d.ts +43 -0
- package/dist/client/gallery.js +86 -0
- package/dist/client/gallery.js.map +1 -0
- package/dist/client/generated/error-codes.d.ts +5 -0
- package/dist/client/generated/error-codes.js +131 -0
- package/dist/client/generated/error-codes.js.map +1 -0
- package/dist/client/generated/routes.d.ts +1086 -0
- package/dist/client/generated/routes.js +1400 -0
- package/dist/client/generated/routes.js.map +1 -0
- package/dist/client/generated/wire.d.ts +630 -0
- package/dist/client/generated/wire.js +6 -0
- package/dist/client/generated/wire.js.map +1 -0
- package/dist/client/http.d.ts +83 -0
- package/dist/client/http.js +82 -0
- package/dist/client/http.js.map +1 -0
- package/dist/client/image.d.ts +24 -0
- package/dist/client/image.js +65 -0
- package/dist/client/image.js.map +1 -0
- package/dist/client/index.d.ts +33 -0
- package/dist/client/media/api.d.ts +36 -0
- package/dist/client/media/api.js +61 -0
- package/dist/client/media/api.js.map +1 -0
- package/dist/client/media/client.d.ts +247 -0
- package/dist/client/media/client.js +407 -0
- package/dist/client/media/client.js.map +1 -0
- package/dist/client/media/encode.d.ts +3 -0
- package/dist/client/media/encode.js +8 -0
- package/dist/client/media/encode.js.map +1 -0
- package/dist/client/media/hash-stream.d.ts +6 -0
- package/dist/client/media/hash-stream.js +16 -0
- package/dist/client/media/hash-stream.js.map +1 -0
- package/dist/client/media/hash.d.ts +12 -0
- package/dist/client/media/hash.js +48 -0
- package/dist/client/media/hash.js.map +1 -0
- package/dist/client/media/hash.worker-inline.js +18 -0
- package/dist/client/media/hash.worker-inline.js.map +1 -0
- package/dist/client/media/pacer.d.ts +21 -0
- package/dist/client/media/pacer.js +25 -0
- package/dist/client/media/pacer.js.map +1 -0
- package/dist/client/media/queue.d.ts +112 -0
- package/dist/client/media/queue.js +274 -0
- package/dist/client/media/queue.js.map +1 -0
- package/dist/client/media/ref.d.ts +6 -0
- package/dist/client/media/ref.js +10 -0
- package/dist/client/media/ref.js.map +1 -0
- package/dist/client/media/rules.d.ts +54 -0
- package/dist/client/media/rules.js +143 -0
- package/dist/client/media/rules.js.map +1 -0
- package/dist/client/media/transport.d.ts +13 -0
- package/dist/client/media/transport.js +33 -0
- package/dist/client/media/transport.js.map +1 -0
- package/dist/client/media/windows.d.ts +15 -0
- package/dist/client/media/windows.js +39 -0
- package/dist/client/media/windows.js.map +1 -0
- package/dist/client/playback.d.ts +200 -0
- package/dist/client/playback.js +142 -0
- package/dist/client/playback.js.map +1 -0
- package/dist/client/player.d.ts +102 -0
- package/dist/client/player.js +155 -0
- package/dist/client/player.js.map +1 -0
- package/dist/client/public.d.ts +25 -0
- package/dist/client/public.js +18 -0
- package/dist/client/public.js.map +1 -0
- package/dist/client/rendition.d.ts +19 -0
- package/dist/client/rendition.js +16 -0
- package/dist/client/rendition.js.map +1 -0
- package/dist/client/route.d.ts +39 -0
- package/dist/client/route.js +31 -0
- package/dist/client/route.js.map +1 -0
- package/dist/client/taxonomy.d.ts +30 -0
- package/dist/client/taxonomy.js +77 -0
- package/dist/client/taxonomy.js.map +1 -0
- package/dist/client.js +33 -0
- package/dist/components/encode-progress.d.ts +15 -0
- package/dist/components/encode-progress.js +49 -0
- package/dist/components/encode-progress.js.map +1 -0
- package/dist/components/hover-preview.d.ts +29 -0
- package/dist/components/hover-preview.js +49 -0
- package/dist/components/hover-preview.js.map +1 -0
- package/dist/components/image-crop-dialog.d.ts +48 -0
- package/dist/components/image-crop-dialog.js +359 -0
- package/dist/components/image-crop-dialog.js.map +1 -0
- package/dist/components/lazy-mount.d.ts +10 -0
- package/dist/components/lazy-mount.js +22 -0
- package/dist/components/lazy-mount.js.map +1 -0
- package/dist/components/media-folder-editor.d.ts +59 -0
- package/dist/components/media-folder-editor.js +611 -0
- package/dist/components/media-folder-editor.js.map +1 -0
- package/dist/components/media-gallery.d.ts +54 -0
- package/dist/components/media-gallery.js +597 -0
- package/dist/components/media-gallery.js.map +1 -0
- package/dist/components/media-readiness-notice.d.ts +24 -0
- package/dist/components/media-readiness-notice.js +61 -0
- package/dist/components/media-readiness-notice.js.map +1 -0
- package/dist/components/player-controls.d.ts +71 -0
- package/dist/components/player-controls.js +264 -0
- package/dist/components/player-controls.js.map +1 -0
- package/dist/components/progress.d.ts +5 -0
- package/dist/components/progress.js +14 -0
- package/dist/components/progress.js.map +1 -0
- package/dist/components/rendition-img.d.ts +34 -0
- package/dist/components/rendition-img.js +78 -0
- package/dist/components/rendition-img.js.map +1 -0
- package/dist/components/slot-editor.d.ts +95 -0
- package/dist/components/slot-editor.js +182 -0
- package/dist/components/slot-editor.js.map +1 -0
- package/dist/components/slot-image.d.ts +23 -0
- package/dist/components/slot-image.js +48 -0
- package/dist/components/slot-image.js.map +1 -0
- package/dist/components/slot-upload.d.ts +41 -0
- package/dist/components/slot-upload.js +215 -0
- package/dist/components/slot-upload.js.map +1 -0
- package/dist/components/social/bans.d.ts +42 -0
- package/dist/components/social/bans.js +300 -0
- package/dist/components/social/bans.js.map +1 -0
- package/dist/components/social/comments.d.ts +42 -0
- package/dist/components/social/comments.js +517 -0
- package/dist/components/social/comments.js.map +1 -0
- package/dist/components/social/engagement.d.ts +45 -0
- package/dist/components/social/engagement.js +129 -0
- package/dist/components/social/engagement.js.map +1 -0
- package/dist/components/social/index.d.ts +6 -0
- package/dist/components/social/moderation.d.ts +32 -0
- package/dist/components/social/moderation.js +383 -0
- package/dist/components/social/moderation.js.map +1 -0
- package/dist/components/social/parts.d.ts +50 -0
- package/dist/components/social/parts.js +106 -0
- package/dist/components/social/parts.js.map +1 -0
- package/dist/components/social/poll-editor.d.ts +34 -0
- package/dist/components/social/poll-editor.js +567 -0
- package/dist/components/social/poll-editor.js.map +1 -0
- package/dist/components/social/poll.d.ts +30 -0
- package/dist/components/social/poll.js +252 -0
- package/dist/components/social/poll.js.map +1 -0
- package/dist/components/sortable-list.d.ts +29 -0
- package/dist/components/sortable-list.js +121 -0
- package/dist/components/sortable-list.js.map +1 -0
- package/dist/components/video-mini-player.d.ts +35 -0
- package/dist/components/video-mini-player.js +236 -0
- package/dist/components/video-mini-player.js.map +1 -0
- package/dist/components/video-player.d.ts +146 -0
- package/dist/components/video-player.js +630 -0
- package/dist/components/video-player.js.map +1 -0
- package/dist/components/video-poster-picker.d.ts +59 -0
- package/dist/components/video-poster-picker.js +335 -0
- package/dist/components/video-poster-picker.js.map +1 -0
- package/dist/components/video-poster.d.ts +24 -0
- package/dist/components/video-poster.js +46 -0
- package/dist/components/video-poster.js.map +1 -0
- package/dist/i18n/context.d.ts +4 -0
- package/dist/i18n/context.js +11 -0
- package/dist/i18n/context.js.map +1 -0
- package/dist/i18n/messages.d.ts +40 -0
- package/dist/i18n/messages.js +94 -0
- package/dist/i18n/messages.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +41 -0
- package/dist/locales/de.d.ts +2 -0
- package/dist/locales/de.js +271 -0
- package/dist/locales/de.js.map +1 -0
- package/dist/locales/en.d.ts +457 -0
- package/dist/locales/en.js +271 -0
- package/dist/locales/en.js.map +1 -0
- package/dist/locales/es.d.ts +2 -0
- package/dist/locales/es.js +271 -0
- package/dist/locales/es.js.map +1 -0
- package/dist/locales/ja.d.ts +2 -0
- package/dist/locales/ja.js +271 -0
- package/dist/locales/ja.js.map +1 -0
- package/dist/locales/ko.d.ts +2 -0
- package/dist/locales/ko.js +271 -0
- package/dist/locales/ko.js.map +1 -0
- package/dist/locales/social/de.d.ts +2 -0
- package/dist/locales/social/de.js +198 -0
- package/dist/locales/social/de.js.map +1 -0
- package/dist/locales/social/en.d.ts +195 -0
- package/dist/locales/social/en.js +198 -0
- package/dist/locales/social/en.js.map +1 -0
- package/dist/locales/social/es.d.ts +2 -0
- package/dist/locales/social/es.js +198 -0
- package/dist/locales/social/es.js.map +1 -0
- package/dist/locales/social/ja.d.ts +2 -0
- package/dist/locales/social/ja.js +198 -0
- package/dist/locales/social/ja.js.map +1 -0
- package/dist/locales/social/ko.d.ts +2 -0
- package/dist/locales/social/ko.js +198 -0
- package/dist/locales/social/ko.js.map +1 -0
- package/dist/locales/social/zh.d.ts +2 -0
- package/dist/locales/social/zh.js +198 -0
- package/dist/locales/social/zh.js.map +1 -0
- package/dist/locales/zh.d.ts +2 -0
- package/dist/locales/zh.js +271 -0
- package/dist/locales/zh.js.map +1 -0
- package/dist/provider.d.ts +22 -0
- package/dist/provider.js +59 -0
- package/dist/provider.js.map +1 -0
- package/dist/react/canonical.d.ts +33 -0
- package/dist/react/canonical.js +78 -0
- package/dist/react/canonical.js.map +1 -0
- package/dist/react/comments.d.ts +82 -0
- package/dist/react/comments.js +155 -0
- package/dist/react/comments.js.map +1 -0
- package/dist/react/config.d.ts +13 -0
- package/dist/react/config.js +14 -0
- package/dist/react/config.js.map +1 -0
- package/dist/react/context.d.ts +55 -0
- package/dist/react/context.js +42 -0
- package/dist/react/context.js.map +1 -0
- package/dist/react/crop.d.ts +49 -0
- package/dist/react/crop.js +107 -0
- package/dist/react/crop.js.map +1 -0
- package/dist/react/engagement.d.ts +38 -0
- package/dist/react/engagement.js +88 -0
- package/dist/react/engagement.js.map +1 -0
- package/dist/react/folder.d.ts +103 -0
- package/dist/react/folder.js +240 -0
- package/dist/react/folder.js.map +1 -0
- package/dist/react/gallery.d.ts +140 -0
- package/dist/react/gallery.js +477 -0
- package/dist/react/gallery.js.map +1 -0
- package/dist/react/index.d.ts +21 -0
- package/dist/react/inline-preview.d.ts +24 -0
- package/dist/react/inline-preview.js +76 -0
- package/dist/react/inline-preview.js.map +1 -0
- package/dist/react/player.d.ts +70 -0
- package/dist/react/player.js +214 -0
- package/dist/react/player.js.map +1 -0
- package/dist/react/polls.d.ts +74 -0
- package/dist/react/polls.js +176 -0
- package/dist/react/polls.js.map +1 -0
- package/dist/react/posts.d.ts +59 -0
- package/dist/react/posts.js +149 -0
- package/dist/react/posts.js.map +1 -0
- package/dist/react/provider.d.ts +27 -0
- package/dist/react/provider.js +49 -0
- package/dist/react/provider.js.map +1 -0
- package/dist/react/public.d.ts +39 -0
- package/dist/react/public.js +70 -0
- package/dist/react/public.js.map +1 -0
- package/dist/react/read.d.ts +52 -0
- package/dist/react/read.js +144 -0
- package/dist/react/read.js.map +1 -0
- package/dist/react/resources.d.ts +73 -0
- package/dist/react/resources.js +247 -0
- package/dist/react/resources.js.map +1 -0
- package/dist/react/slot.d.ts +104 -0
- package/dist/react/slot.js +185 -0
- package/dist/react/slot.js.map +1 -0
- package/dist/react/store.d.ts +51 -0
- package/dist/react/store.js +165 -0
- package/dist/react/store.js.map +1 -0
- package/dist/react/upload.d.ts +86 -0
- package/dist/react/upload.js +155 -0
- package/dist/react/upload.js.map +1 -0
- package/dist/react/use-resource.d.ts +44 -0
- package/dist/react/use-resource.js +74 -0
- package/dist/react/use-resource.js.map +1 -0
- package/dist/react/video.d.ts +118 -0
- package/dist/react/video.js +184 -0
- package/dist/react/video.js.map +1 -0
- package/dist/react/viewport.d.ts +19 -0
- package/dist/react/viewport.js +30 -0
- package/dist/react/viewport.js.map +1 -0
- package/dist/react.js +21 -0
- package/dist/scope.d.ts +14 -0
- package/dist/scope.js +30 -0
- package/dist/scope.js.map +1 -0
- package/dist/styles.css +3 -0
- package/dist/ui/alert-dialog.d.ts +18 -0
- package/dist/ui/alert-dialog.js +86 -0
- package/dist/ui/alert-dialog.js.map +1 -0
- package/dist/ui/alert.d.ts +10 -0
- package/dist/ui/alert.js +38 -0
- package/dist/ui/alert.js.map +1 -0
- package/dist/ui/avatar.d.ts +11 -0
- package/dist/ui/avatar.js +31 -0
- package/dist/ui/avatar.js.map +1 -0
- package/dist/ui/badge.d.ts +7 -0
- package/dist/ui/badge.js +31 -0
- package/dist/ui/badge.js.map +1 -0
- package/dist/ui/button.d.ts +8 -0
- package/dist/ui/button.js +46 -0
- package/dist/ui/button.js.map +1 -0
- package/dist/ui/dialog.d.ts +17 -0
- package/dist/ui/dialog.js +91 -0
- package/dist/ui/dialog.js.map +1 -0
- package/dist/ui/dropdown-menu.d.ts +15 -0
- package/dist/ui/dropdown-menu.js +105 -0
- package/dist/ui/dropdown-menu.js.map +1 -0
- package/dist/ui/input.d.ts +3 -0
- package/dist/ui/input.js +17 -0
- package/dist/ui/input.js.map +1 -0
- package/dist/ui/label.d.ts +3 -0
- package/dist/ui/label.js +15 -0
- package/dist/ui/label.js.map +1 -0
- package/dist/ui/progress.d.ts +7 -0
- package/dist/ui/progress.js +31 -0
- package/dist/ui/progress.js.map +1 -0
- package/dist/ui/select.d.ts +15 -0
- package/dist/ui/select.js +98 -0
- package/dist/ui/select.js.map +1 -0
- package/dist/ui/skeleton.d.ts +2 -0
- package/dist/ui/skeleton.js +14 -0
- package/dist/ui/skeleton.js.map +1 -0
- package/dist/ui/slider.d.ts +3 -0
- package/dist/ui/slider.js +35 -0
- package/dist/ui/slider.js.map +1 -0
- package/dist/ui/switch.d.ts +5 -0
- package/dist/ui/switch.js +20 -0
- package/dist/ui/switch.js.map +1 -0
- package/dist/ui/tabs.d.ts +10 -0
- package/dist/ui/tabs.js +47 -0
- package/dist/ui/tabs.js.map +1 -0
- package/dist/ui/textarea.d.ts +3 -0
- package/dist/ui/textarea.js +15 -0
- package/dist/ui/textarea.js.map +1 -0
- package/dist/ui/toggle-group.d.ts +5 -0
- package/dist/ui/toggle-group.js +23 -0
- package/dist/ui/toggle-group.js.map +1 -0
- package/dist/urls/index.d.ts +100 -0
- package/dist/urls.js +118 -0
- package/dist/urls.js.map +1 -0
- package/package.json +120 -3
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { ratio as e } from "../client/aspect.js";
|
|
2
|
+
import { presetFor as t } from "../client/media/rules.js";
|
|
3
|
+
import { useMessages as n } from "../i18n/context.js";
|
|
4
|
+
import { ContentKitUiRoot as r } from "../scope.js";
|
|
5
|
+
import { usePresets as i } from "../react/public.js";
|
|
6
|
+
import { Button as a } from "../ui/button.js";
|
|
7
|
+
import { SlotImage as o } from "./slot-image.js";
|
|
8
|
+
import { SlotEditError as s, SlotEditor as c, useSlotEditor as l } from "./slot-editor.js";
|
|
9
|
+
import { useState as u } from "react";
|
|
10
|
+
import { Fragment as d, jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
11
|
+
import { cn as m } from "cn";
|
|
12
|
+
import { Camera01Icon as h, CropIcon as g, Delete02Icon as _, ImageUpload01Icon as v, Loading03Icon as y } from "@hugeicons/core-free-icons";
|
|
13
|
+
import { HugeiconsIcon as b } from "@hugeicons/react";
|
|
14
|
+
//#region src/components/slot-upload.tsx
|
|
15
|
+
function x(e) {
|
|
16
|
+
return /* @__PURE__ */ f(C, {
|
|
17
|
+
...e,
|
|
18
|
+
variant: "avatar"
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function S(e) {
|
|
22
|
+
return /* @__PURE__ */ f(C, {
|
|
23
|
+
...e,
|
|
24
|
+
variant: "cover"
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
function C({ variant: e, ...n }) {
|
|
28
|
+
let a = n.path ?? e, { presets: o } = i({ client: n.client }), s = t(o, n.item.kind, a, n.image?.preset);
|
|
29
|
+
return /* @__PURE__ */ f(r, {
|
|
30
|
+
className: m("text-sm", n.className),
|
|
31
|
+
"data-ckui": e === "avatar" ? "avatar-upload" : "cover-upload",
|
|
32
|
+
children: /* @__PURE__ */ f(c, {
|
|
33
|
+
item: n.item,
|
|
34
|
+
path: a,
|
|
35
|
+
image: n.image,
|
|
36
|
+
client: n.client,
|
|
37
|
+
read: n.read,
|
|
38
|
+
onChange: n.onChange,
|
|
39
|
+
aspect: n.aspect || n.image?.aspect || s?.aspect || (e === "avatar" ? "1:1" : "3:1"),
|
|
40
|
+
minWidth: n.minWidth,
|
|
41
|
+
animation: n.animation,
|
|
42
|
+
targetWidth: n.targetWidth ?? (e === "avatar" ? 512 : 3e3),
|
|
43
|
+
round: e === "avatar",
|
|
44
|
+
accept: n.accept,
|
|
45
|
+
disabled: n.disabled,
|
|
46
|
+
removable: n.removable ?? e === "avatar",
|
|
47
|
+
decode: n.decode,
|
|
48
|
+
children: /* @__PURE__ */ f(w, {
|
|
49
|
+
...n,
|
|
50
|
+
variant: e
|
|
51
|
+
})
|
|
52
|
+
})
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function w({ variant: t, ...r }) {
|
|
56
|
+
let { t: i } = n(), c = l(), { crop: x, has: S, busy: C, disabled: w } = c, E = {
|
|
57
|
+
preset: r.image?.preset ?? t,
|
|
58
|
+
aspect: c.image.aspect,
|
|
59
|
+
renditions: c.image.renditions
|
|
60
|
+
}, [D, O] = u(!1), k = x.aspect, A = r.targetWidth ?? (t === "avatar" ? 512 : 3e3), j = (e) => {
|
|
61
|
+
e.preventDefault(), O(!1);
|
|
62
|
+
let t = [...e.dataTransfer.files].find((e) => e.type.startsWith("image/")) ?? e.dataTransfer.files[0];
|
|
63
|
+
t && c.pick(t);
|
|
64
|
+
}, M = r.hint ?? (t === "avatar" ? i("avatar.hint", { size: A }) : i("cover.hint", {
|
|
65
|
+
width: A,
|
|
66
|
+
height: Math.round(A / (e(k) ?? 3))
|
|
67
|
+
})), N = r.label ?? i(t === "avatar" ? "avatar.label" : "cover.label"), P = (e) => /* @__PURE__ */ p(d, { children: [
|
|
68
|
+
/* @__PURE__ */ p(a, {
|
|
69
|
+
variant: e && S ? "secondary" : "outline",
|
|
70
|
+
size: "sm",
|
|
71
|
+
disabled: w,
|
|
72
|
+
onClick: c.choose,
|
|
73
|
+
"data-ckui": "change",
|
|
74
|
+
children: [/* @__PURE__ */ f(b, {
|
|
75
|
+
icon: C ? y : h,
|
|
76
|
+
strokeWidth: 2,
|
|
77
|
+
"data-icon": "inline-start",
|
|
78
|
+
className: C ? "animate-spin" : void 0
|
|
79
|
+
}), i(S ? "common.change" : "common.upload")]
|
|
80
|
+
}),
|
|
81
|
+
S && x.canRecrop && /* @__PURE__ */ p(a, {
|
|
82
|
+
variant: e ? "secondary" : "ghost",
|
|
83
|
+
size: "sm",
|
|
84
|
+
disabled: w,
|
|
85
|
+
onClick: c.recrop,
|
|
86
|
+
"data-ckui": "edit-crop",
|
|
87
|
+
children: [/* @__PURE__ */ f(b, {
|
|
88
|
+
icon: g,
|
|
89
|
+
strokeWidth: 2,
|
|
90
|
+
"data-icon": "inline-start"
|
|
91
|
+
}), i("common.editCrop")]
|
|
92
|
+
}),
|
|
93
|
+
S && c.removable && /* @__PURE__ */ p(a, {
|
|
94
|
+
variant: e ? "secondary" : "ghost",
|
|
95
|
+
size: "sm",
|
|
96
|
+
disabled: w,
|
|
97
|
+
onClick: c.remove,
|
|
98
|
+
"data-ckui": "remove",
|
|
99
|
+
children: [/* @__PURE__ */ f(b, {
|
|
100
|
+
icon: _,
|
|
101
|
+
strokeWidth: 2,
|
|
102
|
+
"data-icon": "inline-start"
|
|
103
|
+
}), i("common.remove")]
|
|
104
|
+
})
|
|
105
|
+
] });
|
|
106
|
+
return t === "avatar" ? /* @__PURE__ */ p("div", {
|
|
107
|
+
className: "flex items-center gap-4",
|
|
108
|
+
children: [/* @__PURE__ */ p("div", {
|
|
109
|
+
className: "relative size-20 shrink-0",
|
|
110
|
+
children: [/* @__PURE__ */ f(o, {
|
|
111
|
+
image: S ? E : null,
|
|
112
|
+
round: !0,
|
|
113
|
+
emptyLabel: i("avatar.empty"),
|
|
114
|
+
className: "size-full ring-1 ring-foreground/10"
|
|
115
|
+
}), C && /* @__PURE__ */ f(T, {
|
|
116
|
+
round: !0,
|
|
117
|
+
label: i(x.status === "decoding" ? "progress.decoding" : "common.saving")
|
|
118
|
+
})]
|
|
119
|
+
}), /* @__PURE__ */ p("div", {
|
|
120
|
+
className: "grid min-w-0 gap-1",
|
|
121
|
+
children: [
|
|
122
|
+
/* @__PURE__ */ f("div", {
|
|
123
|
+
className: "font-medium",
|
|
124
|
+
children: N
|
|
125
|
+
}),
|
|
126
|
+
/* @__PURE__ */ f("div", {
|
|
127
|
+
className: "text-xs text-muted-foreground",
|
|
128
|
+
children: M
|
|
129
|
+
}),
|
|
130
|
+
/* @__PURE__ */ f("div", {
|
|
131
|
+
className: "mt-1.5 flex flex-wrap gap-2",
|
|
132
|
+
children: P(!1)
|
|
133
|
+
}),
|
|
134
|
+
/* @__PURE__ */ f(s, {})
|
|
135
|
+
]
|
|
136
|
+
})]
|
|
137
|
+
}) : /* @__PURE__ */ p("div", {
|
|
138
|
+
className: "grid gap-2",
|
|
139
|
+
children: [
|
|
140
|
+
/* @__PURE__ */ p("div", {
|
|
141
|
+
className: m("group/cover relative overflow-hidden rounded-xl ring-1 ring-foreground/10 transition-shadow", D && "ring-2 ring-ring"),
|
|
142
|
+
onDragOver: (e) => {
|
|
143
|
+
e.preventDefault(), w || O(!0);
|
|
144
|
+
},
|
|
145
|
+
onDragLeave: () => O(!1),
|
|
146
|
+
onDrop: j,
|
|
147
|
+
children: [
|
|
148
|
+
/* @__PURE__ */ f(o, {
|
|
149
|
+
image: S ? E : null,
|
|
150
|
+
aspect: k,
|
|
151
|
+
className: "w-full rounded-none",
|
|
152
|
+
fallback: /* @__PURE__ */ p("div", {
|
|
153
|
+
"aria-label": i("cover.empty"),
|
|
154
|
+
role: "group",
|
|
155
|
+
className: "absolute inset-0 flex flex-col items-center justify-center gap-1.5 bg-[repeating-linear-gradient(135deg,transparent_0_10px,color-mix(in_oklch,var(--ckui-foreground)_3%,transparent)_10px_20px)] p-4 text-center",
|
|
156
|
+
children: [
|
|
157
|
+
/* @__PURE__ */ f(b, {
|
|
158
|
+
icon: v,
|
|
159
|
+
strokeWidth: 1.5,
|
|
160
|
+
className: "size-7 text-muted-foreground"
|
|
161
|
+
}),
|
|
162
|
+
/* @__PURE__ */ f("span", {
|
|
163
|
+
className: "hidden text-xs text-muted-foreground sm:block",
|
|
164
|
+
children: i("cover.drop")
|
|
165
|
+
}),
|
|
166
|
+
/* @__PURE__ */ f("div", {
|
|
167
|
+
className: "mt-1 flex gap-2",
|
|
168
|
+
children: P(!1)
|
|
169
|
+
})
|
|
170
|
+
]
|
|
171
|
+
})
|
|
172
|
+
}),
|
|
173
|
+
C && /* @__PURE__ */ f(T, { label: i(x.status === "decoding" ? "progress.decoding" : "common.saving") }),
|
|
174
|
+
S && /* @__PURE__ */ f("div", {
|
|
175
|
+
className: "absolute right-2 bottom-2 flex gap-2 max-sm:hidden [&_button]:bg-background/80 [&_button]:backdrop-blur-sm",
|
|
176
|
+
children: P(!0)
|
|
177
|
+
})
|
|
178
|
+
]
|
|
179
|
+
}),
|
|
180
|
+
/* @__PURE__ */ p("div", {
|
|
181
|
+
className: "flex flex-wrap items-center justify-between gap-x-3 gap-y-1.5",
|
|
182
|
+
children: [/* @__PURE__ */ p("div", {
|
|
183
|
+
className: "grid min-w-0 gap-0.5 sm:flex sm:flex-1 sm:items-baseline sm:justify-between sm:gap-3",
|
|
184
|
+
children: [/* @__PURE__ */ f("div", {
|
|
185
|
+
className: "font-medium",
|
|
186
|
+
children: N
|
|
187
|
+
}), /* @__PURE__ */ f("div", {
|
|
188
|
+
className: "text-xs text-muted-foreground sm:truncate",
|
|
189
|
+
children: M
|
|
190
|
+
})]
|
|
191
|
+
}), S && /* @__PURE__ */ f("div", {
|
|
192
|
+
className: "flex gap-2 sm:hidden",
|
|
193
|
+
children: P(!1)
|
|
194
|
+
})]
|
|
195
|
+
}),
|
|
196
|
+
/* @__PURE__ */ f(s, {})
|
|
197
|
+
]
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
function T({ round: e, label: t }) {
|
|
201
|
+
return /* @__PURE__ */ f("div", {
|
|
202
|
+
role: "status",
|
|
203
|
+
"aria-label": t,
|
|
204
|
+
className: m("absolute inset-0 flex items-center justify-center bg-background/60 backdrop-blur-[1px]", e && "rounded-full"),
|
|
205
|
+
children: /* @__PURE__ */ f(b, {
|
|
206
|
+
icon: y,
|
|
207
|
+
strokeWidth: 2,
|
|
208
|
+
className: "size-5 animate-spin text-foreground"
|
|
209
|
+
})
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
//#endregion
|
|
213
|
+
export { x as AvatarUpload, S as CoverUpload };
|
|
214
|
+
|
|
215
|
+
//# sourceMappingURL=slot-upload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slot-upload.js","names":[],"sources":["../../src/components/slot-upload.tsx"],"sourcesContent":["import { ratio, type AspectRatio } from \"../client/aspect.js\";\nimport { Camera01Icon, CropIcon, Delete02Icon, ImageUpload01Icon, Loading03Icon } from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { cn } from \"cn\";\nimport { useState, type DragEvent, type ReactNode } from \"react\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport { useMessages } from \"../i18n/context.js\";\nimport type { CropSource } from \"../client/image.js\";\nimport { ContentKitUiRoot } from \"../scope.js\";\nimport type { PublicPreset } from \"../client/public.js\";\nimport type { FileInfo, ReadResult, RefBody } from \"../client/generated/wire.js\";\nimport { presetFor } from \"../client/media/rules.js\";\nimport { usePresets } from \"../react/public.js\";\nimport { Button } from \"#ckui/ui/button\";\nimport { SlotEditError, SlotEditor, useSlotEditor } from \"./slot-editor.js\";\nimport { SlotImage } from \"./slot-image.js\";\n\nexport interface SlotUploadProps {\n /** The item that owns the upload. */\n item: RefBody;\n /** The upload path; default \"avatar\" or \"cover\". */\n path?: string;\n /** The public preset showing it. */\n image?: PublicPreset | null;\n client?: ContentKitClient;\n /** An editor read of the item from the host; otherwise fetched. */\n read?: ReadResult | null;\n /** Called with the processed upload after every save, null after a removal. */\n onChange?: (file: FileInfo | null) => void;\n /** The output's \"W:H\"; default the preset's aspect, else \"1:1\" (avatar) or \"3:1\" (cover). */\n aspect?: AspectRatio;\n /** The narrowest edit the server accepts (the preset's Image.MinWidth). */\n minWidth?: number;\n /** \"reject\" refuses animated images before uploading. */\n animation?: \"reject\";\n /** Crops narrower than this many source pixels get a sharpness warning; default 512 (avatar) or 3000 (cover). */\n targetWidth?: number;\n /** `accept` of the file input. Default \"image/*\". */\n accept?: string;\n disabled?: boolean;\n /** Offers Remove once set; default true for avatars, false for covers. */\n removable?: boolean;\n label?: ReactNode;\n hint?: ReactNode;\n className?: string;\n /** Replaces decodeImage (tests). */\n decode?: (file: File) => Promise<CropSource>;\n}\n\ntype Variant = \"avatar\" | \"cover\";\n\n/** Round 1:1 avatar field: image, label, hint, Change / Edit crop, crop dialog, progress, errors. For custom layouts use SlotEditor. */\nexport function AvatarUpload(p: SlotUploadProps) {\n return <SlotUpload {...p} variant=\"avatar\" />;\n}\n\n/** Wide cover field at the preset's aspect (e.g. 3:1), with drop-to-upload. For custom layouts use SlotEditor. */\nexport function CoverUpload(p: SlotUploadProps) {\n return <SlotUpload {...p} variant=\"cover\" />;\n}\n\nfunction SlotUpload({ variant, ...p }: SlotUploadProps & { variant: Variant }) {\n const path = p.path ?? variant;\n const { presets } = usePresets({ client: p.client });\n const rule = presetFor(presets, p.item.kind, path, p.image?.preset);\n return (\n <ContentKitUiRoot className={cn(\"text-sm\", p.className)} data-ckui={variant === \"avatar\" ? \"avatar-upload\" : \"cover-upload\"}>\n <SlotEditor\n item={p.item}\n path={path}\n image={p.image}\n client={p.client}\n read={p.read}\n onChange={p.onChange}\n aspect={p.aspect || p.image?.aspect || rule?.aspect || (variant === \"avatar\" ? \"1:1\" : \"3:1\")}\n minWidth={p.minWidth}\n animation={p.animation}\n targetWidth={p.targetWidth ?? (variant === \"avatar\" ? 512 : 3000)}\n round={variant === \"avatar\"}\n accept={p.accept}\n disabled={p.disabled}\n removable={p.removable ?? variant === \"avatar\"}\n decode={p.decode}\n >\n <SlotUploadLayout {...p} variant={variant} />\n </SlotEditor>\n </ContentKitUiRoot>\n );\n}\n\nfunction SlotUploadLayout({ variant, ...p }: SlotUploadProps & { variant: Variant }) {\n const { t } = useMessages();\n const s = useSlotEditor();\n const { crop, has, busy, disabled } = s;\n const image = { preset: p.image?.preset ?? variant, aspect: s.image.aspect, renditions: s.image.renditions };\n const [dragging, setDragging] = useState(false);\n const aspect = crop.aspect;\n const target = p.targetWidth ?? (variant === \"avatar\" ? 512 : 3000);\n const onDrop = (e: DragEvent) => {\n e.preventDefault();\n setDragging(false);\n const f = [...e.dataTransfer.files].find((f) => f.type.startsWith(\"image/\")) ?? e.dataTransfer.files[0];\n if (f) s.pick(f);\n };\n\n const hint =\n p.hint ?? (variant === \"avatar\" ? t(\"avatar.hint\", { size: target }) : t(\"cover.hint\", { width: target, height: Math.round(target / (ratio(aspect) ?? 3)) }));\n const label = p.label ?? t(variant === \"avatar\" ? \"avatar.label\" : \"cover.label\");\n\n // overlay: buttons on top of the cover image; otherwise a plain row.\n const actions = (overlay: boolean) => (\n <>\n <Button variant={overlay && has ? \"secondary\" : \"outline\"} size=\"sm\" disabled={disabled} onClick={s.choose} data-ckui=\"change\">\n <HugeiconsIcon icon={busy ? Loading03Icon : Camera01Icon} strokeWidth={2} data-icon=\"inline-start\" className={busy ? \"animate-spin\" : undefined} />\n {has ? t(\"common.change\") : t(\"common.upload\")}\n </Button>\n {has && crop.canRecrop && (\n <Button variant={overlay ? \"secondary\" : \"ghost\"} size=\"sm\" disabled={disabled} onClick={s.recrop} data-ckui=\"edit-crop\">\n <HugeiconsIcon icon={CropIcon} strokeWidth={2} data-icon=\"inline-start\" />\n {t(\"common.editCrop\")}\n </Button>\n )}\n {has && s.removable && (\n <Button variant={overlay ? \"secondary\" : \"ghost\"} size=\"sm\" disabled={disabled} onClick={s.remove} data-ckui=\"remove\">\n <HugeiconsIcon icon={Delete02Icon} strokeWidth={2} data-icon=\"inline-start\" />\n {t(\"common.remove\")}\n </Button>\n )}\n </>\n );\n\n return variant === \"avatar\" ? (\n <div className=\"flex items-center gap-4\">\n <div className=\"relative size-20 shrink-0\">\n <SlotImage image={has ? image : null} round emptyLabel={t(\"avatar.empty\")} className=\"size-full ring-1 ring-foreground/10\" />\n {busy && <BusyOverlay round label={t(crop.status === \"decoding\" ? \"progress.decoding\" : \"common.saving\")} />}\n </div>\n <div className=\"grid min-w-0 gap-1\">\n <div className=\"font-medium\">{label}</div>\n <div className=\"text-xs text-muted-foreground\">{hint}</div>\n <div className=\"mt-1.5 flex flex-wrap gap-2\">{actions(false)}</div>\n <SlotEditError />\n </div>\n </div>\n ) : (\n <div className=\"grid gap-2\">\n <div\n className={cn(\n \"group/cover relative overflow-hidden rounded-xl ring-1 ring-foreground/10 transition-shadow\",\n dragging && \"ring-2 ring-ring\",\n )}\n onDragOver={(e) => {\n e.preventDefault();\n if (!disabled) setDragging(true);\n }}\n onDragLeave={() => setDragging(false)}\n onDrop={onDrop}\n >\n <SlotImage\n image={has ? image : null}\n aspect={aspect}\n className=\"w-full rounded-none\"\n fallback={\n <div aria-label={t(\"cover.empty\")} role=\"group\" className=\"absolute inset-0 flex flex-col items-center justify-center gap-1.5 bg-[repeating-linear-gradient(135deg,transparent_0_10px,color-mix(in_oklch,var(--ckui-foreground)_3%,transparent)_10px_20px)] p-4 text-center\">\n <HugeiconsIcon icon={ImageUpload01Icon} strokeWidth={1.5} className=\"size-7 text-muted-foreground\" />\n <span className=\"hidden text-xs text-muted-foreground sm:block\">{t(\"cover.drop\")}</span>\n <div className=\"mt-1 flex gap-2\">{actions(false)}</div>\n </div>\n }\n />\n {busy && <BusyOverlay label={t(crop.status === \"decoding\" ? \"progress.decoding\" : \"common.saving\")} />}\n {has && (\n <div className=\"absolute right-2 bottom-2 flex gap-2 max-sm:hidden [&_button]:bg-background/80 [&_button]:backdrop-blur-sm\">\n {actions(true)}\n </div>\n )}\n </div>\n <div className=\"flex flex-wrap items-center justify-between gap-x-3 gap-y-1.5\">\n <div className=\"grid min-w-0 gap-0.5 sm:flex sm:flex-1 sm:items-baseline sm:justify-between sm:gap-3\">\n <div className=\"font-medium\">{label}</div>\n <div className=\"text-xs text-muted-foreground sm:truncate\">{hint}</div>\n </div>\n {has && <div className=\"flex gap-2 sm:hidden\">{actions(false)}</div>}\n </div>\n <SlotEditError />\n </div>\n );\n}\n\nfunction BusyOverlay({ round, label }: { round?: boolean; label: string }) {\n return (\n <div role=\"status\" aria-label={label} className={cn(\"absolute inset-0 flex items-center justify-center bg-background/60 backdrop-blur-[1px]\", round && \"rounded-full\")}>\n <HugeiconsIcon icon={Loading03Icon} strokeWidth={2} className=\"size-5 animate-spin text-foreground\" />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ContentKitClient } from '../../client/client.js';
|
|
2
|
+
import { BanScope } from '../../client/content/types.js';
|
|
3
|
+
import { BanNotice as BanNoticeData, CommentBan, PublicUser } from '../../client/generated/wire.js';
|
|
4
|
+
import { ContentKitUiAppearance } from '../../appearance.js';
|
|
5
|
+
import { ContentKitErrorHandler } from '../../react/context.js';
|
|
6
|
+
/** What a banned user is told: where, why and until when (never who). */
|
|
7
|
+
export declare function BanNotice({ ban, className }: {
|
|
8
|
+
ban: BanNoticeData;
|
|
9
|
+
className?: string;
|
|
10
|
+
}): import('react').JSX.Element;
|
|
11
|
+
/** "YYYY-MM-DDTHH:mm" in local time, for a datetime-local input. */
|
|
12
|
+
export declare function localInput(d: Date): string;
|
|
13
|
+
export interface CommentBanDialogProps {
|
|
14
|
+
open: boolean;
|
|
15
|
+
onOpenChange: (open: boolean) => void;
|
|
16
|
+
/** Who to ban: their id and the name to show. */
|
|
17
|
+
user: {
|
|
18
|
+
id: string;
|
|
19
|
+
name?: string;
|
|
20
|
+
};
|
|
21
|
+
/** The scopes the caller may ban in (CommentStanding.ban_scopes); the first is preselected. */
|
|
22
|
+
scopes: readonly BanScope[];
|
|
23
|
+
/** The current ban, when updating one. */
|
|
24
|
+
ban?: CommentBan | null;
|
|
25
|
+
onSaved?: (ban: CommentBan) => void;
|
|
26
|
+
client?: ContentKitClient;
|
|
27
|
+
onError?: ContentKitErrorHandler;
|
|
28
|
+
}
|
|
29
|
+
/** Bans a user from commenting, or replaces their ban: scope, duration presets or an end date, and a reason they see. */
|
|
30
|
+
export declare function CommentBanDialog({ open, onOpenChange, user, scopes, ban, onSaved, client: own, onError }: CommentBanDialogProps): import('react').JSX.Element;
|
|
31
|
+
export interface CommentBansProps {
|
|
32
|
+
/** "global": the site's bans (CommentBan); "owner": the caller's own. Default "global". */
|
|
33
|
+
scope?: BanScope;
|
|
34
|
+
pageSize?: number;
|
|
35
|
+
userHref?: (user: PublicUser) => string | undefined;
|
|
36
|
+
client?: ContentKitClient;
|
|
37
|
+
onError?: ContentKitErrorHandler;
|
|
38
|
+
className?: string;
|
|
39
|
+
appearance?: ContentKitUiAppearance;
|
|
40
|
+
}
|
|
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;
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import { useMessages as e } from "../../i18n/context.js";
|
|
2
|
+
import { ContentKitUiRoot as t } from "../../scope.js";
|
|
3
|
+
import { useContentKitClient as n } from "../../react/context.js";
|
|
4
|
+
import { Alert as r, AlertDescription as i } from "../../ui/alert.js";
|
|
5
|
+
import { Button as a } from "../../ui/button.js";
|
|
6
|
+
import { Dialog as o, DialogContent as s, DialogDescription as c, DialogFooter as l, DialogHeader as u, DialogTitle as d } from "../../ui/dialog.js";
|
|
7
|
+
import { useCommentBans as f } from "../../react/comments.js";
|
|
8
|
+
import { Badge as p } from "../../ui/badge.js";
|
|
9
|
+
import { Input as m } from "../../ui/input.js";
|
|
10
|
+
import { Label as h } from "../../ui/label.js";
|
|
11
|
+
import { Textarea as g } from "../../ui/textarea.js";
|
|
12
|
+
import { ConfirmDialog as _, ErrorLine as v, UserAvatar as y, UserName as b, formatDate as x, useAction as S } from "./parts.js";
|
|
13
|
+
import { useEffect as C, useId as w, useState as T } from "react";
|
|
14
|
+
import { jsx as E, jsxs as D } from "react/jsx-runtime";
|
|
15
|
+
import { cn as O } from "cn";
|
|
16
|
+
//#region src/components/social/bans.tsx
|
|
17
|
+
function k({ ban: t, className: n }) {
|
|
18
|
+
let a = e(), { t: o } = a;
|
|
19
|
+
return /* @__PURE__ */ E(r, {
|
|
20
|
+
variant: "destructive",
|
|
21
|
+
className: n,
|
|
22
|
+
"data-ckui": "ban-notice",
|
|
23
|
+
children: /* @__PURE__ */ D(i, {
|
|
24
|
+
className: "grid gap-1",
|
|
25
|
+
children: [
|
|
26
|
+
/* @__PURE__ */ E("p", {
|
|
27
|
+
className: "font-medium",
|
|
28
|
+
children: o(t.scope === "global" ? "bans.globalNotice" : "bans.ownerNotice")
|
|
29
|
+
}),
|
|
30
|
+
t.reason && /* @__PURE__ */ E("p", { children: o("bans.reason", { reason: t.reason }) }),
|
|
31
|
+
/* @__PURE__ */ E("p", { children: t.until ? o("bans.until", { date: x(a, t.until) }) : o("bans.untilLifted") })
|
|
32
|
+
]
|
|
33
|
+
})
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
var A = 864e5, j = {
|
|
37
|
+
day: A,
|
|
38
|
+
week: 7 * A,
|
|
39
|
+
month: 30 * A,
|
|
40
|
+
forever: 0,
|
|
41
|
+
custom: 0
|
|
42
|
+
};
|
|
43
|
+
function M(e) {
|
|
44
|
+
let t = (e) => String(e).padStart(2, "0");
|
|
45
|
+
return `${e.getFullYear()}-${t(e.getMonth() + 1)}-${t(e.getDate())}T${t(e.getHours())}:${t(e.getMinutes())}`;
|
|
46
|
+
}
|
|
47
|
+
function N({ open: t, onOpenChange: r, user: i, scopes: f, ban: p, onSaved: _, client: y, onError: b }) {
|
|
48
|
+
let { t: x } = e(), O = n(y), k = w(), N = p ? p.scope === "global" ? "global" : "owner" : f[0] ?? "owner", [P, F] = T(N), [I, L] = T(p ? p.until ? "custom" : "forever" : "week"), [R, z] = T(p?.until ? M(new Date(p.until)) : M(new Date(Date.now() + 7 * A))), [B, V] = T(p?.reason ?? ""), { run: H, pending: U, error: W, setError: G } = S("ban.save", b);
|
|
49
|
+
C(() => {
|
|
50
|
+
t && (F(N), L(p ? p.until ? "custom" : "forever" : "week"), z(p?.until ? M(new Date(p.until)) : M(new Date(Date.now() + 7 * A))), V(p?.reason ?? ""), G(null));
|
|
51
|
+
}, [t]);
|
|
52
|
+
let K = i.name ?? i.id, q = async () => {
|
|
53
|
+
let e = I === "forever" ? void 0 : I === "custom" ? new Date(R) : new Date(Date.now() + j[I]), t = await H(() => O.bans.ban(P, i.id, {
|
|
54
|
+
reason: B.trim() || void 0,
|
|
55
|
+
until: e?.toISOString()
|
|
56
|
+
}));
|
|
57
|
+
t && (_?.(t), r(!1));
|
|
58
|
+
};
|
|
59
|
+
return /* @__PURE__ */ E(o, {
|
|
60
|
+
open: t,
|
|
61
|
+
onOpenChange: r,
|
|
62
|
+
children: /* @__PURE__ */ D(s, {
|
|
63
|
+
"data-ckui": "comment-ban-dialog",
|
|
64
|
+
children: [/* @__PURE__ */ D(u, { children: [/* @__PURE__ */ E(d, { children: x("bans.title", { name: K }) }), /* @__PURE__ */ E(c, { children: x(P === "global" ? "bans.globalHelp" : "bans.ownerHelp") })] }), /* @__PURE__ */ D("form", {
|
|
65
|
+
className: "grid gap-4",
|
|
66
|
+
onSubmit: (e) => {
|
|
67
|
+
e.preventDefault(), q();
|
|
68
|
+
},
|
|
69
|
+
children: [
|
|
70
|
+
f.length > 1 && !p && /* @__PURE__ */ D("fieldset", {
|
|
71
|
+
className: "grid gap-2",
|
|
72
|
+
children: [/* @__PURE__ */ E("legend", {
|
|
73
|
+
className: "mb-1 text-sm font-medium",
|
|
74
|
+
children: x("bans.scope")
|
|
75
|
+
}), /* @__PURE__ */ E("div", {
|
|
76
|
+
className: "flex flex-wrap gap-2",
|
|
77
|
+
children: f.map((e) => /* @__PURE__ */ E(a, {
|
|
78
|
+
type: "button",
|
|
79
|
+
size: "sm",
|
|
80
|
+
variant: P === e ? "default" : "outline",
|
|
81
|
+
"aria-pressed": P === e,
|
|
82
|
+
onClick: () => F(e),
|
|
83
|
+
children: x(e === "global" ? "bans.scopeGlobal" : "bans.scopeOwner")
|
|
84
|
+
}, e))
|
|
85
|
+
})]
|
|
86
|
+
}),
|
|
87
|
+
/* @__PURE__ */ D("fieldset", {
|
|
88
|
+
className: "grid gap-2",
|
|
89
|
+
children: [
|
|
90
|
+
/* @__PURE__ */ E("legend", {
|
|
91
|
+
className: "mb-1 text-sm font-medium",
|
|
92
|
+
children: x("bans.duration")
|
|
93
|
+
}),
|
|
94
|
+
/* @__PURE__ */ E("div", {
|
|
95
|
+
className: "flex flex-wrap gap-2",
|
|
96
|
+
children: [
|
|
97
|
+
"day",
|
|
98
|
+
"week",
|
|
99
|
+
"month",
|
|
100
|
+
"forever",
|
|
101
|
+
"custom"
|
|
102
|
+
].map((e) => /* @__PURE__ */ E(a, {
|
|
103
|
+
type: "button",
|
|
104
|
+
size: "sm",
|
|
105
|
+
variant: I === e ? "default" : "outline",
|
|
106
|
+
"aria-pressed": I === e,
|
|
107
|
+
onClick: () => L(e),
|
|
108
|
+
children: x(`bans.${e}`)
|
|
109
|
+
}, e))
|
|
110
|
+
}),
|
|
111
|
+
I === "custom" && /* @__PURE__ */ D("div", {
|
|
112
|
+
className: "grid gap-1.5",
|
|
113
|
+
children: [/* @__PURE__ */ E(h, {
|
|
114
|
+
htmlFor: `${k}-until`,
|
|
115
|
+
children: x("bans.endsAt")
|
|
116
|
+
}), /* @__PURE__ */ E(m, {
|
|
117
|
+
id: `${k}-until`,
|
|
118
|
+
type: "datetime-local",
|
|
119
|
+
required: !0,
|
|
120
|
+
value: R,
|
|
121
|
+
min: M(/* @__PURE__ */ new Date()),
|
|
122
|
+
onChange: (e) => z(e.target.value)
|
|
123
|
+
})]
|
|
124
|
+
})
|
|
125
|
+
]
|
|
126
|
+
}),
|
|
127
|
+
/* @__PURE__ */ D("div", {
|
|
128
|
+
className: "grid gap-1.5",
|
|
129
|
+
children: [/* @__PURE__ */ E(h, {
|
|
130
|
+
htmlFor: `${k}-reason`,
|
|
131
|
+
children: x("bans.reasonLabel")
|
|
132
|
+
}), /* @__PURE__ */ E(g, {
|
|
133
|
+
id: `${k}-reason`,
|
|
134
|
+
maxLength: 500,
|
|
135
|
+
rows: 3,
|
|
136
|
+
placeholder: x("bans.reasonPlaceholder"),
|
|
137
|
+
value: B,
|
|
138
|
+
onChange: (e) => V(e.target.value)
|
|
139
|
+
})]
|
|
140
|
+
}),
|
|
141
|
+
/* @__PURE__ */ E(v, { error: W }),
|
|
142
|
+
/* @__PURE__ */ D(l, { children: [/* @__PURE__ */ E(a, {
|
|
143
|
+
type: "button",
|
|
144
|
+
variant: "outline",
|
|
145
|
+
onClick: () => r(!1),
|
|
146
|
+
children: x("common.cancel")
|
|
147
|
+
}), /* @__PURE__ */ E(a, {
|
|
148
|
+
type: "submit",
|
|
149
|
+
variant: "destructive",
|
|
150
|
+
disabled: U,
|
|
151
|
+
children: x(U ? "common.saving" : p ? "bans.update" : "bans.save")
|
|
152
|
+
})] })
|
|
153
|
+
]
|
|
154
|
+
})]
|
|
155
|
+
})
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
function P({ scope: n = "global", pageSize: r = 25, userHref: i, client: o, onError: s, className: c, appearance: l }) {
|
|
159
|
+
let u = e(), { t: d } = u, g = f({
|
|
160
|
+
scope: n,
|
|
161
|
+
pageSize: r,
|
|
162
|
+
client: o
|
|
163
|
+
}), C = w(), [k, A] = T(null), [j, M] = T(null), [P, F] = T(""), I = S("ban.lift", s);
|
|
164
|
+
return /* @__PURE__ */ D(t, {
|
|
165
|
+
appearance: l,
|
|
166
|
+
className: O("grid gap-4 text-sm", c),
|
|
167
|
+
"data-ckui": "comment-bans",
|
|
168
|
+
children: [
|
|
169
|
+
/* @__PURE__ */ D("form", {
|
|
170
|
+
className: "flex flex-wrap items-end gap-2",
|
|
171
|
+
onSubmit: (e) => {
|
|
172
|
+
e.preventDefault(), P.trim() && A({ user: { id: P.trim() } });
|
|
173
|
+
},
|
|
174
|
+
children: [/* @__PURE__ */ D("div", {
|
|
175
|
+
className: "grid min-w-48 flex-1 gap-1.5",
|
|
176
|
+
children: [/* @__PURE__ */ E(h, {
|
|
177
|
+
htmlFor: `${C}-user`,
|
|
178
|
+
children: d("bans.user")
|
|
179
|
+
}), /* @__PURE__ */ E(m, {
|
|
180
|
+
id: `${C}-user`,
|
|
181
|
+
value: P,
|
|
182
|
+
placeholder: d("bans.userPlaceholder"),
|
|
183
|
+
onChange: (e) => F(e.target.value)
|
|
184
|
+
})]
|
|
185
|
+
}), /* @__PURE__ */ E(a, {
|
|
186
|
+
type: "submit",
|
|
187
|
+
variant: "outline",
|
|
188
|
+
disabled: !P.trim(),
|
|
189
|
+
children: d("bans.add")
|
|
190
|
+
})]
|
|
191
|
+
}),
|
|
192
|
+
/* @__PURE__ */ E(v, { error: I.error }),
|
|
193
|
+
g.error && !g.items.length ? /* @__PURE__ */ D("div", {
|
|
194
|
+
className: "grid justify-items-start gap-2",
|
|
195
|
+
children: [/* @__PURE__ */ E(v, { children: d("bans.loadFailed") }), /* @__PURE__ */ E(a, {
|
|
196
|
+
size: "sm",
|
|
197
|
+
variant: "outline",
|
|
198
|
+
onClick: g.reload,
|
|
199
|
+
children: d("common.retry")
|
|
200
|
+
})]
|
|
201
|
+
}) : !g.loading && !g.items.length ? /* @__PURE__ */ E("p", {
|
|
202
|
+
className: "text-muted-foreground",
|
|
203
|
+
children: d("bans.empty")
|
|
204
|
+
}) : /* @__PURE__ */ E("ul", {
|
|
205
|
+
className: "grid divide-y divide-border rounded-lg border border-border",
|
|
206
|
+
"aria-busy": g.loading,
|
|
207
|
+
children: g.items.map((e) => {
|
|
208
|
+
let t = e.user?.username ?? e.user_id;
|
|
209
|
+
return /* @__PURE__ */ D("li", {
|
|
210
|
+
className: "flex flex-wrap items-start gap-3 p-3",
|
|
211
|
+
"data-ckui": "comment-ban",
|
|
212
|
+
children: [
|
|
213
|
+
/* @__PURE__ */ E(y, {
|
|
214
|
+
user: e.user,
|
|
215
|
+
name: t
|
|
216
|
+
}),
|
|
217
|
+
/* @__PURE__ */ D("div", {
|
|
218
|
+
className: "grid min-w-0 flex-1 gap-0.5",
|
|
219
|
+
children: [
|
|
220
|
+
/* @__PURE__ */ D("div", {
|
|
221
|
+
className: "flex flex-wrap items-center gap-2",
|
|
222
|
+
children: [/* @__PURE__ */ E(b, {
|
|
223
|
+
user: e.user,
|
|
224
|
+
name: t,
|
|
225
|
+
href: i
|
|
226
|
+
}), /* @__PURE__ */ E(p, {
|
|
227
|
+
variant: e.expired ? "outline" : "destructive",
|
|
228
|
+
children: d(e.expired ? "bans.expired" : "bans.active")
|
|
229
|
+
})]
|
|
230
|
+
}),
|
|
231
|
+
e.reason && /* @__PURE__ */ E("p", {
|
|
232
|
+
className: "break-words",
|
|
233
|
+
children: d("bans.reason", { reason: e.reason })
|
|
234
|
+
}),
|
|
235
|
+
/* @__PURE__ */ D("p", {
|
|
236
|
+
className: "text-muted-foreground",
|
|
237
|
+
children: [
|
|
238
|
+
e.until ? d("bans.until", { date: x(u, e.until) }) : d("bans.untilLifted"),
|
|
239
|
+
" · ",
|
|
240
|
+
d("bans.bannedAt", { date: x(u, e.banned_at, !1) })
|
|
241
|
+
]
|
|
242
|
+
})
|
|
243
|
+
]
|
|
244
|
+
}),
|
|
245
|
+
/* @__PURE__ */ D("div", {
|
|
246
|
+
className: "flex gap-2",
|
|
247
|
+
children: [/* @__PURE__ */ E(a, {
|
|
248
|
+
size: "sm",
|
|
249
|
+
variant: "outline",
|
|
250
|
+
onClick: () => A({
|
|
251
|
+
user: {
|
|
252
|
+
id: e.user_id,
|
|
253
|
+
name: t
|
|
254
|
+
},
|
|
255
|
+
ban: e
|
|
256
|
+
}),
|
|
257
|
+
children: d("bans.update")
|
|
258
|
+
}), /* @__PURE__ */ E(a, {
|
|
259
|
+
size: "sm",
|
|
260
|
+
variant: "destructive",
|
|
261
|
+
onClick: () => M(e),
|
|
262
|
+
children: d("bans.lift")
|
|
263
|
+
})]
|
|
264
|
+
})
|
|
265
|
+
]
|
|
266
|
+
}, e.user_id);
|
|
267
|
+
})
|
|
268
|
+
}),
|
|
269
|
+
g.hasMore && /* @__PURE__ */ E(a, {
|
|
270
|
+
variant: "outline",
|
|
271
|
+
className: "justify-self-center",
|
|
272
|
+
disabled: g.loadingMore,
|
|
273
|
+
onClick: () => void g.loadMore(),
|
|
274
|
+
children: d("moderation.loadMore")
|
|
275
|
+
}),
|
|
276
|
+
k && /* @__PURE__ */ E(N, {
|
|
277
|
+
open: !0,
|
|
278
|
+
onOpenChange: (e) => !e && A(null),
|
|
279
|
+
user: k.user,
|
|
280
|
+
scopes: [n],
|
|
281
|
+
ban: k.ban,
|
|
282
|
+
client: o,
|
|
283
|
+
onError: s,
|
|
284
|
+
onSaved: () => F("")
|
|
285
|
+
}),
|
|
286
|
+
/* @__PURE__ */ E(_, {
|
|
287
|
+
open: !!j,
|
|
288
|
+
onOpenChange: (e) => !e && M(null),
|
|
289
|
+
title: d("bans.liftTitle", { name: j?.user?.username ?? j?.user_id ?? "" }),
|
|
290
|
+
description: d("bans.liftBody"),
|
|
291
|
+
confirm: d("bans.lift"),
|
|
292
|
+
onConfirm: () => j && void I.run(() => g.lift(j.user_id))
|
|
293
|
+
})
|
|
294
|
+
]
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
//#endregion
|
|
298
|
+
export { k as BanNotice, N as CommentBanDialog, P as CommentBans, M as localInput };
|
|
299
|
+
|
|
300
|
+
//# sourceMappingURL=bans.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bans.js","names":[],"sources":["../../../src/components/social/bans.tsx"],"sourcesContent":["import { cn } from \"cn\";\nimport { useEffect, useId, useState } from \"react\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport type { BanScope } from \"../../client/content/types.js\";\nimport type { BanNotice as BanNoticeData, CommentBan, PublicUser } from \"../../client/generated/wire.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport type { ContentKitUiAppearance } from \"../../appearance.js\";\nimport type { ContentKitErrorHandler } from \"../../react/context.js\";\nimport { useCommentBans } from \"../../react/comments.js\";\nimport { useContentKitClient } from \"../../react/context.js\";\nimport { ContentKitUiRoot } from \"../../scope.js\";\nimport { Alert, AlertDescription } from \"#ckui/ui/alert\";\nimport { Badge } from \"#ckui/ui/badge\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from \"#ckui/ui/dialog\";\nimport { Input } from \"#ckui/ui/input\";\nimport { Label } from \"#ckui/ui/label\";\nimport { Textarea } from \"#ckui/ui/textarea\";\nimport { ConfirmDialog, ErrorLine, formatDate, UserAvatar, UserName, useAction } from \"./parts.js\";\n\n/** What a banned user is told: where, why and until when (never who). */\nexport function BanNotice({ ban, className }: { ban: BanNoticeData; className?: string }) {\n const m = useMessages();\n const { t } = m;\n return (\n <Alert variant=\"destructive\" className={className} data-ckui=\"ban-notice\">\n <AlertDescription className=\"grid gap-1\">\n <p className=\"font-medium\">{t(ban.scope === \"global\" ? \"bans.globalNotice\" : \"bans.ownerNotice\")}</p>\n {ban.reason && <p>{t(\"bans.reason\", { reason: ban.reason })}</p>}\n <p>{ban.until ? t(\"bans.until\", { date: formatDate(m, ban.until) }) : t(\"bans.untilLifted\")}</p>\n </AlertDescription>\n </Alert>\n );\n}\n\nconst DAY = 86_400_000;\ntype Duration = \"day\" | \"week\" | \"month\" | \"forever\" | \"custom\";\nconst span: Record<Duration, number> = { day: DAY, week: 7 * DAY, month: 30 * DAY, forever: 0, custom: 0 };\n\n/** \"YYYY-MM-DDTHH:mm\" in local time, for a datetime-local input. */\nexport function localInput(d: Date): string {\n const p = (n: number) => String(n).padStart(2, \"0\");\n return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}T${p(d.getHours())}:${p(d.getMinutes())}`;\n}\n\nexport interface CommentBanDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n /** Who to ban: their id and the name to show. */\n user: { id: string; name?: string };\n /** The scopes the caller may ban in (CommentStanding.ban_scopes); the first is preselected. */\n scopes: readonly BanScope[];\n /** The current ban, when updating one. */\n ban?: CommentBan | null;\n onSaved?: (ban: CommentBan) => void;\n client?: ContentKitClient;\n onError?: ContentKitErrorHandler;\n}\n\n/** Bans a user from commenting, or replaces their ban: scope, duration presets or an end date, and a reason they see. */\nexport function CommentBanDialog({ open, onOpenChange, user, scopes, ban, onSaved, client: own, onError }: CommentBanDialogProps) {\n const m = useMessages();\n const { t } = m;\n const client = useContentKitClient(own);\n const ids = useId();\n const initialScope: BanScope = ban ? (ban.scope === \"global\" ? \"global\" : \"owner\") : (scopes[0] ?? \"owner\");\n const [scope, setScope] = useState<BanScope>(initialScope);\n const [duration, setDuration] = useState<Duration>(ban ? (ban.until ? \"custom\" : \"forever\") : \"week\");\n const [until, setUntil] = useState(ban?.until ? localInput(new Date(ban.until)) : localInput(new Date(Date.now() + 7 * DAY)));\n const [reason, setReason] = useState(ban?.reason ?? \"\");\n const { run, pending, error, setError } = useAction(\"ban.save\", onError);\n useEffect(() => {\n if (!open) return;\n setScope(initialScope);\n setDuration(ban ? (ban.until ? \"custom\" : \"forever\") : \"week\");\n setUntil(ban?.until ? localInput(new Date(ban.until)) : localInput(new Date(Date.now() + 7 * DAY)));\n setReason(ban?.reason ?? \"\");\n setError(null);\n // Reset when it opens.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open]);\n const name = user.name ?? user.id;\n const save = async () => {\n const end = duration === \"forever\" ? undefined : duration === \"custom\" ? new Date(until) : new Date(Date.now() + span[duration]);\n const saved = await run(() => client.bans.ban(scope, user.id, { reason: reason.trim() || undefined, until: end?.toISOString() }));\n if (saved) {\n onSaved?.(saved);\n onOpenChange(false);\n }\n };\n const durations: Duration[] = [\"day\", \"week\", \"month\", \"forever\", \"custom\"];\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent data-ckui=\"comment-ban-dialog\">\n <DialogHeader>\n <DialogTitle>{t(\"bans.title\", { name })}</DialogTitle>\n <DialogDescription>{t(scope === \"global\" ? \"bans.globalHelp\" : \"bans.ownerHelp\")}</DialogDescription>\n </DialogHeader>\n <form\n className=\"grid gap-4\"\n onSubmit={(e) => {\n e.preventDefault();\n void save();\n }}\n >\n {scopes.length > 1 && !ban && (\n <fieldset className=\"grid gap-2\">\n <legend className=\"mb-1 text-sm font-medium\">{t(\"bans.scope\")}</legend>\n <div className=\"flex flex-wrap gap-2\">\n {scopes.map((s) => (\n <Button key={s} type=\"button\" size=\"sm\" variant={scope === s ? \"default\" : \"outline\"} aria-pressed={scope === s} onClick={() => setScope(s)}>\n {t(s === \"global\" ? \"bans.scopeGlobal\" : \"bans.scopeOwner\")}\n </Button>\n ))}\n </div>\n </fieldset>\n )}\n <fieldset className=\"grid gap-2\">\n <legend className=\"mb-1 text-sm font-medium\">{t(\"bans.duration\")}</legend>\n <div className=\"flex flex-wrap gap-2\">\n {durations.map((d) => (\n <Button key={d} type=\"button\" size=\"sm\" variant={duration === d ? \"default\" : \"outline\"} aria-pressed={duration === d} onClick={() => setDuration(d)}>\n {t(`bans.${d}`)}\n </Button>\n ))}\n </div>\n {duration === \"custom\" && (\n <div className=\"grid gap-1.5\">\n <Label htmlFor={`${ids}-until`}>{t(\"bans.endsAt\")}</Label>\n <Input id={`${ids}-until`} type=\"datetime-local\" required value={until} min={localInput(new Date())} onChange={(e) => setUntil(e.target.value)} />\n </div>\n )}\n </fieldset>\n <div className=\"grid gap-1.5\">\n <Label htmlFor={`${ids}-reason`}>{t(\"bans.reasonLabel\")}</Label>\n <Textarea id={`${ids}-reason`} maxLength={500} rows={3} placeholder={t(\"bans.reasonPlaceholder\")} value={reason} onChange={(e) => setReason(e.target.value)} />\n </div>\n <ErrorLine error={error} />\n <DialogFooter>\n <Button type=\"button\" variant=\"outline\" onClick={() => onOpenChange(false)}>\n {t(\"common.cancel\")}\n </Button>\n <Button type=\"submit\" variant=\"destructive\" disabled={pending}>\n {pending ? t(\"common.saving\") : t(ban ? \"bans.update\" : \"bans.save\")}\n </Button>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n );\n}\n\nexport interface CommentBansProps {\n /** \"global\": the site's bans (CommentBan); \"owner\": the caller's own. Default \"global\". */\n scope?: BanScope;\n pageSize?: number;\n userHref?: (user: PublicUser) => string | undefined;\n client?: ContentKitClient;\n onError?: ContentKitErrorHandler;\n className?: string;\n appearance?: ContentKitUiAppearance;\n}\n\n/** A scope's comment bans, newest first: who, why, until when; ban a user by id, update or lift a ban. */\nexport function CommentBans({ scope = \"global\", pageSize = 25, userHref, client, onError, className, appearance }: CommentBansProps) {\n const m = useMessages();\n const { t } = m;\n const bans = useCommentBans({ scope, pageSize, client });\n const ids = useId();\n const [editing, setEditing] = useState<{ user: { id: string; name?: string }; ban?: CommentBan } | null>(null);\n const [lifting, setLifting] = useState<CommentBan | null>(null);\n const [userId, setUserId] = useState(\"\");\n const lift = useAction(\"ban.lift\", onError);\n return (\n <ContentKitUiRoot appearance={appearance} className={cn(\"grid gap-4 text-sm\", className)} data-ckui=\"comment-bans\">\n <form\n className=\"flex flex-wrap items-end gap-2\"\n onSubmit={(e) => {\n e.preventDefault();\n if (userId.trim()) setEditing({ user: { id: userId.trim() } });\n }}\n >\n <div className=\"grid min-w-48 flex-1 gap-1.5\">\n <Label htmlFor={`${ids}-user`}>{t(\"bans.user\")}</Label>\n <Input id={`${ids}-user`} value={userId} placeholder={t(\"bans.userPlaceholder\")} onChange={(e) => setUserId(e.target.value)} />\n </div>\n <Button type=\"submit\" variant=\"outline\" disabled={!userId.trim()}>\n {t(\"bans.add\")}\n </Button>\n </form>\n <ErrorLine error={lift.error} />\n {bans.error && !bans.items.length ? (\n <div className=\"grid justify-items-start gap-2\">\n <ErrorLine>{t(\"bans.loadFailed\")}</ErrorLine>\n <Button size=\"sm\" variant=\"outline\" onClick={bans.reload}>\n {t(\"common.retry\")}\n </Button>\n </div>\n ) : !bans.loading && !bans.items.length ? (\n <p className=\"text-muted-foreground\">{t(\"bans.empty\")}</p>\n ) : (\n <ul className=\"grid divide-y divide-border rounded-lg border border-border\" aria-busy={bans.loading}>\n {bans.items.map((b) => {\n const name = b.user?.username ?? b.user_id;\n return (\n <li key={b.user_id} className=\"flex flex-wrap items-start gap-3 p-3\" data-ckui=\"comment-ban\">\n <UserAvatar user={b.user} name={name} />\n <div className=\"grid min-w-0 flex-1 gap-0.5\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <UserName user={b.user} name={name} href={userHref} />\n <Badge variant={b.expired ? \"outline\" : \"destructive\"}>{t(b.expired ? \"bans.expired\" : \"bans.active\")}</Badge>\n </div>\n {b.reason && <p className=\"break-words\">{t(\"bans.reason\", { reason: b.reason })}</p>}\n <p className=\"text-muted-foreground\">\n {b.until ? t(\"bans.until\", { date: formatDate(m, b.until) }) : t(\"bans.untilLifted\")} · {t(\"bans.bannedAt\", { date: formatDate(m, b.banned_at, false) })}\n </p>\n </div>\n <div className=\"flex gap-2\">\n <Button size=\"sm\" variant=\"outline\" onClick={() => setEditing({ user: { id: b.user_id, name }, ban: b })}>\n {t(\"bans.update\")}\n </Button>\n <Button size=\"sm\" variant=\"destructive\" onClick={() => setLifting(b)}>\n {t(\"bans.lift\")}\n </Button>\n </div>\n </li>\n );\n })}\n </ul>\n )}\n {bans.hasMore && (\n <Button variant=\"outline\" className=\"justify-self-center\" disabled={bans.loadingMore} onClick={() => void bans.loadMore()}>\n {t(\"moderation.loadMore\")}\n </Button>\n )}\n {editing && (\n <CommentBanDialog\n open\n onOpenChange={(o) => !o && setEditing(null)}\n user={editing.user}\n scopes={[scope]}\n ban={editing.ban}\n client={client}\n onError={onError}\n onSaved={() => setUserId(\"\")}\n />\n )}\n <ConfirmDialog\n open={!!lifting}\n onOpenChange={(o) => !o && setLifting(null)}\n title={t(\"bans.liftTitle\", { name: lifting?.user?.username ?? lifting?.user_id ?? \"\" })}\n description={t(\"bans.liftBody\")}\n confirm={t(\"bans.lift\")}\n onConfirm={() => lifting && void lift.run(() => bans.lift(lifting.user_id))}\n />\n </ContentKitUiRoot>\n );\n}\n"],"mappings":"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"}
|