@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,42 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { ContentKitClient } from '../../client/client.js';
|
|
3
|
+
import { Sort } from '../../client/content/types.js';
|
|
4
|
+
import { Comment, PublicUser, RefBody } from '../../client/generated/wire.js';
|
|
5
|
+
import { ContentKitUiAppearance } from '../../appearance.js';
|
|
6
|
+
import { ContentKitErrorHandler } from '../../react/context.js';
|
|
7
|
+
export interface CommentsProps {
|
|
8
|
+
/** The commented item. */
|
|
9
|
+
item: RefBody;
|
|
10
|
+
/** The item's comment count, for the heading; without it the heading has none. */
|
|
11
|
+
count?: number;
|
|
12
|
+
/** Initial order: newest (default) or best (top). */
|
|
13
|
+
sort?: Sort;
|
|
14
|
+
/** Top-level comments per page. Default 20. */
|
|
15
|
+
pageSize?: number;
|
|
16
|
+
/** Replies per page. Default 10. */
|
|
17
|
+
repliesPageSize?: number;
|
|
18
|
+
/**
|
|
19
|
+
* Asks a signed-out visitor to sign in where the server takes no anonymous
|
|
20
|
+
* comments or reactions (default the provider's). Where it does, they
|
|
21
|
+
* comment under a name and react anonymously.
|
|
22
|
+
*/
|
|
23
|
+
onSignIn?: () => void;
|
|
24
|
+
/** A body as the host formats it (links, spoilers); default plain text. */
|
|
25
|
+
renderBody?: (body: string, comment: Comment) => ReactNode;
|
|
26
|
+
/** A profile URL for an author. */
|
|
27
|
+
userHref?: (user: PublicUser) => string | undefined;
|
|
28
|
+
/** The heading; false hides it. */
|
|
29
|
+
heading?: ReactNode | false;
|
|
30
|
+
client?: ContentKitClient;
|
|
31
|
+
onError?: ContentKitErrorHandler;
|
|
32
|
+
className?: string;
|
|
33
|
+
appearance?: ContentKitUiAppearance;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* An item's comment thread: top-level comments a page at a time with
|
|
37
|
+
* one-level replies, tombstones, held and rejected states shown to their
|
|
38
|
+
* author, reactions, edit, delete, ban and rate-limit notices, and a sign-in
|
|
39
|
+
* prompt. Moderators (as the server says) edit, delete and restore any
|
|
40
|
+
* comment; an item's owner and site staff ban commenters.
|
|
41
|
+
*/
|
|
42
|
+
export declare function Comments(p: CommentsProps): import('react').JSX.Element;
|
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
import { toContentKitError as e } from "../../client/errors.js";
|
|
2
|
+
import { useMessages as t } from "../../i18n/context.js";
|
|
3
|
+
import { ContentKitUiRoot as n } from "../../scope.js";
|
|
4
|
+
import { ContentKitContext as r, useErrorReporter as i } from "../../react/context.js";
|
|
5
|
+
import { Button as a } from "../../ui/button.js";
|
|
6
|
+
import { DropdownMenu as o, DropdownMenuContent as s, DropdownMenuItem as c, DropdownMenuTrigger as l } from "../../ui/dropdown-menu.js";
|
|
7
|
+
import { useCanComment as u, useCommentBans as d, useCommentReplies as f, useComments as p } from "../../react/comments.js";
|
|
8
|
+
import { useContentConfig as m } from "../../react/config.js";
|
|
9
|
+
import { Badge as h } from "../../ui/badge.js";
|
|
10
|
+
import { Input as g } from "../../ui/input.js";
|
|
11
|
+
import { Label as _ } from "../../ui/label.js";
|
|
12
|
+
import { Select as v, SelectContent as y, SelectItem as b, SelectTrigger as x, SelectValue as S } from "../../ui/select.js";
|
|
13
|
+
import { Skeleton as C } from "../../ui/skeleton.js";
|
|
14
|
+
import { Textarea as w } from "../../ui/textarea.js";
|
|
15
|
+
import { ConfirmDialog as T, ErrorLine as E, RelativeTime as D, UserAvatar as O, UserName as k, contentError as A } from "./parts.js";
|
|
16
|
+
import { BanNotice as j, CommentBanDialog as M } from "./bans.js";
|
|
17
|
+
import { createContext as N, useContext as P, useId as F, useMemo as I, useRef as L, useState as R } from "react";
|
|
18
|
+
import { Fragment as z, jsx as B, jsxs as V } from "react/jsx-runtime";
|
|
19
|
+
import { cn as ee } from "cn";
|
|
20
|
+
import { MoreHorizontalIcon as H, ThumbsDownIcon as U, ThumbsUpIcon as W } from "@hugeicons/core-free-icons";
|
|
21
|
+
import { HugeiconsIcon as G } from "@hugeicons/react";
|
|
22
|
+
//#region src/components/social/comments.tsx
|
|
23
|
+
var K = N(null), q = () => P(K), J = typeof navigator < "u" && /Mac|iP(hone|ad)/.test(navigator.platform), Y = 300, X = (e, t) => e.author?.username ?? e.anon_name ?? t;
|
|
24
|
+
function Z(e) {
|
|
25
|
+
let o = t(), { t: s } = o, c = P(r), [l, f] = R(e.sort ?? "newest"), h = p(e.item, {
|
|
26
|
+
sort: l,
|
|
27
|
+
pageSize: e.pageSize ?? 20,
|
|
28
|
+
client: e.client
|
|
29
|
+
}), { standing: g, reload: _ } = u(e.item, { client: e.client }), { config: C } = m({ client: e.client }), w = i(e.onError), E = e.onSignIn ?? c?.onSignIn, D = c?.viewer, O = g ? !!g.user_id : D ? !0 : D !== null && void 0, k = I(() => g?.ban_scopes ?? [], [g]), A = d({
|
|
30
|
+
scope: "owner",
|
|
31
|
+
pageSize: 100,
|
|
32
|
+
enabled: k.includes("owner"),
|
|
33
|
+
client: e.client
|
|
34
|
+
}), N = d({
|
|
35
|
+
scope: "global",
|
|
36
|
+
pageSize: 100,
|
|
37
|
+
enabled: k.includes("global"),
|
|
38
|
+
client: e.client
|
|
39
|
+
}), [F, L] = R(null), [z, H] = R(null), [U, W] = R(null), G = I(() => {
|
|
40
|
+
let e = /* @__PURE__ */ new Map(), t = (t, n) => {
|
|
41
|
+
for (let r of n) r.expired || e.set(r.user_id, [...e.get(r.user_id) ?? [], {
|
|
42
|
+
scope: t,
|
|
43
|
+
ban: r
|
|
44
|
+
}]);
|
|
45
|
+
};
|
|
46
|
+
return k.includes("owner") && t("owner", A.items), k.includes("global") && t("global", N.items), e;
|
|
47
|
+
}, [
|
|
48
|
+
k,
|
|
49
|
+
A.items,
|
|
50
|
+
N.items
|
|
51
|
+
]), q = (e) => O === !1 && (e === "comment" ? g?.anonymous === !1 : C?.anonymous.reactions === !1), J = {
|
|
52
|
+
item: e.item,
|
|
53
|
+
comments: h,
|
|
54
|
+
standing: g,
|
|
55
|
+
signedIn: O,
|
|
56
|
+
gate: (e, t) => q(e) ? E?.() : t(),
|
|
57
|
+
can: (e) => !q(e) || !!E,
|
|
58
|
+
maxLength: g?.max_length,
|
|
59
|
+
repliesPageSize: e.repliesPageSize ?? 10,
|
|
60
|
+
renderBody: e.renderBody,
|
|
61
|
+
userHref: e.userHref,
|
|
62
|
+
report: (e, t) => w(e, t),
|
|
63
|
+
banned: G,
|
|
64
|
+
openBan: (e, t) => L({
|
|
65
|
+
user: e,
|
|
66
|
+
ban: t
|
|
67
|
+
}),
|
|
68
|
+
liftBan: H,
|
|
69
|
+
onBanned: (e) => {
|
|
70
|
+
W(e), _();
|
|
71
|
+
}
|
|
72
|
+
}, Y = g?.ban ?? U, X = !g || g.can_comment, Z = e.heading === void 0 ? e.count === void 0 ? s("comments.title") : o.plural("comments.count", e.count) : e.heading;
|
|
73
|
+
return /* @__PURE__ */ B(K.Provider, {
|
|
74
|
+
value: J,
|
|
75
|
+
children: /* @__PURE__ */ V(n, {
|
|
76
|
+
appearance: e.appearance,
|
|
77
|
+
className: ee("grid gap-4 text-sm", e.className),
|
|
78
|
+
"data-ckui": "comments",
|
|
79
|
+
children: [
|
|
80
|
+
(Z !== !1 || h.items.length > 1) && /* @__PURE__ */ V("div", {
|
|
81
|
+
className: "flex flex-wrap items-center justify-between gap-2",
|
|
82
|
+
children: [Z !== !1 && /* @__PURE__ */ B("h2", {
|
|
83
|
+
className: "text-base font-semibold",
|
|
84
|
+
children: Z
|
|
85
|
+
}), /* @__PURE__ */ V(v, {
|
|
86
|
+
value: l,
|
|
87
|
+
onValueChange: (e) => f(e),
|
|
88
|
+
children: [/* @__PURE__ */ B(x, {
|
|
89
|
+
size: "sm",
|
|
90
|
+
"aria-label": s("comments.sort"),
|
|
91
|
+
className: "ms-auto",
|
|
92
|
+
children: /* @__PURE__ */ B(S, { children: (e) => s(e === "best" ? "comments.best" : "comments.newest") })
|
|
93
|
+
}), /* @__PURE__ */ V(y, { children: [/* @__PURE__ */ B(b, {
|
|
94
|
+
value: "newest",
|
|
95
|
+
children: s("comments.newest")
|
|
96
|
+
}), /* @__PURE__ */ B(b, {
|
|
97
|
+
value: "best",
|
|
98
|
+
children: s("comments.best")
|
|
99
|
+
})] })]
|
|
100
|
+
})]
|
|
101
|
+
}),
|
|
102
|
+
Y ? /* @__PURE__ */ B(j, { ban: Y }) : q("comment") ? E ? /* @__PURE__ */ B(a, {
|
|
103
|
+
variant: "outline",
|
|
104
|
+
className: "justify-self-start",
|
|
105
|
+
onClick: E,
|
|
106
|
+
children: s("comments.signIn")
|
|
107
|
+
}) : /* @__PURE__ */ B("p", {
|
|
108
|
+
className: "rounded-lg border border-border p-3 text-muted-foreground",
|
|
109
|
+
children: s("comments.signIn")
|
|
110
|
+
}) : X ? /* @__PURE__ */ B($, {
|
|
111
|
+
placeholder: s("comments.placeholder"),
|
|
112
|
+
submit: s("comments.post"),
|
|
113
|
+
askName: O === !1,
|
|
114
|
+
onSubmit: async (e, t) => (await h.post(e, { anonName: t }), !0),
|
|
115
|
+
operation: "comment.post"
|
|
116
|
+
}) : /* @__PURE__ */ B("p", {
|
|
117
|
+
className: "rounded-lg border border-border p-3 text-muted-foreground",
|
|
118
|
+
children: s("comments.locked")
|
|
119
|
+
}),
|
|
120
|
+
/* @__PURE__ */ B(te, {}),
|
|
121
|
+
F && /* @__PURE__ */ B(M, {
|
|
122
|
+
open: !0,
|
|
123
|
+
onOpenChange: (e) => !e && L(null),
|
|
124
|
+
user: F.user,
|
|
125
|
+
scopes: F.ban ? [F.ban.scope === "global" ? "global" : "owner"] : k,
|
|
126
|
+
ban: F.ban,
|
|
127
|
+
client: e.client,
|
|
128
|
+
onError: e.onError
|
|
129
|
+
}),
|
|
130
|
+
/* @__PURE__ */ B(T, {
|
|
131
|
+
open: !!z,
|
|
132
|
+
onOpenChange: (e) => !e && H(null),
|
|
133
|
+
title: s("bans.liftTitle", { name: z?.name ?? "" }),
|
|
134
|
+
description: s("bans.liftBody"),
|
|
135
|
+
confirm: s("bans.lift"),
|
|
136
|
+
onConfirm: () => {
|
|
137
|
+
if (z) for (let e of G.get(z.id) ?? []) (e.scope === "global" ? N : A).lift(z.id).catch((e) => w(e, "ban.lift"));
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
]
|
|
141
|
+
})
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
function te() {
|
|
145
|
+
let { t: e } = t(), { comments: n } = q();
|
|
146
|
+
return n.loading && !n.items.length ? /* @__PURE__ */ B("div", {
|
|
147
|
+
className: "grid gap-4",
|
|
148
|
+
"aria-busy": !0,
|
|
149
|
+
"aria-label": e("comments.loading"),
|
|
150
|
+
children: [
|
|
151
|
+
0,
|
|
152
|
+
1,
|
|
153
|
+
2
|
|
154
|
+
].map((e) => /* @__PURE__ */ V("div", {
|
|
155
|
+
className: "flex gap-3",
|
|
156
|
+
children: [/* @__PURE__ */ B(C, { className: "size-8 rounded-full" }), /* @__PURE__ */ V("div", {
|
|
157
|
+
className: "grid flex-1 gap-2",
|
|
158
|
+
children: [/* @__PURE__ */ B(C, { className: "h-3 w-32" }), /* @__PURE__ */ B(C, { className: "h-3 w-full" })]
|
|
159
|
+
})]
|
|
160
|
+
}, e))
|
|
161
|
+
}) : n.error && !n.items.length ? /* @__PURE__ */ V("div", {
|
|
162
|
+
className: "grid justify-items-start gap-2",
|
|
163
|
+
"data-ckui": "comments-error",
|
|
164
|
+
children: [/* @__PURE__ */ B(E, { children: e("comments.loadFailed") }), /* @__PURE__ */ B(a, {
|
|
165
|
+
size: "sm",
|
|
166
|
+
variant: "outline",
|
|
167
|
+
onClick: n.reload,
|
|
168
|
+
children: e("common.retry")
|
|
169
|
+
})]
|
|
170
|
+
}) : n.items.length ? /* @__PURE__ */ V(z, { children: [
|
|
171
|
+
/* @__PURE__ */ B("ul", {
|
|
172
|
+
className: "grid divide-y divide-border",
|
|
173
|
+
children: n.items.map((e) => /* @__PURE__ */ B("li", {
|
|
174
|
+
className: "py-3 first:pt-0",
|
|
175
|
+
children: /* @__PURE__ */ B(ne, { comment: e })
|
|
176
|
+
}, e.id))
|
|
177
|
+
}),
|
|
178
|
+
n.error && /* @__PURE__ */ B(E, { error: n.error }),
|
|
179
|
+
n.hasMore && /* @__PURE__ */ B(a, {
|
|
180
|
+
variant: "outline",
|
|
181
|
+
className: "justify-self-center",
|
|
182
|
+
disabled: n.loadingMore,
|
|
183
|
+
onClick: () => void n.loadMore(),
|
|
184
|
+
children: n.loadingMore ? e("comments.loading") : e("comments.loadMore")
|
|
185
|
+
})
|
|
186
|
+
] }) : /* @__PURE__ */ B("p", {
|
|
187
|
+
className: "text-muted-foreground",
|
|
188
|
+
children: e("comments.empty")
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
function ne({ comment: e }) {
|
|
192
|
+
let { t: n, plural: r } = t(), i = q(), [o, s] = R(!1), [c, l] = R(null), u = f(e.id, {
|
|
193
|
+
pageSize: i.repliesPageSize,
|
|
194
|
+
enabled: o
|
|
195
|
+
}), d = (t) => i.gate("comment", () => {
|
|
196
|
+
l(t), e.reply_count > 0 && s(!0);
|
|
197
|
+
});
|
|
198
|
+
return /* @__PURE__ */ V("div", {
|
|
199
|
+
className: "grid gap-2",
|
|
200
|
+
children: [
|
|
201
|
+
/* @__PURE__ */ B(Q, {
|
|
202
|
+
comment: e,
|
|
203
|
+
onReply: e.deleted || e.moderation || !i.can("comment") ? void 0 : d
|
|
204
|
+
}),
|
|
205
|
+
(e.reply_count > 0 || o && u.items.length > 0) && /* @__PURE__ */ B(a, {
|
|
206
|
+
variant: "link",
|
|
207
|
+
size: "xs",
|
|
208
|
+
className: "ms-11 justify-self-start px-0",
|
|
209
|
+
"aria-expanded": o,
|
|
210
|
+
onClick: () => s(!o),
|
|
211
|
+
children: o ? n("comments.hideReplies") : r("comments.showReplies", e.reply_count)
|
|
212
|
+
}),
|
|
213
|
+
o && /* @__PURE__ */ V("ul", {
|
|
214
|
+
className: "ms-11 grid gap-3 border-s border-border ps-3",
|
|
215
|
+
"aria-busy": u.loading,
|
|
216
|
+
children: [
|
|
217
|
+
u.loading && !u.items.length && /* @__PURE__ */ B("li", {
|
|
218
|
+
className: "text-muted-foreground",
|
|
219
|
+
children: n("comments.loadingReplies")
|
|
220
|
+
}),
|
|
221
|
+
u.items.map((e) => /* @__PURE__ */ B("li", { children: /* @__PURE__ */ B(Q, {
|
|
222
|
+
comment: e,
|
|
223
|
+
onReply: e.deleted || e.moderation || !i.can("comment") ? void 0 : d
|
|
224
|
+
}) }, e.id)),
|
|
225
|
+
u.error && /* @__PURE__ */ B("li", { children: /* @__PURE__ */ B(E, { error: u.error }) }),
|
|
226
|
+
u.hasMore && /* @__PURE__ */ B("li", { children: /* @__PURE__ */ B(a, {
|
|
227
|
+
variant: "link",
|
|
228
|
+
size: "xs",
|
|
229
|
+
className: "px-0",
|
|
230
|
+
disabled: u.loadingMore,
|
|
231
|
+
onClick: () => void u.loadMore(),
|
|
232
|
+
children: n("comments.moreReplies")
|
|
233
|
+
}) })
|
|
234
|
+
]
|
|
235
|
+
}),
|
|
236
|
+
c !== null && /* @__PURE__ */ V("div", {
|
|
237
|
+
className: "ms-11 grid gap-1",
|
|
238
|
+
children: [/* @__PURE__ */ B("p", {
|
|
239
|
+
className: "text-xs text-muted-foreground",
|
|
240
|
+
children: n("comments.replyingTo", { name: c })
|
|
241
|
+
}), /* @__PURE__ */ B($, {
|
|
242
|
+
autoFocus: !0,
|
|
243
|
+
placeholder: n("comments.replyPlaceholder"),
|
|
244
|
+
submit: n("comments.reply"),
|
|
245
|
+
askName: i.signedIn === !1,
|
|
246
|
+
onCancel: () => l(null),
|
|
247
|
+
operation: "comment.post",
|
|
248
|
+
onSubmit: async (t, n) => (await i.comments.post(t, {
|
|
249
|
+
replyTo: e.id,
|
|
250
|
+
anonName: n
|
|
251
|
+
}), l(null), s(!0), !0)
|
|
252
|
+
})]
|
|
253
|
+
})
|
|
254
|
+
]
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
function Q({ comment: n, onReply: r }) {
|
|
258
|
+
let { t: i } = t(), u = q(), { standing: d } = u, f = X(n, i("comments.anonymous")), p = !!d?.user_id && n.user_id === d.user_id, m = !n.deleted && (p || !!d?.moderate), g = !n.deleted && !!n.user_id && !p && (d?.ban_scopes.length ?? 0) > 0, _ = n.user_id ? u.banned.get(n.user_id) : void 0, [v, y] = R(!1), [b, x] = R(!1), [S, C] = R(!1), [w, A] = R(null), j = async (t, n) => {
|
|
259
|
+
A(null);
|
|
260
|
+
try {
|
|
261
|
+
await n();
|
|
262
|
+
} catch (n) {
|
|
263
|
+
let r = e(n);
|
|
264
|
+
A(r), u.report(r, t);
|
|
265
|
+
}
|
|
266
|
+
}, M = (e) => u.gate("react", () => void j("comment.react", () => u.comments.react(n, n.mine === e ? 0 : e))), N = !u.renderBody && n.body.length > 340, P = N && !S ? n.body.slice(0, Y).trimEnd() + "…" : n.body;
|
|
267
|
+
return /* @__PURE__ */ V("article", {
|
|
268
|
+
className: "flex gap-3",
|
|
269
|
+
"data-ckui": "comment",
|
|
270
|
+
"data-comment": n.id,
|
|
271
|
+
"aria-label": f,
|
|
272
|
+
children: [
|
|
273
|
+
/* @__PURE__ */ B(O, {
|
|
274
|
+
user: n.deleted ? void 0 : n.author,
|
|
275
|
+
name: n.deleted ? "?" : f
|
|
276
|
+
}),
|
|
277
|
+
/* @__PURE__ */ V("div", {
|
|
278
|
+
className: "grid min-w-0 flex-1 gap-1",
|
|
279
|
+
children: [
|
|
280
|
+
/* @__PURE__ */ V("header", {
|
|
281
|
+
className: "flex flex-wrap items-center gap-x-2 gap-y-0.5",
|
|
282
|
+
children: [
|
|
283
|
+
n.deleted ? /* @__PURE__ */ B("span", {
|
|
284
|
+
className: "text-muted-foreground",
|
|
285
|
+
children: i("comments.anonymous")
|
|
286
|
+
}) : /* @__PURE__ */ B(k, {
|
|
287
|
+
user: n.author,
|
|
288
|
+
name: f,
|
|
289
|
+
href: u.userHref
|
|
290
|
+
}),
|
|
291
|
+
/* @__PURE__ */ B(D, {
|
|
292
|
+
at: n.created_at,
|
|
293
|
+
className: "text-xs text-muted-foreground"
|
|
294
|
+
}),
|
|
295
|
+
n.moderation === "held" && /* @__PURE__ */ B(h, {
|
|
296
|
+
variant: "secondary",
|
|
297
|
+
children: i("comments.heldBadge")
|
|
298
|
+
}),
|
|
299
|
+
n.moderation === "rejected" && /* @__PURE__ */ B(h, {
|
|
300
|
+
variant: "destructive",
|
|
301
|
+
children: i("comments.rejectedBadge")
|
|
302
|
+
}),
|
|
303
|
+
(m || g || n.deleted && d?.moderate) && /* @__PURE__ */ V(o, { children: [/* @__PURE__ */ B(l, {
|
|
304
|
+
render: /* @__PURE__ */ B(a, {
|
|
305
|
+
variant: "ghost",
|
|
306
|
+
size: "icon-xs",
|
|
307
|
+
className: "ms-auto",
|
|
308
|
+
"aria-label": i("comments.actions")
|
|
309
|
+
}),
|
|
310
|
+
children: /* @__PURE__ */ B(G, {
|
|
311
|
+
icon: H,
|
|
312
|
+
strokeWidth: 2
|
|
313
|
+
})
|
|
314
|
+
}), /* @__PURE__ */ V(s, {
|
|
315
|
+
align: "end",
|
|
316
|
+
children: [
|
|
317
|
+
m && /* @__PURE__ */ B(c, {
|
|
318
|
+
onClick: () => y(!0),
|
|
319
|
+
children: i("comments.edit")
|
|
320
|
+
}),
|
|
321
|
+
m && /* @__PURE__ */ B(c, {
|
|
322
|
+
className: "text-destructive",
|
|
323
|
+
onClick: () => x(!0),
|
|
324
|
+
children: i("comments.delete")
|
|
325
|
+
}),
|
|
326
|
+
n.deleted && d?.moderate && /* @__PURE__ */ B(c, {
|
|
327
|
+
onClick: () => void j("comment.restore", () => u.comments.restore(n.id)),
|
|
328
|
+
children: i("comments.restore")
|
|
329
|
+
}),
|
|
330
|
+
g && !_ && /* @__PURE__ */ B(c, {
|
|
331
|
+
onClick: () => u.openBan({
|
|
332
|
+
id: n.user_id,
|
|
333
|
+
name: f
|
|
334
|
+
}),
|
|
335
|
+
children: i("comments.ban")
|
|
336
|
+
}),
|
|
337
|
+
g && _ && /* @__PURE__ */ B(c, {
|
|
338
|
+
onClick: () => u.liftBan({
|
|
339
|
+
id: n.user_id,
|
|
340
|
+
name: f
|
|
341
|
+
}),
|
|
342
|
+
children: i("comments.unban")
|
|
343
|
+
})
|
|
344
|
+
]
|
|
345
|
+
})] })
|
|
346
|
+
]
|
|
347
|
+
}),
|
|
348
|
+
v ? /* @__PURE__ */ B($, {
|
|
349
|
+
autoFocus: !0,
|
|
350
|
+
initial: n.body,
|
|
351
|
+
submit: i("common.save"),
|
|
352
|
+
onCancel: () => y(!1),
|
|
353
|
+
operation: "comment.edit",
|
|
354
|
+
onSubmit: async (e) => (e !== n.body && await u.comments.edit(n.id, e), y(!1), !0)
|
|
355
|
+
}) : n.deleted ? /* @__PURE__ */ B("p", {
|
|
356
|
+
className: "text-muted-foreground italic",
|
|
357
|
+
children: i("comments.deleted")
|
|
358
|
+
}) : /* @__PURE__ */ V("div", {
|
|
359
|
+
className: "break-words whitespace-pre-wrap",
|
|
360
|
+
children: [u.renderBody ? u.renderBody(n.body, n) : P, N && /* @__PURE__ */ B(a, {
|
|
361
|
+
variant: "link",
|
|
362
|
+
size: "xs",
|
|
363
|
+
className: "ms-1 h-auto px-0",
|
|
364
|
+
onClick: () => C(!S),
|
|
365
|
+
children: i(S ? "comments.showLess" : "comments.showMore")
|
|
366
|
+
})]
|
|
367
|
+
}),
|
|
368
|
+
n.moderation === "held" && /* @__PURE__ */ B("p", {
|
|
369
|
+
className: "text-xs text-muted-foreground",
|
|
370
|
+
children: i("comments.held")
|
|
371
|
+
}),
|
|
372
|
+
n.moderation === "rejected" && /* @__PURE__ */ B("p", {
|
|
373
|
+
className: "text-xs text-destructive",
|
|
374
|
+
children: n.moderation_reason ? i("comments.rejected", { reason: n.moderation_reason }) : i("comments.rejectedNoReason")
|
|
375
|
+
}),
|
|
376
|
+
!n.deleted && !n.moderation && !v && /* @__PURE__ */ V("div", {
|
|
377
|
+
className: "-ms-2 flex flex-wrap items-center gap-1",
|
|
378
|
+
children: [
|
|
379
|
+
/* @__PURE__ */ V(a, {
|
|
380
|
+
variant: n.mine === 1 ? "secondary" : "ghost",
|
|
381
|
+
size: "xs",
|
|
382
|
+
"aria-pressed": n.mine === 1,
|
|
383
|
+
"aria-label": i("comments.like"),
|
|
384
|
+
disabled: !u.can("react"),
|
|
385
|
+
onClick: () => M(1),
|
|
386
|
+
children: [/* @__PURE__ */ B(G, {
|
|
387
|
+
icon: W,
|
|
388
|
+
strokeWidth: 2
|
|
389
|
+
}), /* @__PURE__ */ B("span", { children: n.likes })]
|
|
390
|
+
}),
|
|
391
|
+
/* @__PURE__ */ V(a, {
|
|
392
|
+
variant: n.mine === -1 ? "secondary" : "ghost",
|
|
393
|
+
size: "xs",
|
|
394
|
+
"aria-pressed": n.mine === -1,
|
|
395
|
+
"aria-label": i("comments.dislike"),
|
|
396
|
+
disabled: !u.can("react"),
|
|
397
|
+
onClick: () => M(-1),
|
|
398
|
+
children: [/* @__PURE__ */ B(G, {
|
|
399
|
+
icon: U,
|
|
400
|
+
strokeWidth: 2
|
|
401
|
+
}), /* @__PURE__ */ B("span", { children: n.dislikes })]
|
|
402
|
+
}),
|
|
403
|
+
r && /* @__PURE__ */ B(a, {
|
|
404
|
+
variant: "ghost",
|
|
405
|
+
size: "xs",
|
|
406
|
+
onClick: () => r(f),
|
|
407
|
+
children: i("comments.reply")
|
|
408
|
+
})
|
|
409
|
+
]
|
|
410
|
+
}),
|
|
411
|
+
/* @__PURE__ */ B(E, { error: w })
|
|
412
|
+
]
|
|
413
|
+
}),
|
|
414
|
+
/* @__PURE__ */ B(T, {
|
|
415
|
+
open: b,
|
|
416
|
+
onOpenChange: x,
|
|
417
|
+
title: i("comments.deleteTitle"),
|
|
418
|
+
description: i("comments.deleteBody"),
|
|
419
|
+
confirm: i("comments.delete"),
|
|
420
|
+
onConfirm: () => void j("comment.delete", () => u.comments.remove(n.id))
|
|
421
|
+
})
|
|
422
|
+
]
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
function $(n) {
|
|
426
|
+
let r = t(), { t: i } = r, o = q(), s = F(), [c, l] = R(n.initial ?? ""), [u, d] = R(""), [f, p] = R(!1), [m, h] = R(null), [v, y] = R(null), b = L(null), x = o.maxLength, S = x === void 0 ? void 0 : x - c.length, C = async () => {
|
|
427
|
+
let t = c.trim();
|
|
428
|
+
if (!t) return h(i("comments.required"));
|
|
429
|
+
if (n.askName && !u.trim()) return h(i("comments.nameRequired"));
|
|
430
|
+
h(null), y(null), p(!0);
|
|
431
|
+
try {
|
|
432
|
+
await n.onSubmit(t, n.askName ? u.trim() : void 0) && l("");
|
|
433
|
+
} catch (t) {
|
|
434
|
+
let a = e(t);
|
|
435
|
+
o.report(a, n.operation), a.code === "comment_banned" && a.ban ? o.onBanned(a.ban) : a.code === "rate_limited" ? y(a.retryAfter ? i("comments.rateLimited", { seconds: a.retryAfter }) : i("comments.rateLimitedSoon")) : y(A(r, a));
|
|
436
|
+
} finally {
|
|
437
|
+
p(!1);
|
|
438
|
+
}
|
|
439
|
+
};
|
|
440
|
+
return /* @__PURE__ */ V("form", {
|
|
441
|
+
className: "grid gap-2",
|
|
442
|
+
"data-ckui": "comment-composer",
|
|
443
|
+
onSubmit: (e) => {
|
|
444
|
+
e.preventDefault(), C();
|
|
445
|
+
},
|
|
446
|
+
children: [
|
|
447
|
+
n.askName && /* @__PURE__ */ V("div", {
|
|
448
|
+
className: "grid gap-1.5 sm:max-w-xs",
|
|
449
|
+
children: [/* @__PURE__ */ B(_, {
|
|
450
|
+
htmlFor: `${s}-name`,
|
|
451
|
+
children: i("comments.name")
|
|
452
|
+
}), /* @__PURE__ */ B(g, {
|
|
453
|
+
id: `${s}-name`,
|
|
454
|
+
value: u,
|
|
455
|
+
maxLength: 60,
|
|
456
|
+
placeholder: i("comments.namePlaceholder"),
|
|
457
|
+
onChange: (e) => d(e.target.value),
|
|
458
|
+
autoComplete: "nickname"
|
|
459
|
+
})]
|
|
460
|
+
}),
|
|
461
|
+
/* @__PURE__ */ B(w, {
|
|
462
|
+
ref: b,
|
|
463
|
+
value: c,
|
|
464
|
+
rows: n.initial === void 0 ? 2 : 3,
|
|
465
|
+
maxLength: x,
|
|
466
|
+
autoFocus: n.autoFocus,
|
|
467
|
+
placeholder: n.placeholder,
|
|
468
|
+
"aria-label": n.placeholder ?? n.submit,
|
|
469
|
+
"aria-invalid": !!m,
|
|
470
|
+
"aria-describedby": `${s}-hint`,
|
|
471
|
+
disabled: f,
|
|
472
|
+
onChange: (e) => {
|
|
473
|
+
l(e.target.value), m && h(null);
|
|
474
|
+
},
|
|
475
|
+
onKeyDown: (e) => {
|
|
476
|
+
e.key === "Enter" && (e.metaKey || e.ctrlKey) ? (e.preventDefault(), C()) : e.key === "Escape" && n.onCancel && n.onCancel();
|
|
477
|
+
}
|
|
478
|
+
}),
|
|
479
|
+
/* @__PURE__ */ V("div", {
|
|
480
|
+
className: "flex flex-wrap items-center gap-2",
|
|
481
|
+
children: [
|
|
482
|
+
/* @__PURE__ */ B("span", {
|
|
483
|
+
id: `${s}-hint`,
|
|
484
|
+
className: "me-auto text-xs text-muted-foreground",
|
|
485
|
+
"aria-live": "polite",
|
|
486
|
+
children: m ? /* @__PURE__ */ B("span", {
|
|
487
|
+
className: "text-destructive",
|
|
488
|
+
children: m
|
|
489
|
+
}) : S !== void 0 && x !== void 0 && S <= x * .2 ? r.plural("comments.charsLeft", S) : /* @__PURE__ */ B("span", {
|
|
490
|
+
className: "pointer-coarse:hidden",
|
|
491
|
+
children: i("comments.submitHint", { key: J ? "⌘" : "Ctrl" })
|
|
492
|
+
})
|
|
493
|
+
}),
|
|
494
|
+
n.onCancel && /* @__PURE__ */ B(a, {
|
|
495
|
+
type: "button",
|
|
496
|
+
size: "sm",
|
|
497
|
+
variant: "ghost",
|
|
498
|
+
onClick: n.onCancel,
|
|
499
|
+
disabled: f,
|
|
500
|
+
children: i("common.cancel")
|
|
501
|
+
}),
|
|
502
|
+
/* @__PURE__ */ B(a, {
|
|
503
|
+
type: "submit",
|
|
504
|
+
size: "sm",
|
|
505
|
+
disabled: f,
|
|
506
|
+
children: f ? i("comments.posting") : n.submit
|
|
507
|
+
})
|
|
508
|
+
]
|
|
509
|
+
}),
|
|
510
|
+
v && /* @__PURE__ */ B(E, { children: v })
|
|
511
|
+
]
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
//#endregion
|
|
515
|
+
export { Z as Comments };
|
|
516
|
+
|
|
517
|
+
//# sourceMappingURL=comments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comments.js","names":[],"sources":["../../../src/components/social/comments.tsx"],"sourcesContent":["import { MoreHorizontalIcon, ThumbsDownIcon, ThumbsUpIcon } from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { cn } from \"cn\";\nimport { createContext, useContext, useId, useMemo, useRef, useState, type KeyboardEvent, type ReactNode } from \"react\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport type { BanScope, Reaction, Sort } from \"../../client/content/types.js\";\nimport { toContentKitError, type ContentKitError } from \"../../client/errors.js\";\nimport type { BanNotice as BanNoticeData, Comment, CommentBan, CommentStanding, PublicUser, RefBody } from \"../../client/generated/wire.js\";\nimport type { ContentKitUiAppearance } from \"../../appearance.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport { useCanComment, useCommentBans, useCommentReplies, useComments, type UseComments } from \"../../react/comments.js\";\nimport { useContentConfig } from \"../../react/config.js\";\nimport { ContentKitContext, useErrorReporter, type ContentKitErrorHandler } from \"../../react/context.js\";\nimport { ContentKitUiRoot } from \"../../scope.js\";\nimport { Badge } from \"#ckui/ui/badge\";\nimport { Button } from \"#ckui/ui/button\";\nimport { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from \"#ckui/ui/dropdown-menu\";\nimport { Input } from \"#ckui/ui/input\";\nimport { Label } from \"#ckui/ui/label\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"#ckui/ui/select\";\nimport { Skeleton } from \"#ckui/ui/skeleton\";\nimport { Textarea } from \"#ckui/ui/textarea\";\nimport { BanNotice, CommentBanDialog } from \"./bans.js\";\nimport { ConfirmDialog, contentError, ErrorLine, RelativeTime, UserAvatar, UserName } from \"./parts.js\";\n\nexport interface CommentsProps {\n /** The commented item. */\n item: RefBody;\n /** The item's comment count, for the heading; without it the heading has none. */\n count?: number;\n /** Initial order: newest (default) or best (top). */\n sort?: Sort;\n /** Top-level comments per page. Default 20. */\n pageSize?: number;\n /** Replies per page. Default 10. */\n repliesPageSize?: number;\n /**\n * Asks a signed-out visitor to sign in where the server takes no anonymous\n * comments or reactions (default the provider's). Where it does, they\n * comment under a name and react anonymously.\n */\n onSignIn?: () => void;\n /** A body as the host formats it (links, spoilers); default plain text. */\n renderBody?: (body: string, comment: Comment) => ReactNode;\n /** A profile URL for an author. */\n userHref?: (user: PublicUser) => string | undefined;\n /** The heading; false hides it. */\n heading?: ReactNode | false;\n client?: ContentKitClient;\n onError?: ContentKitErrorHandler;\n className?: string;\n appearance?: ContentKitUiAppearance;\n}\n\ninterface Thread {\n item: RefBody;\n comments: UseComments;\n standing: CommentStanding | null;\n /** undefined: not known yet. */\n signedIn?: boolean;\n /** Runs fn, or asks to sign in where signed-out visitors may not comment or react. */\n gate: (kind: Act, fn: () => void) => void;\n /** false: signed out where the server refuses it, with no sign-in to offer. */\n can: (kind: Act) => boolean;\n /** The server's longest comment (the standing's); undefined until it loads. */\n maxLength?: number;\n repliesPageSize: number;\n renderBody?: CommentsProps[\"renderBody\"];\n userHref?: CommentsProps[\"userHref\"];\n report: (e: unknown, op: \"comment.post\" | \"comment.edit\" | \"comment.delete\" | \"comment.react\" | \"comment.restore\") => void;\n /** Users banned in each scope the caller holds, with the ban. */\n banned: Map<string, { scope: BanScope; ban: CommentBan }[]>;\n openBan: (user: { id: string; name: string }, ban?: CommentBan) => void;\n liftBan: (user: { id: string; name: string }) => void;\n /** A post was refused by a ban: its notice. */\n onBanned: (ban: BanNoticeData) => void;\n}\n\ntype Act = \"comment\" | \"react\";\n\nconst ThreadContext = createContext<Thread | null>(null);\nconst useThread = () => useContext(ThreadContext)!;\n\nconst mac = typeof navigator !== \"undefined\" && /Mac|iP(hone|ad)/.test(navigator.platform);\nconst TRUNCATE = 300;\n\nconst authorName = (c: Comment, anonymous: string) => c.author?.username ?? c.anon_name ?? anonymous;\n\n/**\n * An item's comment thread: top-level comments a page at a time with\n * one-level replies, tombstones, held and rejected states shown to their\n * author, reactions, edit, delete, ban and rate-limit notices, and a sign-in\n * prompt. Moderators (as the server says) edit, delete and restore any\n * comment; an item's owner and site staff ban commenters.\n */\nexport function Comments(p: CommentsProps) {\n const m = useMessages();\n const { t } = m;\n const ctx = useContext(ContentKitContext);\n const [sort, setSort] = useState<Sort>(p.sort ?? \"newest\");\n const comments = useComments(p.item, { sort, pageSize: p.pageSize ?? 20, client: p.client });\n const { standing, reload: reloadStanding } = useCanComment(p.item, { client: p.client });\n const { config } = useContentConfig({ client: p.client });\n const report = useErrorReporter(p.onError);\n const signIn = p.onSignIn ?? ctx?.onSignIn;\n const viewer = ctx?.viewer;\n const signedIn = standing ? !!standing.user_id : viewer ? true : viewer === null ? false : undefined;\n const scopes = useMemo(() => standing?.ban_scopes ?? [], [standing]);\n const ownerBans = useCommentBans({ scope: \"owner\", pageSize: 100, enabled: scopes.includes(\"owner\"), client: p.client });\n const globalBans = useCommentBans({ scope: \"global\", pageSize: 100, enabled: scopes.includes(\"global\"), client: p.client });\n const [banning, setBanning] = useState<{ user: { id: string; name: string }; ban?: CommentBan } | null>(null);\n const [lifting, setLifting] = useState<{ id: string; name: string } | null>(null);\n const [refusal, setRefusal] = useState<BanNoticeData | null>(null);\n\n const banned = useMemo(() => {\n const out = new Map<string, { scope: BanScope; ban: CommentBan }[]>();\n const add = (scope: BanScope, list: CommentBan[]) => {\n for (const ban of list) if (!ban.expired) out.set(ban.user_id, [...(out.get(ban.user_id) ?? []), { scope, ban }]);\n };\n if (scopes.includes(\"owner\")) add(\"owner\", ownerBans.items);\n if (scopes.includes(\"global\")) add(\"global\", globalBans.items);\n return out;\n }, [scopes, ownerBans.items, globalBans.items]);\n\n // Signed out where the server refuses it: the standing says for comments, the config for reactions.\n const mustSignIn = (kind: Act) => signedIn === false && (kind === \"comment\" ? standing?.anonymous === false : config?.anonymous.reactions === false);\n const thread: Thread = {\n item: p.item,\n comments,\n standing,\n signedIn,\n gate: (kind, fn) => (mustSignIn(kind) ? signIn?.() : fn()),\n can: (kind) => !mustSignIn(kind) || !!signIn,\n maxLength: standing?.max_length,\n repliesPageSize: p.repliesPageSize ?? 10,\n renderBody: p.renderBody,\n userHref: p.userHref,\n report: (e, op) => report(e, op),\n banned,\n openBan: (user, ban) => setBanning({ user, ban }),\n liftBan: setLifting,\n onBanned: (ban) => {\n setRefusal(ban);\n reloadStanding();\n },\n };\n const ban = standing?.ban ?? refusal;\n const canWrite = standing ? standing.can_comment : true;\n const heading = p.heading === undefined ? (p.count === undefined ? t(\"comments.title\") : m.plural(\"comments.count\", p.count)) : p.heading;\n\n return (\n <ThreadContext.Provider value={thread}>\n <ContentKitUiRoot appearance={p.appearance} className={cn(\"grid gap-4 text-sm\", p.className)} data-ckui=\"comments\">\n {(heading !== false || comments.items.length > 1) && (\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n {heading !== false && <h2 className=\"text-base font-semibold\">{heading}</h2>}\n <Select value={sort} onValueChange={(v) => setSort(v as Sort)}>\n <SelectTrigger size=\"sm\" aria-label={t(\"comments.sort\")} className=\"ms-auto\">\n <SelectValue>{(v: string) => t(v === \"best\" ? \"comments.best\" : \"comments.newest\")}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"newest\">{t(\"comments.newest\")}</SelectItem>\n <SelectItem value=\"best\">{t(\"comments.best\")}</SelectItem>\n </SelectContent>\n </Select>\n </div>\n )}\n {ban ? (\n <BanNotice ban={ban} />\n ) : mustSignIn(\"comment\") ? (\n signIn ? (\n <Button variant=\"outline\" className=\"justify-self-start\" onClick={signIn}>\n {t(\"comments.signIn\")}\n </Button>\n ) : (\n <p className=\"rounded-lg border border-border p-3 text-muted-foreground\">{t(\"comments.signIn\")}</p>\n )\n ) : !canWrite ? (\n <p className=\"rounded-lg border border-border p-3 text-muted-foreground\">{t(\"comments.locked\")}</p>\n ) : (\n <Composer\n placeholder={t(\"comments.placeholder\")}\n submit={t(\"comments.post\")}\n askName={signedIn === false}\n onSubmit={async (body, name) => (await comments.post(body, { anonName: name }), true)}\n operation=\"comment.post\"\n />\n )}\n <CommentList />\n {banning && (\n <CommentBanDialog\n open\n onOpenChange={(o) => !o && setBanning(null)}\n user={banning.user}\n scopes={banning.ban ? [banning.ban.scope === \"global\" ? \"global\" : \"owner\"] : scopes}\n ban={banning.ban}\n client={p.client}\n onError={p.onError}\n />\n )}\n <ConfirmDialog\n open={!!lifting}\n onOpenChange={(o) => !o && setLifting(null)}\n title={t(\"bans.liftTitle\", { name: lifting?.name ?? \"\" })}\n description={t(\"bans.liftBody\")}\n confirm={t(\"bans.lift\")}\n onConfirm={() => {\n if (!lifting) return;\n for (const b of banned.get(lifting.id) ?? []) {\n void (b.scope === \"global\" ? globalBans : ownerBans).lift(lifting.id).catch((e) => report(e, \"ban.lift\"));\n }\n }}\n />\n </ContentKitUiRoot>\n </ThreadContext.Provider>\n );\n}\n\nfunction CommentList() {\n const { t } = useMessages();\n const { comments } = useThread();\n if (comments.loading && !comments.items.length) {\n return (\n <div className=\"grid gap-4\" aria-busy aria-label={t(\"comments.loading\")}>\n {[0, 1, 2].map((i) => (\n <div key={i} className=\"flex gap-3\">\n <Skeleton className=\"size-8 rounded-full\" />\n <div className=\"grid flex-1 gap-2\">\n <Skeleton className=\"h-3 w-32\" />\n <Skeleton className=\"h-3 w-full\" />\n </div>\n </div>\n ))}\n </div>\n );\n }\n if (comments.error && !comments.items.length) {\n return (\n <div className=\"grid justify-items-start gap-2\" data-ckui=\"comments-error\">\n <ErrorLine>{t(\"comments.loadFailed\")}</ErrorLine>\n <Button size=\"sm\" variant=\"outline\" onClick={comments.reload}>\n {t(\"common.retry\")}\n </Button>\n </div>\n );\n }\n if (!comments.items.length) return <p className=\"text-muted-foreground\">{t(\"comments.empty\")}</p>;\n return (\n <>\n <ul className=\"grid divide-y divide-border\">\n {comments.items.map((c) => (\n <li key={c.id} className=\"py-3 first:pt-0\">\n <TopLevel comment={c} />\n </li>\n ))}\n </ul>\n {comments.error && <ErrorLine error={comments.error} />}\n {comments.hasMore && (\n <Button variant=\"outline\" className=\"justify-self-center\" disabled={comments.loadingMore} onClick={() => void comments.loadMore()}>\n {comments.loadingMore ? t(\"comments.loading\") : t(\"comments.loadMore\")}\n </Button>\n )}\n </>\n );\n}\n\nfunction TopLevel({ comment }: { comment: Comment }) {\n const { t, plural } = useMessages();\n const thread = useThread();\n const [open, setOpen] = useState(false);\n const [replyTo, setReplyTo] = useState<string | null>(null);\n const replies = useCommentReplies(comment.id, { pageSize: thread.repliesPageSize, enabled: open });\n const startReply = (name: string) =>\n thread.gate(\"comment\", () => {\n setReplyTo(name);\n if (comment.reply_count > 0) setOpen(true);\n });\n return (\n <div className=\"grid gap-2\">\n <Row comment={comment} onReply={comment.deleted || comment.moderation || !thread.can(\"comment\") ? undefined : startReply} />\n {(comment.reply_count > 0 || (open && replies.items.length > 0)) && (\n <Button variant=\"link\" size=\"xs\" className=\"ms-11 justify-self-start px-0\" aria-expanded={open} onClick={() => setOpen(!open)}>\n {open ? t(\"comments.hideReplies\") : plural(\"comments.showReplies\", comment.reply_count)}\n </Button>\n )}\n {open && (\n <ul className=\"ms-11 grid gap-3 border-s border-border ps-3\" aria-busy={replies.loading}>\n {replies.loading && !replies.items.length && <li className=\"text-muted-foreground\">{t(\"comments.loadingReplies\")}</li>}\n {replies.items.map((r) => (\n <li key={r.id}>\n <Row comment={r} onReply={r.deleted || r.moderation || !thread.can(\"comment\") ? undefined : startReply} />\n </li>\n ))}\n {replies.error && (\n <li>\n <ErrorLine error={replies.error} />\n </li>\n )}\n {replies.hasMore && (\n <li>\n <Button variant=\"link\" size=\"xs\" className=\"px-0\" disabled={replies.loadingMore} onClick={() => void replies.loadMore()}>\n {t(\"comments.moreReplies\")}\n </Button>\n </li>\n )}\n </ul>\n )}\n {replyTo !== null && (\n <div className=\"ms-11 grid gap-1\">\n <p className=\"text-xs text-muted-foreground\">{t(\"comments.replyingTo\", { name: replyTo })}</p>\n <Composer\n autoFocus\n placeholder={t(\"comments.replyPlaceholder\")}\n submit={t(\"comments.reply\")}\n askName={thread.signedIn === false}\n onCancel={() => setReplyTo(null)}\n operation=\"comment.post\"\n onSubmit={async (body, name) => {\n await thread.comments.post(body, { replyTo: comment.id, anonName: name });\n setReplyTo(null);\n setOpen(true);\n return true;\n }}\n />\n </div>\n )}\n </div>\n );\n}\n\nfunction Row({ comment: c, onReply }: { comment: Comment; onReply?: (name: string) => void }) {\n const m = useMessages();\n const { t } = m;\n const thread = useThread();\n const { standing } = thread;\n const name = authorName(c, t(\"comments.anonymous\"));\n const own = !!standing?.user_id && c.user_id === standing.user_id;\n const canEdit = !c.deleted && (own || !!standing?.moderate);\n const canBan = !c.deleted && !!c.user_id && !own && (standing?.ban_scopes.length ?? 0) > 0;\n const bans = c.user_id ? thread.banned.get(c.user_id) : undefined;\n const [editing, setEditing] = useState(false);\n const [deleting, setDeleting] = useState(false);\n const [expanded, setExpanded] = useState(false);\n const [error, setError] = useState<ContentKitError | null>(null);\n const act = async (op: \"comment.delete\" | \"comment.react\" | \"comment.restore\", fn: () => Promise<unknown>) => {\n setError(null);\n try {\n await fn();\n } catch (e) {\n const err = toContentKitError(e);\n setError(err);\n thread.report(err, op);\n }\n };\n const react = (v: Reaction) => thread.gate(\"react\", () => void act(\"comment.react\", () => thread.comments.react(c, c.mine === v ? 0 : v)));\n const long = !thread.renderBody && c.body.length > TRUNCATE + 40;\n const body = long && !expanded ? c.body.slice(0, TRUNCATE).trimEnd() + \"…\" : c.body;\n\n return (\n <article className=\"flex gap-3\" data-ckui=\"comment\" data-comment={c.id} aria-label={name}>\n <UserAvatar user={c.deleted ? undefined : c.author} name={c.deleted ? \"?\" : name} />\n <div className=\"grid min-w-0 flex-1 gap-1\">\n <header className=\"flex flex-wrap items-center gap-x-2 gap-y-0.5\">\n {c.deleted ? <span className=\"text-muted-foreground\">{t(\"comments.anonymous\")}</span> : <UserName user={c.author} name={name} href={thread.userHref} />}\n <RelativeTime at={c.created_at} className=\"text-xs text-muted-foreground\" />\n {c.moderation === \"held\" && <Badge variant=\"secondary\">{t(\"comments.heldBadge\")}</Badge>}\n {c.moderation === \"rejected\" && <Badge variant=\"destructive\">{t(\"comments.rejectedBadge\")}</Badge>}\n {(canEdit || canBan || (c.deleted && standing?.moderate)) && (\n <DropdownMenu>\n <DropdownMenuTrigger render={<Button variant=\"ghost\" size=\"icon-xs\" className=\"ms-auto\" aria-label={t(\"comments.actions\")} />}>\n <HugeiconsIcon icon={MoreHorizontalIcon} strokeWidth={2} />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {canEdit && <DropdownMenuItem onClick={() => setEditing(true)}>{t(\"comments.edit\")}</DropdownMenuItem>}\n {canEdit && (\n <DropdownMenuItem className=\"text-destructive\" onClick={() => setDeleting(true)}>\n {t(\"comments.delete\")}\n </DropdownMenuItem>\n )}\n {c.deleted && standing?.moderate && <DropdownMenuItem onClick={() => void act(\"comment.restore\", () => thread.comments.restore(c.id))}>{t(\"comments.restore\")}</DropdownMenuItem>}\n {canBan && !bans && <DropdownMenuItem onClick={() => thread.openBan({ id: c.user_id!, name })}>{t(\"comments.ban\")}</DropdownMenuItem>}\n {canBan && bans && <DropdownMenuItem onClick={() => thread.liftBan({ id: c.user_id!, name })}>{t(\"comments.unban\")}</DropdownMenuItem>}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n </header>\n {editing ? (\n <Composer\n autoFocus\n initial={c.body}\n submit={t(\"common.save\")}\n onCancel={() => setEditing(false)}\n operation=\"comment.edit\"\n onSubmit={async (next) => {\n if (next !== c.body) await thread.comments.edit(c.id, next);\n setEditing(false);\n return true;\n }}\n />\n ) : c.deleted ? (\n <p className=\"text-muted-foreground italic\">{t(\"comments.deleted\")}</p>\n ) : (\n <div className=\"break-words whitespace-pre-wrap\">\n {thread.renderBody ? thread.renderBody(c.body, c) : body}\n {long && (\n <Button variant=\"link\" size=\"xs\" className=\"ms-1 h-auto px-0\" onClick={() => setExpanded(!expanded)}>\n {expanded ? t(\"comments.showLess\") : t(\"comments.showMore\")}\n </Button>\n )}\n </div>\n )}\n {c.moderation === \"held\" && <p className=\"text-xs text-muted-foreground\">{t(\"comments.held\")}</p>}\n {c.moderation === \"rejected\" && (\n <p className=\"text-xs text-destructive\">{c.moderation_reason ? t(\"comments.rejected\", { reason: c.moderation_reason }) : t(\"comments.rejectedNoReason\")}</p>\n )}\n {!c.deleted && !c.moderation && !editing && (\n <div className=\"-ms-2 flex flex-wrap items-center gap-1\">\n <Button variant={c.mine === 1 ? \"secondary\" : \"ghost\"} size=\"xs\" aria-pressed={c.mine === 1} aria-label={t(\"comments.like\")} disabled={!thread.can(\"react\")} onClick={() => react(1)}>\n <HugeiconsIcon icon={ThumbsUpIcon} strokeWidth={2} />\n <span>{c.likes}</span>\n </Button>\n <Button variant={c.mine === -1 ? \"secondary\" : \"ghost\"} size=\"xs\" aria-pressed={c.mine === -1} aria-label={t(\"comments.dislike\")} disabled={!thread.can(\"react\")} onClick={() => react(-1)}>\n <HugeiconsIcon icon={ThumbsDownIcon} strokeWidth={2} />\n <span>{c.dislikes}</span>\n </Button>\n {onReply && (\n <Button variant=\"ghost\" size=\"xs\" onClick={() => onReply(name)}>\n {t(\"comments.reply\")}\n </Button>\n )}\n </div>\n )}\n <ErrorLine error={error} />\n </div>\n <ConfirmDialog\n open={deleting}\n onOpenChange={setDeleting}\n title={t(\"comments.deleteTitle\")}\n description={t(\"comments.deleteBody\")}\n confirm={t(\"comments.delete\")}\n onConfirm={() => void act(\"comment.delete\", () => thread.comments.remove(c.id))}\n />\n </article>\n );\n}\n\ninterface ComposerProps {\n initial?: string;\n placeholder?: string;\n submit: string;\n /** A signed-out visitor gives a name. */\n askName?: boolean;\n autoFocus?: boolean;\n onCancel?: () => void;\n operation: \"comment.post\" | \"comment.edit\";\n /** Resolves true to clear the field. */\n onSubmit: (body: string, name?: string) => Promise<boolean>;\n}\n\nfunction Composer(p: ComposerProps) {\n const m = useMessages();\n const { t } = m;\n const thread = useThread();\n const ids = useId();\n const [body, setBody] = useState(p.initial ?? \"\");\n const [name, setName] = useState(\"\");\n const [pending, setPending] = useState(false);\n const [invalid, setInvalid] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n const area = useRef<HTMLTextAreaElement>(null);\n const max = thread.maxLength;\n const left = max === undefined ? undefined : max - body.length;\n\n const send = async () => {\n const text = body.trim();\n if (!text) return setInvalid(t(\"comments.required\"));\n if (p.askName && !name.trim()) return setInvalid(t(\"comments.nameRequired\"));\n setInvalid(null);\n setError(null);\n setPending(true);\n try {\n if (await p.onSubmit(text, p.askName ? name.trim() : undefined)) setBody(\"\");\n } catch (e) {\n const err = toContentKitError(e);\n thread.report(err, p.operation);\n if (err.code === \"comment_banned\" && err.ban) thread.onBanned(err.ban);\n else if (err.code === \"rate_limited\") setError(err.retryAfter ? t(\"comments.rateLimited\", { seconds: err.retryAfter }) : t(\"comments.rateLimitedSoon\"));\n else setError(contentError(m, err));\n } finally {\n setPending(false);\n }\n };\n const onKey = (e: KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === \"Enter\" && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n void send();\n } else if (e.key === \"Escape\" && p.onCancel) p.onCancel();\n };\n return (\n <form\n className=\"grid gap-2\"\n data-ckui=\"comment-composer\"\n onSubmit={(e) => {\n e.preventDefault();\n void send();\n }}\n >\n {p.askName && (\n <div className=\"grid gap-1.5 sm:max-w-xs\">\n <Label htmlFor={`${ids}-name`}>{t(\"comments.name\")}</Label>\n <Input id={`${ids}-name`} value={name} maxLength={60} placeholder={t(\"comments.namePlaceholder\")} onChange={(e) => setName(e.target.value)} autoComplete=\"nickname\" />\n </div>\n )}\n <Textarea\n ref={area}\n value={body}\n rows={p.initial === undefined ? 2 : 3}\n maxLength={max}\n autoFocus={p.autoFocus}\n placeholder={p.placeholder}\n aria-label={p.placeholder ?? p.submit}\n aria-invalid={!!invalid}\n aria-describedby={`${ids}-hint`}\n disabled={pending}\n onChange={(e) => {\n setBody(e.target.value);\n if (invalid) setInvalid(null);\n }}\n onKeyDown={onKey}\n />\n <div className=\"flex flex-wrap items-center gap-2\">\n <span id={`${ids}-hint`} className=\"me-auto text-xs text-muted-foreground\" aria-live=\"polite\">\n {invalid ? (\n <span className=\"text-destructive\">{invalid}</span>\n ) : left !== undefined && max !== undefined && left <= max * 0.2 ? (\n m.plural(\"comments.charsLeft\", left)\n ) : (\n <span className=\"pointer-coarse:hidden\">{t(\"comments.submitHint\", { key: mac ? \"⌘\" : \"Ctrl\" })}</span>\n )}\n </span>\n {p.onCancel && (\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" onClick={p.onCancel} disabled={pending}>\n {t(\"common.cancel\")}\n </Button>\n )}\n <Button type=\"submit\" size=\"sm\" disabled={pending}>\n {pending ? t(\"comments.posting\") : p.submit}\n </Button>\n </div>\n {error && <ErrorLine>{error}</ErrorLine>}\n </form>\n );\n}\n"],"mappings":"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"}
|