@openrails/contentkit-ui 0.83.0 → 0.86.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 (219) hide show
  1. package/README.md +18 -7
  2. package/dist/client/beacons.d.ts +18 -6
  3. package/dist/client/beacons.js +26 -11
  4. package/dist/client/beacons.js.map +1 -1
  5. package/dist/client/client.d.ts +3 -0
  6. package/dist/client/client.js +29 -27
  7. package/dist/client/client.js.map +1 -1
  8. package/dist/client/codes.d.ts +6 -1
  9. package/dist/client/codes.js +4 -1
  10. package/dist/client/codes.js.map +1 -1
  11. package/dist/client/content/moderation.d.ts +14 -2
  12. package/dist/client/content/moderation.js +34 -0
  13. package/dist/client/content/moderation.js.map +1 -1
  14. package/dist/client/content/types.d.ts +13 -0
  15. package/dist/client/content/types.js.map +1 -1
  16. package/dist/client/discovery.d.ts +6 -0
  17. package/dist/client/discovery.js.map +1 -1
  18. package/dist/client/generated/error-codes.d.ts +1 -1
  19. package/dist/client/generated/error-codes.js +9 -1
  20. package/dist/client/generated/error-codes.js.map +1 -1
  21. package/dist/client/generated/routes.d.ts +91 -13
  22. package/dist/client/generated/routes.js +123 -2
  23. package/dist/client/generated/routes.js.map +1 -1
  24. package/dist/client/generated/wire.d.ts +81 -0
  25. package/dist/client/generated/wire.js.map +1 -1
  26. package/dist/client/index.d.ts +4 -2
  27. package/dist/client/media/queue.d.ts +4 -2
  28. package/dist/client/media/queue.js +18 -12
  29. package/dist/client/media/queue.js.map +1 -1
  30. package/dist/client/media/rules.d.ts +7 -1
  31. package/dist/client/media/rules.js +27 -21
  32. package/dist/client/media/rules.js.map +1 -1
  33. package/dist/client/reader-meta.d.ts +27 -0
  34. package/dist/client/reader-meta.js +99 -0
  35. package/dist/client/reader-meta.js.map +1 -0
  36. package/dist/client/stats.d.ts +32 -0
  37. package/dist/client/stats.js +35 -0
  38. package/dist/client/stats.js.map +1 -0
  39. package/dist/client/versions.d.ts +1 -1
  40. package/dist/client/versions.js +7 -2
  41. package/dist/client/versions.js.map +1 -1
  42. package/dist/client.js +30 -28
  43. package/dist/components/admin/content-manager.js +206 -206
  44. package/dist/components/admin/content-manager.js.map +1 -1
  45. package/dist/components/admin/group-manager.js +71 -70
  46. package/dist/components/admin/group-manager.js.map +1 -1
  47. package/dist/components/admin/media-item-panel.d.ts +24 -7
  48. package/dist/components/admin/media-item-panel.js +209 -197
  49. package/dist/components/admin/media-item-panel.js.map +1 -1
  50. package/dist/components/admin/poll-manager.js +25 -25
  51. package/dist/components/admin/reader-manifest.d.ts +18 -0
  52. package/dist/components/admin/reader-manifest.js +490 -0
  53. package/dist/components/admin/reader-manifest.js.map +1 -0
  54. package/dist/components/admin/stats-dashboard.d.ts +22 -0
  55. package/dist/components/admin/stats-dashboard.js +257 -0
  56. package/dist/components/admin/stats-dashboard.js.map +1 -0
  57. package/dist/components/content/card.js +43 -43
  58. package/dist/components/content/card.js.map +1 -1
  59. package/dist/components/content/editors.d.ts +2 -1
  60. package/dist/components/content/editors.js +479 -416
  61. package/dist/components/content/editors.js.map +1 -1
  62. package/dist/components/content/grid.js +47 -47
  63. package/dist/components/content/index.d.ts +2 -1
  64. package/dist/components/content/listing.js +34 -34
  65. package/dist/components/content/listing.js.map +1 -1
  66. package/dist/components/content/paywall.d.ts +17 -5
  67. package/dist/components/content/paywall.js +115 -100
  68. package/dist/components/content/paywall.js.map +1 -1
  69. package/dist/components/content/reader-stats.d.ts +12 -0
  70. package/dist/components/content/reader-stats.js +47 -0
  71. package/dist/components/content/reader-stats.js.map +1 -0
  72. package/dist/components/groups/banner.d.ts +1 -1
  73. package/dist/components/groups/banner.js +34 -34
  74. package/dist/components/groups/banner.js.map +1 -1
  75. package/dist/components/groups/directory.js +11 -11
  76. package/dist/components/groups/editor.js +294 -294
  77. package/dist/components/groups/editor.js.map +1 -1
  78. package/dist/components/groups/header.js +27 -27
  79. package/dist/components/groups/header.js.map +1 -1
  80. package/dist/components/groups/memberships.js +180 -180
  81. package/dist/components/groups/parts.d.ts +2 -4
  82. package/dist/components/groups/parts.js +69 -88
  83. package/dist/components/groups/parts.js.map +1 -1
  84. package/dist/components/media-folder-editor.js +239 -189
  85. package/dist/components/media-folder-editor.js.map +1 -1
  86. package/dist/components/notifications.js +17 -17
  87. package/dist/components/slot-upload.d.ts +2 -2
  88. package/dist/components/slot-upload.js +84 -79
  89. package/dist/components/slot-upload.js.map +1 -1
  90. package/dist/components/social/bans.js +34 -34
  91. package/dist/components/social/comments.js +59 -45
  92. package/dist/components/social/comments.js.map +1 -1
  93. package/dist/components/social/index.d.ts +1 -0
  94. package/dist/components/social/moderation.d.ts +5 -4
  95. package/dist/components/social/moderation.js +177 -160
  96. package/dist/components/social/moderation.js.map +1 -1
  97. package/dist/components/social/parts.js +22 -14
  98. package/dist/components/social/parts.js.map +1 -1
  99. package/dist/components/social/rules.d.ts +23 -0
  100. package/dist/components/social/rules.js +261 -0
  101. package/dist/components/social/rules.js.map +1 -0
  102. package/dist/components/video-player.d.ts +2 -0
  103. package/dist/components/video-player.js +318 -314
  104. package/dist/components/video-player.js.map +1 -1
  105. package/dist/i18n/context.d.ts +2 -0
  106. package/dist/i18n/context.js +23 -5
  107. package/dist/i18n/context.js.map +1 -1
  108. package/dist/index.d.ts +3 -1
  109. package/dist/index.js +28 -24
  110. package/dist/locales/admin/de.js +105 -0
  111. package/dist/locales/admin/de.js.map +1 -1
  112. package/dist/locales/admin/en.d.ts +105 -0
  113. package/dist/locales/admin/en.js +105 -0
  114. package/dist/locales/admin/en.js.map +1 -1
  115. package/dist/locales/admin/es.js +105 -0
  116. package/dist/locales/admin/es.js.map +1 -1
  117. package/dist/locales/admin/ja.js +105 -0
  118. package/dist/locales/admin/ja.js.map +1 -1
  119. package/dist/locales/admin/ko.js +105 -0
  120. package/dist/locales/admin/ko.js.map +1 -1
  121. package/dist/locales/admin/zh.js +105 -0
  122. package/dist/locales/admin/zh.js.map +1 -1
  123. package/dist/locales/content/de.js +6 -0
  124. package/dist/locales/content/de.js.map +1 -1
  125. package/dist/locales/content/en.d.ts +6 -0
  126. package/dist/locales/content/en.js +6 -0
  127. package/dist/locales/content/en.js.map +1 -1
  128. package/dist/locales/content/es.js +6 -0
  129. package/dist/locales/content/es.js.map +1 -1
  130. package/dist/locales/content/ja.js +6 -0
  131. package/dist/locales/content/ja.js.map +1 -1
  132. package/dist/locales/content/ko.js +6 -0
  133. package/dist/locales/content/ko.js.map +1 -1
  134. package/dist/locales/content/zh.js +6 -0
  135. package/dist/locales/content/zh.js.map +1 -1
  136. package/dist/locales/de.js +4 -1
  137. package/dist/locales/de.js.map +1 -1
  138. package/dist/locales/discovery/de.js +1 -0
  139. package/dist/locales/discovery/de.js.map +1 -1
  140. package/dist/locales/discovery/en.d.ts +1 -0
  141. package/dist/locales/discovery/en.js +1 -0
  142. package/dist/locales/discovery/en.js.map +1 -1
  143. package/dist/locales/discovery/es.js +1 -0
  144. package/dist/locales/discovery/es.js.map +1 -1
  145. package/dist/locales/discovery/ja.js +1 -0
  146. package/dist/locales/discovery/ja.js.map +1 -1
  147. package/dist/locales/discovery/ko.js +1 -0
  148. package/dist/locales/discovery/ko.js.map +1 -1
  149. package/dist/locales/discovery/zh.js +1 -0
  150. package/dist/locales/discovery/zh.js.map +1 -1
  151. package/dist/locales/en.d.ts +118 -0
  152. package/dist/locales/en.js +4 -1
  153. package/dist/locales/en.js.map +1 -1
  154. package/dist/locales/es.js +4 -1
  155. package/dist/locales/es.js.map +1 -1
  156. package/dist/locales/ja.js +4 -1
  157. package/dist/locales/ja.js.map +1 -1
  158. package/dist/locales/ko.js +4 -1
  159. package/dist/locales/ko.js.map +1 -1
  160. package/dist/locales/social/de.js +3 -0
  161. package/dist/locales/social/de.js.map +1 -1
  162. package/dist/locales/social/en.d.ts +3 -0
  163. package/dist/locales/social/en.js +3 -0
  164. package/dist/locales/social/en.js.map +1 -1
  165. package/dist/locales/social/es.js +3 -0
  166. package/dist/locales/social/es.js.map +1 -1
  167. package/dist/locales/social/ja.js +3 -0
  168. package/dist/locales/social/ja.js.map +1 -1
  169. package/dist/locales/social/ko.js +3 -0
  170. package/dist/locales/social/ko.js.map +1 -1
  171. package/dist/locales/social/zh.js +3 -0
  172. package/dist/locales/social/zh.js.map +1 -1
  173. package/dist/locales/zh.js +4 -1
  174. package/dist/locales/zh.js.map +1 -1
  175. package/dist/react/admin.d.ts +1 -1
  176. package/dist/react/admin.js +24 -23
  177. package/dist/react/admin.js.map +1 -1
  178. package/dist/react/canonical.d.ts +4 -3
  179. package/dist/react/canonical.js +34 -33
  180. package/dist/react/canonical.js.map +1 -1
  181. package/dist/react/comments.d.ts +29 -1
  182. package/dist/react/comments.js +30 -2
  183. package/dist/react/comments.js.map +1 -1
  184. package/dist/react/contents.js +144 -144
  185. package/dist/react/contents.js.map +1 -1
  186. package/dist/react/context.d.ts +1 -1
  187. package/dist/react/context.js.map +1 -1
  188. package/dist/react/detail.d.ts +12 -6
  189. package/dist/react/detail.js +31 -24
  190. package/dist/react/detail.js.map +1 -1
  191. package/dist/react/discovery.js +1 -1
  192. package/dist/react/discovery.js.map +1 -1
  193. package/dist/react/folder.d.ts +7 -2
  194. package/dist/react/folder.js +165 -147
  195. package/dist/react/folder.js.map +1 -1
  196. package/dist/react/groups.d.ts +0 -1
  197. package/dist/react/groups.js +13 -12
  198. package/dist/react/groups.js.map +1 -1
  199. package/dist/react/index.d.ts +5 -3
  200. package/dist/react/location.d.ts +11 -0
  201. package/dist/react/location.js +18 -0
  202. package/dist/react/location.js.map +1 -0
  203. package/dist/react/public.d.ts +8 -0
  204. package/dist/react/public.js +32 -27
  205. package/dist/react/public.js.map +1 -1
  206. package/dist/react/resources.js +6 -0
  207. package/dist/react/resources.js.map +1 -1
  208. package/dist/react/stats.d.ts +24 -0
  209. package/dist/react/stats.js +28 -0
  210. package/dist/react/stats.js.map +1 -0
  211. package/dist/react/use-resource.js +8 -7
  212. package/dist/react/use-resource.js.map +1 -1
  213. package/dist/react/versions.js +20 -20
  214. package/dist/react.js +26 -24
  215. package/dist/styles.css +1 -1
  216. package/dist/urls/index.d.ts +35 -10
  217. package/dist/urls.js +100 -70
  218. package/dist/urls.js.map +1 -1
  219. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"media-item-panel.js","names":[],"sources":["../../../src/components/admin/media-item-panel.tsx"],"sourcesContent":["import { useId, useRef, useState } from \"react\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport { toContentKitError, type ContentKitError } from \"../../client/errors.js\";\nimport type { FileInfo, RefBody } from \"../../client/generated/wire.js\";\nimport type { Progress } from \"../../client/media/client.js\";\nimport { samePath } from \"../../client/media/client.js\";\nimport { isProcessing } from \"../../client/media/windows.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport { useFlowClient } from \"../../react/admin.js\";\nimport { useErrorReporter, useGuarded } from \"../../react/context.js\";\nimport { usePublicImage } from \"../../react/public.js\";\nimport { useMediaRead } from \"../../react/read.js\";\nimport { Alert, AlertDescription } from \"#ckui/ui/alert\";\nimport { Badge } from \"#ckui/ui/badge\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Input } from \"#ckui/ui/input\";\nimport { Label } from \"#ckui/ui/label\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"#ckui/ui/select\";\nimport { Switch } from \"#ckui/ui/switch\";\nimport { EncodeProgress } from \"../encode-progress.js\";\nimport { SlotImage } from \"../slot-image.js\";\nimport { VideoPosterPicker } from \"../video-poster-picker.js\";\nimport { ErrorLine, useAction } from \"../social/parts.js\";\nimport { AdminRoot, LoadFailed, NoAccess, Rows, useConfirm, type AdminFlowProps } from \"./shell.js\";\n\ntype Choice = string | { value: string; label: string };\n\nexport interface MediaItemPanelProps extends AdminFlowProps {\n /** The video item. */\n item: RefBody;\n /** The video's upload path. Default \"source\". */\n source?: string;\n /** The subtitle uploads' path pattern; null hides them. Default \"subs/{name}\". */\n subtitles?: string | null;\n /** The poster's upload path (its frames come from the video); null hides it. Default \"poster\". */\n poster?: string | null;\n /** The poster's public preset. Default \"poster\". */\n posterPreset?: string;\n /** Subtitle languages offered: codes, or codes with labels. Without them the language is typed. */\n languages?: readonly Choice[];\n}\n\ntype ItemState = \"ready\" | \"processing\" | \"failed\" | \"empty\";\nconst choices = (list?: readonly Choice[]) => (list ?? []).map((c) => (typeof c === \"string\" ? { value: c, label: c } : c));\nconst under = (pattern: string) => pattern.slice(0, pattern.indexOf(\"{name}\"));\n\n/**\n * One video item for its editors: its encode state and progress, the source\n * (replace it), subtitle sidecars (language, label, forced), the poster from\n * a frame or an image, and regenerate, which retries failed uploads.\n */\nexport function MediaItemPanel({ client: own, baseUrl, auth, guard, appearance, className, language, messages, ...p }: MediaItemPanelProps) {\n const client = useFlowClient({ client: own, baseUrl, auth });\n return (\n <AdminRoot flow=\"media-item-panel\" appearance={appearance} className={className} language={language} messages={messages} guard={guard}>\n <Panel {...p} client={client} />\n </AdminRoot>\n );\n}\n\ntype Inner = Omit<MediaItemPanelProps, \"client\" | \"baseUrl\" | \"auth\" | \"guard\" | \"appearance\" | \"className\" | \"language\" | \"messages\"> & { client: ContentKitClient };\n\nfunction Panel({ item, client, source = \"source\", subtitles = \"subs/{name}\", poster = \"poster\", posterPreset = \"poster\", languages, onError }: Inner) {\n const m = useMessages();\n const { t } = m;\n const r = useMediaRead(item, { editor: true, client });\n const regen = useAction(\"media.save\", onError);\n if (!r.read) {\n if (r.error?.code === \"not_found\") return <NoAccess>{t(\"mediaPanel.noAccess\")}</NoAccess>;\n return r.error ? <LoadFailed error={r.error} message={t(\"mediaPanel.loadFailed\")} retry={r.reload} /> : <Rows count={2} />;\n }\n if (!r.read.uploads) return <NoAccess>{t(\"mediaPanel.noAccess\")}</NoAccess>;\n const uploads = r.read.files.filter((f) => f.upload && !f.unattached);\n const video = uploads.find((f) => samePath(f.path, source));\n const failed = uploads.filter((f) => f.failed);\n const state: ItemState = !video ? \"empty\" : failed.length ? \"failed\" : uploads.some(isProcessing) ? \"processing\" : \"ready\";\n const subs = subtitles === null ? [] : uploads.filter((f) => f.path.startsWith(under(subtitles)));\n return (\n <>\n <div className=\"flex flex-wrap items-center gap-2\">\n <h2 className=\"text-base font-semibold\">{t(\"mediaPanel.title\")}</h2>\n <Badge variant={state === \"failed\" ? \"destructive\" : state === \"ready\" ? \"outline\" : \"secondary\"} data-ckui=\"media-state\" data-state={state}>\n {t(`mediaPanel.${state}`)}\n </Badge>\n <Button size=\"sm\" variant=\"outline\" className=\"ms-auto\" disabled={regen.pending || !uploads.length} onClick={() => void regen.run(() => client.media.commit(item, [{ op: \"regenerate\" }]))}>\n {t(\"mediaPanel.regenerate\")}\n </Button>\n </div>\n <ErrorLine error={regen.error} />\n {failed.map((f) => (\n <Alert key={f.path} variant=\"destructive\" data-ckui=\"media-failure\">\n <AlertDescription>\n {t(\"mediaPanel.failedFile\", { name: f.path.split(\"/\").pop()!, reason: m.error({ code: f.failed!.code, message: f.failed!.message, status: 422 }) })}\n </AlertDescription>\n </Alert>\n ))}\n <SourceSection item={item} path={source} video={video} client={client} onError={onError} />\n {poster !== null && video && <PosterSection item={item} path={poster} video={source} preset={posterPreset} client={client} onError={onError} />}\n {subtitles !== null && <Subtitles item={item} pattern={subtitles} files={subs} languages={languages} client={client} onError={onError} />}\n </>\n );\n}\n\nfunction bytes(n?: number): string {\n if (!n) return \"\";\n const mb = n / (1 << 20);\n return mb >= 1024 ? `${(mb / 1024).toFixed(1)} GB` : `${mb.toFixed(mb < 10 ? 1 : 0)} MB`;\n}\n\nfunction duration(s?: number): string {\n if (!s) return \"\";\n const m = Math.floor(s / 60);\n const sec = Math.round(s - m * 60);\n return `${m}:${String(sec).padStart(2, \"0\")}`;\n}\n\nfunction SourceSection({ item, path, video, client, onError }: { item: RefBody; path: string; video?: FileInfo; client: ContentKitClient; onError?: Inner[\"onError\"] }) {\n const { t } = useMessages();\n const file = useRef<HTMLInputElement>(null);\n const [progress, setProgress] = useState<Progress | null>(null);\n const report = useErrorReporter(onError);\n const guarded = useGuarded();\n const [error, setError] = useState<ContentKitError | null>(null);\n const replace = async (f: File) => {\n setError(null);\n try {\n await guarded(() => client.media.put(f, { ref: item, path, wait: false, onProgress: setProgress }));\n } catch (e) {\n const err = toContentKitError(e);\n setError(err);\n report(err, \"media.save\");\n } finally {\n setProgress(null);\n }\n };\n const facts = video ? [video.w && video.h ? `${video.w}×${video.h}` : \"\", duration(video.dur), bytes(video.size)].filter(Boolean).join(\" · \") : \"\";\n return (\n <section className=\"grid gap-2\" data-ckui=\"media-source\">\n <h3 className=\"font-medium\">{t(\"mediaPanel.source\")}</h3>\n <div className=\"flex flex-wrap items-center gap-3\">\n <span className=\"min-w-0 flex-1 text-muted-foreground\">{video ? facts || video.path : t(\"mediaPanel.noSource\")}</span>\n <Button size=\"sm\" variant=\"outline\" disabled={!!progress} onClick={() => file.current?.click()}>\n {t(video ? \"mediaPanel.replace\" : \"mediaPanel.upload\")}\n </Button>\n <input\n ref={file}\n type=\"file\"\n accept=\"video/*\"\n hidden\n aria-label={t(\"mediaPanel.source\")}\n onChange={(e) => {\n const f = e.target.files?.[0];\n e.target.value = \"\";\n if (f) void replace(f);\n }}\n />\n </div>\n {progress && (\n <div className=\"grid gap-1\" role=\"status\">\n <div className=\"h-1.5 overflow-hidden rounded-full bg-muted\">\n <div className=\"h-full bg-primary transition-[width]\" style={{ width: `${progress.total ? Math.round((progress.loaded / progress.total) * 100) : 0}%` }} />\n </div>\n <span className=\"text-xs text-muted-foreground\">{t(`mediaPanel.phase_${progress.phase}`)}</span>\n </div>\n )}\n {video && isProcessing(video) && !progress && <EncodeProgress progress={video.progress} />}\n <ErrorLine error={error} />\n </section>\n );\n}\n\nfunction PosterSection({ item, path, video, preset, client, onError }: { item: RefBody; path: string; video: string; preset: string; client: ContentKitClient; onError?: Inner[\"onError\"] }) {\n const { t } = useMessages();\n const [open, setOpen] = useState(false);\n const { image, reload } = usePublicImage(item, preset, { client });\n return (\n <section className=\"grid gap-2\" data-ckui=\"media-poster\">\n <h3 className=\"font-medium\">{t(\"mediaPanel.poster\")}</h3>\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"w-40 overflow-hidden rounded-md border border-border\">\n <SlotImage image={image} fallback={<div className=\"aspect-video bg-muted\" />} />\n </div>\n <Button size=\"sm\" variant=\"outline\" onClick={() => setOpen(true)}>\n {t(\"mediaPanel.choosePoster\")}\n </Button>\n </div>\n <VideoPosterPicker open={open} onOpenChange={setOpen} item={item} video={video} path={path} image={image} client={client} onError={onError} onChange={() => reload()} />\n </section>\n );\n}\n\nfunction Subtitles({ item, pattern, files, languages: offered, client, onError }: { item: RefBody; pattern: string; files: FileInfo[]; languages?: readonly Choice[]; client: ContentKitClient; onError?: Inner[\"onError\"] }) {\n const { t } = useMessages();\n const ids = useId();\n const languages = choices(offered);\n const [lang, setLang] = useState(languages[0]?.value ?? \"\");\n const [label, setLabel] = useState(\"\");\n const [forced, setForced] = useState(false);\n const [file, setFile] = useState<File | null>(null);\n const input = useRef<HTMLInputElement>(null);\n const add = useAction(\"media.save\", onError);\n const remove = useAction(\"media.save\", onError);\n const { confirm, dialog } = useConfirm();\n const save = async () => {\n if (!file || !lang.trim()) return;\n const code = lang.trim();\n const name = `${code}${forced ? \"-forced\" : \"\"}`;\n const done = await add.run(() =>\n client.media.put(file, {\n ref: item,\n path: pattern.replace(\"{name}\", name),\n wait: false,\n meta: { lang: code, label: label.trim() || (languages.find((l) => l.value === code)?.label ?? code), forced },\n }),\n );\n if (done) {\n setFile(null);\n if (input.current) input.current.value = \"\";\n setLabel(\"\");\n setForced(false);\n }\n };\n const drop = async (f: FileInfo) => {\n if (await confirm({ title: t(\"mediaPanel.removeSubtitleTitle\", { name: String(f.meta?.label ?? f.path) }), confirm: t(\"common.remove\") })) {\n await remove.run(() => client.media.commit(item, [{ op: \"remove\", path: f.path }]));\n }\n };\n return (\n <section className=\"grid gap-2\" data-ckui=\"media-subtitles\">\n <h3 className=\"font-medium\">{t(\"mediaPanel.subtitles\")}</h3>\n {files.length ? (\n <ul className=\"grid divide-y divide-border rounded-lg border border-border\">\n {files.map((f) => (\n <li key={f.path} className=\"flex flex-wrap items-center gap-2 p-2.5\" data-ckui=\"subtitle\">\n <Badge variant=\"outline\">{String(f.meta?.lang ?? \"?\")}</Badge>\n <span className=\"min-w-0 flex-1 break-words\">{String(f.meta?.label ?? f.path.split(\"/\").pop())}</span>\n {f.meta?.forced === true && <Badge variant=\"secondary\">{t(\"mediaPanel.forced\")}</Badge>}\n {f.failed && <Badge variant=\"destructive\">{t(\"mediaPanel.failed\")}</Badge>}\n <Button size=\"xs\" variant=\"ghost\" disabled={remove.pending} onClick={() => void drop(f)}>\n {t(\"common.remove\")}\n </Button>\n </li>\n ))}\n </ul>\n ) : (\n <p className=\"text-muted-foreground\">{t(\"mediaPanel.noSubtitles\")}</p>\n )}\n <form\n className=\"grid gap-2 rounded-lg border border-dashed border-border p-3 sm:grid-cols-2\"\n onSubmit={(e) => {\n e.preventDefault();\n void save();\n }}\n >\n <div className=\"grid gap-1.5\">\n <Label htmlFor={`${ids}-file`}>{t(\"mediaPanel.subtitleFile\")}</Label>\n <Input id={`${ids}-file`} ref={input} type=\"file\" accept=\".vtt,.srt,text/vtt,application/x-subrip\" onChange={(e) => setFile(e.target.files?.[0] ?? null)} />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor={`${ids}-lang`}>{t(\"mediaPanel.language\")}</Label>\n {languages.length ? (\n <Select value={lang} onValueChange={(v) => setLang(String(v))}>\n <SelectTrigger id={`${ids}-lang`} className=\"w-full\">\n <SelectValue>{(v: string) => languages.find((l) => l.value === v)?.label ?? v}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n {languages.map((l) => (\n <SelectItem key={l.value} value={l.value}>\n {l.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n ) : (\n <Input id={`${ids}-lang`} value={lang} placeholder=\"en\" onChange={(e) => setLang(e.target.value)} />\n )}\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor={`${ids}-label`}>{t(\"mediaPanel.label\")}</Label>\n <Input id={`${ids}-label`} value={label} placeholder={t(\"mediaPanel.labelPlaceholder\")} onChange={(e) => setLabel(e.target.value)} />\n </div>\n <div className=\"flex items-center gap-2 self-end\">\n <Switch id={`${ids}-forced`} checked={forced} onCheckedChange={setForced} />\n <Label htmlFor={`${ids}-forced`}>{t(\"mediaPanel.forcedLabel\")}</Label>\n </div>\n <ErrorLine error={add.error} className=\"sm:col-span-2\" />\n <Button type=\"submit\" size=\"sm\" className=\"justify-self-start\" disabled={add.pending || !file || !lang.trim()}>\n {add.pending ? t(\"common.saving\") : t(\"mediaPanel.addSubtitle\")}\n </Button>\n </form>\n <ErrorLine error={remove.error} />\n {dialog}\n </section>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"media-item-panel.js","names":[],"sources":["../../../src/components/admin/media-item-panel.tsx"],"sourcesContent":["import { useId, useRef, useState } from \"react\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport { toContentKitError, type ContentKitError } from \"../../client/errors.js\";\nimport type { FileInfo, RefBody, UploadRule } from \"../../client/generated/wire.js\";\nimport { isSubtitleType, isVideoType } from \"../../client/gallery.js\";\nimport { acceptOf, isPattern } from \"../../client/media/rules.js\";\nimport type { Progress } from \"../../client/media/client.js\";\nimport { samePath } from \"../../client/media/client.js\";\nimport { isProcessing } from \"../../client/media/windows.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport { useFlowClient } from \"../../react/admin.js\";\nimport { useContentKitClient, useErrorReporter, useGuarded, type ContentKitErrorHandler } from \"../../react/context.js\";\nimport { usePublicImage } from \"../../react/public.js\";\nimport { useMediaRead } from \"../../react/read.js\";\nimport { Alert, AlertDescription } from \"#ckui/ui/alert\";\nimport { Badge } from \"#ckui/ui/badge\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Input } from \"#ckui/ui/input\";\nimport { Label } from \"#ckui/ui/label\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"#ckui/ui/select\";\nimport { Switch } from \"#ckui/ui/switch\";\nimport { EncodeProgress } from \"../encode-progress.js\";\nimport { SlotImage } from \"../slot-image.js\";\nimport { VideoPosterPicker } from \"../video-poster-picker.js\";\nimport { ErrorLine, useAction } from \"../social/parts.js\";\nimport { AdminRoot, LoadFailed, NoAccess, Rows, useConfirm, type AdminFlowProps } from \"./shell.js\";\n\ntype Choice = string | { value: string; label: string };\n\ninterface VideoPaths {\n /** The video's upload path. Default the kind's literal video upload. */\n source?: string;\n /** The subtitle uploads' path pattern; null hides them. Default the kind's subtitle pattern. */\n subtitles?: string | null;\n /** The poster's upload path (its frames come from the video); null hides it. Default the kind's upload framed from the video. */\n poster?: string | null;\n /** The poster's public preset. Default \"poster\". */\n posterPreset?: string;\n /** Subtitle languages offered: codes, or codes with labels. Without them the language is typed. */\n languages?: readonly Choice[];\n}\n\nexport interface MediaItemPanelProps extends AdminFlowProps, VideoPaths {\n /** The video item. */\n item: RefBody;\n}\n\n/** A video item's upload paths from its kind's rules: the literal video upload, the image upload framed from it, a subtitle pattern. */\nexport function videoPaths(rules: readonly UploadRule[]): { source?: string; poster?: string; subtitles?: string } {\n const only = (r: UploadRule, is: (t: string) => boolean) => r.types.length > 0 && r.types.every(is);\n const source = rules.find((r) => !isPattern(r.path) && only(r, isVideoType))?.path;\n return {\n source,\n poster: source ? rules.find((r) => !isPattern(r.path) && r.frames === source)?.path : undefined,\n subtitles: rules.find((r) => isPattern(r.path) && only(r, isSubtitleType))?.path,\n };\n}\n\ntype ItemState = \"ready\" | \"processing\" | \"failed\" | \"empty\";\nconst choices = (list?: readonly Choice[]) => (list ?? []).map((c) => (typeof c === \"string\" ? { value: c, label: c } : c));\nconst under = (pattern: string) => pattern.slice(0, pattern.indexOf(\"{name}\"));\n\n/**\n * One video item for its editors: its encode state and progress, the source\n * (replace it), subtitle sidecars (language, label, forced), the poster from\n * a frame or an image, and regenerate, which retries failed uploads.\n */\nexport function MediaItemPanel({ client: own, baseUrl, auth, guard, appearance, className, language, messages, ...p }: MediaItemPanelProps) {\n const client = useFlowClient({ client: own, baseUrl, auth });\n return (\n <AdminRoot flow=\"media-item-panel\" appearance={appearance} className={className} language={language} messages={messages} guard={guard}>\n <VideoMediaEditor {...p} client={client} />\n </AdminRoot>\n );\n}\n\nexport interface VideoMediaEditorProps extends VideoPaths {\n item: RefBody;\n client?: ContentKitClient;\n onError?: ContentKitErrorHandler;\n}\n\n/** MediaItemPanel's body, for a host's own editor (the content manager's version media). */\nexport function VideoMediaEditor({ item, client: own, source: givenSource, subtitles: givenSubtitles, poster: givenPoster, posterPreset = \"poster\", languages, onError }: VideoMediaEditorProps) {\n const m = useMessages();\n const { t } = m;\n const client = useContentKitClient(own);\n const r = useMediaRead(item, { editor: true, client });\n const regen = useAction(\"media.save\", onError);\n if (!r.read) {\n if (r.error?.code === \"not_found\") return <NoAccess>{t(\"mediaPanel.noAccess\")}</NoAccess>;\n return r.error ? <LoadFailed error={r.error} message={t(\"mediaPanel.loadFailed\")} retry={r.reload} /> : <Rows count={2} />;\n }\n if (!r.read.uploads) return <NoAccess>{t(\"mediaPanel.noAccess\")}</NoAccess>;\n const rules = r.read.uploads;\n const derived = videoPaths(rules);\n const source = givenSource ?? derived.source;\n const poster = givenPoster === undefined ? derived.poster : givenPoster;\n const subtitles = givenSubtitles === undefined ? derived.subtitles : givenSubtitles;\n const accept = (path: string) => acceptOf(rules.filter((x) => x.path === path));\n const uploads = r.read.files.filter((f) => f.upload && !f.unattached);\n const video = source ? uploads.find((f) => samePath(f.path, source)) : undefined;\n const failed = uploads.filter((f) => f.failed);\n const state: ItemState = !video ? \"empty\" : failed.length ? \"failed\" : uploads.some(isProcessing) ? \"processing\" : \"ready\";\n const subs = subtitles ? uploads.filter((f) => f.path.startsWith(under(subtitles))) : [];\n return (\n <>\n <div className=\"flex flex-wrap items-center gap-2\">\n <h2 className=\"text-base font-semibold\">{t(\"mediaPanel.title\")}</h2>\n <Badge variant={state === \"failed\" ? \"destructive\" : state === \"ready\" ? \"outline\" : \"secondary\"} data-ckui=\"media-state\" data-state={state}>\n {t(`mediaPanel.${state}`)}\n </Badge>\n <Button size=\"sm\" variant=\"outline\" className=\"ms-auto\" disabled={regen.pending || !uploads.length} onClick={() => void regen.run(() => client.media.commit(item, [{ op: \"regenerate\" }]))}>\n {t(\"mediaPanel.regenerate\")}\n </Button>\n </div>\n <ErrorLine error={regen.error} />\n {failed.map((f) => (\n <Alert key={f.path} variant=\"destructive\" data-ckui=\"media-failure\">\n <AlertDescription>\n {t(\"mediaPanel.failedFile\", { name: f.path.split(\"/\").pop()!, reason: m.error({ code: f.failed!.code, message: f.failed!.message, status: 422 }) })}\n </AlertDescription>\n </Alert>\n ))}\n {source && <SourceSection item={item} path={source} accept={accept(source) ?? \"video/*\"} video={video} client={client} onError={onError} />}\n {source && poster && video && <PosterSection item={item} path={poster} video={source} preset={posterPreset} client={client} onError={onError} />}\n {subtitles && <Subtitles item={item} pattern={subtitles} accept={accept(subtitles)} files={subs} languages={languages} client={client} onError={onError} />}\n </>\n );\n}\n\ntype Inner = { client: ContentKitClient; onError?: ContentKitErrorHandler };\n\nfunction bytes(n?: number): string {\n if (!n) return \"\";\n const mb = n / (1 << 20);\n return mb >= 1024 ? `${(mb / 1024).toFixed(1)} GB` : `${mb.toFixed(mb < 10 ? 1 : 0)} MB`;\n}\n\nfunction duration(s?: number): string {\n if (!s) return \"\";\n const m = Math.floor(s / 60);\n const sec = Math.round(s - m * 60);\n return `${m}:${String(sec).padStart(2, \"0\")}`;\n}\n\nfunction SourceSection({ item, path, accept, video, client, onError }: { item: RefBody; path: string; accept: string; video?: FileInfo } & Inner) {\n const { t } = useMessages();\n const file = useRef<HTMLInputElement>(null);\n const [progress, setProgress] = useState<Progress | null>(null);\n const report = useErrorReporter(onError);\n const guarded = useGuarded();\n const [error, setError] = useState<ContentKitError | null>(null);\n const replace = async (f: File) => {\n setError(null);\n try {\n await guarded(() => client.media.put(f, { ref: item, path, wait: false, onProgress: setProgress }));\n } catch (e) {\n const err = toContentKitError(e);\n setError(err);\n report(err, \"media.save\");\n } finally {\n setProgress(null);\n }\n };\n const facts = video ? [video.w && video.h ? `${video.w}×${video.h}` : \"\", duration(video.dur), bytes(video.size)].filter(Boolean).join(\" · \") : \"\";\n return (\n <section className=\"grid gap-2\" data-ckui=\"media-source\">\n <h3 className=\"font-medium\">{t(\"mediaPanel.source\")}</h3>\n <div className=\"flex flex-wrap items-center gap-3\">\n <span className=\"min-w-0 flex-1 text-muted-foreground\">{video ? facts || video.path : t(\"mediaPanel.noSource\")}</span>\n <Button size=\"sm\" variant=\"outline\" disabled={!!progress} onClick={() => file.current?.click()}>\n {t(video ? \"mediaPanel.replace\" : \"mediaPanel.upload\")}\n </Button>\n <input\n ref={file}\n type=\"file\"\n accept={accept}\n hidden\n aria-label={t(\"mediaPanel.source\")}\n onChange={(e) => {\n const f = e.target.files?.[0];\n e.target.value = \"\";\n if (f) void replace(f);\n }}\n />\n </div>\n {progress && (\n <div className=\"grid gap-1\" role=\"status\">\n <div className=\"h-1.5 overflow-hidden rounded-full bg-muted\">\n <div className=\"h-full bg-primary transition-[width]\" style={{ width: `${progress.total ? Math.round((progress.loaded / progress.total) * 100) : 0}%` }} />\n </div>\n <span className=\"text-xs text-muted-foreground\">{t(`mediaPanel.phase_${progress.phase}`)}</span>\n </div>\n )}\n {video && isProcessing(video) && !progress && <EncodeProgress progress={video.progress} />}\n <ErrorLine error={error} />\n </section>\n );\n}\n\nfunction PosterSection({ item, path, video, preset, client, onError }: { item: RefBody; path: string; video: string; preset: string } & Inner) {\n const { t } = useMessages();\n const [open, setOpen] = useState(false);\n const { image, reload } = usePublicImage(item, preset, { client });\n return (\n <section className=\"grid gap-2\" data-ckui=\"media-poster\">\n <h3 className=\"font-medium\">{t(\"mediaPanel.poster\")}</h3>\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"w-40 overflow-hidden rounded-md border border-border\">\n <SlotImage image={image} fallback={<div className=\"aspect-video bg-muted\" />} />\n </div>\n <Button size=\"sm\" variant=\"outline\" onClick={() => setOpen(true)}>\n {t(\"mediaPanel.choosePoster\")}\n </Button>\n </div>\n <VideoPosterPicker open={open} onOpenChange={setOpen} item={item} video={video} path={path} image={image} client={client} onError={onError} onChange={() => reload()} />\n </section>\n );\n}\n\nfunction Subtitles({ item, pattern, accept, files, languages: offered, client, onError }: { item: RefBody; pattern: string; accept?: string; files: FileInfo[]; languages?: readonly Choice[] } & Inner) {\n const { t } = useMessages();\n const ids = useId();\n const languages = choices(offered);\n const [lang, setLang] = useState(languages[0]?.value ?? \"\");\n const [label, setLabel] = useState(\"\");\n const [forced, setForced] = useState(false);\n const [file, setFile] = useState<File | null>(null);\n const input = useRef<HTMLInputElement>(null);\n const add = useAction(\"media.save\", onError);\n const remove = useAction(\"media.save\", onError);\n const { confirm, dialog } = useConfirm();\n const save = async () => {\n if (!file || !lang.trim()) return;\n const code = lang.trim();\n const name = `${code}${forced ? \"-forced\" : \"\"}`;\n const done = await add.run(() =>\n client.media.put(file, {\n ref: item,\n path: pattern.replace(\"{name}\", name),\n wait: false,\n meta: { lang: code, label: label.trim() || (languages.find((l) => l.value === code)?.label ?? code), forced },\n }),\n );\n if (done) {\n setFile(null);\n if (input.current) input.current.value = \"\";\n setLabel(\"\");\n setForced(false);\n }\n };\n const drop = async (f: FileInfo) => {\n if (await confirm({ title: t(\"mediaPanel.removeSubtitleTitle\", { name: String(f.meta?.label ?? f.path) }), confirm: t(\"common.remove\") })) {\n await remove.run(() => client.media.commit(item, [{ op: \"remove\", path: f.path }]));\n }\n };\n return (\n <section className=\"grid gap-2\" data-ckui=\"media-subtitles\">\n <h3 className=\"font-medium\">{t(\"mediaPanel.subtitles\")}</h3>\n {files.length ? (\n <ul className=\"grid divide-y divide-border rounded-lg border border-border\">\n {files.map((f) => (\n <li key={f.path} className=\"flex flex-wrap items-center gap-2 p-2.5\" data-ckui=\"subtitle\">\n <Badge variant=\"outline\">{String(f.meta?.lang ?? \"?\")}</Badge>\n <span className=\"min-w-0 flex-1 break-words\">{String(f.meta?.label ?? f.path.split(\"/\").pop())}</span>\n {f.meta?.forced === true && <Badge variant=\"secondary\">{t(\"mediaPanel.forced\")}</Badge>}\n {f.failed && <Badge variant=\"destructive\">{t(\"mediaPanel.failed\")}</Badge>}\n <Button size=\"xs\" variant=\"ghost\" disabled={remove.pending} onClick={() => void drop(f)}>\n {t(\"common.remove\")}\n </Button>\n </li>\n ))}\n </ul>\n ) : (\n <p className=\"text-muted-foreground\">{t(\"mediaPanel.noSubtitles\")}</p>\n )}\n <form\n className=\"grid gap-2 rounded-lg border border-dashed border-border p-3 sm:grid-cols-2\"\n onSubmit={(e) => {\n e.preventDefault();\n void save();\n }}\n >\n <div className=\"grid gap-1.5\">\n <Label htmlFor={`${ids}-file`}>{t(\"mediaPanel.subtitleFile\")}</Label>\n <Input id={`${ids}-file`} ref={input} type=\"file\" accept={accept ?? \".vtt,.srt,text/vtt,application/x-subrip\"} onChange={(e) => setFile(e.target.files?.[0] ?? null)} />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor={`${ids}-lang`}>{t(\"mediaPanel.language\")}</Label>\n {languages.length ? (\n <Select value={lang} onValueChange={(v) => setLang(String(v))}>\n <SelectTrigger id={`${ids}-lang`} className=\"w-full\">\n <SelectValue>{(v: string) => languages.find((l) => l.value === v)?.label ?? v}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n {languages.map((l) => (\n <SelectItem key={l.value} value={l.value}>\n {l.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n ) : (\n <Input id={`${ids}-lang`} value={lang} placeholder=\"en\" onChange={(e) => setLang(e.target.value)} />\n )}\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor={`${ids}-label`}>{t(\"mediaPanel.label\")}</Label>\n <Input id={`${ids}-label`} value={label} placeholder={t(\"mediaPanel.labelPlaceholder\")} onChange={(e) => setLabel(e.target.value)} />\n </div>\n <div className=\"flex items-center gap-2 self-end\">\n <Switch id={`${ids}-forced`} checked={forced} onCheckedChange={setForced} />\n <Label htmlFor={`${ids}-forced`}>{t(\"mediaPanel.forcedLabel\")}</Label>\n </div>\n <ErrorLine error={add.error} className=\"sm:col-span-2\" />\n <Button type=\"submit\" size=\"sm\" className=\"justify-self-start\" disabled={add.pending || !file || !lang.trim()}>\n {add.pending ? t(\"common.saving\") : t(\"mediaPanel.addSubtitle\")}\n </Button>\n </form>\n <ErrorLine error={remove.error} />\n {dialog}\n </section>\n );\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { useMessages as e } from "../../i18n/context.js";
2
- import { Button as t } from "../../ui/button.js";
3
- import { keyOf as n, useContentScope as r, usePaged as i } from "../../react/use-resource.js";
2
+ import { keyOf as t, useContentScope as n, usePaged as r } from "../../react/use-resource.js";
3
+ import { Button as i } from "../../ui/button.js";
4
4
  import { Badge as a } from "../../ui/badge.js";
5
5
  import { Input as o } from "../../ui/input.js";
6
6
  import { Label as s } from "../../ui/label.js";
@@ -46,33 +46,33 @@ function L({ client: e, baseUrl: t, auth: n, guard: r, appearance: i, className:
46
46
  })
47
47
  });
48
48
  }
49
- function R({ basePath: n, navigation: r, ...i }) {
50
- let { t: a } = e(), o = w(n, r), s = N({ client: i.client });
49
+ function R({ basePath: t, navigation: n, ...r }) {
50
+ let { t: a } = e(), o = w(t, n), s = N({ client: r.client });
51
51
  if (s.loading) return /* @__PURE__ */ j(b, {});
52
52
  if (!s.allowed.polls) return /* @__PURE__ */ j(v, { children: a("pollManager.noAccess") });
53
53
  if (!o.view) return /* @__PURE__ */ j(z, {
54
- ...i,
54
+ ...r,
55
55
  loc: o
56
56
  });
57
- let c = /* @__PURE__ */ j(t, {
57
+ let c = /* @__PURE__ */ j(i, {
58
58
  variant: "ghost",
59
59
  size: "sm",
60
60
  className: "justify-self-start",
61
61
  onClick: () => o.go(""),
62
62
  children: a("pollManager.back")
63
- }), l = I(i.languages);
63
+ }), l = I(r.languages);
64
64
  return /* @__PURE__ */ M(A, { children: [c, o.view === "new" ? /* @__PURE__ */ j(C, {
65
65
  languages: l.length ? l : void 0,
66
- freeText: i.freeText,
67
- maxOptions: i.maxOptions,
68
- client: i.client,
69
- onError: i.onError,
66
+ freeText: r.freeText,
67
+ maxOptions: r.maxOptions,
68
+ client: r.client,
69
+ onError: r.onError,
70
70
  onCreated: (e) => o.go(e.id, void 0, { replace: !0 })
71
71
  }) : /* @__PURE__ */ j(C, {
72
72
  poll: o.view,
73
- maxOptions: i.maxOptions,
74
- client: i.client,
75
- onError: i.onError,
73
+ maxOptions: r.maxOptions,
74
+ client: r.client,
75
+ onError: r.onError,
76
76
  onDeleted: () => o.go("", void 0, { replace: !0 })
77
77
  }, o.view)] });
78
78
  }
@@ -88,7 +88,7 @@ function z({ loc: g, client: v, languages: C, pageSize: w = 20, onError: T }) {
88
88
  ...e
89
89
  }), [q, J] = k(R);
90
90
  D(() => J(R), [R]);
91
- let { store: Y, scope: X } = r(v), Z = i(Y, n("polls-page", X, R, z, V, H, U, w), { type: "polls" }, W, w, (e, t) => v.polls.adminList({
91
+ let { store: Y, scope: X } = n(v), Z = r(Y, t("polls-page", X, R, z, V, H, U, w), { type: "polls" }, W, w, (e, t) => v.polls.adminList({
92
92
  ...e,
93
93
  q: R || void 0,
94
94
  language: z || void 0,
@@ -111,7 +111,7 @@ function z({ loc: g, client: v, languages: C, pageSize: w = 20, onError: T }) {
111
111
  children: [/* @__PURE__ */ j("h2", {
112
112
  className: "text-base font-semibold",
113
113
  children: A("pollManager.title")
114
- }), /* @__PURE__ */ j(t, {
114
+ }), /* @__PURE__ */ j(i, {
115
115
  size: "sm",
116
116
  onClick: () => g.go("new"),
117
117
  children: A("pollManager.new")
@@ -139,7 +139,7 @@ function z({ loc: g, client: v, languages: C, pageSize: w = 20, onError: T }) {
139
139
  placeholder: A("pollManager.search"),
140
140
  onChange: (e) => J(e.target.value)
141
141
  }),
142
- /* @__PURE__ */ j(t, {
142
+ /* @__PURE__ */ j(i, {
143
143
  type: "submit",
144
144
  size: "sm",
145
145
  variant: "outline",
@@ -214,7 +214,7 @@ function z({ loc: g, client: v, languages: C, pageSize: w = 20, onError: T }) {
214
214
  })
215
215
  })]
216
216
  }),
217
- (H || U || R || z || V) && /* @__PURE__ */ j(t, {
217
+ (H || U || R || z || V) && /* @__PURE__ */ j(i, {
218
218
  size: "sm",
219
219
  variant: "ghost",
220
220
  onClick: () => g.go(""),
@@ -231,11 +231,11 @@ function z({ loc: g, client: v, languages: C, pageSize: w = 20, onError: T }) {
231
231
  className: "grid divide-y divide-border rounded-lg border border-border",
232
232
  "aria-busy": Z.loading,
233
233
  children: Z.items.map((e) => {
234
- let n = P(e);
234
+ let t = P(e);
235
235
  return /* @__PURE__ */ M("li", {
236
236
  className: "flex flex-wrap items-start gap-3 p-3",
237
237
  "data-ckui": "poll-row",
238
- "data-state": n,
238
+ "data-state": t,
239
239
  children: [/* @__PURE__ */ M("div", {
240
240
  className: "grid min-w-0 flex-1 gap-1",
241
241
  children: [/* @__PURE__ */ j("button", {
@@ -247,24 +247,24 @@ function z({ loc: g, client: v, languages: C, pageSize: w = 20, onError: T }) {
247
247
  className: "flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted-foreground",
248
248
  children: [
249
249
  /* @__PURE__ */ j(a, {
250
- variant: n === "live" ? "default" : n === "inactive" ? "outline" : "secondary",
251
- children: A(`pollManager.${n}`)
250
+ variant: t === "live" ? "default" : t === "inactive" ? "outline" : "secondary",
251
+ children: A(`pollManager.${t}`)
252
252
  }),
253
253
  /* @__PURE__ */ j("span", { children: e.language }),
254
254
  e.kind === "free_text" && /* @__PURE__ */ j("span", { children: A("pollEditor.freeText") }),
255
- /* @__PURE__ */ j("span", { children: A(n === "scheduled" ? "pollManager.goesLive" : "pollManager.wentLive", { date: m(E, e.live_at) }) }),
255
+ /* @__PURE__ */ j("span", { children: A(t === "scheduled" ? "pollManager.goesLive" : "pollManager.wentLive", { date: m(E, e.live_at) }) }),
256
256
  e.closes_at && /* @__PURE__ */ j("span", { children: A("poll.closes", { date: m(E, e.closes_at) }) }),
257
257
  /* @__PURE__ */ j("span", { children: e.kind === "free_text" ? E.plural("poll.answers", e.answer_count ?? 0) : E.plural("poll.votes", e.total_votes) })
258
258
  ]
259
259
  })]
260
260
  }), /* @__PURE__ */ M("div", {
261
261
  className: "flex gap-2",
262
- children: [/* @__PURE__ */ j(t, {
262
+ children: [/* @__PURE__ */ j(i, {
263
263
  size: "sm",
264
264
  variant: "outline",
265
265
  onClick: () => g.go(e.id),
266
266
  children: A("comments.edit")
267
- }), /* @__PURE__ */ j(t, {
267
+ }), /* @__PURE__ */ j(i, {
268
268
  size: "sm",
269
269
  variant: "destructive",
270
270
  disabled: Q.pending,
@@ -0,0 +1,18 @@
1
+ import { ContentKitUiAppearance } from '../../appearance.js';
2
+ import { ContentKitClient } from '../../client/client.js';
3
+ import { ContentKitErrorHandler } from '../../react/context.js';
4
+ export interface ReaderManifestEditorProps {
5
+ content: string;
6
+ version: string;
7
+ client?: ContentKitClient;
8
+ onError?: ContentKitErrorHandler;
9
+ className?: string;
10
+ appearance?: ContentKitUiAppearance;
11
+ }
12
+ /**
13
+ * Editors: a reader version's manifest over its published pages and audio:
14
+ * scroll anchors, foreground cues (one track at a page or anchor, matched
15
+ * from file names in one step), background tracks over a range, and the
16
+ * auto-advance default. Page order is the version's media order.
17
+ */
18
+ export declare function ReaderManifestEditor({ content, version, client: own, onError, className, appearance }: ReaderManifestEditorProps): import('react').JSX.Element;