@openrails/contentkit-ui 0.79.0 → 0.81.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (295) hide show
  1. package/README.md +82 -54
  2. package/dist/client/beacons.d.ts +53 -0
  3. package/dist/client/beacons.js +72 -0
  4. package/dist/client/beacons.js.map +1 -0
  5. package/dist/client/catalog.d.ts +2 -2
  6. package/dist/client/catalog.js +1 -1
  7. package/dist/client/catalog.js.map +1 -1
  8. package/dist/client/client.d.ts +24 -11
  9. package/dist/client/client.js +37 -29
  10. package/dist/client/client.js.map +1 -1
  11. package/dist/client/content/comments.d.ts +12 -8
  12. package/dist/client/content/comments.js +33 -20
  13. package/dist/client/content/comments.js.map +1 -1
  14. package/dist/client/content/favorites.d.ts +24 -9
  15. package/dist/client/content/favorites.js +21 -22
  16. package/dist/client/content/favorites.js.map +1 -1
  17. package/dist/client/content/moderation.d.ts +1 -1
  18. package/dist/client/content/moderation.js.map +1 -1
  19. package/dist/client/content/reactions.d.ts +11 -6
  20. package/dist/client/content/reactions.js +23 -18
  21. package/dist/client/content/reactions.js.map +1 -1
  22. package/dist/client/content/types.d.ts +40 -21
  23. package/dist/client/content/types.js +5 -2
  24. package/dist/client/content/types.js.map +1 -1
  25. package/dist/client/contents.d.ts +55 -0
  26. package/dist/client/contents.js +144 -0
  27. package/dist/client/contents.js.map +1 -0
  28. package/dist/client/discovery.d.ts +126 -0
  29. package/dist/client/discovery.js +125 -0
  30. package/dist/client/discovery.js.map +1 -0
  31. package/dist/client/generated/error-codes.d.ts +1 -1
  32. package/dist/client/generated/error-codes.js +12 -0
  33. package/dist/client/generated/error-codes.js.map +1 -1
  34. package/dist/client/generated/routes.d.ts +1244 -370
  35. package/dist/client/generated/routes.js +1870 -554
  36. package/dist/client/generated/routes.js.map +1 -1
  37. package/dist/client/generated/wire.d.ts +960 -134
  38. package/dist/client/generated/wire.js.map +1 -1
  39. package/dist/client/group-fields.d.ts +25 -0
  40. package/dist/client/group-fields.js +63 -0
  41. package/dist/client/group-fields.js.map +1 -0
  42. package/dist/client/groups.d.ts +58 -0
  43. package/dist/client/groups.js +119 -0
  44. package/dist/client/groups.js.map +1 -0
  45. package/dist/client/http.d.ts +24 -12
  46. package/dist/client/http.js +20 -24
  47. package/dist/client/http.js.map +1 -1
  48. package/dist/client/index.d.ts +11 -6
  49. package/dist/client/media/api.d.ts +1 -1
  50. package/dist/client/media/api.js +4 -2
  51. package/dist/client/media/api.js.map +1 -1
  52. package/dist/client/media/client.d.ts +8 -9
  53. package/dist/client/media/client.js +58 -71
  54. package/dist/client/media/client.js.map +1 -1
  55. package/dist/client/media/ref.d.ts +30 -0
  56. package/dist/client/media/ref.js +10 -3
  57. package/dist/client/media/ref.js.map +1 -1
  58. package/dist/client/offers.d.ts +41 -0
  59. package/dist/client/offers.js +66 -0
  60. package/dist/client/offers.js.map +1 -0
  61. package/dist/client/route.d.ts +2 -0
  62. package/dist/client/route.js +2 -1
  63. package/dist/client/route.js.map +1 -1
  64. package/dist/client/versions.d.ts +20 -0
  65. package/dist/client/versions.js +53 -0
  66. package/dist/client/versions.js.map +1 -0
  67. package/dist/client.js +35 -30
  68. package/dist/components/admin/content-manager.d.ts +80 -0
  69. package/dist/components/admin/content-manager.js +591 -0
  70. package/dist/components/admin/content-manager.js.map +1 -0
  71. package/dist/components/admin/group-manager.d.ts +24 -0
  72. package/dist/components/admin/group-manager.js +244 -0
  73. package/dist/components/admin/group-manager.js.map +1 -0
  74. package/dist/components/admin/media-item-panel.js +1 -1
  75. package/dist/components/admin/media-item-panel.js.map +1 -1
  76. package/dist/components/content/card.d.ts +44 -0
  77. package/dist/components/content/card.js +285 -0
  78. package/dist/components/content/card.js.map +1 -0
  79. package/dist/components/content/editors.d.ts +40 -0
  80. package/dist/components/content/editors.js +764 -0
  81. package/dist/components/content/editors.js.map +1 -0
  82. package/dist/components/content/filters.d.ts +28 -0
  83. package/dist/components/content/filters.js +134 -0
  84. package/dist/components/content/filters.js.map +1 -0
  85. package/dist/components/content/grid.d.ts +62 -0
  86. package/dist/components/content/grid.js +233 -0
  87. package/dist/components/content/grid.js.map +1 -0
  88. package/dist/components/content/index.d.ts +8 -0
  89. package/dist/components/content/listing.d.ts +20 -0
  90. package/dist/components/content/listing.js +150 -0
  91. package/dist/components/content/listing.js.map +1 -0
  92. package/dist/components/content/offer-fields.d.ts +8 -0
  93. package/dist/components/content/offer-fields.js +127 -0
  94. package/dist/components/content/offer-fields.js.map +1 -0
  95. package/dist/components/content/paywall.d.ts +53 -0
  96. package/dist/components/content/paywall.js +221 -0
  97. package/dist/components/content/paywall.js.map +1 -0
  98. package/dist/components/content/search.d.ts +27 -0
  99. package/dist/components/content/search.js +164 -0
  100. package/dist/components/content/search.js.map +1 -0
  101. package/dist/components/groups/banner.d.ts +51 -0
  102. package/dist/components/groups/banner.js +194 -0
  103. package/dist/components/groups/banner.js.map +1 -0
  104. package/dist/components/groups/directory.d.ts +37 -0
  105. package/dist/components/groups/directory.js +117 -0
  106. package/dist/components/groups/directory.js.map +1 -0
  107. package/dist/components/groups/editor.d.ts +44 -0
  108. package/dist/components/groups/editor.js +860 -0
  109. package/dist/components/groups/editor.js.map +1 -0
  110. package/dist/components/groups/fields.d.ts +13 -0
  111. package/dist/components/groups/fields.js +68 -0
  112. package/dist/components/groups/fields.js.map +1 -0
  113. package/dist/components/groups/header.d.ts +25 -0
  114. package/dist/components/groups/header.js +131 -0
  115. package/dist/components/groups/header.js.map +1 -0
  116. package/dist/components/groups/index.d.ts +6 -0
  117. package/dist/components/groups/memberships.d.ts +55 -0
  118. package/dist/components/groups/memberships.js +527 -0
  119. package/dist/components/groups/memberships.js.map +1 -0
  120. package/dist/components/groups/parts.d.ts +49 -0
  121. package/dist/components/groups/parts.js +172 -0
  122. package/dist/components/groups/parts.js.map +1 -0
  123. package/dist/components/media-folder-editor.js +153 -152
  124. package/dist/components/media-folder-editor.js.map +1 -1
  125. package/dist/components/social/comments.d.ts +7 -5
  126. package/dist/components/social/comments.js +6 -2
  127. package/dist/components/social/comments.js.map +1 -1
  128. package/dist/components/social/engagement.d.ts +4 -3
  129. package/dist/components/social/engagement.js.map +1 -1
  130. package/dist/components/social/moderation.d.ts +1 -1
  131. package/dist/components/social/moderation.js +3 -3
  132. package/dist/components/social/moderation.js.map +1 -1
  133. package/dist/editor/rich-text-editor.d.ts +4 -4
  134. package/dist/editor/rich-text-editor.js.map +1 -1
  135. package/dist/index.d.ts +4 -2
  136. package/dist/index.js +23 -9
  137. package/dist/locales/admin/de.js +5 -66
  138. package/dist/locales/admin/de.js.map +1 -1
  139. package/dist/locales/admin/en.d.ts +5 -66
  140. package/dist/locales/admin/en.js +19 -80
  141. package/dist/locales/admin/en.js.map +1 -1
  142. package/dist/locales/admin/es.js +5 -66
  143. package/dist/locales/admin/es.js.map +1 -1
  144. package/dist/locales/admin/ja.js +5 -66
  145. package/dist/locales/admin/ja.js.map +1 -1
  146. package/dist/locales/admin/ko.js +5 -66
  147. package/dist/locales/admin/ko.js.map +1 -1
  148. package/dist/locales/admin/zh.js +5 -66
  149. package/dist/locales/admin/zh.js.map +1 -1
  150. package/dist/locales/content/de.d.ts +2 -0
  151. package/dist/locales/content/de.js +98 -0
  152. package/dist/locales/content/de.js.map +1 -0
  153. package/dist/locales/content/en.d.ts +93 -0
  154. package/dist/locales/content/en.js +98 -0
  155. package/dist/locales/content/en.js.map +1 -0
  156. package/dist/locales/content/es.d.ts +2 -0
  157. package/dist/locales/content/es.js +98 -0
  158. package/dist/locales/content/es.js.map +1 -0
  159. package/dist/locales/content/ja.d.ts +2 -0
  160. package/dist/locales/content/ja.js +98 -0
  161. package/dist/locales/content/ja.js.map +1 -0
  162. package/dist/locales/content/ko.d.ts +2 -0
  163. package/dist/locales/content/ko.js +98 -0
  164. package/dist/locales/content/ko.js.map +1 -0
  165. package/dist/locales/content/zh.d.ts +2 -0
  166. package/dist/locales/content/zh.js +98 -0
  167. package/dist/locales/content/zh.js.map +1 -0
  168. package/dist/locales/de.js +11 -2
  169. package/dist/locales/de.js.map +1 -1
  170. package/dist/locales/discovery/de.d.ts +2 -0
  171. package/dist/locales/discovery/de.js +68 -0
  172. package/dist/locales/discovery/de.js.map +1 -0
  173. package/dist/locales/discovery/en.d.ts +63 -0
  174. package/dist/locales/discovery/en.js +68 -0
  175. package/dist/locales/discovery/en.js.map +1 -0
  176. package/dist/locales/discovery/es.d.ts +2 -0
  177. package/dist/locales/discovery/es.js +68 -0
  178. package/dist/locales/discovery/es.js.map +1 -0
  179. package/dist/locales/discovery/ja.d.ts +2 -0
  180. package/dist/locales/discovery/ja.js +68 -0
  181. package/dist/locales/discovery/ja.js.map +1 -0
  182. package/dist/locales/discovery/ko.d.ts +2 -0
  183. package/dist/locales/discovery/ko.js +68 -0
  184. package/dist/locales/discovery/ko.js.map +1 -0
  185. package/dist/locales/discovery/zh.d.ts +2 -0
  186. package/dist/locales/discovery/zh.js +68 -0
  187. package/dist/locales/discovery/zh.js.map +1 -0
  188. package/dist/locales/en.d.ts +288 -67
  189. package/dist/locales/en.js +11 -2
  190. package/dist/locales/en.js.map +1 -1
  191. package/dist/locales/es.js +11 -2
  192. package/dist/locales/es.js.map +1 -1
  193. package/dist/locales/groups/de.d.ts +2 -0
  194. package/dist/locales/groups/de.js +133 -0
  195. package/dist/locales/groups/de.js.map +1 -0
  196. package/dist/locales/groups/en.d.ts +128 -0
  197. package/dist/locales/groups/en.js +133 -0
  198. package/dist/locales/groups/en.js.map +1 -0
  199. package/dist/locales/groups/es.d.ts +2 -0
  200. package/dist/locales/groups/es.js +133 -0
  201. package/dist/locales/groups/es.js.map +1 -0
  202. package/dist/locales/groups/ja.d.ts +2 -0
  203. package/dist/locales/groups/ja.js +133 -0
  204. package/dist/locales/groups/ja.js.map +1 -0
  205. package/dist/locales/groups/ko.d.ts +2 -0
  206. package/dist/locales/groups/ko.js +133 -0
  207. package/dist/locales/groups/ko.js.map +1 -0
  208. package/dist/locales/groups/zh.d.ts +2 -0
  209. package/dist/locales/groups/zh.js +133 -0
  210. package/dist/locales/groups/zh.js.map +1 -0
  211. package/dist/locales/ja.js +11 -2
  212. package/dist/locales/ja.js.map +1 -1
  213. package/dist/locales/ko.js +11 -2
  214. package/dist/locales/ko.js.map +1 -1
  215. package/dist/locales/social/de.js +2 -1
  216. package/dist/locales/social/de.js.map +1 -1
  217. package/dist/locales/social/en.d.ts +2 -1
  218. package/dist/locales/social/en.js +2 -1
  219. package/dist/locales/social/en.js.map +1 -1
  220. package/dist/locales/social/es.js +2 -1
  221. package/dist/locales/social/es.js.map +1 -1
  222. package/dist/locales/social/ja.js +2 -1
  223. package/dist/locales/social/ja.js.map +1 -1
  224. package/dist/locales/social/ko.js +2 -1
  225. package/dist/locales/social/ko.js.map +1 -1
  226. package/dist/locales/social/zh.js +2 -1
  227. package/dist/locales/social/zh.js.map +1 -1
  228. package/dist/locales/zh.js +11 -2
  229. package/dist/locales/zh.js.map +1 -1
  230. package/dist/react/admin.d.ts +1 -1
  231. package/dist/react/admin.js +8 -6
  232. package/dist/react/admin.js.map +1 -1
  233. package/dist/react/comments.d.ts +9 -7
  234. package/dist/react/comments.js +42 -27
  235. package/dist/react/comments.js.map +1 -1
  236. package/dist/react/contents.d.ts +57 -0
  237. package/dist/react/contents.js +214 -0
  238. package/dist/react/contents.js.map +1 -0
  239. package/dist/react/context.d.ts +1 -1
  240. package/dist/react/context.js.map +1 -1
  241. package/dist/react/crop.js +45 -44
  242. package/dist/react/crop.js.map +1 -1
  243. package/dist/react/detail.d.ts +30 -0
  244. package/dist/react/detail.js +42 -0
  245. package/dist/react/detail.js.map +1 -0
  246. package/dist/react/discovery.d.ts +138 -0
  247. package/dist/react/discovery.js +299 -0
  248. package/dist/react/discovery.js.map +1 -0
  249. package/dist/react/engagement.d.ts +5 -5
  250. package/dist/react/engagement.js +55 -41
  251. package/dist/react/engagement.js.map +1 -1
  252. package/dist/react/folder.js +54 -53
  253. package/dist/react/folder.js.map +1 -1
  254. package/dist/react/groups.d.ts +115 -0
  255. package/dist/react/groups.js +229 -0
  256. package/dist/react/groups.js.map +1 -0
  257. package/dist/react/index.d.ts +5 -1
  258. package/dist/react/public.d.ts +6 -5
  259. package/dist/react/public.js +19 -22
  260. package/dist/react/public.js.map +1 -1
  261. package/dist/react/read.js +105 -106
  262. package/dist/react/read.js.map +1 -1
  263. package/dist/react/resources.d.ts +2 -2
  264. package/dist/react/resources.js +69 -40
  265. package/dist/react/resources.js.map +1 -1
  266. package/dist/react/store.js +41 -39
  267. package/dist/react/store.js.map +1 -1
  268. package/dist/react/upload.js +54 -53
  269. package/dist/react/upload.js.map +1 -1
  270. package/dist/react/use-resource.d.ts +2 -1
  271. package/dist/react/use-resource.js +1 -0
  272. package/dist/react/use-resource.js.map +1 -1
  273. package/dist/react/versions.d.ts +57 -0
  274. package/dist/react/versions.js +94 -0
  275. package/dist/react/versions.js.map +1 -0
  276. package/dist/react/video.js +87 -86
  277. package/dist/react/video.js.map +1 -1
  278. package/dist/react.js +9 -5
  279. package/dist/styles.css +1 -1
  280. package/package.json +1 -1
  281. package/dist/client/content/posts.d.ts +0 -52
  282. package/dist/client/content/posts.js +0 -84
  283. package/dist/client/content/posts.js.map +0 -1
  284. package/dist/client/taxonomy.d.ts +0 -34
  285. package/dist/client/taxonomy.js +0 -84
  286. package/dist/client/taxonomy.js.map +0 -1
  287. package/dist/components/admin/post-manager.d.ts +0 -45
  288. package/dist/components/admin/post-manager.js +0 -602
  289. package/dist/components/admin/post-manager.js.map +0 -1
  290. package/dist/components/admin/taxonomy-manager.d.ts +0 -54
  291. package/dist/components/admin/taxonomy-manager.js +0 -976
  292. package/dist/components/admin/taxonomy-manager.js.map +0 -1
  293. package/dist/react/posts.d.ts +0 -61
  294. package/dist/react/posts.js +0 -183
  295. package/dist/react/posts.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"media-folder-editor.js","names":[],"sources":["../../src/components/media-folder-editor.tsx"],"sourcesContent":["import {\n Alert02Icon,\n CropIcon,\n Delete02Icon,\n Edit02Icon,\n File01Icon,\n Image01Icon,\n ImageAdd01Icon,\n Loading03Icon,\n MusicNote01Icon,\n Refresh01Icon,\n RepeatIcon,\n Video01Icon,\n} from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon, type IconSvgElement } from \"@hugeicons/react\";\nimport { cn } from \"cn\";\nimport { useEffect, useImperativeHandle, useMemo, useRef, useState, type DragEvent, type ReactNode, type Ref } from \"react\";\nimport type { ContentKitUiAppearance } from \"../appearance.js\";\nimport type { AspectRatio } from \"../client/aspect.js\";\nimport { failureError } from \"../client/errors.js\";\nimport { isAudioType, isImageType, isSubtitleType, isVideoType } from \"../client/gallery.js\";\nimport type { FileInfo, RefBody, UploadRule } from \"../client/generated/wire.js\";\nimport { stem } from \"../client/media/client.js\";\nimport type { QueueItem } from \"../client/media/queue.js\";\nimport { acceptOf, ratioLabel } from \"../client/media/rules.js\";\nimport { isProcessing } from \"../client/media/windows.js\";\nimport { useMessages } from \"../i18n/context.js\";\nimport { megabytes, type Translator } from \"../i18n/messages.js\";\nimport { useEditorCrop } from \"../react/crop.js\";\nimport { nameIn, thumbnailOf, useMediaFolder, type FolderGroup, type MediaFolderOptions, type UseMediaFolder } from \"../react/folder.js\";\nimport { ContentKitUiRoot } from \"../scope.js\";\nimport { Alert, AlertDescription, AlertTitle } from \"#ckui/ui/alert\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Progress } from \"#ckui/ui/progress\";\nimport { EncodeProgress } from \"./encode-progress.js\";\nimport { ImageCropDialog } from \"./image-crop-dialog.js\";\nimport { progressLabel, progressValue } from \"./progress.js\";\nimport { SortableList } from \"./sortable-list.js\";\n\nexport interface MediaFolderEditorHandle {\n /** Stops every upload and empties the queue (before deleting a draft). */\n discard: () => void;\n /** Commits the uploaded files (commit=\"manual\"). */\n commit: () => Promise<FileInfo[]>;\n /** The folder's state and updates. */\n folder: UseMediaFolder;\n}\n\nexport interface MediaFolderEditorViewProps {\n ref?: Ref<MediaFolderEditorHandle>;\n /** Heading; default \"Media\". */\n label?: ReactNode;\n /** Beside \"Add files\" in the header, e.g. a ZIP import. */\n toolbar?: ReactNode;\n /** Extra actions on each upload, beside crop, rename, replace and remove. */\n rowActions?: (file: FileInfo) => ReactNode;\n /** Below the lists, e.g. what readers without access see. */\n footer?: ReactNode;\n /** Shapes offered when cropping an image whose path has no preset shape; \"\" is the original's. */\n aspects?: readonly AspectRatio[];\n /** Asked before removing selected uploads; default the browser's confirm; false skips it. */\n confirmRemove?: ((count: number) => boolean | Promise<boolean>) | false;\n disabled?: boolean;\n className?: string;\n appearance?: ContentKitUiAppearance;\n}\n\n/**\n * Either the item, and the editor opens its folder with the options; or a\n * folder the host opened (`folder={useMediaFolder(ref, options)}`), whose\n * state the host reads and renders with.\n */\nexport type MediaFolderEditorProps = MediaFolderEditorViewProps &\n (\n | ({\n /** The item whose folder this edits. */\n item: RefBody;\n folder?: never;\n } & MediaFolderOptions)\n | ({\n /** The host's folder (useMediaFolder); its ref may be null until the item exists. */\n folder: UseMediaFolder;\n item?: never;\n } & { [K in keyof MediaFolderOptions]?: never })\n );\n\nconst ASPECTS: readonly AspectRatio[] = [\"\", \"1:1\", \"4:5\", \"16:9\"];\n\ntype Kind = \"image\" | \"video\" | \"audio\" | \"subtitle\" | \"file\";\n\nfunction kindOf(type: string | undefined): Kind {\n if (isImageType(type)) return \"image\";\n if (isVideoType(type)) return \"video\";\n if (isAudioType(type)) return \"audio\";\n if (isSubtitleType(type)) return \"subtitle\";\n return \"file\";\n}\n\nconst ICONS: Record<Kind, IconSvgElement> = { image: Image01Icon, video: Video01Icon, audio: MusicNote01Icon, subtitle: File01Icon, file: File01Icon };\n\n/** What a rule takes: one kind when every type is of it, else files. */\nfunction ruleKind(rule: UploadRule | undefined): Kind {\n const kinds = new Set((rule?.types ?? []).map(kindOf));\n return kinds.size === 1 ? [...kinds][0]! : \"file\";\n}\n\n/** The rules as a sentence for the drop zone: sizes, caps and video shapes. */\nexport function describeRules(t: Translator[\"t\"], rules: readonly UploadRule[]): string {\n const parts: string[] = [];\n for (const r of rules) {\n if (!r.types.length) continue;\n const what = t(`folder.kinds.${ruleKind(r)}`);\n const size = r.max_bytes > 0 ? t(\"folder.limitSize\", { what, size: megabytes(r.max_bytes) }) : what;\n parts.push(r.max ? `${size}, ${t(\"folder.limitMax\", { max: r.max })}` : size);\n if (r.min_aspect && r.max_aspect) parts.push(t(\"folder.limitAspect\", { min: ratioLabel(r.min_aspect), max: ratioLabel(r.max_aspect) }));\n }\n return parts.join(\" · \");\n}\n\n/**\n * An item's folder for its editors: drop or pick files (screened against the\n * kind's upload rules), a queue with progress, retry and remove, and each\n * upload path's uploads as a sortable list with thumbnail, name, edited\n * badge, encode progress and failures; crop, rename, replace and bulk\n * remove. commit=\"manual\" adds the queue with \"Add N\"; \"auto\" commits as\n * files finish (a draft; discard() through the ref).\n */\nexport function MediaFolderEditor(p: MediaFolderEditorProps) {\n // Editor state (selection, crop, rename) belongs to one item.\n if (p.folder) {\n const { folder, ...view } = p;\n return <FolderView key={folder.ref ? `${folder.ref.kind}/${folder.ref.id}` : \"\"} folder={folder} {...view} />;\n }\n // The queue belongs to one item: another item gets a fresh editor.\n return <OwnFolder key={`${p.item.kind}/${p.item.id}`} {...p} />;\n}\n\nfunction OwnFolder(p: MediaFolderEditorViewProps & MediaFolderOptions & { item: RefBody }) {\n const { item, ref, label, toolbar, rowActions, footer, aspects, confirmRemove, disabled, className, appearance, ...options } = p;\n const folder = useMediaFolder(item, options);\n return <FolderView {...{ folder, ref, label, toolbar, rowActions, footer, aspects, confirmRemove, disabled, className, appearance }} />;\n}\n\nconst NO_ITEM: RefBody = { kind: \"\", id: \"\" };\n\nfunction FolderView(p: MediaFolderEditorViewProps & { folder: UseMediaFolder }) {\n const { folder, ref, label, toolbar, rowActions, footer, aspects = ASPECTS, confirmRemove, disabled, className, appearance } = p;\n const { t, error: errorText } = useMessages();\n const { groups, queue, read, options } = folder;\n useImperativeHandle(ref, () => ({ discard: folder.discard, commit: folder.commit, folder }), [folder]);\n const auto = options.commit === \"auto\";\n const rules = groups.flatMap((g) => (g.rule ? [g.rule] : []));\n const accept = acceptOf(rules);\n const count = folder.uploads.length + queue.items.length + folder.waiting.length;\n const empty = count === 0;\n const off = !!disabled;\n\n const [selected, setSelected] = useState<ReadonlySet<string>>(new Set());\n useEffect(() => {\n const paths = new Set(folder.uploads.map((f) => f.path));\n setSelected((s) => ([...s].every((x) => paths.has(x)) ? s : new Set([...s].filter((x) => paths.has(x)))));\n }, [folder.uploads]);\n const [cropping, setCropping] = useState<string | null>(null);\n const crop = useEditorCrop(folder.ref ?? NO_ITEM, cropping, { client: options.client, onError: options.onError, onSaved: () => setCropping(null) });\n const cropRule = cropping ? groups.find((g) => g.files.some((f) => f.path === cropping))?.rule : undefined;\n const [renaming, setRenaming] = useState<string | null>(null);\n const replaceInput = useRef<HTMLInputElement>(null);\n const [replacing, setReplacing] = useState<string | null>(null);\n const [over, setOver] = useState(false);\n\n const drop = {\n onDragOver: (e: DragEvent) => {\n if (off || !e.dataTransfer.types.includes(\"Files\")) return;\n e.preventDefault();\n setOver(true);\n },\n onDragLeave: (e: DragEvent) => {\n if (!e.currentTarget.contains(e.relatedTarget as Node | null)) setOver(false);\n },\n onDrop: (e: DragEvent) => {\n if (off || !e.dataTransfer.files.length) return;\n e.preventDefault();\n setOver(false);\n folder.add(e.dataTransfer.files);\n },\n };\n\n const removeSelected = async () => {\n const paths = [...selected];\n const ok = confirmRemove === false ? true : confirmRemove ? await confirmRemove(paths.length) : globalThis.confirm?.(t(\"folder.confirmRemove\", { count: paths.length })) ?? true;\n if (!ok) return;\n await folder.remove(paths).then(() => setSelected(new Set()), () => {});\n };\n\n const uploaded = queue.items.filter((i) => i.status === \"uploaded\").length;\n const picker = (big: boolean) => (\n <label\n className={cn(\n big\n ? \"flex cursor-pointer flex-col items-center justify-center gap-2 rounded-lg border border-dashed border-border px-4 py-8 text-center text-sm text-muted-foreground transition-colors hover:border-primary hover:bg-primary/5\"\n : \"inline-flex h-8 cursor-pointer items-center gap-1.5 rounded-md border border-border bg-background px-2.5 text-sm font-medium transition-colors hover:bg-muted focus-within:ring-3 focus-within:ring-ring/50\",\n big && over && \"border-primary bg-primary/5\",\n off && \"pointer-events-none opacity-50\",\n )}\n data-ckui={big ? \"folder-drop\" : \"folder-add\"}\n >\n <HugeiconsIcon icon={ImageAdd01Icon} strokeWidth={1.75} className={big ? \"size-7\" : \"size-4\"} />\n {big ? <strong className=\"font-medium text-foreground\">{t(\"folder.drop\")}</strong> : t(\"folder.add\")}\n {big && rules.length > 0 && <span className=\"text-xs\">{describeRules(t, rules)}</span>}\n <input\n type=\"file\"\n multiple\n accept={accept}\n className=\"sr-only\"\n disabled={off}\n data-ckui=\"file\"\n onChange={(e) => {\n folder.add([...(e.target.files ?? [])]);\n e.target.value = \"\";\n }}\n />\n </label>\n );\n\n return (\n <ContentKitUiRoot appearance={appearance} className={cn(\"grid gap-3\", className)} data-ckui=\"media-folder\" data-over={over ? \"\" : undefined} {...drop}>\n <div className=\"flex flex-wrap items-center justify-between gap-2\" data-ckui=\"folder-header\">\n <h3 className=\"text-sm font-semibold\">{label ?? t(\"folder.label\")}</h3>\n <div className=\"flex flex-wrap items-center gap-2\">\n {toolbar}\n {!empty && picker(false)}\n </div>\n </div>\n {empty && (read.read || !folder.ref) && picker(true)}\n {empty && !read.read && read.loading && (\n <div className=\"flex justify-center py-6 text-muted-foreground\" data-ckui=\"folder-loading\">\n <HugeiconsIcon icon={Loading03Icon} strokeWidth={2} className=\"size-5 motion-safe:animate-spin\" />\n </div>\n )}\n\n {folder.refused.length > 0 && (\n <Alert variant=\"destructive\" role=\"alert\" data-ckui=\"folder-refused\">\n <HugeiconsIcon icon={Alert02Icon} strokeWidth={2} />\n <AlertDescription>\n <ul className=\"grid gap-0.5\">\n {folder.refused.map((r, i) => (\n <li key={i}>\n <span className=\"font-medium\">{r.file.name}</span>: {errorText(r.error)}\n </li>\n ))}\n </ul>\n <Button variant=\"outline\" size=\"xs\" className=\"mt-1 w-fit\" onClick={folder.dismiss}>\n {t(\"folder.dismiss\")}\n </Button>\n </AlertDescription>\n </Alert>\n )}\n {queue.blocked && (\n <Alert variant=\"destructive\" role=\"alert\" data-ckui=\"folder-paused\">\n <HugeiconsIcon icon={Alert02Icon} strokeWidth={2} />\n <AlertTitle>{t(\"folder.paused\")}</AlertTitle>\n <AlertDescription>\n {errorText(queue.blocked)}\n <Button variant=\"outline\" size=\"xs\" className=\"mt-1 w-fit\" onClick={() => queue.start()}>\n {t(\"folder.resume\")}\n </Button>\n </AlertDescription>\n </Alert>\n )}\n {folder.error && (\n <Alert variant=\"destructive\" role=\"alert\" data-ckui=\"folder-error\">\n <HugeiconsIcon icon={Alert02Icon} strokeWidth={2} />\n <AlertDescription>{errorText(folder.error)}</AlertDescription>\n </Alert>\n )}\n\n {selected.size > 0 && (\n <div className=\"flex flex-wrap items-center gap-2 rounded-md bg-muted px-3 py-1.5 text-sm\" data-ckui=\"folder-selection\">\n <span className=\"tabular-nums\">{t(\"folder.selected\", { count: selected.size })}</span>\n <Button variant=\"destructive\" size=\"xs\" disabled={off || folder.updating} onClick={() => void removeSelected()}>\n <HugeiconsIcon icon={Delete02Icon} strokeWidth={2} />\n {t(\"folder.removeSelected\")}\n </Button>\n <Button variant=\"ghost\" size=\"xs\" onClick={() => setSelected(new Set())}>\n {t(\"folder.clearSelection\")}\n </Button>\n </div>\n )}\n\n {groups.map((g) =>\n g.files.length ? (\n <Group\n key={g.path}\n group={g}\n titled={groups.length > 1}\n folder={folder}\n disabled={off}\n selected={selected}\n onSelect={(path, on) => setSelected((s) => (on ? new Set([...s, path]) : new Set([...s].filter((x) => x !== path))))}\n renaming={renaming}\n onRename={setRenaming}\n onCrop={setCropping}\n onReplace={(path) => {\n setReplacing(path);\n replaceInput.current?.click();\n }}\n rowActions={rowActions}\n />\n ) : null,\n )}\n\n {folder.waiting.length > 0 && (\n <ul className=\"grid\" aria-label={t(\"folder.label\")}>\n {folder.waiting.map((f, i) => (\n <li key={i} className=\"flex min-h-11 items-center gap-2 px-1\" data-ckui=\"queue-row\" data-status=\"waiting\">\n <Thumb kind={kindOf(f.type)} />\n <div className=\"grid min-w-0 flex-1 gap-1\">\n <span className=\"truncate text-sm\">{f.name}</span>\n <span className=\"text-xs text-muted-foreground\" data-ckui=\"queue-status\">\n {t(\"folder.queued\")}\n </span>\n </div>\n </li>\n ))}\n </ul>\n )}\n\n {queue.items.length > 0 && (\n <SortableList\n items={queue.items}\n id={(i) => i.id}\n name={(i) => i.file.name}\n disabled={auto || off}\n label={t(\"folder.label\")}\n onMove={(from, to) => queue.move(queue.items[from]!.id, to)}\n row={(i) => ({ className: \"flex min-h-11 items-center gap-2 px-1\", \"data-ckui\": \"queue-row\", \"data-status\": i.status })}\n >\n {(i, handle) => <QueueRow item={i} handle={auto ? null : handle} auto={auto} folder={folder} />}\n </SortableList>\n )}\n\n {((!auto && uploaded > 0) || (auto && folder.error && uploaded > 0)) && (\n <Button className=\"w-fit\" disabled={off || !queue.ready || folder.committing} onClick={() => void folder.commit().catch(() => {})} data-ckui=\"folder-commit\">\n {folder.committing && <HugeiconsIcon icon={Loading03Icon} strokeWidth={2} className=\"motion-safe:animate-spin\" />}\n {auto ? t(\"folder.commitAgain\") : t(\"folder.commit\", { count: queue.items.filter((i) => i.status !== \"committed\").length })}\n </Button>\n )}\n {footer}\n\n <input\n ref={replaceInput}\n type=\"file\"\n accept={accept}\n className=\"sr-only\"\n tabIndex={-1}\n aria-hidden\n onChange={(e) => {\n const f = e.target.files?.[0];\n e.target.value = \"\";\n if (f && replacing) void folder.replace(replacing, f).catch(() => {});\n setReplacing(null);\n }}\n />\n <ImageCropDialog\n open={!!cropping}\n onOpenChange={(o) => !o && crop.status !== \"saving\" && setCropping(null)}\n source={\"source\" in crop ? (crop.source ?? null) : null}\n aspect={cropRule?.aspect ?? \"\"}\n aspects={cropRule?.aspect ? undefined : aspects}\n initialEdit={\"edit\" in crop ? crop.edit : null}\n minWidth={cropRule?.min_width}\n title={t(\"folder.crop\")}\n busy={crop.status === \"saving\"}\n error={crop.status === \"error\" ? errorText(crop.error) : undefined}\n onConfirm={(edit) => void crop.save(edit)}\n />\n </ContentKitUiRoot>\n );\n}\n\nfunction Group({\n group,\n titled,\n folder,\n disabled,\n selected,\n onSelect,\n renaming,\n onRename,\n onCrop,\n onReplace,\n rowActions,\n}: {\n group: FolderGroup;\n titled: boolean;\n folder: UseMediaFolder;\n disabled: boolean;\n selected: ReadonlySet<string>;\n onSelect: (path: string, on: boolean) => void;\n renaming: string | null;\n onRename: (path: string | null) => void;\n onCrop: (path: string) => void;\n onReplace: (path: string) => void;\n rowActions?: (file: FileInfo) => ReactNode;\n}) {\n const { t } = useMessages();\n const kind = ruleKind(group.rule);\n const title = t(`folder.kinds.${kind}`);\n const max = group.rule?.max;\n return (\n <section className=\"grid gap-1\" data-ckui=\"folder-group\" data-path={group.path}>\n {titled && (\n <h4 className=\"px-1 text-xs font-medium text-muted-foreground tabular-nums\">\n {title} · {max ? `${group.files.length} / ${max}` : group.files.length}\n </h4>\n )}\n <SortableList\n items={group.files}\n id={(f) => f.path}\n name={(f) => nameIn(group, f.path)}\n disabled={disabled || folder.updating}\n label={title}\n onMove={(from, to) => void folder.move(group.files[from]!.path, to).catch(() => {})}\n row={(f) => ({ className: \"flex min-h-12 items-center gap-2 px-1\", \"data-ckui\": \"upload-row\", \"data-path\": f.path })}\n >\n {(f, handle) => (\n <UploadRow\n file={f}\n group={group}\n handle={handle}\n folder={folder}\n disabled={disabled}\n selected={selected.has(f.path)}\n onSelect={(on) => onSelect(f.path, on)}\n renaming={renaming === f.path}\n onRename={onRename}\n onCrop={onCrop}\n onReplace={onReplace}\n actions={rowActions?.(f)}\n />\n )}\n </SortableList>\n </section>\n );\n}\n\nfunction Thumb({ kind, url, busy }: { kind: Kind; url?: string; busy?: boolean }) {\n return (\n <span className=\"relative flex size-10 shrink-0 items-center justify-center overflow-hidden rounded-md bg-muted text-muted-foreground\" data-ckui=\"thumb\">\n {url ? <img src={url} alt=\"\" loading=\"lazy\" decoding=\"async\" className=\"size-full object-cover\" /> : <HugeiconsIcon icon={ICONS[kind]} strokeWidth={1.75} className=\"size-4.5\" />}\n {busy && !url && <span aria-hidden className=\"absolute inset-1.5 rounded-full border-2 border-current/25 border-t-current motion-safe:animate-spin\" />}\n </span>\n );\n}\n\nfunction UploadRow({\n file: f,\n group,\n handle,\n folder,\n disabled,\n selected,\n onSelect,\n renaming,\n onRename,\n onCrop,\n onReplace,\n actions,\n}: {\n file: FileInfo;\n group: FolderGroup;\n handle: ReactNode;\n folder: UseMediaFolder;\n disabled: boolean;\n selected: boolean;\n onSelect: (on: boolean) => void;\n renaming: boolean;\n onRename: (path: string | null) => void;\n onCrop: (path: string) => void;\n onReplace: (path: string) => void;\n actions?: ReactNode;\n}) {\n const { t, error: errorText } = useMessages();\n const kind = kindOf(f.type);\n const name = nameIn(group, f.path);\n const busy = isProcessing(f);\n const thumb = useMemo(() => thumbnailOf(folder.read.read, f), [folder.read.read, f]);\n const locked = disabled || folder.updating;\n const failure = f.failed ? errorText(failureError(f.failed)) : undefined;\n return (\n <>\n {handle}\n <input\n type=\"checkbox\"\n className=\"size-4 shrink-0 accent-primary\"\n checked={selected}\n disabled={disabled}\n aria-label={t(\"folder.select\", { name })}\n onChange={(e) => onSelect(e.target.checked)}\n />\n <Thumb kind={kind} url={thumb?.url} busy={busy} />\n <div className=\"grid min-w-0 flex-1 gap-1\">\n <div className=\"flex min-w-0 flex-wrap items-center gap-x-2 gap-y-0.5\">\n {renaming ? (\n <RenameInput name={stem(name)} label={t(\"folder.renameLabel\", { name })} onDone={(to) => (to === null ? onRename(null) : folder.rename(f.path, to).then(() => onRename(null)))} />\n ) : (\n <span className=\"max-w-full truncate text-sm\" title={f.path} data-ckui=\"upload-name\">\n {name}\n </span>\n )}\n {f.edit && (\n <span className=\"shrink-0 rounded-sm border border-border px-1.5 text-[11px] text-muted-foreground\" data-ckui=\"edited\">\n {t(\"folder.edited\")}\n </span>\n )}\n {failure && (\n <span className=\"shrink-0 rounded-sm bg-destructive/10 px-1.5 text-[11px] font-medium text-destructive\" title={failure} data-ckui=\"failed\">\n {kind === \"video\" ? t(\"folder.failedVideo\") : t(\"folder.failed\")}\n </span>\n )}\n </div>\n {failure && <p className=\"text-xs text-destructive\">{failure}</p>}\n {busy && kind === \"video\" && <EncodeProgress progress={f.progress} className=\"max-w-sm text-xs\" />}\n {busy && kind !== \"video\" && <span className=\"text-xs text-muted-foreground\">{t(\"folder.processing\")}</span>}\n </div>\n <span className=\"flex shrink-0 items-center gap-0.5\" data-ckui=\"upload-actions\">\n {actions}\n {kind === \"image\" && (\n <Button variant=\"ghost\" size=\"icon-sm\" aria-label={t(\"folder.crop\")} title={t(\"folder.crop\")} disabled={locked || !!f.staged || !f.size} onClick={() => onCrop(f.path)}>\n <HugeiconsIcon icon={CropIcon} strokeWidth={2} />\n </Button>\n )}\n {!group.rule?.named && (\n <Button variant=\"ghost\" size=\"icon-sm\" aria-label={t(\"common.rename\")} title={t(\"common.rename\")} disabled={locked} onClick={() => onRename(f.path)}>\n <HugeiconsIcon icon={Edit02Icon} strokeWidth={2} />\n </Button>\n )}\n <Button variant=\"ghost\" size=\"icon-sm\" aria-label={t(\"common.replace\")} title={t(\"common.replace\")} disabled={locked} onClick={() => onReplace(f.path)}>\n <HugeiconsIcon icon={RepeatIcon} strokeWidth={2} />\n </Button>\n <Button variant=\"ghost\" size=\"icon-sm\" aria-label={t(\"common.remove\")} title={t(\"common.remove\")} disabled={locked} onClick={() => void folder.remove([f.path]).catch(() => {})}>\n <HugeiconsIcon icon={Delete02Icon} strokeWidth={2} />\n </Button>\n </span>\n </>\n );\n}\n\nfunction RenameInput({ name, label, onDone }: { name: string; label: string; onDone: (to: string | null) => unknown }) {\n const [value, setValue] = useState(name);\n const done = useRef(false);\n const finish = (to: string | null) => {\n if (done.current) return;\n done.current = true;\n Promise.resolve(onDone(to && to.trim() && to.trim() !== name ? to.trim() : null)).catch(() => (done.current = false));\n };\n return (\n <input\n autoFocus\n aria-label={label}\n value={value}\n className=\"h-7 min-w-0 flex-1 rounded-md border border-input bg-background px-2 text-sm outline-none focus-visible:ring-3 focus-visible:ring-ring/50\"\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n e.preventDefault();\n finish(value);\n } else if (e.key === \"Escape\") {\n e.preventDefault();\n finish(null);\n }\n }}\n onBlur={() => finish(value)}\n data-ckui=\"rename\"\n />\n );\n}\n\nfunction queueLabel(t: Translator[\"t\"], errorText: Translator[\"error\"], i: QueueItem, auto: boolean): string {\n if (i.status === \"failed\") return errorText(i.error);\n if (i.status === \"uploading\") return progressLabel(t, i.progress);\n if (i.status === \"uploaded\") {\n const p = i.processing;\n if (p?.failed) return errorText(failureError(p.failed));\n if (i.unattached && !i.processed) return p?.progress && p.progress.phase !== \"queued\" ? t(\"folder.processingPercent\", { percent: Math.round(p.progress.percent) }) : t(\"folder.processing\");\n return auto ? t(\"folder.adding\") : t(\"folder.uploaded\");\n }\n return i.status === \"committed\" ? t(\"folder.adding\") : t(\"folder.queued\");\n}\n\nfunction QueueRow({ item: i, handle, auto, folder }: { item: QueueItem; handle: ReactNode; auto: boolean; folder: UseMediaFolder }) {\n const { t, error: errorText } = useMessages();\n const { queue } = folder;\n const kind = kindOf(i.file.type);\n const label = queueLabel(t, errorText, i, auto);\n const value = i.status === \"uploading\" ? progressValue(i.progress) : i.unattached && !i.processed && i.processing?.progress ? i.processing.progress.percent : null;\n return (\n <>\n {handle}\n <Thumb kind={kind} busy={i.status === \"uploading\" || (!!i.unattached && !i.processed)} />\n <div className=\"grid min-w-0 flex-1 gap-1\">\n <span className=\"truncate text-sm\" title={i.path}>\n {i.file.name}\n </span>\n {value !== null && <Progress value={value} aria-label={label} className=\"max-w-sm\" />}\n <span className={cn(\"text-xs\", i.status === \"failed\" ? \"text-destructive\" : \"text-muted-foreground\")} data-ckui=\"queue-status\">\n {label}\n </span>\n </div>\n <span className=\"flex shrink-0 items-center gap-0.5\">\n {i.status === \"failed\" && (\n <Button variant=\"ghost\" size=\"icon-sm\" aria-label={t(\"common.retry\")} title={t(\"common.retry\")} onClick={() => queue.retry(i.id)}>\n <HugeiconsIcon icon={Refresh01Icon} strokeWidth={2} />\n </Button>\n )}\n <Button variant=\"ghost\" size=\"icon-sm\" aria-label={t(\"common.remove\")} title={t(\"common.remove\")} onClick={() => queue.remove(i.id)}>\n <HugeiconsIcon icon={Delete02Icon} strokeWidth={2} />\n </Button>\n </span>\n </>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"media-folder-editor.js","names":[],"sources":["../../src/components/media-folder-editor.tsx"],"sourcesContent":["import {\n Alert02Icon,\n CropIcon,\n Delete02Icon,\n Edit02Icon,\n File01Icon,\n Image01Icon,\n ImageAdd01Icon,\n Loading03Icon,\n MusicNote01Icon,\n Refresh01Icon,\n RepeatIcon,\n Video01Icon,\n} from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon, type IconSvgElement } from \"@hugeicons/react\";\nimport { itemKey } from \"../client/media/ref.js\";\nimport { cn } from \"cn\";\nimport { useEffect, useImperativeHandle, useMemo, useRef, useState, type DragEvent, type ReactNode, type Ref } from \"react\";\nimport type { ContentKitUiAppearance } from \"../appearance.js\";\nimport type { AspectRatio } from \"../client/aspect.js\";\nimport { failureError } from \"../client/errors.js\";\nimport { isAudioType, isImageType, isSubtitleType, isVideoType } from \"../client/gallery.js\";\nimport type { FileInfo, RefBody, UploadRule } from \"../client/generated/wire.js\";\nimport { stem } from \"../client/media/client.js\";\nimport type { QueueItem } from \"../client/media/queue.js\";\nimport { acceptOf, ratioLabel } from \"../client/media/rules.js\";\nimport { isProcessing } from \"../client/media/windows.js\";\nimport { useMessages } from \"../i18n/context.js\";\nimport { megabytes, type Translator } from \"../i18n/messages.js\";\nimport { useEditorCrop } from \"../react/crop.js\";\nimport { nameIn, thumbnailOf, useMediaFolder, type FolderGroup, type MediaFolderOptions, type UseMediaFolder } from \"../react/folder.js\";\nimport { ContentKitUiRoot } from \"../scope.js\";\nimport { Alert, AlertDescription, AlertTitle } from \"#ckui/ui/alert\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Progress } from \"#ckui/ui/progress\";\nimport { EncodeProgress } from \"./encode-progress.js\";\nimport { ImageCropDialog } from \"./image-crop-dialog.js\";\nimport { progressLabel, progressValue } from \"./progress.js\";\nimport { SortableList } from \"./sortable-list.js\";\n\nexport interface MediaFolderEditorHandle {\n /** Stops every upload and empties the queue (before deleting a draft). */\n discard: () => void;\n /** Commits the uploaded files (commit=\"manual\"). */\n commit: () => Promise<FileInfo[]>;\n /** The folder's state and updates. */\n folder: UseMediaFolder;\n}\n\nexport interface MediaFolderEditorViewProps {\n ref?: Ref<MediaFolderEditorHandle>;\n /** Heading; default \"Media\". */\n label?: ReactNode;\n /** Beside \"Add files\" in the header, e.g. a ZIP import. */\n toolbar?: ReactNode;\n /** Extra actions on each upload, beside crop, rename, replace and remove. */\n rowActions?: (file: FileInfo) => ReactNode;\n /** Below the lists, e.g. what readers without access see. */\n footer?: ReactNode;\n /** Shapes offered when cropping an image whose path has no preset shape; \"\" is the original's. */\n aspects?: readonly AspectRatio[];\n /** Asked before removing selected uploads; default the browser's confirm; false skips it. */\n confirmRemove?: ((count: number) => boolean | Promise<boolean>) | false;\n disabled?: boolean;\n className?: string;\n appearance?: ContentKitUiAppearance;\n}\n\n/**\n * Either the item, and the editor opens its folder with the options; or a\n * folder the host opened (`folder={useMediaFolder(ref, options)}`), whose\n * state the host reads and renders with.\n */\nexport type MediaFolderEditorProps = MediaFolderEditorViewProps &\n (\n | ({\n /** The item whose folder this edits. */\n item: RefBody;\n folder?: never;\n } & MediaFolderOptions)\n | ({\n /** The host's folder (useMediaFolder); its ref may be null until the item exists. */\n folder: UseMediaFolder;\n item?: never;\n } & { [K in keyof MediaFolderOptions]?: never })\n );\n\nconst ASPECTS: readonly AspectRatio[] = [\"\", \"1:1\", \"4:5\", \"16:9\"];\n\ntype Kind = \"image\" | \"video\" | \"audio\" | \"subtitle\" | \"file\";\n\nfunction kindOf(type: string | undefined): Kind {\n if (isImageType(type)) return \"image\";\n if (isVideoType(type)) return \"video\";\n if (isAudioType(type)) return \"audio\";\n if (isSubtitleType(type)) return \"subtitle\";\n return \"file\";\n}\n\nconst ICONS: Record<Kind, IconSvgElement> = { image: Image01Icon, video: Video01Icon, audio: MusicNote01Icon, subtitle: File01Icon, file: File01Icon };\n\n/** What a rule takes: one kind when every type is of it, else files. */\nfunction ruleKind(rule: UploadRule | undefined): Kind {\n const kinds = new Set((rule?.types ?? []).map(kindOf));\n return kinds.size === 1 ? [...kinds][0]! : \"file\";\n}\n\n/** The rules as a sentence for the drop zone: sizes, caps and video shapes. */\nexport function describeRules(t: Translator[\"t\"], rules: readonly UploadRule[]): string {\n const parts: string[] = [];\n for (const r of rules) {\n if (!r.types.length) continue;\n const what = t(`folder.kinds.${ruleKind(r)}`);\n const size = r.max_bytes > 0 ? t(\"folder.limitSize\", { what, size: megabytes(r.max_bytes) }) : what;\n parts.push(r.max ? `${size}, ${t(\"folder.limitMax\", { max: r.max })}` : size);\n if (r.min_aspect && r.max_aspect) parts.push(t(\"folder.limitAspect\", { min: ratioLabel(r.min_aspect), max: ratioLabel(r.max_aspect) }));\n }\n return parts.join(\" · \");\n}\n\n/**\n * An item's folder for its editors: drop or pick files (screened against the\n * kind's upload rules), a queue with progress, retry and remove, and each\n * upload path's uploads as a sortable list with thumbnail, name, edited\n * badge, encode progress and failures; crop, rename, replace and bulk\n * remove. commit=\"manual\" adds the queue with \"Add N\"; \"auto\" commits as\n * files finish (a draft; discard() through the ref).\n */\nexport function MediaFolderEditor(p: MediaFolderEditorProps) {\n // Editor state (selection, crop, rename) belongs to one item.\n if (p.folder) {\n const { folder, ...view } = p;\n return <FolderView key={folder.ref ? itemKey(folder.ref) : \"\"} folder={folder} {...view} />;\n }\n // The queue belongs to one item: another item gets a fresh editor.\n return <OwnFolder key={itemKey(p.item)} {...p} />;\n}\n\nfunction OwnFolder(p: MediaFolderEditorViewProps & MediaFolderOptions & { item: RefBody }) {\n const { item, ref, label, toolbar, rowActions, footer, aspects, confirmRemove, disabled, className, appearance, ...options } = p;\n const folder = useMediaFolder(item, options);\n return <FolderView {...{ folder, ref, label, toolbar, rowActions, footer, aspects, confirmRemove, disabled, className, appearance }} />;\n}\n\nconst NO_ITEM: RefBody = { kind: \"\", id: \"\" };\n\nfunction FolderView(p: MediaFolderEditorViewProps & { folder: UseMediaFolder }) {\n const { folder, ref, label, toolbar, rowActions, footer, aspects = ASPECTS, confirmRemove, disabled, className, appearance } = p;\n const { t, error: errorText } = useMessages();\n const { groups, queue, read, options } = folder;\n useImperativeHandle(ref, () => ({ discard: folder.discard, commit: folder.commit, folder }), [folder]);\n const auto = options.commit === \"auto\";\n const rules = groups.flatMap((g) => (g.rule ? [g.rule] : []));\n const accept = acceptOf(rules);\n const count = folder.uploads.length + queue.items.length + folder.waiting.length;\n const empty = count === 0;\n const off = !!disabled;\n\n const [selected, setSelected] = useState<ReadonlySet<string>>(new Set());\n useEffect(() => {\n const paths = new Set(folder.uploads.map((f) => f.path));\n setSelected((s) => ([...s].every((x) => paths.has(x)) ? s : new Set([...s].filter((x) => paths.has(x)))));\n }, [folder.uploads]);\n const [cropping, setCropping] = useState<string | null>(null);\n const crop = useEditorCrop(folder.ref ?? NO_ITEM, cropping, { client: options.client, onError: options.onError, onSaved: () => setCropping(null) });\n const cropRule = cropping ? groups.find((g) => g.files.some((f) => f.path === cropping))?.rule : undefined;\n const [renaming, setRenaming] = useState<string | null>(null);\n const replaceInput = useRef<HTMLInputElement>(null);\n const [replacing, setReplacing] = useState<string | null>(null);\n const [over, setOver] = useState(false);\n\n const drop = {\n onDragOver: (e: DragEvent) => {\n if (off || !e.dataTransfer.types.includes(\"Files\")) return;\n e.preventDefault();\n setOver(true);\n },\n onDragLeave: (e: DragEvent) => {\n if (!e.currentTarget.contains(e.relatedTarget as Node | null)) setOver(false);\n },\n onDrop: (e: DragEvent) => {\n if (off || !e.dataTransfer.files.length) return;\n e.preventDefault();\n setOver(false);\n folder.add(e.dataTransfer.files);\n },\n };\n\n const removeSelected = async () => {\n const paths = [...selected];\n const ok = confirmRemove === false ? true : confirmRemove ? await confirmRemove(paths.length) : globalThis.confirm?.(t(\"folder.confirmRemove\", { count: paths.length })) ?? true;\n if (!ok) return;\n await folder.remove(paths).then(() => setSelected(new Set()), () => {});\n };\n\n const uploaded = queue.items.filter((i) => i.status === \"uploaded\").length;\n const picker = (big: boolean) => (\n <label\n className={cn(\n big\n ? \"flex cursor-pointer flex-col items-center justify-center gap-2 rounded-lg border border-dashed border-border px-4 py-8 text-center text-sm text-muted-foreground transition-colors hover:border-primary hover:bg-primary/5\"\n : \"inline-flex h-8 cursor-pointer items-center gap-1.5 rounded-md border border-border bg-background px-2.5 text-sm font-medium transition-colors hover:bg-muted focus-within:ring-3 focus-within:ring-ring/50\",\n big && over && \"border-primary bg-primary/5\",\n off && \"pointer-events-none opacity-50\",\n )}\n data-ckui={big ? \"folder-drop\" : \"folder-add\"}\n >\n <HugeiconsIcon icon={ImageAdd01Icon} strokeWidth={1.75} className={big ? \"size-7\" : \"size-4\"} />\n {big ? <strong className=\"font-medium text-foreground\">{t(\"folder.drop\")}</strong> : t(\"folder.add\")}\n {big && rules.length > 0 && <span className=\"text-xs\">{describeRules(t, rules)}</span>}\n <input\n type=\"file\"\n multiple\n accept={accept}\n className=\"sr-only\"\n disabled={off}\n data-ckui=\"file\"\n onChange={(e) => {\n folder.add([...(e.target.files ?? [])]);\n e.target.value = \"\";\n }}\n />\n </label>\n );\n\n return (\n <ContentKitUiRoot appearance={appearance} className={cn(\"grid gap-3\", className)} data-ckui=\"media-folder\" data-over={over ? \"\" : undefined} {...drop}>\n <div className=\"flex flex-wrap items-center justify-between gap-2\" data-ckui=\"folder-header\">\n <h3 className=\"text-sm font-semibold\">{label ?? t(\"folder.label\")}</h3>\n <div className=\"flex flex-wrap items-center gap-2\">\n {toolbar}\n {!empty && picker(false)}\n </div>\n </div>\n {empty && (read.read || !folder.ref) && picker(true)}\n {empty && !read.read && read.loading && (\n <div className=\"flex justify-center py-6 text-muted-foreground\" data-ckui=\"folder-loading\">\n <HugeiconsIcon icon={Loading03Icon} strokeWidth={2} className=\"size-5 motion-safe:animate-spin\" />\n </div>\n )}\n\n {folder.refused.length > 0 && (\n <Alert variant=\"destructive\" role=\"alert\" data-ckui=\"folder-refused\">\n <HugeiconsIcon icon={Alert02Icon} strokeWidth={2} />\n <AlertDescription>\n <ul className=\"grid gap-0.5\">\n {folder.refused.map((r, i) => (\n <li key={i}>\n <span className=\"font-medium\">{r.file.name}</span>: {errorText(r.error)}\n </li>\n ))}\n </ul>\n <Button variant=\"outline\" size=\"xs\" className=\"mt-1 w-fit\" onClick={folder.dismiss}>\n {t(\"folder.dismiss\")}\n </Button>\n </AlertDescription>\n </Alert>\n )}\n {queue.blocked && (\n <Alert variant=\"destructive\" role=\"alert\" data-ckui=\"folder-paused\">\n <HugeiconsIcon icon={Alert02Icon} strokeWidth={2} />\n <AlertTitle>{t(\"folder.paused\")}</AlertTitle>\n <AlertDescription>\n {errorText(queue.blocked)}\n <Button variant=\"outline\" size=\"xs\" className=\"mt-1 w-fit\" onClick={() => queue.start()}>\n {t(\"folder.resume\")}\n </Button>\n </AlertDescription>\n </Alert>\n )}\n {folder.error && (\n <Alert variant=\"destructive\" role=\"alert\" data-ckui=\"folder-error\">\n <HugeiconsIcon icon={Alert02Icon} strokeWidth={2} />\n <AlertDescription>{errorText(folder.error)}</AlertDescription>\n </Alert>\n )}\n\n {selected.size > 0 && (\n <div className=\"flex flex-wrap items-center gap-2 rounded-md bg-muted px-3 py-1.5 text-sm\" data-ckui=\"folder-selection\">\n <span className=\"tabular-nums\">{t(\"folder.selected\", { count: selected.size })}</span>\n <Button variant=\"destructive\" size=\"xs\" disabled={off || folder.updating} onClick={() => void removeSelected()}>\n <HugeiconsIcon icon={Delete02Icon} strokeWidth={2} />\n {t(\"folder.removeSelected\")}\n </Button>\n <Button variant=\"ghost\" size=\"xs\" onClick={() => setSelected(new Set())}>\n {t(\"folder.clearSelection\")}\n </Button>\n </div>\n )}\n\n {groups.map((g) =>\n g.files.length ? (\n <Group\n key={g.path}\n group={g}\n titled={groups.length > 1}\n folder={folder}\n disabled={off}\n selected={selected}\n onSelect={(path, on) => setSelected((s) => (on ? new Set([...s, path]) : new Set([...s].filter((x) => x !== path))))}\n renaming={renaming}\n onRename={setRenaming}\n onCrop={setCropping}\n onReplace={(path) => {\n setReplacing(path);\n replaceInput.current?.click();\n }}\n rowActions={rowActions}\n />\n ) : null,\n )}\n\n {folder.waiting.length > 0 && (\n <ul className=\"grid\" aria-label={t(\"folder.label\")}>\n {folder.waiting.map((f, i) => (\n <li key={i} className=\"flex min-h-11 items-center gap-2 px-1\" data-ckui=\"queue-row\" data-status=\"waiting\">\n <Thumb kind={kindOf(f.type)} />\n <div className=\"grid min-w-0 flex-1 gap-1\">\n <span className=\"truncate text-sm\">{f.name}</span>\n <span className=\"text-xs text-muted-foreground\" data-ckui=\"queue-status\">\n {t(\"folder.queued\")}\n </span>\n </div>\n </li>\n ))}\n </ul>\n )}\n\n {queue.items.length > 0 && (\n <SortableList\n items={queue.items}\n id={(i) => i.id}\n name={(i) => i.file.name}\n disabled={auto || off}\n label={t(\"folder.label\")}\n onMove={(from, to) => queue.move(queue.items[from]!.id, to)}\n row={(i) => ({ className: \"flex min-h-11 items-center gap-2 px-1\", \"data-ckui\": \"queue-row\", \"data-status\": i.status })}\n >\n {(i, handle) => <QueueRow item={i} handle={auto ? null : handle} auto={auto} folder={folder} />}\n </SortableList>\n )}\n\n {((!auto && uploaded > 0) || (auto && folder.error && uploaded > 0)) && (\n <Button className=\"w-fit\" disabled={off || !queue.ready || folder.committing} onClick={() => void folder.commit().catch(() => {})} data-ckui=\"folder-commit\">\n {folder.committing && <HugeiconsIcon icon={Loading03Icon} strokeWidth={2} className=\"motion-safe:animate-spin\" />}\n {auto ? t(\"folder.commitAgain\") : t(\"folder.commit\", { count: queue.items.filter((i) => i.status !== \"committed\").length })}\n </Button>\n )}\n {footer}\n\n <input\n ref={replaceInput}\n type=\"file\"\n accept={accept}\n className=\"sr-only\"\n tabIndex={-1}\n aria-hidden\n onChange={(e) => {\n const f = e.target.files?.[0];\n e.target.value = \"\";\n if (f && replacing) void folder.replace(replacing, f).catch(() => {});\n setReplacing(null);\n }}\n />\n <ImageCropDialog\n open={!!cropping}\n onOpenChange={(o) => !o && crop.status !== \"saving\" && setCropping(null)}\n source={\"source\" in crop ? (crop.source ?? null) : null}\n aspect={cropRule?.aspect ?? \"\"}\n aspects={cropRule?.aspect ? undefined : aspects}\n initialEdit={\"edit\" in crop ? crop.edit : null}\n minWidth={cropRule?.min_width}\n title={t(\"folder.crop\")}\n busy={crop.status === \"saving\"}\n error={crop.status === \"error\" ? errorText(crop.error) : undefined}\n onConfirm={(edit) => void crop.save(edit)}\n />\n </ContentKitUiRoot>\n );\n}\n\nfunction Group({\n group,\n titled,\n folder,\n disabled,\n selected,\n onSelect,\n renaming,\n onRename,\n onCrop,\n onReplace,\n rowActions,\n}: {\n group: FolderGroup;\n titled: boolean;\n folder: UseMediaFolder;\n disabled: boolean;\n selected: ReadonlySet<string>;\n onSelect: (path: string, on: boolean) => void;\n renaming: string | null;\n onRename: (path: string | null) => void;\n onCrop: (path: string) => void;\n onReplace: (path: string) => void;\n rowActions?: (file: FileInfo) => ReactNode;\n}) {\n const { t } = useMessages();\n const kind = ruleKind(group.rule);\n const title = t(`folder.kinds.${kind}`);\n const max = group.rule?.max;\n return (\n <section className=\"grid gap-1\" data-ckui=\"folder-group\" data-path={group.path}>\n {titled && (\n <h4 className=\"px-1 text-xs font-medium text-muted-foreground tabular-nums\">\n {title} · {max ? `${group.files.length} / ${max}` : group.files.length}\n </h4>\n )}\n <SortableList\n items={group.files}\n id={(f) => f.path}\n name={(f) => nameIn(group, f.path)}\n disabled={disabled || folder.updating}\n label={title}\n onMove={(from, to) => void folder.move(group.files[from]!.path, to).catch(() => {})}\n row={(f) => ({ className: \"flex min-h-12 items-center gap-2 px-1\", \"data-ckui\": \"upload-row\", \"data-path\": f.path })}\n >\n {(f, handle) => (\n <UploadRow\n file={f}\n group={group}\n handle={handle}\n folder={folder}\n disabled={disabled}\n selected={selected.has(f.path)}\n onSelect={(on) => onSelect(f.path, on)}\n renaming={renaming === f.path}\n onRename={onRename}\n onCrop={onCrop}\n onReplace={onReplace}\n actions={rowActions?.(f)}\n />\n )}\n </SortableList>\n </section>\n );\n}\n\nfunction Thumb({ kind, url, busy }: { kind: Kind; url?: string; busy?: boolean }) {\n return (\n <span className=\"relative flex size-10 shrink-0 items-center justify-center overflow-hidden rounded-md bg-muted text-muted-foreground\" data-ckui=\"thumb\">\n {url ? <img src={url} alt=\"\" loading=\"lazy\" decoding=\"async\" className=\"size-full object-cover\" /> : <HugeiconsIcon icon={ICONS[kind]} strokeWidth={1.75} className=\"size-4.5\" />}\n {busy && !url && <span aria-hidden className=\"absolute inset-1.5 rounded-full border-2 border-current/25 border-t-current motion-safe:animate-spin\" />}\n </span>\n );\n}\n\nfunction UploadRow({\n file: f,\n group,\n handle,\n folder,\n disabled,\n selected,\n onSelect,\n renaming,\n onRename,\n onCrop,\n onReplace,\n actions,\n}: {\n file: FileInfo;\n group: FolderGroup;\n handle: ReactNode;\n folder: UseMediaFolder;\n disabled: boolean;\n selected: boolean;\n onSelect: (on: boolean) => void;\n renaming: boolean;\n onRename: (path: string | null) => void;\n onCrop: (path: string) => void;\n onReplace: (path: string) => void;\n actions?: ReactNode;\n}) {\n const { t, error: errorText } = useMessages();\n const kind = kindOf(f.type);\n const name = nameIn(group, f.path);\n const busy = isProcessing(f);\n const thumb = useMemo(() => thumbnailOf(folder.read.read, f), [folder.read.read, f]);\n const locked = disabled || folder.updating;\n const failure = f.failed ? errorText(failureError(f.failed)) : undefined;\n return (\n <>\n {handle}\n <input\n type=\"checkbox\"\n className=\"size-4 shrink-0 accent-primary\"\n checked={selected}\n disabled={disabled}\n aria-label={t(\"folder.select\", { name })}\n onChange={(e) => onSelect(e.target.checked)}\n />\n <Thumb kind={kind} url={thumb?.url} busy={busy} />\n <div className=\"grid min-w-0 flex-1 gap-1\">\n <div className=\"flex min-w-0 flex-wrap items-center gap-x-2 gap-y-0.5\">\n {renaming ? (\n <RenameInput name={stem(name)} label={t(\"folder.renameLabel\", { name })} onDone={(to) => (to === null ? onRename(null) : folder.rename(f.path, to).then(() => onRename(null)))} />\n ) : (\n <span className=\"max-w-full truncate text-sm\" title={f.path} data-ckui=\"upload-name\">\n {name}\n </span>\n )}\n {f.edit && (\n <span className=\"shrink-0 rounded-sm border border-border px-1.5 text-[11px] text-muted-foreground\" data-ckui=\"edited\">\n {t(\"folder.edited\")}\n </span>\n )}\n {failure && (\n <span className=\"shrink-0 rounded-sm bg-destructive/10 px-1.5 text-[11px] font-medium text-destructive\" title={failure} data-ckui=\"failed\">\n {kind === \"video\" ? t(\"folder.failedVideo\") : t(\"folder.failed\")}\n </span>\n )}\n </div>\n {failure && <p className=\"text-xs text-destructive\">{failure}</p>}\n {busy && kind === \"video\" && <EncodeProgress progress={f.progress} className=\"max-w-sm text-xs\" />}\n {busy && kind !== \"video\" && <span className=\"text-xs text-muted-foreground\">{t(\"folder.processing\")}</span>}\n </div>\n <span className=\"flex shrink-0 items-center gap-0.5\" data-ckui=\"upload-actions\">\n {actions}\n {kind === \"image\" && (\n <Button variant=\"ghost\" size=\"icon-sm\" aria-label={t(\"folder.crop\")} title={t(\"folder.crop\")} disabled={locked || !!f.staged || !f.size} onClick={() => onCrop(f.path)}>\n <HugeiconsIcon icon={CropIcon} strokeWidth={2} />\n </Button>\n )}\n {!group.rule?.named && (\n <Button variant=\"ghost\" size=\"icon-sm\" aria-label={t(\"common.rename\")} title={t(\"common.rename\")} disabled={locked} onClick={() => onRename(f.path)}>\n <HugeiconsIcon icon={Edit02Icon} strokeWidth={2} />\n </Button>\n )}\n <Button variant=\"ghost\" size=\"icon-sm\" aria-label={t(\"common.replace\")} title={t(\"common.replace\")} disabled={locked} onClick={() => onReplace(f.path)}>\n <HugeiconsIcon icon={RepeatIcon} strokeWidth={2} />\n </Button>\n <Button variant=\"ghost\" size=\"icon-sm\" aria-label={t(\"common.remove\")} title={t(\"common.remove\")} disabled={locked} onClick={() => void folder.remove([f.path]).catch(() => {})}>\n <HugeiconsIcon icon={Delete02Icon} strokeWidth={2} />\n </Button>\n </span>\n </>\n );\n}\n\nfunction RenameInput({ name, label, onDone }: { name: string; label: string; onDone: (to: string | null) => unknown }) {\n const [value, setValue] = useState(name);\n const done = useRef(false);\n const finish = (to: string | null) => {\n if (done.current) return;\n done.current = true;\n Promise.resolve(onDone(to && to.trim() && to.trim() !== name ? to.trim() : null)).catch(() => (done.current = false));\n };\n return (\n <input\n autoFocus\n aria-label={label}\n value={value}\n className=\"h-7 min-w-0 flex-1 rounded-md border border-input bg-background px-2 text-sm outline-none focus-visible:ring-3 focus-visible:ring-ring/50\"\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n e.preventDefault();\n finish(value);\n } else if (e.key === \"Escape\") {\n e.preventDefault();\n finish(null);\n }\n }}\n onBlur={() => finish(value)}\n data-ckui=\"rename\"\n />\n );\n}\n\nfunction queueLabel(t: Translator[\"t\"], errorText: Translator[\"error\"], i: QueueItem, auto: boolean): string {\n if (i.status === \"failed\") return errorText(i.error);\n if (i.status === \"uploading\") return progressLabel(t, i.progress);\n if (i.status === \"uploaded\") {\n const p = i.processing;\n if (p?.failed) return errorText(failureError(p.failed));\n if (i.unattached && !i.processed) return p?.progress && p.progress.phase !== \"queued\" ? t(\"folder.processingPercent\", { percent: Math.round(p.progress.percent) }) : t(\"folder.processing\");\n return auto ? t(\"folder.adding\") : t(\"folder.uploaded\");\n }\n return i.status === \"committed\" ? t(\"folder.adding\") : t(\"folder.queued\");\n}\n\nfunction QueueRow({ item: i, handle, auto, folder }: { item: QueueItem; handle: ReactNode; auto: boolean; folder: UseMediaFolder }) {\n const { t, error: errorText } = useMessages();\n const { queue } = folder;\n const kind = kindOf(i.file.type);\n const label = queueLabel(t, errorText, i, auto);\n const value = i.status === \"uploading\" ? progressValue(i.progress) : i.unattached && !i.processed && i.processing?.progress ? i.processing.progress.percent : null;\n return (\n <>\n {handle}\n <Thumb kind={kind} busy={i.status === \"uploading\" || (!!i.unattached && !i.processed)} />\n <div className=\"grid min-w-0 flex-1 gap-1\">\n <span className=\"truncate text-sm\" title={i.path}>\n {i.file.name}\n </span>\n {value !== null && <Progress value={value} aria-label={label} className=\"max-w-sm\" />}\n <span className={cn(\"text-xs\", i.status === \"failed\" ? \"text-destructive\" : \"text-muted-foreground\")} data-ckui=\"queue-status\">\n {label}\n </span>\n </div>\n <span className=\"flex shrink-0 items-center gap-0.5\">\n {i.status === \"failed\" && (\n <Button variant=\"ghost\" size=\"icon-sm\" aria-label={t(\"common.retry\")} title={t(\"common.retry\")} onClick={() => queue.retry(i.id)}>\n <HugeiconsIcon icon={Refresh01Icon} strokeWidth={2} />\n </Button>\n )}\n <Button variant=\"ghost\" size=\"icon-sm\" aria-label={t(\"common.remove\")} title={t(\"common.remove\")} onClick={() => queue.remove(i.id)}>\n <HugeiconsIcon icon={Delete02Icon} strokeWidth={2} />\n </Button>\n </span>\n </>\n );\n}\n"],"mappings":"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"}
@@ -1,12 +1,14 @@
1
1
  import { ReactNode } from 'react';
2
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';
3
+ import { Sort, Target } from '../../client/content/types.js';
4
+ import { Comment, PublicUser } from '../../client/generated/wire.js';
5
5
  import { ContentKitUiAppearance } from '../../appearance.js';
6
6
  import { ContentKitErrorHandler } from '../../react/context.js';
7
7
  export interface CommentsProps {
8
- /** The commented item. */
9
- item: RefBody;
8
+ /** The commented content item, version or group. */
9
+ item: Target;
10
+ /** One language's thread: shown, and joined by new comments. */
11
+ language?: string;
10
12
  /** The item's comment count, for the heading; without it the heading has none. */
11
13
  count?: number;
12
14
  /** Initial order: newest (default) or best (top). */
@@ -39,4 +41,4 @@ export interface CommentsProps {
39
41
  * prompt. Moderators (as the server says) edit, delete and restore any
40
42
  * comment; an item's owner and site staff ban commenters.
41
43
  */
42
- export declare function Comments(p: CommentsProps): import('react').JSX.Element;
44
+ export declare function Comments(p: CommentsProps): import('react').JSX.Element | null;
@@ -24,6 +24,7 @@ var K = N(null), q = () => P(K), J = typeof navigator < "u" && /Mac|iP(hone|ad)/
24
24
  function Z(e) {
25
25
  let o = t(), { t: s } = o, c = P(r), [l, f] = R(e.sort ?? "newest"), h = p(e.item, {
26
26
  sort: l,
27
+ language: e.language,
27
28
  pageSize: e.pageSize ?? 20,
28
29
  client: e.client
29
30
  }), { 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({
@@ -70,7 +71,7 @@ function Z(e) {
70
71
  W(e), _();
71
72
  }
72
73
  }, 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
+ return g?.comments === "hidden" ? null : /* @__PURE__ */ B(K.Provider, {
74
75
  value: J,
75
76
  children: /* @__PURE__ */ V(n, {
76
77
  appearance: e.appearance,
@@ -99,7 +100,10 @@ function Z(e) {
99
100
  })] })]
100
101
  })]
101
102
  }),
102
- Y ? /* @__PURE__ */ B(j, { ban: Y }) : q("comment") ? E ? /* @__PURE__ */ B(a, {
103
+ g?.comments === "closed" ? /* @__PURE__ */ B("p", {
104
+ className: "rounded-lg border border-border p-3 text-muted-foreground",
105
+ children: s("comments.closed")
106
+ }) : Y ? /* @__PURE__ */ B(j, { ban: Y }) : q("comment") ? E ? /* @__PURE__ */ B(a, {
103
107
  variant: "outline",
104
108
  className: "justify-self-start",
105
109
  onClick: E,
@@ -1 +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":";;;;;;;;;;;;;;;;;;;;;;AAgFA,IAAM,IAAgB,EAA6B,IAAI,GACjD,UAAkB,EAAW,CAAa,GAE1C,IAAM,OAAO,YAAc,OAAe,kBAAkB,KAAK,UAAU,QAAQ,GACnF,IAAW,KAEX,KAAc,GAAY,MAAsB,EAAE,QAAQ,YAAY,EAAE,aAAa;AAS3F,SAAgB,EAAS,GAAkB;CACzC,IAAM,IAAI,EAAY,GAChB,EAAE,SAAM,GACR,IAAM,EAAW,CAAiB,GAClC,CAAC,GAAM,KAAW,EAAe,EAAE,QAAQ,QAAQ,GACnD,IAAW,EAAY,EAAE,MAAM;EAAE;EAAM,UAAU,EAAE,YAAY;EAAI,QAAQ,EAAE;CAAO,CAAC,GACrF,EAAE,aAAU,QAAQ,MAAmB,EAAc,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,GACjF,EAAE,cAAW,EAAiB,EAAE,QAAQ,EAAE,OAAO,CAAC,GAClD,IAAS,EAAiB,EAAE,OAAO,GACnC,IAAS,EAAE,YAAY,GAAK,UAC5B,IAAS,GAAK,QACd,IAAW,IAAW,CAAC,CAAC,EAAS,UAAU,IAAS,KAAO,MAAW,QAAe,KAAA,GACrF,IAAS,QAAc,GAAU,cAAc,CAAC,GAAG,CAAC,CAAQ,CAAC,GAC7D,IAAY,EAAe;EAAE,OAAO;EAAS,UAAU;EAAK,SAAS,EAAO,SAAS,OAAO;EAAG,QAAQ,EAAE;CAAO,CAAC,GACjH,IAAa,EAAe;EAAE,OAAO;EAAU,UAAU;EAAK,SAAS,EAAO,SAAS,QAAQ;EAAG,QAAQ,EAAE;CAAO,CAAC,GACpH,CAAC,GAAS,KAAc,EAA0E,IAAI,GACtG,CAAC,GAAS,KAAc,EAA8C,IAAI,GAC1E,CAAC,GAAS,KAAc,EAA+B,IAAI,GAE3D,IAAS,QAAc;EAC3B,IAAM,oBAAM,IAAI,IAAoD,GAC9D,KAAO,GAAiB,MAAuB;GACnD,KAAK,IAAM,KAAO,GAAM,AAAK,EAAI,WAAS,EAAI,IAAI,EAAI,SAAS,CAAC,GAAI,EAAI,IAAI,EAAI,OAAO,KAAK,CAAC,GAAI;IAAE;IAAO;GAAI,CAAC,CAAC;EAClH;EAGA,OAFI,EAAO,SAAS,OAAO,KAAG,EAAI,SAAS,EAAU,KAAK,GACtD,EAAO,SAAS,QAAQ,KAAG,EAAI,UAAU,EAAW,KAAK,GACtD;CACT,GAAG;EAAC;EAAQ,EAAU;EAAO,EAAW;CAAK,CAAC,GAGxC,KAAc,MAAc,MAAa,OAAU,MAAS,YAAY,GAAU,cAAc,KAAQ,GAAQ,UAAU,cAAc,KACxI,IAAiB;EACrB,MAAM,EAAE;EACR;EACA;EACA;EACA,OAAO,GAAM,MAAQ,EAAW,CAAI,IAAI,IAAS,IAAI,EAAG;EACxD,MAAM,MAAS,CAAC,EAAW,CAAI,KAAK,CAAC,CAAC;EACtC,WAAW,GAAU;EACrB,iBAAiB,EAAE,mBAAmB;EACtC,YAAY,EAAE;EACd,UAAU,EAAE;EACZ,SAAS,GAAG,MAAO,EAAO,GAAG,CAAE;EAC/B;EACA,UAAU,GAAM,MAAQ,EAAW;GAAE;GAAM;EAAI,CAAC;EAChD,SAAS;EACT,WAAW,MAAQ;GAEjB,AADA,EAAW,CAAG,GACd,EAAe;EACjB;CACF,GACM,IAAM,GAAU,OAAO,GACvB,IAAW,MAAW,EAAS,aAC/B,IAAU,EAAE,YAAY,KAAA,IAAa,EAAE,UAAU,KAAA,IAAY,EAAE,gBAAgB,IAAI,EAAE,OAAO,kBAAkB,EAAE,KAAK,IAAK,EAAE;CAElI,OACE,kBAAC,EAAc,UAAf;EAAwB,OAAO;EAC7B,UAAA,kBAAC,GAAD;GAAkB,YAAY,EAAE;GAAY,WAAW,GAAG,sBAAsB,EAAE,SAAS;GAAG,aAAU;GAAxG,UAAA;KACI,MAAY,MAAS,EAAS,MAAM,SAAS,MAC7C,kBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACG,MAAY,MAAS,kBAAC,MAAD;MAAI,WAAU;MAA2B,UAAA;KAAY,CAAA,GAC3E,kBAAC,GAAD;MAAQ,OAAO;MAAM,gBAAgB,MAAM,EAAQ,CAAS;MAA5D,UAAA,CACE,kBAAC,GAAD;OAAe,MAAK;OAAK,cAAY,EAAE,eAAe;OAAG,WAAU;OACjE,UAAA,kBAAC,GAAD,EAAA,WAAe,MAAc,EAAE,MAAM,SAAS,kBAAkB,iBAAiB,EAAe,CAAA;MACnF,CAAA,GACf,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;OAAY,OAAM;OAAU,UAAA,EAAE,iBAAiB;MAAc,CAAA,GAC7D,kBAAC,GAAD;OAAY,OAAM;OAAQ,UAAA,EAAE,eAAe;MAAc,CAAA,CAC5C,EAAA,CAAA,CACT;KACL,CAAA,CAAA;;IAEN,IACC,kBAAC,GAAD,EAAgB,OAAM,CAAA,IACpB,EAAW,SAAS,IACtB,IACE,kBAAC,GAAD;KAAQ,SAAQ;KAAU,WAAU;KAAqB,SAAS;KAC/D,UAAA,EAAE,iBAAiB;IACd,CAAA,IAER,kBAAC,KAAD;KAAG,WAAU;KAA6D,UAAA,EAAE,iBAAiB;IAAK,CAAA,IAEjG,IAGH,kBAAC,GAAD;KACE,aAAa,EAAE,sBAAsB;KACrC,QAAQ,EAAE,eAAe;KACzB,SAAS,MAAa;KACtB,UAAU,OAAO,GAAM,OAAU,MAAM,EAAS,KAAK,GAAM,EAAE,UAAU,EAAK,CAAC,GAAG;KAChF,WAAU;IACX,CAAA,IARD,kBAAC,KAAD;KAAG,WAAU;KAA6D,UAAA,EAAE,iBAAiB;IAAK,CAAA;IAUpG,kBAAC,IAAD,CAAc,CAAA;IACb,KACC,kBAAC,GAAD;KACE,MAAA;KACA,eAAe,MAAM,CAAC,KAAK,EAAW,IAAI;KAC1C,MAAM,EAAQ;KACd,QAAQ,EAAQ,MAAM,CAAC,EAAQ,IAAI,UAAU,WAAW,WAAW,OAAO,IAAI;KAC9E,KAAK,EAAQ;KACb,QAAQ,EAAE;KACV,SAAS,EAAE;IACZ,CAAA;IAEH,kBAAC,GAAD;KACE,MAAM,CAAC,CAAC;KACR,eAAe,MAAM,CAAC,KAAK,EAAW,IAAI;KAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,GAAS,QAAQ,GAAG,CAAC;KACxD,aAAa,EAAE,eAAe;KAC9B,SAAS,EAAE,WAAW;KACtB,iBAAiB;MACV,OACL,KAAK,IAAM,KAAK,EAAO,IAAI,EAAQ,EAAE,KAAK,CAAC,GACzC,CAAM,EAAE,UAAU,WAAW,IAAa,EAAA,CAAW,KAAK,EAAQ,EAAE,CAAC,CAAC,OAAO,MAAM,EAAO,GAAG,UAAU,CAAC;KAE5G;IACD,CAAA;GACe;;CACI,CAAA;AAE5B;AAEA,SAAS,KAAc;CACrB,IAAM,EAAE,SAAM,EAAY,GACpB,EAAE,gBAAa,EAAU;CA2B/B,OA1BI,EAAS,WAAW,CAAC,EAAS,MAAM,SAEpC,kBAAC,OAAD;EAAK,WAAU;EAAa,aAAA;EAAU,cAAY,EAAE,kBAAkB;EACnE,UAAA;GAAC;GAAG;GAAG;EAAC,CAAC,CAAC,KAAK,MACd,kBAAC,OAAD;GAAa,WAAU;GAAvB,UAAA,CACE,kBAAC,GAAD,EAAU,WAAU,sBAAuB,CAAA,GAC3C,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA,GAChC,kBAAC,GAAD,EAAU,WAAU,aAAc,CAAA,CAC/B;GACF,CAAA,CAAA;EANK,GAAA,CAML,CACN;CACE,CAAA,IAGL,EAAS,SAAS,CAAC,EAAS,MAAM,SAElC,kBAAC,OAAD;EAAK,WAAU;EAAiC,aAAU;EAA1D,UAAA,CACE,kBAAC,GAAD,EAAA,UAAY,EAAE,qBAAqB,EAAa,CAAA,GAChD,kBAAC,GAAD;GAAQ,MAAK;GAAK,SAAQ;GAAU,SAAS,EAAS;GACnD,UAAA,EAAE,cAAc;EACX,CAAA,CACL;MAGJ,EAAS,MAAM,SAElB,kBAAA,GAAA,EAAA,UAAA;EACE,kBAAC,MAAD;GAAI,WAAU;GACX,UAAA,EAAS,MAAM,KAAK,MACnB,kBAAC,MAAD;IAAe,WAAU;IACvB,UAAA,kBAAC,IAAD,EAAU,SAAS,EAAI,CAAA;GACrB,GAFK,EAAE,EAEP,CACL;EACC,CAAA;EACH,EAAS,SAAS,kBAAC,GAAD,EAAW,OAAO,EAAS,MAAQ,CAAA;EACrD,EAAS,WACR,kBAAC,GAAD;GAAQ,SAAQ;GAAU,WAAU;GAAsB,UAAU,EAAS;GAAa,eAAe,KAAK,EAAS,SAAS;GAC7H,UAAA,EAAS,cAAc,EAAE,kBAAkB,IAAI,EAAE,mBAAmB;EAC/D,CAAA;CAEV,EAAA,CAAA,IAhB+B,kBAAC,KAAD;EAAG,WAAU;EAAyB,UAAA,EAAE,gBAAgB;CAAK,CAAA;AAkBlG;AAEA,SAAS,GAAS,EAAE,cAAiC;CACnD,IAAM,EAAE,MAAG,cAAW,EAAY,GAC5B,IAAS,EAAU,GACnB,CAAC,GAAM,KAAW,EAAS,EAAK,GAChC,CAAC,GAAS,KAAc,EAAwB,IAAI,GACpD,IAAU,EAAkB,EAAQ,IAAI;EAAE,UAAU,EAAO;EAAiB,SAAS;CAAK,CAAC,GAC3F,KAAc,MAClB,EAAO,KAAK,iBAAiB;EAE3B,AADA,EAAW,CAAI,GACX,EAAQ,cAAc,KAAG,EAAQ,EAAI;CAC3C,CAAC;CACH,OACE,kBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACE,kBAAC,GAAD;IAAc;IAAS,SAAS,EAAQ,WAAW,EAAQ,cAAc,CAAC,EAAO,IAAI,SAAS,IAAI,KAAA,IAAY;GAAa,CAAA;IACzH,EAAQ,cAAc,KAAM,KAAQ,EAAQ,MAAM,SAAS,MAC3D,kBAAC,GAAD;IAAQ,SAAQ;IAAO,MAAK;IAAK,WAAU;IAAgC,iBAAe;IAAM,eAAe,EAAQ,CAAC,CAAI;IACzH,UAAA,IAAO,EAAE,sBAAsB,IAAI,EAAO,wBAAwB,EAAQ,WAAW;GAChF,CAAA;GAET,KACC,kBAAC,MAAD;IAAI,WAAU;IAA+C,aAAW,EAAQ;IAAhF,UAAA;KACG,EAAQ,WAAW,CAAC,EAAQ,MAAM,UAAU,kBAAC,MAAD;MAAI,WAAU;MAAyB,UAAA,EAAE,yBAAyB;KAAM,CAAA;KACpH,EAAQ,MAAM,KAAK,MAClB,kBAAC,MAAD,EAAA,UACE,kBAAC,GAAD;MAAK,SAAS;MAAG,SAAS,EAAE,WAAW,EAAE,cAAc,CAAC,EAAO,IAAI,SAAS,IAAI,KAAA,IAAY;KAAa,CAAA,EACvG,GAFK,EAAE,EAEP,CACL;KACA,EAAQ,SACP,kBAAC,MAAD,EAAA,UACE,kBAAC,GAAD,EAAW,OAAO,EAAQ,MAAQ,CAAA,EAChC,CAAA;KAEL,EAAQ,WACP,kBAAC,MAAD,EAAA,UACE,kBAAC,GAAD;MAAQ,SAAQ;MAAO,MAAK;MAAK,WAAU;MAAO,UAAU,EAAQ;MAAa,eAAe,KAAK,EAAQ,SAAS;MACnH,UAAA,EAAE,sBAAsB;KACnB,CAAA,EACN,CAAA;IAEJ;;GAEL,MAAY,QACX,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,KAAD;KAAG,WAAU;KAAiC,UAAA,EAAE,uBAAuB,EAAE,MAAM,EAAQ,CAAC;IAAK,CAAA,GAC7F,kBAAC,GAAD;KACE,WAAA;KACA,aAAa,EAAE,2BAA2B;KAC1C,QAAQ,EAAE,gBAAgB;KAC1B,SAAS,EAAO,aAAa;KAC7B,gBAAgB,EAAW,IAAI;KAC/B,WAAU;KACV,UAAU,OAAO,GAAM,OACrB,MAAM,EAAO,SAAS,KAAK,GAAM;MAAE,SAAS,EAAQ;MAAI,UAAU;KAAK,CAAC,GACxE,EAAW,IAAI,GACf,EAAQ,EAAI,GACL;IAEV,CAAA,CACE;;EAEJ;;AAET;AAEA,SAAS,EAAI,EAAE,SAAS,GAAG,cAAmE;CAE5F,IAAM,EAAE,SADE,EACI,GACR,IAAS,EAAU,GACnB,EAAE,gBAAa,GACf,IAAO,EAAW,GAAG,EAAE,oBAAoB,CAAC,GAC5C,IAAM,CAAC,CAAC,GAAU,WAAW,EAAE,YAAY,EAAS,SACpD,IAAU,CAAC,EAAE,YAAY,KAAO,CAAC,CAAC,GAAU,WAC5C,IAAS,CAAC,EAAE,WAAW,CAAC,CAAC,EAAE,WAAW,CAAC,MAAQ,GAAU,WAAW,UAAU,KAAK,GACnF,IAAO,EAAE,UAAU,EAAO,OAAO,IAAI,EAAE,OAAO,IAAI,KAAA,GAClD,CAAC,GAAS,KAAc,EAAS,EAAK,GACtC,CAAC,GAAU,KAAe,EAAS,EAAK,GACxC,CAAC,GAAU,KAAe,EAAS,EAAK,GACxC,CAAC,GAAO,KAAY,EAAiC,IAAI,GACzD,IAAM,OAAO,GAA4D,MAA+B;EAC5G,EAAS,IAAI;EACb,IAAI;GACF,MAAM,EAAG;EACX,SAAS,GAAG;GACV,IAAM,IAAM,EAAkB,CAAC;GAE/B,AADA,EAAS,CAAG,GACZ,EAAO,OAAO,GAAK,CAAE;EACvB;CACF,GACM,KAAS,MAAgB,EAAO,KAAK,eAAe,KAAK,EAAI,uBAAuB,EAAO,SAAS,MAAM,GAAG,EAAE,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,GACnI,IAAO,CAAC,EAAO,cAAc,EAAE,KAAK,SAAS,KAC7C,IAAO,KAAQ,CAAC,IAAW,EAAE,KAAK,MAAM,GAAG,CAAQ,CAAC,CAAC,QAAQ,IAAI,MAAM,EAAE;CAE/E,OACE,kBAAC,WAAD;EAAS,WAAU;EAAa,aAAU;EAAU,gBAAc,EAAE;EAAI,cAAY;EAApF,UAAA;GACE,kBAAC,GAAD;IAAY,MAAM,EAAE,UAAU,KAAA,IAAY,EAAE;IAAQ,MAAM,EAAE,UAAU,MAAM;GAAO,CAAA;GACnF,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,kBAAC,UAAD;MAAQ,WAAU;MAAlB,UAAA;OACG,EAAE,UAAU,kBAAC,QAAD;QAAM,WAAU;QAAyB,UAAA,EAAE,oBAAoB;OAAQ,CAAA,IAAI,kBAAC,GAAD;QAAU,MAAM,EAAE;QAAc;QAAM,MAAM,EAAO;OAAW,CAAA;OACtJ,kBAAC,GAAD;QAAc,IAAI,EAAE;QAAY,WAAU;OAAiC,CAAA;OAC1E,EAAE,eAAe,UAAU,kBAAC,GAAD;QAAO,SAAQ;QAAa,UAAA,EAAE,oBAAoB;OAAS,CAAA;OACtF,EAAE,eAAe,cAAc,kBAAC,GAAD;QAAO,SAAQ;QAAe,UAAA,EAAE,wBAAwB;OAAS,CAAA;QAC/F,KAAW,KAAW,EAAE,WAAW,GAAU,aAC7C,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;QAAqB,QAAQ,kBAAC,GAAD;SAAQ,SAAQ;SAAQ,MAAK;SAAU,WAAU;SAAU,cAAY,EAAE,kBAAkB;QAAI,CAAA;QAC1H,UAAA,kBAAC,GAAD;SAAe,MAAM;SAAoB,aAAa;QAAI,CAAA;OACvC,CAAA,GACrB,kBAAC,GAAD;QAAqB,OAAM;QAA3B,UAAA;SACG,KAAW,kBAAC,GAAD;UAAkB,eAAe,EAAW,EAAI;UAAI,UAAA,EAAE,eAAe;SAAoB,CAAA;SACpG,KACC,kBAAC,GAAD;UAAkB,WAAU;UAAmB,eAAe,EAAY,EAAI;UAC3E,UAAA,EAAE,iBAAiB;SACJ,CAAA;SAEnB,EAAE,WAAW,GAAU,YAAY,kBAAC,GAAD;UAAkB,eAAe,KAAK,EAAI,yBAAyB,EAAO,SAAS,QAAQ,EAAE,EAAE,CAAC;UAAI,UAAA,EAAE,kBAAkB;SAAoB,CAAA;SAC/K,KAAU,CAAC,KAAQ,kBAAC,GAAD;UAAkB,eAAe,EAAO,QAAQ;WAAE,IAAI,EAAE;WAAU;UAAK,CAAC;UAAI,UAAA,EAAE,cAAc;SAAoB,CAAA;SACnI,KAAU,KAAQ,kBAAC,GAAD;UAAkB,eAAe,EAAO,QAAQ;WAAE,IAAI,EAAE;WAAU;UAAK,CAAC;UAAI,UAAA,EAAE,gBAAgB;SAAoB,CAAA;QAClH;OACT,CAAA,CAAA,EAAA,CAAA;MAEV;;KACP,IACC,kBAAC,GAAD;MACE,WAAA;MACA,SAAS,EAAE;MACX,QAAQ,EAAE,aAAa;MACvB,gBAAgB,EAAW,EAAK;MAChC,WAAU;MACV,UAAU,OAAO,OACX,MAAS,EAAE,QAAM,MAAM,EAAO,SAAS,KAAK,EAAE,IAAI,CAAI,GAC1D,EAAW,EAAK,GACT;KAEV,CAAA,IACC,EAAE,UACJ,kBAAC,KAAD;MAAG,WAAU;MAAgC,UAAA,EAAE,kBAAkB;KAAK,CAAA,IAEtE,kBAAC,OAAD;MAAK,WAAU;MAAf,UAAA,CACG,EAAO,aAAa,EAAO,WAAW,EAAE,MAAM,CAAC,IAAI,GACnD,KACC,kBAAC,GAAD;OAAQ,SAAQ;OAAO,MAAK;OAAK,WAAU;OAAmB,eAAe,EAAY,CAAC,CAAQ;OAC/F,UAAW,EAAX,IAAa,sBAAyB,mBAAmB;MACpD,CAAA,CAEP;;KAEN,EAAE,eAAe,UAAU,kBAAC,KAAD;MAAG,WAAU;MAAiC,UAAA,EAAE,eAAe;KAAK,CAAA;KAC/F,EAAE,eAAe,cAChB,kBAAC,KAAD;MAAG,WAAU;MAA4B,UAAA,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,QAAQ,EAAE,kBAAkB,CAAC,IAAI,EAAE,2BAA2B;KAAK,CAAA;KAE5J,CAAC,EAAE,WAAW,CAAC,EAAE,cAAc,CAAC,KAC/B,kBAAC,OAAD;MAAK,WAAU;MAAf,UAAA;OACE,kBAAC,GAAD;QAAQ,SAAS,EAAE,SAAS,IAAI,cAAc;QAAS,MAAK;QAAK,gBAAc,EAAE,SAAS;QAAG,cAAY,EAAE,eAAe;QAAG,UAAU,CAAC,EAAO,IAAI,OAAO;QAAG,eAAe,EAAM,CAAC;QAAnL,UAAA,CACE,kBAAC,GAAD;SAAe,MAAM;SAAc,aAAa;QAAI,CAAA,GACpD,kBAAC,QAAD,EAAA,UAAO,EAAE,MAAY,CAAA,CACf;;OACR,kBAAC,GAAD;QAAQ,SAAS,EAAE,SAAS,KAAK,cAAc;QAAS,MAAK;QAAK,gBAAc,EAAE,SAAS;QAAI,cAAY,EAAE,kBAAkB;QAAG,UAAU,CAAC,EAAO,IAAI,OAAO;QAAG,eAAe,EAAM,EAAE;QAAzL,UAAA,CACE,kBAAC,GAAD;SAAe,MAAM;SAAgB,aAAa;QAAI,CAAA,GACtD,kBAAC,QAAD,EAAA,UAAO,EAAE,SAAe,CAAA,CAClB;;OACP,KACC,kBAAC,GAAD;QAAQ,SAAQ;QAAQ,MAAK;QAAK,eAAe,EAAQ,CAAI;QAC1D,UAAA,EAAE,gBAAgB;OACb,CAAA;MAEP;;KAEP,kBAAC,GAAD,EAAkB,SAAQ,CAAA;IACvB;;GACL,kBAAC,GAAD;IACE,MAAM;IACN,cAAc;IACd,OAAO,EAAE,sBAAsB;IAC/B,aAAa,EAAE,qBAAqB;IACpC,SAAS,EAAE,iBAAiB;IAC5B,iBAAiB,KAAK,EAAI,wBAAwB,EAAO,SAAS,OAAO,EAAE,EAAE,CAAC;GAC/E,CAAA;EACM;;AAEb;AAeA,SAAS,EAAS,GAAkB;CAClC,IAAM,IAAI,EAAY,GAChB,EAAE,SAAM,GACR,IAAS,EAAU,GACnB,IAAM,EAAM,GACZ,CAAC,GAAM,KAAW,EAAS,EAAE,WAAW,EAAE,GAC1C,CAAC,GAAM,KAAW,EAAS,EAAE,GAC7B,CAAC,GAAS,KAAc,EAAS,EAAK,GACtC,CAAC,GAAS,KAAc,EAAwB,IAAI,GACpD,CAAC,GAAO,KAAY,EAAwB,IAAI,GAChD,IAAO,EAA4B,IAAI,GACvC,IAAM,EAAO,WACb,IAAO,MAAQ,KAAA,IAAY,KAAA,IAAY,IAAM,EAAK,QAElD,IAAO,YAAY;EACvB,IAAM,IAAO,EAAK,KAAK;EACvB,IAAI,CAAC,GAAM,OAAO,EAAW,EAAE,mBAAmB,CAAC;EACnD,IAAI,EAAE,WAAW,CAAC,EAAK,KAAK,GAAG,OAAO,EAAW,EAAE,uBAAuB,CAAC;EAG3E,AAFA,EAAW,IAAI,GACf,EAAS,IAAI,GACb,EAAW,EAAI;EACf,IAAI;GACF,AAAI,MAAM,EAAE,SAAS,GAAM,EAAE,UAAU,EAAK,KAAK,IAAI,KAAA,CAAS,KAAG,EAAQ,EAAE;EAC7E,SAAS,GAAG;GACV,IAAM,IAAM,EAAkB,CAAC;GAE/B,AADA,EAAO,OAAO,GAAK,EAAE,SAAS,GAC1B,EAAI,SAAS,oBAAoB,EAAI,MAAK,EAAO,SAAS,EAAI,GAAG,IAC5D,EAAI,SAAS,iBAAgB,EAAS,EAAI,aAAa,EAAE,wBAAwB,EAAE,SAAS,EAAI,WAAW,CAAC,IAAI,EAAE,0BAA0B,CAAC,IACjJ,EAAS,EAAa,GAAG,CAAG,CAAC;EACpC,UAAU;GACR,EAAW,EAAK;EAClB;CACF;CAOA,OACE,kBAAC,QAAD;EACE,WAAU;EACV,aAAU;EACV,WAAW,MAAM;GAEf,AADA,EAAE,eAAe,GACjB,EAAU;EACZ;EANF,UAAA;GAQG,EAAE,WACD,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,GAAD;KAAO,SAAS,GAAG,EAAI;KAAS,UAAA,EAAE,eAAe;IAAS,CAAA,GAC1D,kBAAC,GAAD;KAAO,IAAI,GAAG,EAAI;KAAQ,OAAO;KAAM,WAAW;KAAI,aAAa,EAAE,0BAA0B;KAAG,WAAW,MAAM,EAAQ,EAAE,OAAO,KAAK;KAAG,cAAa;IAAY,CAAA,CAClK;;GAEP,kBAAC,GAAD;IACE,KAAK;IACL,OAAO;IACP,MAAM,EAAE,YAAY,KAAA,IAAY,IAAI;IACpC,WAAW;IACX,WAAW,EAAE;IACb,aAAa,EAAE;IACf,cAAY,EAAE,eAAe,EAAE;IAC/B,gBAAc,CAAC,CAAC;IAChB,oBAAkB,GAAG,EAAI;IACzB,UAAU;IACV,WAAW,MAAM;KAEf,AADA,EAAQ,EAAE,OAAO,KAAK,GAClB,KAAS,EAAW,IAAI;IAC9B;IACA,YApCS,MAA0C;KACvD,AAAI,EAAE,QAAQ,YAAY,EAAE,WAAW,EAAE,YACvC,EAAE,eAAe,GACjB,EAAU,KACD,EAAE,QAAQ,YAAY,EAAE,YAAU,EAAE,SAAS;IAC1D;GAgCK,CAAA;GACD,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,kBAAC,QAAD;MAAM,IAAI,GAAG,EAAI;MAAQ,WAAU;MAAwC,aAAU;MAClF,UAAA,IACC,kBAAC,QAAD;OAAM,WAAU;OAAoB,UAAA;MAAc,CAAA,IAChD,MAAS,KAAA,KAAa,MAAQ,KAAA,KAAa,KAAQ,IAAM,KAC3D,EAAE,OAAO,sBAAsB,CAAI,IAEnC,kBAAC,QAAD;OAAM,WAAU;OAAyB,UAAA,EAAE,uBAAuB,EAAE,KAAK,IAAM,MAAM,OAAO,CAAC;MAAQ,CAAA;KAEnG,CAAA;KACL,EAAE,YACD,kBAAC,GAAD;MAAQ,MAAK;MAAS,MAAK;MAAK,SAAQ;MAAQ,SAAS,EAAE;MAAU,UAAU;MAC5E,UAAA,EAAE,eAAe;KACZ,CAAA;KAEV,kBAAC,GAAD;MAAQ,MAAK;MAAS,MAAK;MAAK,UAAU;MACvC,UAAA,IAAU,EAAE,kBAAkB,IAAI,EAAE;KAC/B,CAAA;IACL;;GACJ,KAAS,kBAAC,GAAD,EAAA,UAAY,EAAiB,CAAA;EACnC;;AAEV"}
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 { Target } from \"../../client/content/types.js\";\nimport type { BanNotice as BanNoticeData, Comment, CommentBan, CommentStanding, PublicUser } 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 content item, version or group. */\n item: Target;\n /** One language's thread: shown, and joined by new comments. */\n language?: string;\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: Target;\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, language: p.language, 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 if (standing?.comments === \"hidden\") return null;\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 {standing?.comments === \"closed\" ? (\n <p className=\"rounded-lg border border-border p-3 text-muted-foreground\">{t(\"comments.closed\")}</p>\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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"}
@@ -1,9 +1,10 @@
1
1
  import { ContentKitClient } from '../../client/client.js';
2
- import { ReactionCounts, RefBody } from '../../client/generated/wire.js';
2
+ import { Target } from '../../client/content/types.js';
3
+ import { ReactionCounts } from '../../client/generated/wire.js';
3
4
  import { ContentKitUiAppearance } from '../../appearance.js';
4
5
  import { ContentKitErrorHandler } from '../../react/context.js';
5
6
  export interface ReactionButtonsProps {
6
- item: RefBody;
7
+ item: Target;
7
8
  /** Counts the host already has, used instead of reading them. */
8
9
  counts?: ReactionCounts;
9
10
  /** Offer dislike too. Default true. */
@@ -23,7 +24,7 @@ export interface ReactionButtonsProps {
23
24
  */
24
25
  export declare function ReactionButtons({ item, counts: initial, dislike, onSignIn, size, client, onError, className, appearance }: ReactionButtonsProps): import('react').JSX.Element;
25
26
  export interface FavoriteButtonProps {
26
- item: RefBody;
27
+ item: Target;
27
28
  /** Whether it is favorited and the item's count, as the host already has them: both given, nothing is read. */
28
29
  favorited?: boolean;
29
30
  count?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"engagement.js","names":[],"sources":["../../../src/components/social/engagement.tsx"],"sourcesContent":["import { FavouriteIcon, ThumbsDownIcon, ThumbsUpIcon } from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { cn } from \"cn\";\nimport { useContext, useState } from \"react\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport type { ContentKitError } from \"../../client/errors.js\";\nimport { toContentKitError } from \"../../client/errors.js\";\nimport type { ReactionCounts, RefBody } from \"../../client/generated/wire.js\";\nimport type { ContentKitUiAppearance } from \"../../appearance.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport { ContentKitContext, useErrorReporter, type ContentKitErrorHandler } from \"../../react/context.js\";\nimport { useContentConfig } from \"../../react/config.js\";\nimport { useFavorite, useReaction } from \"../../react/engagement.js\";\nimport { ContentKitUiRoot } from \"../../scope.js\";\nimport { Button } from \"#ckui/ui/button\";\nimport { contentError } from \"./parts.js\";\n\n\nconst compact = (n: number, language?: string) => new Intl.NumberFormat(language, { notation: \"compact\", maximumFractionDigits: 1 }).format(n);\n\nexport interface ReactionButtonsProps {\n item: RefBody;\n /** Counts the host already has, used instead of reading them. */\n counts?: ReactionCounts;\n /** Offer dislike too. Default true. */\n dislike?: boolean;\n /** Asks a signed-out visitor to sign in where the server takes no anonymous reactions (default the provider's). */\n onSignIn?: () => void;\n size?: \"sm\" | \"default\";\n client?: ContentKitClient;\n onError?: ContentKitErrorHandler;\n className?: string;\n appearance?: ContentKitUiAppearance;\n}\n\n/**\n * Like and dislike toggles with counts: they change at once and roll back if\n * the server refuses. Signed out, they react anonymously where the server\n * allows it (`Config.anonymous.reactions`) and ask to sign in elsewhere.\n */\nexport function ReactionButtons({ item, counts: initial, dislike = true, onSignIn, size = \"default\", client, onError, className, appearance }: ReactionButtonsProps) {\n const m = useMessages();\n const { t } = m;\n const r = useReaction(item, { initial, client });\n const ctx = useContext(ContentKitContext);\n const { config } = useContentConfig({ client });\n const signIn = onSignIn ?? ctx?.onSignIn;\n // Signed out where the server takes no anonymous reactions.\n const mustSignIn = ctx?.viewer === null && config?.anonymous.reactions === false;\n const report = useErrorReporter(onError);\n const [error, setError] = useState<ContentKitError | null>(null);\n const toggle = (v: 1 | -1) => {\n if (mustSignIn) return signIn?.();\n setError(null);\n r.toggle(v).catch((e) => {\n const err = toContentKitError(e);\n if (err.code === \"unauthorized\" && signIn) return signIn();\n setError(err);\n report(err, \"reaction.save\");\n });\n };\n const btn = size === \"sm\" ? \"sm\" : \"default\";\n const hint = mustSignIn ? t(\"reactions.signIn\") : undefined;\n const disabled = mustSignIn && !signIn;\n return (\n <ContentKitUiRoot appearance={appearance} className={cn(\"inline-flex flex-wrap items-center gap-1 text-sm\", className)} data-ckui=\"reaction-buttons\">\n <div className=\"inline-flex items-center gap-1\">\n <Button variant={r.counts.mine === 1 ? \"secondary\" : \"ghost\"} size={btn} aria-pressed={r.counts.mine === 1} aria-label={t(\"reactions.like\")} title={hint} disabled={disabled} onClick={() => toggle(1)}>\n <HugeiconsIcon icon={ThumbsUpIcon} strokeWidth={2} />\n <span>{compact(r.counts.likes, m.language)}</span>\n </Button>\n {dislike && (\n <Button variant={r.counts.mine === -1 ? \"secondary\" : \"ghost\"} size={btn} aria-pressed={r.counts.mine === -1} aria-label={t(\"reactions.dislike\")} title={hint} disabled={disabled} onClick={() => toggle(-1)}>\n <HugeiconsIcon icon={ThumbsDownIcon} strokeWidth={2} />\n <span>{compact(r.counts.dislikes, m.language)}</span>\n </Button>\n )}\n </div>\n {error && (\n <span role=\"alert\" className=\"text-xs text-destructive\">\n {error.code === \"rate_limited\" || error.code === \"forbidden\" ? contentError(m, error) : t(\"reactions.failed\")}\n </span>\n )}\n </ContentKitUiRoot>\n );\n}\n\nexport interface FavoriteButtonProps {\n item: RefBody;\n /** Whether it is favorited and the item's count, as the host already has them: both given, nothing is read. */\n favorited?: boolean;\n count?: number;\n /** Show the item's favorite count. Default true. */\n showCount?: boolean;\n /** Show the label beside the icon. Default true. */\n label?: boolean;\n /** Asks a signed-out visitor to sign in (default the provider's). */\n onSignIn?: () => void;\n /** After each saved change. */\n onChange?: (favorited: boolean) => void;\n size?: \"sm\" | \"default\";\n client?: ContentKitClient;\n onError?: ContentKitErrorHandler;\n className?: string;\n appearance?: ContentKitUiAppearance;\n}\n\n/** Adds the item to the signed-in visitor's favorites, or removes it, with the server's count; changes at once and rolls back if refused. */\nexport function FavoriteButton({ item, favorited, count, showCount = true, label = true, onSignIn, onChange, size = \"default\", client, onError, className, appearance }: FavoriteButtonProps) {\n const m = useMessages();\n const { t } = m;\n const ctx = useContext(ContentKitContext);\n const f = useFavorite(item, { initial: favorited !== undefined && count !== undefined ? { favorited, count } : undefined, client });\n const signIn = onSignIn ?? ctx?.onSignIn;\n const report = useErrorReporter(onError);\n const [error, setError] = useState<ContentKitError | null>(null);\n const [status, setStatus] = useState(\"\");\n const shown = showCount ? f.count : undefined;\n const click = () => {\n if (ctx?.viewer === null) return signIn?.();\n setError(null);\n const next = !f.favorited;\n f.set(next).then(\n () => {\n setStatus(t(next ? \"favorites.added\" : \"favorites.removed\"));\n onChange?.(next);\n },\n (e) => {\n const err = toContentKitError(e);\n if (err.code === \"unauthorized\" && signIn) return signIn();\n setError(err);\n report(err, \"favorite.save\");\n },\n );\n };\n const text = t(ctx?.viewer === null && signIn ? \"favorites.signIn\" : f.favorited ? \"favorites.remove\" : \"favorites.add\");\n return (\n <ContentKitUiRoot appearance={appearance} className={cn(\"inline-flex flex-wrap items-center gap-2 text-sm\", className)} data-ckui=\"favorite-button\">\n <Button\n variant={f.favorited ? \"secondary\" : \"outline\"}\n size={label ? (size === \"sm\" ? \"sm\" : \"default\") : size === \"sm\" ? \"icon-sm\" : \"icon\"}\n aria-pressed={f.favorited}\n aria-label={label ? undefined : text}\n disabled={f.pending}\n onClick={click}\n >\n <HugeiconsIcon icon={FavouriteIcon} strokeWidth={2} className={cn(f.favorited && \"fill-current text-destructive\")} />\n {label && <span>{text}</span>}\n {shown !== undefined && <span className=\"tabular-nums text-muted-foreground\">{compact(Math.max(0, shown), m.language)}</span>}\n </Button>\n <span className=\"sr-only\" role=\"status\">\n {status}\n </span>\n {error && (\n <span role=\"alert\" className=\"text-xs text-destructive\">\n {contentError(m, error)}\n </span>\n )}\n </ContentKitUiRoot>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"engagement.js","names":[],"sources":["../../../src/components/social/engagement.tsx"],"sourcesContent":["import { FavouriteIcon, ThumbsDownIcon, ThumbsUpIcon } from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { cn } from \"cn\";\nimport { useContext, useState } from \"react\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport type { ContentKitError } from \"../../client/errors.js\";\nimport { toContentKitError } from \"../../client/errors.js\";\nimport type { Target } from \"../../client/content/types.js\";\nimport type { ReactionCounts } from \"../../client/generated/wire.js\";\nimport type { ContentKitUiAppearance } from \"../../appearance.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport { ContentKitContext, useErrorReporter, type ContentKitErrorHandler } from \"../../react/context.js\";\nimport { useContentConfig } from \"../../react/config.js\";\nimport { useFavorite, useReaction } from \"../../react/engagement.js\";\nimport { ContentKitUiRoot } from \"../../scope.js\";\nimport { Button } from \"#ckui/ui/button\";\nimport { contentError } from \"./parts.js\";\n\n\nconst compact = (n: number, language?: string) => new Intl.NumberFormat(language, { notation: \"compact\", maximumFractionDigits: 1 }).format(n);\n\nexport interface ReactionButtonsProps {\n item: Target;\n /** Counts the host already has, used instead of reading them. */\n counts?: ReactionCounts;\n /** Offer dislike too. Default true. */\n dislike?: boolean;\n /** Asks a signed-out visitor to sign in where the server takes no anonymous reactions (default the provider's). */\n onSignIn?: () => void;\n size?: \"sm\" | \"default\";\n client?: ContentKitClient;\n onError?: ContentKitErrorHandler;\n className?: string;\n appearance?: ContentKitUiAppearance;\n}\n\n/**\n * Like and dislike toggles with counts: they change at once and roll back if\n * the server refuses. Signed out, they react anonymously where the server\n * allows it (`Config.anonymous.reactions`) and ask to sign in elsewhere.\n */\nexport function ReactionButtons({ item, counts: initial, dislike = true, onSignIn, size = \"default\", client, onError, className, appearance }: ReactionButtonsProps) {\n const m = useMessages();\n const { t } = m;\n const r = useReaction(item, { initial, client });\n const ctx = useContext(ContentKitContext);\n const { config } = useContentConfig({ client });\n const signIn = onSignIn ?? ctx?.onSignIn;\n // Signed out where the server takes no anonymous reactions.\n const mustSignIn = ctx?.viewer === null && config?.anonymous.reactions === false;\n const report = useErrorReporter(onError);\n const [error, setError] = useState<ContentKitError | null>(null);\n const toggle = (v: 1 | -1) => {\n if (mustSignIn) return signIn?.();\n setError(null);\n r.toggle(v).catch((e) => {\n const err = toContentKitError(e);\n if (err.code === \"unauthorized\" && signIn) return signIn();\n setError(err);\n report(err, \"reaction.save\");\n });\n };\n const btn = size === \"sm\" ? \"sm\" : \"default\";\n const hint = mustSignIn ? t(\"reactions.signIn\") : undefined;\n const disabled = mustSignIn && !signIn;\n return (\n <ContentKitUiRoot appearance={appearance} className={cn(\"inline-flex flex-wrap items-center gap-1 text-sm\", className)} data-ckui=\"reaction-buttons\">\n <div className=\"inline-flex items-center gap-1\">\n <Button variant={r.counts.mine === 1 ? \"secondary\" : \"ghost\"} size={btn} aria-pressed={r.counts.mine === 1} aria-label={t(\"reactions.like\")} title={hint} disabled={disabled} onClick={() => toggle(1)}>\n <HugeiconsIcon icon={ThumbsUpIcon} strokeWidth={2} />\n <span>{compact(r.counts.likes, m.language)}</span>\n </Button>\n {dislike && (\n <Button variant={r.counts.mine === -1 ? \"secondary\" : \"ghost\"} size={btn} aria-pressed={r.counts.mine === -1} aria-label={t(\"reactions.dislike\")} title={hint} disabled={disabled} onClick={() => toggle(-1)}>\n <HugeiconsIcon icon={ThumbsDownIcon} strokeWidth={2} />\n <span>{compact(r.counts.dislikes, m.language)}</span>\n </Button>\n )}\n </div>\n {error && (\n <span role=\"alert\" className=\"text-xs text-destructive\">\n {error.code === \"rate_limited\" || error.code === \"forbidden\" ? contentError(m, error) : t(\"reactions.failed\")}\n </span>\n )}\n </ContentKitUiRoot>\n );\n}\n\nexport interface FavoriteButtonProps {\n item: Target;\n /** Whether it is favorited and the item's count, as the host already has them: both given, nothing is read. */\n favorited?: boolean;\n count?: number;\n /** Show the item's favorite count. Default true. */\n showCount?: boolean;\n /** Show the label beside the icon. Default true. */\n label?: boolean;\n /** Asks a signed-out visitor to sign in (default the provider's). */\n onSignIn?: () => void;\n /** After each saved change. */\n onChange?: (favorited: boolean) => void;\n size?: \"sm\" | \"default\";\n client?: ContentKitClient;\n onError?: ContentKitErrorHandler;\n className?: string;\n appearance?: ContentKitUiAppearance;\n}\n\n/** Adds the item to the signed-in visitor's favorites, or removes it, with the server's count; changes at once and rolls back if refused. */\nexport function FavoriteButton({ item, favorited, count, showCount = true, label = true, onSignIn, onChange, size = \"default\", client, onError, className, appearance }: FavoriteButtonProps) {\n const m = useMessages();\n const { t } = m;\n const ctx = useContext(ContentKitContext);\n const f = useFavorite(item, { initial: favorited !== undefined && count !== undefined ? { favorited, count } : undefined, client });\n const signIn = onSignIn ?? ctx?.onSignIn;\n const report = useErrorReporter(onError);\n const [error, setError] = useState<ContentKitError | null>(null);\n const [status, setStatus] = useState(\"\");\n const shown = showCount ? f.count : undefined;\n const click = () => {\n if (ctx?.viewer === null) return signIn?.();\n setError(null);\n const next = !f.favorited;\n f.set(next).then(\n () => {\n setStatus(t(next ? \"favorites.added\" : \"favorites.removed\"));\n onChange?.(next);\n },\n (e) => {\n const err = toContentKitError(e);\n if (err.code === \"unauthorized\" && signIn) return signIn();\n setError(err);\n report(err, \"favorite.save\");\n },\n );\n };\n const text = t(ctx?.viewer === null && signIn ? \"favorites.signIn\" : f.favorited ? \"favorites.remove\" : \"favorites.add\");\n return (\n <ContentKitUiRoot appearance={appearance} className={cn(\"inline-flex flex-wrap items-center gap-2 text-sm\", className)} data-ckui=\"favorite-button\">\n <Button\n variant={f.favorited ? \"secondary\" : \"outline\"}\n size={label ? (size === \"sm\" ? \"sm\" : \"default\") : size === \"sm\" ? \"icon-sm\" : \"icon\"}\n aria-pressed={f.favorited}\n aria-label={label ? undefined : text}\n disabled={f.pending}\n onClick={click}\n >\n <HugeiconsIcon icon={FavouriteIcon} strokeWidth={2} className={cn(f.favorited && \"fill-current text-destructive\")} />\n {label && <span>{text}</span>}\n {shown !== undefined && <span className=\"tabular-nums text-muted-foreground\">{compact(Math.max(0, shown), m.language)}</span>}\n </Button>\n <span className=\"sr-only\" role=\"status\">\n {status}\n </span>\n {error && (\n <span role=\"alert\" className=\"text-xs text-destructive\">\n {contentError(m, error)}\n </span>\n )}\n </ContentKitUiRoot>\n );\n}\n"],"mappings":"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"}
@@ -23,7 +23,7 @@ export declare function useCommentModerationAccess(o?: FlowClientOptions): Staff
23
23
  /**
24
24
  * Staff: every comment (deleted, held and rejected ones with their text) to
25
25
  * delete, restore or ban its author, by content kind or author; the review
26
- * queue of held comments and posts to approve or reject; and the site's
26
+ * queue of held comments and content to approve or reject; and the site's
27
27
  * comment bans. Sections, filters and pages live in the URL under basePath;
28
28
  * the caller sees only the sections its permissions allow.
29
29
  */
@@ -294,7 +294,7 @@ function J({ loc: c, view: _, client: S, ...C }) {
294
294
  });
295
295
  }
296
296
  function Y({ loc: e, view: n, ...r }) {
297
- let { t: a } = t(), o = e.query.get("kind") === "post" ? "post" : "comment", s = c({
297
+ let { t: a } = t(), o = e.query.get("kind") === "content" ? "content" : "comment", s = c({
298
298
  kind: o,
299
299
  pageSize: r.pageSize,
300
300
  client: r.client
@@ -306,12 +306,12 @@ function Y({ loc: e, view: n, ...r }) {
306
306
  className: "flex gap-2",
307
307
  role: "group",
308
308
  "aria-label": a("moderation.queue"),
309
- children: ["comment", "post"].map((t) => /* @__PURE__ */ V(i, {
309
+ children: ["comment", "content"].map((t) => /* @__PURE__ */ V(i, {
310
310
  size: "sm",
311
311
  variant: o === t ? "default" : "outline",
312
312
  "aria-pressed": o === t,
313
313
  onClick: () => e.go(n, { kind: t === "comment" ? void 0 : t }),
314
- children: a(t === "post" ? "moderation.queuePosts" : "moderation.queueComments")
314
+ children: a(t === "content" ? "moderation.queueContent" : "moderation.queueComments")
315
315
  }, t))
316
316
  }),
317
317
  /* @__PURE__ */ V(Z, {