@openrails/contentkit-ui 0.0.0-stage → 0.68.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +425 -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 +51 -0
- package/dist/client/client.js +35 -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 +93 -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 +148 -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 +91 -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 +79 -0
- package/dist/client/http.js +74 -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 +52 -0
- package/dist/client/media/rules.js +139 -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 +45 -0
- package/dist/components/media-folder-editor.js +564 -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 +213 -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 +88 -0
- package/dist/react/canonical.js.map +1 -0
- package/dist/react/comments.d.ts +82 -0
- package/dist/react/comments.js +147 -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 +48 -0
- package/dist/react/context.js +37 -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 +83 -0
- package/dist/react/folder.js +183 -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 +23 -0
- package/dist/react/provider.js +35 -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 +143 -0
- package/dist/react/read.js.map +1 -0
- package/dist/react/resources.d.ts +70 -0
- package/dist/react/resources.js +247 -0
- package/dist/react/resources.js.map +1 -0
- package/dist/react/slot.d.ts +102 -0
- package/dist/react/slot.js +181 -0
- package/dist/react/slot.js.map +1 -0
- package/dist/react/store.d.ts +51 -0
- package/dist/react/store.js +164 -0
- package/dist/react/store.js.map +1 -0
- package/dist/react/upload.d.ts +85 -0
- package/dist/react/upload.js +150 -0
- package/dist/react/upload.js.map +1 -0
- package/dist/react/use-resource.d.ts +43 -0
- package/dist/react/use-resource.js +66 -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 +118 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"moderation.js","names":[],"sources":["../../../src/components/social/moderation.tsx"],"sourcesContent":["import { cn } from \"cn\";\nimport { useMemo, useState } from \"react\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport type { Decision, HeldKind } from \"../../client/content/types.js\";\nimport { toContentKitError, type ContentKitError } from \"../../client/errors.js\";\nimport type { AdminComment, HeldItem, PublicUser } from \"../../client/generated/wire.js\";\nimport type { ContentKitUiAppearance } from \"../../appearance.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport { useAdminComments, useModerationQueue } from \"../../react/comments.js\";\nimport { 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 { Input } from \"#ckui/ui/input\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"#ckui/ui/select\";\nimport { Skeleton } from \"#ckui/ui/skeleton\";\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from \"#ckui/ui/tabs\";\nimport { CommentBanDialog, CommentBans } from \"./bans.js\";\nimport { contentError, ErrorLine, RelativeTime, UserAvatar, UserName } from \"./parts.js\";\n\nexport type ModerationSection = \"comments\" | \"queue\" | \"bans\";\n\nexport interface CommentModerationProps {\n /** Content kinds offered as a filter of the comment list: codes, or codes with labels. */\n contentKinds?: readonly (string | { value: string; label: string })[];\n /** A link to a commented item. */\n itemHref?: (item: { kind: string; id: string }) => string | undefined;\n userHref?: (user: PublicUser) => string | undefined;\n /** The sections, in order. Default all: every comment, the review queue, the site's bans. */\n sections?: readonly ModerationSection[];\n pageSize?: number;\n client?: ContentKitClient;\n onError?: ContentKitErrorHandler;\n className?: string;\n appearance?: ContentKitUiAppearance;\n}\n\n/**\n * Staff: every comment (deleted, held and rejected ones with their text) to\n * delete, restore or ban its author; the review queue of held comments and\n * posts to approve or reject; and the site's comment bans. Each section\n * shows what the caller's permissions allow and says so when they don't.\n */\nexport function CommentModeration({ sections = [\"comments\", \"queue\", \"bans\"], className, appearance, ...p }: CommentModerationProps) {\n const { t } = useMessages();\n const [tab, setTab] = useState<ModerationSection>(sections[0] ?? \"comments\");\n const label: Record<ModerationSection, string> = { comments: t(\"moderation.all\"), queue: t(\"moderation.queue\"), bans: t(\"moderation.bans\") };\n return (\n <ContentKitUiRoot appearance={appearance} className={cn(\"grid gap-4 text-sm\", className)} data-ckui=\"comment-moderation\">\n <h2 className=\"text-base font-semibold\">{t(\"moderation.title\")}</h2>\n <Tabs value={tab} onValueChange={(v) => setTab(v as ModerationSection)}>\n {sections.length > 1 && (\n <TabsList>\n {sections.map((s) => (\n <TabsTrigger key={s} value={s}>\n {label[s]}\n </TabsTrigger>\n ))}\n </TabsList>\n )}\n {sections.includes(\"comments\") && (\n <TabsContent value=\"comments\" className=\"pt-3\">\n <AllComments {...p} />\n </TabsContent>\n )}\n {sections.includes(\"queue\") && (\n <TabsContent value=\"queue\" className=\"pt-3\">\n <Queue {...p} />\n </TabsContent>\n )}\n {sections.includes(\"bans\") && (\n <TabsContent value=\"bans\" className=\"pt-3\">\n <CommentBans scope=\"global\" pageSize={p.pageSize} userHref={p.userHref} client={p.client} onError={p.onError} />\n </TabsContent>\n )}\n </Tabs>\n </ContentKitUiRoot>\n );\n}\n\ntype Rest = Omit<CommentModerationProps, \"sections\" | \"className\" | \"appearance\">;\n\nfunction status(c: AdminComment): \"deleted\" | \"held\" | \"rejected\" | \"published\" {\n if (c.deleted) return \"deleted\";\n return c.moderation === \"held\" ? \"held\" : c.moderation === \"rejected\" ? \"rejected\" : \"published\";\n}\n\nfunction AllComments(p: Rest) {\n const m = useMessages();\n const { t } = m;\n const kinds = useMemo(() => (p.contentKinds ?? []).map((k) => (typeof k === \"string\" ? { value: k, label: k } : k)), [p.contentKinds]);\n const [kind, setKind] = useState(\"\");\n const list = useAdminComments({ contentKind: kind, pageSize: p.pageSize, client: p.client });\n const report = useErrorReporter(p.onError);\n const [error, setError] = useState<ContentKitError | null>(null);\n const [banning, setBanning] = useState<{ id: string; name: string } | null>(null);\n const act = (op: \"comment.delete\" | \"comment.restore\", fn: () => Promise<unknown>) => {\n setError(null);\n fn().catch((e) => {\n const err = toContentKitError(e);\n setError(err);\n report(err, op);\n });\n };\n return (\n <div className=\"grid gap-3\">\n {kinds.length > 0 && (\n <Select value={kind} onValueChange={(v) => setKind(String(v ?? \"\"))}>\n <SelectTrigger size=\"sm\" aria-label={t(\"moderation.kind\")}>\n <SelectValue>{(v: string) => (v ? (kinds.find((k) => k.value === v)?.label ?? v) : t(\"moderation.allKinds\"))}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"\">{t(\"moderation.allKinds\")}</SelectItem>\n {kinds.map((k) => (\n <SelectItem key={k.value} value={k.value}>\n {k.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )}\n <ErrorLine error={error} />\n <Listing loading={list.loading} error={list.error} empty={t(\"moderation.empty\")} count={list.items.length} reload={list.reload}>\n {list.items.map((c) => {\n const name = c.author?.username ?? c.anon_name ?? c.user_id ?? t(\"comments.anonymous\");\n const s = status(c);\n const href = p.itemHref?.({ kind: c.content_kind, id: c.content_id });\n return (\n <li key={c.id} className=\"grid gap-2 p-3\" data-ckui=\"admin-comment\" data-status={s}>\n <div className=\"flex flex-wrap items-center gap-x-2 gap-y-1\">\n <UserAvatar user={c.author} name={name} size=\"sm\" />\n <UserName user={c.author} name={name} href={p.userHref} />\n <RelativeTime at={c.created_at} className=\"text-xs text-muted-foreground\" />\n <Badge variant={s === \"published\" ? \"outline\" : s === \"held\" ? \"secondary\" : \"destructive\"}>{t(`moderation.${s}`)}</Badge>\n {c.reply_to_id && <Badge variant=\"outline\">{t(\"moderation.reply\")}</Badge>}\n <span className=\"text-xs text-muted-foreground\">\n {t(\"moderation.on\")}{\" \"}\n {href ? (\n <a className=\"hover:underline\" href={href}>\n {c.content_kind}/{c.content_id}\n </a>\n ) : (\n `${c.content_kind}/${c.content_id}`\n )}\n </span>\n </div>\n <p className={cn(\"line-clamp-4 break-words whitespace-pre-wrap\", c.deleted && \"text-muted-foreground line-through\")}>{c.body}</p>\n {c.moderation_reason && <p className=\"text-xs text-muted-foreground\">{t(\"moderation.heldBecause\", { reason: c.moderation_reason })}</p>}\n <div className=\"flex flex-wrap gap-2\">\n {c.deleted ? (\n <Button size=\"sm\" variant=\"outline\" onClick={() => act(\"comment.restore\", () => list.restore(c.id))}>\n {t(\"moderation.restore\")}\n </Button>\n ) : (\n <Button size=\"sm\" variant=\"destructive\" onClick={() => act(\"comment.delete\", () => list.remove(c.id))}>\n {t(\"moderation.delete\")}\n </Button>\n )}\n {c.user_id && (\n <Button size=\"sm\" variant=\"ghost\" onClick={() => setBanning({ id: c.user_id!, name })}>\n {t(\"comments.ban\")}\n </Button>\n )}\n </div>\n </li>\n );\n })}\n </Listing>\n {list.hasMore && (\n <Button variant=\"outline\" className=\"justify-self-center\" disabled={list.loadingMore} onClick={() => void list.loadMore()}>\n {t(\"moderation.loadMore\")}\n </Button>\n )}\n {banning && <CommentBanDialog open onOpenChange={(o) => !o && setBanning(null)} user={banning} scopes={[\"global\"]} client={p.client} onError={p.onError} />}\n </div>\n );\n}\n\nfunction Queue(p: Rest) {\n const m = useMessages();\n const { t } = m;\n const [kind, setKind] = useState<HeldKind>(\"comment\");\n const queue = useModerationQueue({ kind, pageSize: p.pageSize, client: p.client });\n return (\n <div className=\"grid gap-3\">\n <div className=\"flex gap-2\" role=\"group\" aria-label={t(\"moderation.queue\")}>\n {([\"comment\", \"post\"] as const).map((k) => (\n <Button key={k} size=\"sm\" variant={kind === k ? \"default\" : \"outline\"} aria-pressed={kind === k} onClick={() => setKind(k)}>\n {t(k === \"post\" ? \"moderation.queuePosts\" : \"moderation.queueComments\")}\n </Button>\n ))}\n </div>\n <Listing loading={queue.loading} error={queue.error} empty={t(\"moderation.queueEmpty\")} count={queue.items.length} reload={queue.reload}>\n {queue.items.map((it) => (\n <HeldRow key={it.id} item={it} itemHref={p.itemHref} userHref={p.userHref} onResolve={queue.resolve} reload={queue.reload} onError={p.onError} />\n ))}\n </Listing>\n {queue.hasMore && (\n <Button variant=\"outline\" className=\"justify-self-center\" disabled={queue.loadingMore} onClick={() => void queue.loadMore()}>\n {t(\"moderation.loadMore\")}\n </Button>\n )}\n </div>\n );\n}\n\nfunction HeldRow(p: {\n item: HeldItem;\n itemHref?: Rest[\"itemHref\"];\n userHref?: Rest[\"userHref\"];\n onResolve: (item: HeldItem, d: Decision, reason?: string) => Promise<void>;\n reload: () => void;\n onError?: ContentKitErrorHandler;\n}) {\n const m = useMessages();\n const { t } = m;\n const report = useErrorReporter(p.onError);\n const { item: it } = p;\n const [rejecting, setRejecting] = useState(false);\n const [reason, setReason] = useState(\"\");\n const [pending, setPending] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const name = it.author?.username ?? it.anon_name ?? it.author_id ?? t(\"comments.anonymous\");\n const href = p.itemHref?.({ kind: it.ref.content_kind, id: it.ref.content_id });\n const resolve = async (d: Decision) => {\n setPending(true);\n setError(null);\n try {\n await p.onResolve(it, d, d === \"reject\" ? reason.trim() || undefined : undefined);\n } catch (e) {\n const err = toContentKitError(e);\n report(err, \"moderation.resolve\");\n // A stale revision: the text changed since it was listed.\n if (err.code === \"not_found\" || err.code === \"conflict\") {\n setError(t(\"moderation.stale\"));\n p.reload();\n } else setError(contentError(m, err));\n } finally {\n setPending(false);\n }\n };\n return (\n <li className=\"grid gap-2 p-3\" data-ckui=\"held-item\">\n <div className=\"flex flex-wrap items-center gap-x-2 gap-y-1\">\n <UserAvatar user={it.author} name={name} size=\"sm\" />\n <UserName user={it.author} name={name} href={p.userHref} />\n <RelativeTime at={it.held_at} className=\"text-xs text-muted-foreground\" />\n {href && (\n <a className=\"text-xs text-muted-foreground hover:underline\" href={href}>\n {t(\"moderation.on\")} {it.ref.content_kind}/{it.ref.content_id}\n </a>\n )}\n </div>\n {it.title && <p className=\"font-medium\">{it.title}</p>}\n <p className=\"line-clamp-6 break-words whitespace-pre-wrap\">{it.body}</p>\n {(it.reason || it.error) && <p className=\"text-xs text-muted-foreground\">{t(\"moderation.heldBecause\", { reason: it.reason || it.error || \"\" })}</p>}\n {rejecting && (\n <Input value={reason} maxLength={500} placeholder={t(\"moderation.rejectReason\")} aria-label={t(\"moderation.rejectReason\")} onChange={(e) => setReason(e.target.value)} autoFocus />\n )}\n <div className=\"flex flex-wrap gap-2\">\n <Button size=\"sm\" disabled={pending} onClick={() => void resolve(\"approve\")}>\n {t(\"moderation.approve\")}\n </Button>\n <Button size=\"sm\" variant=\"destructive\" disabled={pending} onClick={() => (rejecting ? void resolve(\"reject\") : setRejecting(true))}>\n {t(\"moderation.reject\")}\n </Button>\n {rejecting && (\n <Button size=\"sm\" variant=\"ghost\" onClick={() => setRejecting(false)}>\n {t(\"common.cancel\")}\n </Button>\n )}\n </div>\n {error && <ErrorLine>{error}</ErrorLine>}\n </li>\n );\n}\n\nfunction Listing(p: { loading: boolean; error?: ContentKitError; empty: string; count: number; reload: () => void; children: React.ReactNode }) {\n const m = useMessages();\n const { t } = m;\n if (p.loading && !p.count) {\n return (\n <div className=\"grid gap-3\" aria-busy>\n <Skeleton className=\"h-16 w-full\" />\n <Skeleton className=\"h-16 w-full\" />\n </div>\n );\n }\n if (p.error && !p.count) {\n return (\n <div className=\"grid justify-items-start gap-2\">\n <ErrorLine>{p.error.code === \"forbidden\" || p.error.code === \"unauthorized\" ? contentError(m, p.error) : t(\"moderation.loadFailed\")}</ErrorLine>\n <Button size=\"sm\" variant=\"outline\" onClick={p.reload}>\n {t(\"common.retry\")}\n </Button>\n </div>\n );\n }\n if (!p.count) return <p className=\"text-muted-foreground\">{p.empty}</p>;\n return <ul className=\"grid divide-y divide-border rounded-lg border border-border\">{p.children}</ul>;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { ContentKitError } from '../../client/errors.js';
|
|
3
|
+
import { PublicUser } from '../../client/generated/wire.js';
|
|
4
|
+
import { Translator } from '../../i18n/messages.js';
|
|
5
|
+
import { ContentKitErrorHandler, SocialOperation } from '../../react/context.js';
|
|
6
|
+
/** A content refusal or fault in words: the content wording for shared codes, else the code's. */
|
|
7
|
+
export declare function contentError(m: Translator, e: unknown): string;
|
|
8
|
+
/** Runs one async action at a time: its pending state and last error, reported once. */
|
|
9
|
+
export declare function useAction(operation: SocialOperation, onError?: ContentKitErrorHandler): {
|
|
10
|
+
run: <T>(fn: () => Promise<T>) => Promise<T | undefined>;
|
|
11
|
+
pending: boolean;
|
|
12
|
+
error: ContentKitError | null;
|
|
13
|
+
setError: import('react').Dispatch<import('react').SetStateAction<ContentKitError | null>>;
|
|
14
|
+
};
|
|
15
|
+
/** "3 minutes ago", in the UI's language. */
|
|
16
|
+
export declare function relativeTime(m: Translator, iso: string, now?: number): string;
|
|
17
|
+
export declare function formatDate(m: Translator, iso: string, time?: boolean): string;
|
|
18
|
+
/** A relative time with the full date as its title. */
|
|
19
|
+
export declare function RelativeTime({ at, className }: {
|
|
20
|
+
at: string;
|
|
21
|
+
className?: string;
|
|
22
|
+
}): import('react').JSX.Element;
|
|
23
|
+
/** A user's avatar, or their initial. */
|
|
24
|
+
export declare function UserAvatar({ user, name, size }: {
|
|
25
|
+
user?: PublicUser;
|
|
26
|
+
name: string;
|
|
27
|
+
size?: "default" | "sm" | "lg";
|
|
28
|
+
}): import('react').JSX.Element;
|
|
29
|
+
/** A user's name, linked when the host gives a profile URL. */
|
|
30
|
+
export declare function UserName({ user, name, href, className }: {
|
|
31
|
+
user?: PublicUser;
|
|
32
|
+
name: string;
|
|
33
|
+
href?: (u: PublicUser) => string | undefined;
|
|
34
|
+
className?: string;
|
|
35
|
+
}): import('react').JSX.Element;
|
|
36
|
+
/** A confirmation for a destructive action. */
|
|
37
|
+
export declare function ConfirmDialog(p: {
|
|
38
|
+
open: boolean;
|
|
39
|
+
onOpenChange: (open: boolean) => void;
|
|
40
|
+
title: ReactNode;
|
|
41
|
+
description?: ReactNode;
|
|
42
|
+
confirm: ReactNode;
|
|
43
|
+
onConfirm: () => void;
|
|
44
|
+
}): import('react').JSX.Element;
|
|
45
|
+
/** A failure line, announced politely. */
|
|
46
|
+
export declare function ErrorLine({ error, children, className }: {
|
|
47
|
+
error?: ContentKitError | null;
|
|
48
|
+
children?: ReactNode;
|
|
49
|
+
className?: string;
|
|
50
|
+
}): import('react').JSX.Element | null;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { toContentKitError as e } from "../../client/errors.js";
|
|
2
|
+
import { useMessages as t } from "../../i18n/context.js";
|
|
3
|
+
import { useErrorReporter as n } from "../../react/context.js";
|
|
4
|
+
import { AlertDialog as r, AlertDialogAction as i, AlertDialogCancel as a, AlertDialogContent as o, AlertDialogDescription as s, AlertDialogFooter as c, AlertDialogHeader as l, AlertDialogTitle as u } from "../../ui/alert-dialog.js";
|
|
5
|
+
import { Avatar as d, AvatarFallback as f, AvatarImage as p } from "../../ui/avatar.js";
|
|
6
|
+
import { useCallback as m, useState as h } from "react";
|
|
7
|
+
import { jsx as g, jsxs as _ } from "react/jsx-runtime";
|
|
8
|
+
import { cn as v } from "cn";
|
|
9
|
+
//#region src/components/social/parts.tsx
|
|
10
|
+
function y(t, n) {
|
|
11
|
+
let r = e(n);
|
|
12
|
+
return r.code === "rate_limited" ? t.t("contentErrors.rate_limited", { seconds: r.retryAfter ?? 60 }) : r.code === "forbidden" || r.code === "unauthorized" || r.code === "not_found" || r.code === "conflict" ? t.t(`contentErrors.${r.code}`) : r.code === "moderation_rejected" ? r.message ? t.t("comments.rejected", { reason: r.message }) : t.t("comments.rejectedNoReason") : t.error(r);
|
|
13
|
+
}
|
|
14
|
+
function b(t, r) {
|
|
15
|
+
let i = n(r), [a, o] = h(!1), [s, c] = h(null);
|
|
16
|
+
return {
|
|
17
|
+
run: m(async (n) => {
|
|
18
|
+
o(!0), c(null);
|
|
19
|
+
try {
|
|
20
|
+
return await n();
|
|
21
|
+
} catch (n) {
|
|
22
|
+
let r = e(n);
|
|
23
|
+
r.code !== "aborted" && (c(r), i(r, t));
|
|
24
|
+
return;
|
|
25
|
+
} finally {
|
|
26
|
+
o(!1);
|
|
27
|
+
}
|
|
28
|
+
}, [t, i]),
|
|
29
|
+
pending: a,
|
|
30
|
+
error: s,
|
|
31
|
+
setError: c
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function x(e, t, n = Date.now()) {
|
|
35
|
+
let r = (Date.parse(t) - n) / 1e3, i = Math.abs(r);
|
|
36
|
+
if (i < 45) return e.t("time.justNow");
|
|
37
|
+
let a = new Intl.RelativeTimeFormat(e.language, { numeric: "auto" });
|
|
38
|
+
return i < 2700 ? a.format(Math.round(r / 60), "minute") : i < 79200 ? a.format(Math.round(r / 3600), "hour") : i < 2246400 ? a.format(Math.round(r / 86400), "day") : i < 28512e3 ? a.format(Math.round(r / 2592e3), "month") : a.format(Math.round(r / 31536e3), "year");
|
|
39
|
+
}
|
|
40
|
+
function S(e, t, n = !0) {
|
|
41
|
+
return new Intl.DateTimeFormat(e.language, n ? {
|
|
42
|
+
dateStyle: "medium",
|
|
43
|
+
timeStyle: "short"
|
|
44
|
+
} : { dateStyle: "medium" }).format(new Date(t));
|
|
45
|
+
}
|
|
46
|
+
function C({ at: e, className: n }) {
|
|
47
|
+
let r = t();
|
|
48
|
+
return /* @__PURE__ */ g("time", {
|
|
49
|
+
dateTime: e,
|
|
50
|
+
title: S(r, e),
|
|
51
|
+
className: n,
|
|
52
|
+
children: x(r, e)
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function w({ user: e, name: t, size: n = "default" }) {
|
|
56
|
+
return /* @__PURE__ */ _(d, {
|
|
57
|
+
size: n,
|
|
58
|
+
children: [e?.avatar && /* @__PURE__ */ g(p, {
|
|
59
|
+
src: e.avatar,
|
|
60
|
+
srcSet: e.avatar_srcset,
|
|
61
|
+
sizes: n === "lg" ? "40px" : n === "sm" ? "24px" : "32px",
|
|
62
|
+
alt: "",
|
|
63
|
+
loading: "lazy"
|
|
64
|
+
}), /* @__PURE__ */ g(f, {
|
|
65
|
+
"aria-hidden": !0,
|
|
66
|
+
children: (t.trim()[0] ?? "?").toUpperCase()
|
|
67
|
+
})]
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function T({ user: e, name: t, href: n, className: r }) {
|
|
71
|
+
let i = e && n?.(e), a = v("font-medium text-foreground", r);
|
|
72
|
+
return i ? /* @__PURE__ */ g("a", {
|
|
73
|
+
href: i,
|
|
74
|
+
className: v(a, "hover:underline"),
|
|
75
|
+
children: t
|
|
76
|
+
}) : /* @__PURE__ */ g("span", {
|
|
77
|
+
className: a,
|
|
78
|
+
children: t
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
function E(e) {
|
|
82
|
+
let { t: n } = t();
|
|
83
|
+
return /* @__PURE__ */ g(r, {
|
|
84
|
+
open: e.open,
|
|
85
|
+
onOpenChange: e.onOpenChange,
|
|
86
|
+
children: /* @__PURE__ */ _(o, { children: [/* @__PURE__ */ _(l, { children: [/* @__PURE__ */ g(u, { children: e.title }), e.description && /* @__PURE__ */ g(s, { children: e.description })] }), /* @__PURE__ */ _(c, { children: [/* @__PURE__ */ g(a, { children: n("common.cancel") }), /* @__PURE__ */ g(i, {
|
|
87
|
+
variant: "destructive",
|
|
88
|
+
onClick: () => {
|
|
89
|
+
e.onOpenChange(!1), e.onConfirm();
|
|
90
|
+
},
|
|
91
|
+
children: e.confirm
|
|
92
|
+
})] })] })
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
function D({ error: e, children: n, className: r }) {
|
|
96
|
+
let i = t();
|
|
97
|
+
return !e && !n ? null : /* @__PURE__ */ g("p", {
|
|
98
|
+
role: "alert",
|
|
99
|
+
className: v("text-sm text-destructive", r),
|
|
100
|
+
children: n ?? y(i, e)
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
//#endregion
|
|
104
|
+
export { E as ConfirmDialog, D as ErrorLine, C as RelativeTime, w as UserAvatar, T as UserName, y as contentError, S as formatDate, x as relativeTime, b as useAction };
|
|
105
|
+
|
|
106
|
+
//# sourceMappingURL=parts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parts.js","names":[],"sources":["../../../src/components/social/parts.tsx"],"sourcesContent":["import { cn } from \"cn\";\nimport { useCallback, useState, type ReactNode } from \"react\";\nimport { toContentKitError, type ContentKitError } from \"../../client/errors.js\";\nimport type { PublicUser } from \"../../client/generated/wire.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport type { Translator } from \"../../i18n/messages.js\";\nimport { useErrorReporter, type ContentKitErrorHandler, type SocialOperation } from \"../../react/context.js\";\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n} from \"#ckui/ui/alert-dialog\";\nimport { Avatar, AvatarFallback, AvatarImage } from \"#ckui/ui/avatar\";\n\n/** A content refusal or fault in words: the content wording for shared codes, else the code's. */\nexport function contentError(m: Translator, e: unknown): string {\n const err = toContentKitError(e);\n if (err.code === \"rate_limited\") return m.t(\"contentErrors.rate_limited\", { seconds: err.retryAfter ?? 60 });\n if (err.code === \"forbidden\" || err.code === \"unauthorized\" || err.code === \"not_found\" || err.code === \"conflict\") return m.t(`contentErrors.${err.code}`);\n if (err.code === \"moderation_rejected\") return err.message ? m.t(\"comments.rejected\", { reason: err.message }) : m.t(\"comments.rejectedNoReason\");\n return m.error(err);\n}\n\n/** Runs one async action at a time: its pending state and last error, reported once. */\nexport function useAction(operation: SocialOperation, onError?: ContentKitErrorHandler) {\n const report = useErrorReporter(onError);\n const [pending, setPending] = useState(false);\n const [error, setError] = useState<ContentKitError | null>(null);\n const run = useCallback(\n async <T,>(fn: () => Promise<T>): Promise<T | undefined> => {\n setPending(true);\n setError(null);\n try {\n return await fn();\n } catch (e) {\n const err = toContentKitError(e);\n if (err.code !== \"aborted\") {\n setError(err);\n report(err, operation);\n }\n return undefined;\n } finally {\n setPending(false);\n }\n },\n [operation, report],\n );\n return { run, pending, error, setError };\n}\n\n/** \"3 minutes ago\", in the UI's language. */\nexport function relativeTime(m: Translator, iso: string, now = Date.now()): string {\n const s = (Date.parse(iso) - now) / 1000;\n const a = Math.abs(s);\n if (a < 45) return m.t(\"time.justNow\");\n const f = new Intl.RelativeTimeFormat(m.language, { numeric: \"auto\" });\n if (a < 2700) return f.format(Math.round(s / 60), \"minute\");\n if (a < 79200) return f.format(Math.round(s / 3600), \"hour\");\n if (a < 2246400) return f.format(Math.round(s / 86400), \"day\");\n if (a < 28512000) return f.format(Math.round(s / 2592000), \"month\");\n return f.format(Math.round(s / 31536000), \"year\");\n}\n\nexport function formatDate(m: Translator, iso: string, time = true): string {\n return new Intl.DateTimeFormat(m.language, time ? { dateStyle: \"medium\", timeStyle: \"short\" } : { dateStyle: \"medium\" }).format(new Date(iso));\n}\n\n/** A relative time with the full date as its title. */\nexport function RelativeTime({ at, className }: { at: string; className?: string }) {\n const m = useMessages();\n return (\n <time dateTime={at} title={formatDate(m, at)} className={className}>\n {relativeTime(m, at)}\n </time>\n );\n}\n\n/** A user's avatar, or their initial. */\nexport function UserAvatar({ user, name, size = \"default\" }: { user?: PublicUser; name: string; size?: \"default\" | \"sm\" | \"lg\" }) {\n return (\n <Avatar size={size}>\n {user?.avatar && <AvatarImage src={user.avatar} srcSet={user.avatar_srcset} sizes={size === \"lg\" ? \"40px\" : size === \"sm\" ? \"24px\" : \"32px\"} alt=\"\" loading=\"lazy\" />}\n <AvatarFallback aria-hidden>{(name.trim()[0] ?? \"?\").toUpperCase()}</AvatarFallback>\n </Avatar>\n );\n}\n\n/** A user's name, linked when the host gives a profile URL. */\nexport function UserName({ user, name, href, className }: { user?: PublicUser; name: string; href?: (u: PublicUser) => string | undefined; className?: string }) {\n const url = user && href?.(user);\n const cls = cn(\"font-medium text-foreground\", className);\n return url ? (\n <a href={url} className={cn(cls, \"hover:underline\")}>\n {name}\n </a>\n ) : (\n <span className={cls}>{name}</span>\n );\n}\n\n/** A confirmation for a destructive action. */\nexport function ConfirmDialog(p: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n title: ReactNode;\n description?: ReactNode;\n confirm: ReactNode;\n onConfirm: () => void;\n}) {\n const { t } = useMessages();\n return (\n <AlertDialog open={p.open} onOpenChange={p.onOpenChange}>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>{p.title}</AlertDialogTitle>\n {p.description && <AlertDialogDescription>{p.description}</AlertDialogDescription>}\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>{t(\"common.cancel\")}</AlertDialogCancel>\n <AlertDialogAction\n variant=\"destructive\"\n onClick={() => {\n p.onOpenChange(false);\n p.onConfirm();\n }}\n >\n {p.confirm}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n );\n}\n\n/** A failure line, announced politely. */\nexport function ErrorLine({ error, children, className }: { error?: ContentKitError | null; children?: ReactNode; className?: string }) {\n const m = useMessages();\n if (!error && !children) return null;\n return (\n <p role=\"alert\" className={cn(\"text-sm text-destructive\", className)}>\n {children ?? contentError(m, error)}\n </p>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ContentKitClient } from '../../client/client.js';
|
|
2
|
+
import { Poll } from '../../client/generated/wire.js';
|
|
3
|
+
import { ContentKitUiAppearance } from '../../appearance.js';
|
|
4
|
+
import { ContentKitErrorHandler } from '../../react/context.js';
|
|
5
|
+
export interface PollEditorProps {
|
|
6
|
+
/** The poll to edit; none creates one. */
|
|
7
|
+
poll?: string | null;
|
|
8
|
+
/** Languages offered for a new poll: codes, or codes with labels. Without them the language is typed. */
|
|
9
|
+
languages?: readonly (string | {
|
|
10
|
+
value: string;
|
|
11
|
+
label: string;
|
|
12
|
+
})[];
|
|
13
|
+
/** A new poll's language. Default the first offered, else "en". */
|
|
14
|
+
defaultLanguage?: string;
|
|
15
|
+
/** Offer free-text polls (the host registered an answer classifier). Default false. */
|
|
16
|
+
freeText?: boolean;
|
|
17
|
+
/** Most options. Default 10. */
|
|
18
|
+
maxOptions?: number;
|
|
19
|
+
onCreated?: (poll: Poll) => void;
|
|
20
|
+
onSaved?: (poll: Poll) => void;
|
|
21
|
+
onDeleted?: () => void;
|
|
22
|
+
client?: ContentKitClient;
|
|
23
|
+
onError?: ContentKitErrorHandler;
|
|
24
|
+
className?: string;
|
|
25
|
+
appearance?: ContentKitUiAppearance;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Staff: creates or edits a poll (PollWrite): question, language, type, when
|
|
29
|
+
* it goes live and closes, visibility, a question image, and options with
|
|
30
|
+
* images, reordered with the move buttons. A new poll is written at once with
|
|
31
|
+
* its images; an existing one saves its fields with Save and each option
|
|
32
|
+
* change as it is made.
|
|
33
|
+
*/
|
|
34
|
+
export declare function PollEditor(p: PollEditorProps): import('react').JSX.Element;
|