@openrails/contentkit-ui 0.103.1 → 0.104.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/README.md +105 -43
  2. package/dist/client/beacons.d.ts +3 -13
  3. package/dist/client/beacons.js +4 -45
  4. package/dist/client/beacons.js.map +1 -1
  5. package/dist/client/client.d.ts +3 -0
  6. package/dist/client/client.js +45 -43
  7. package/dist/client/client.js.map +1 -1
  8. package/dist/client/content/favorites.d.ts +2 -0
  9. package/dist/client/content/favorites.js.map +1 -1
  10. package/dist/client/content/types.d.ts +3 -0
  11. package/dist/client/content/types.js.map +1 -1
  12. package/dist/client/discovery.d.ts +28 -3
  13. package/dist/client/discovery.js +22 -1
  14. package/dist/client/discovery.js.map +1 -1
  15. package/dist/client/engagement.d.ts +70 -0
  16. package/dist/client/engagement.js +191 -0
  17. package/dist/client/engagement.js.map +1 -0
  18. package/dist/client/generated/routes.d.ts +35 -9
  19. package/dist/client/generated/routes.js +59 -2
  20. package/dist/client/generated/routes.js.map +1 -1
  21. package/dist/client/generated/wire.d.ts +53 -12
  22. package/dist/client/generated/wire.js.map +1 -1
  23. package/dist/client/guest-reading-history.d.ts +40 -0
  24. package/dist/client/guest-reading-history.js +144 -0
  25. package/dist/client/guest-reading-history.js.map +1 -0
  26. package/dist/client/index.d.ts +4 -2
  27. package/dist/client/stats.d.ts +5 -5
  28. package/dist/client/stats.js.map +1 -1
  29. package/dist/client.js +24 -22
  30. package/dist/components/admin/content-manager.d.ts +1 -1
  31. package/dist/components/admin/content-manager.js +342 -302
  32. package/dist/components/admin/content-manager.js.map +1 -1
  33. package/dist/components/admin/page-review.js +106 -97
  34. package/dist/components/admin/page-review.js.map +1 -1
  35. package/dist/components/admin/quick-search.d.ts +14 -0
  36. package/dist/components/admin/quick-search.js +60 -0
  37. package/dist/components/admin/quick-search.js.map +1 -0
  38. package/dist/components/admin/reader-content-editor.d.ts +6 -0
  39. package/dist/components/admin/reader-content-editor.js +733 -0
  40. package/dist/components/admin/reader-content-editor.js.map +1 -0
  41. package/dist/components/admin/reader-manifest.js +120 -105
  42. package/dist/components/admin/reader-manifest.js.map +1 -1
  43. package/dist/components/admin/stats-dashboard.d.ts +4 -4
  44. package/dist/components/admin/stats-dashboard.js +132 -134
  45. package/dist/components/admin/stats-dashboard.js.map +1 -1
  46. package/dist/components/content/daily-releases.js +143 -191
  47. package/dist/components/content/daily-releases.js.map +1 -1
  48. package/dist/components/content/editor-save.d.ts +32 -0
  49. package/dist/components/content/editor-save.js +51 -0
  50. package/dist/components/content/editor-save.js.map +1 -0
  51. package/dist/components/content/editors.d.ts +17 -2
  52. package/dist/components/content/editors.js +359 -328
  53. package/dist/components/content/editors.js.map +1 -1
  54. package/dist/components/content/favorites.d.ts +6 -0
  55. package/dist/components/content/favorites.js +33 -0
  56. package/dist/components/content/favorites.js.map +1 -0
  57. package/dist/components/content/filter-dialog.js +19 -15
  58. package/dist/components/content/filter-dialog.js.map +1 -1
  59. package/dist/components/content/filters.d.ts +2 -0
  60. package/dist/components/content/filters.js +5 -1
  61. package/dist/components/content/filters.js.map +1 -1
  62. package/dist/components/content/grid.d.ts +34 -13
  63. package/dist/components/content/grid.js +300 -271
  64. package/dist/components/content/grid.js.map +1 -1
  65. package/dist/components/content/history.d.ts +6 -0
  66. package/dist/components/content/history.js +91 -0
  67. package/dist/components/content/history.js.map +1 -0
  68. package/dist/components/content/index.d.ts +1 -0
  69. package/dist/components/content/offer-fields.d.ts +1 -1
  70. package/dist/components/content/offer-fields.js +86 -64
  71. package/dist/components/content/offer-fields.js.map +1 -1
  72. package/dist/components/content/search.d.ts +11 -4
  73. package/dist/components/content/search.js +22 -11
  74. package/dist/components/content/search.js.map +1 -1
  75. package/dist/components/content/summary-tile.d.ts +14 -0
  76. package/dist/components/content/summary-tile.js +63 -0
  77. package/dist/components/content/summary-tile.js.map +1 -0
  78. package/dist/components/groups/memberships.d.ts +11 -1
  79. package/dist/components/groups/memberships.js +1 -1
  80. package/dist/components/groups/memberships.js.map +1 -1
  81. package/dist/components/media-folder-editor.d.ts +4 -0
  82. package/dist/components/media-folder-editor.js +178 -168
  83. package/dist/components/media-folder-editor.js.map +1 -1
  84. package/dist/components/video-mini-player.d.ts +4 -1
  85. package/dist/components/video-mini-player.js +77 -71
  86. package/dist/components/video-mini-player.js.map +1 -1
  87. package/dist/components/video-player.d.ts +4 -1
  88. package/dist/components/video-player.js +280 -276
  89. package/dist/components/video-player.js.map +1 -1
  90. package/dist/index.d.ts +1 -0
  91. package/dist/index.js +17 -14
  92. package/dist/locales/admin/de.js +33 -8
  93. package/dist/locales/admin/de.js.map +1 -1
  94. package/dist/locales/admin/en.d.ts +29 -4
  95. package/dist/locales/admin/en.js +33 -8
  96. package/dist/locales/admin/en.js.map +1 -1
  97. package/dist/locales/admin/es.js +33 -8
  98. package/dist/locales/admin/es.js.map +1 -1
  99. package/dist/locales/admin/ja.js +33 -8
  100. package/dist/locales/admin/ja.js.map +1 -1
  101. package/dist/locales/admin/ko.js +33 -8
  102. package/dist/locales/admin/ko.js.map +1 -1
  103. package/dist/locales/admin/zh.js +33 -8
  104. package/dist/locales/admin/zh.js.map +1 -1
  105. package/dist/locales/discovery/de.js +0 -1
  106. package/dist/locales/discovery/de.js.map +1 -1
  107. package/dist/locales/discovery/en.d.ts +0 -1
  108. package/dist/locales/discovery/en.js +0 -1
  109. package/dist/locales/discovery/en.js.map +1 -1
  110. package/dist/locales/discovery/es.js +0 -1
  111. package/dist/locales/discovery/es.js.map +1 -1
  112. package/dist/locales/discovery/ja.js +0 -1
  113. package/dist/locales/discovery/ja.js.map +1 -1
  114. package/dist/locales/discovery/ko.js +0 -1
  115. package/dist/locales/discovery/ko.js.map +1 -1
  116. package/dist/locales/discovery/zh.js +0 -1
  117. package/dist/locales/discovery/zh.js.map +1 -1
  118. package/dist/locales/en.d.ts +29 -5
  119. package/dist/react/discovery.d.ts +20 -17
  120. package/dist/react/discovery.js +273 -221
  121. package/dist/react/discovery.js.map +1 -1
  122. package/dist/react/index.d.ts +2 -1
  123. package/dist/react/page-review.d.ts +1 -1
  124. package/dist/react/page-review.js +6 -5
  125. package/dist/react/page-review.js.map +1 -1
  126. package/dist/react/resources.d.ts +3 -1
  127. package/dist/react/resources.js +4 -0
  128. package/dist/react/resources.js.map +1 -1
  129. package/dist/react/stats.d.ts +2 -2
  130. package/dist/react/stats.js.map +1 -1
  131. package/dist/react/use-draft.d.ts +8 -0
  132. package/dist/react/use-draft.js +35 -0
  133. package/dist/react/use-draft.js.map +1 -0
  134. package/dist/react/use-engagement.d.ts +26 -0
  135. package/dist/react/use-engagement.js +221 -0
  136. package/dist/react/use-engagement.js.map +1 -0
  137. package/dist/react/use-resource.d.ts +4 -3
  138. package/dist/react/use-resource.js +2 -1
  139. package/dist/react/use-resource.js.map +1 -1
  140. package/dist/react.js +12 -11
  141. package/dist/styles.css +1 -1
  142. package/dist/ui/dialog.d.ts +2 -1
  143. package/dist/ui/dialog.js +23 -20
  144. package/dist/ui/dialog.js.map +1 -1
  145. package/package.json +1 -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 { 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 + folder.pending.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 + folder.pending.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 {folder.pending.length > 0 && (\n <ul className=\"grid\" aria-label={t(\"folder.label\")} data-ckui=\"folder-pending\">\n {folder.pending.map((f) => (\n <PendingRow key={f.path} file={f} folder={folder} auto={auto} disabled={off} />\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.items.length > 0 && !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 + folder.pending.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\n/** An upload on the server not yet added: an earlier visit's, kept across reloads. */\nfunction PendingRow({ file: f, folder, auto, disabled }: { file: FileInfo; folder: UseMediaFolder; auto: boolean; disabled: boolean }) {\n const { t, error: errorText } = useMessages();\n const kind = kindOf(f.type);\n const busy = isProcessing(f);\n const thumb = useMemo(() => thumbnailOf(folder.read.read, f), [folder.read.read, f]);\n const label = f.failed\n ? errorText(failureError(f.failed))\n : busy\n ? f.progress && f.progress.phase !== \"queued\"\n ? t(\"folder.processingPercent\", { percent: Math.round(f.progress.percent) })\n : t(\"folder.processing\")\n : auto\n ? t(\"folder.adding\")\n : t(\"folder.notAdded\");\n return (\n <li className=\"flex min-h-11 items-center gap-2 px-1\" data-ckui=\"pending-row\" data-path={f.path}>\n <Thumb kind={kind} url={thumb?.url} busy={busy} />\n <div className=\"grid min-w-0 flex-1 gap-1\">\n <span className=\"truncate text-sm\" title={f.path}>\n {f.path.slice(f.path.lastIndexOf(\"/\") + 1)}\n </span>\n <span className={cn(\"text-xs\", f.failed ? \"text-destructive\" : \"text-muted-foreground\")} data-ckui=\"queue-status\">\n {label}\n </span>\n </div>\n <Button variant=\"ghost\" size=\"icon-sm\" aria-label={t(\"common.remove\")} title={t(\"common.remove\")} disabled={disabled || folder.updating} onClick={() => void folder.remove([f.path]).catch(() => {})}>\n <HugeiconsIcon icon={Delete02Icon} strokeWidth={2} />\n </Button>\n </li>\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":";;;;;;;;;;;;;;;;;;;;;;;;AAuFA,IAAM,KAAkC;CAAC;CAAI;CAAO;CAAO;AAAM;AAIjE,SAAS,EAAO,GAAgC;CAK9C,OAJI,EAAY,CAAI,IAAU,UAC1B,EAAY,CAAI,IAAU,UAC1B,EAAY,CAAI,IAAU,UAC1B,EAAe,CAAI,IAAU,aAC1B;AACT;AAEA,IAAM,IAAsC;CAAE,OAAO;CAAa,OAAO;CAAa,OAAO;CAAiB,UAAU;CAAY,MAAM;AAAW;AAGrJ,SAAS,EAAS,GAAoC;CACpD,IAAM,IAAQ,IAAI,KAAK,GAAM,SAAS,CAAC,EAAA,CAAG,IAAI,CAAM,CAAC;CACrD,OAAO,EAAM,SAAS,IAAI,CAAC,GAAG,CAAK,CAAC,CAAC,KAAM;AAC7C;AAGA,SAAgB,GAAc,GAAoB,GAAsC;CACtF,IAAM,IAAkB,CAAC;CACzB,KAAK,IAAM,KAAK,GAAO;EACrB,IAAI,CAAC,EAAE,MAAM,QAAQ;EACrB,IAAM,IAAO,EAAE,gBAAgB,EAAS,CAAC,GAAG,GACtC,IAAO,EAAE,YAAY,IAAI,EAAE,oBAAoB;GAAE;GAAM,MAAM,EAAU,EAAE,SAAS;EAAE,CAAC,IAAI;EAE/F,AADA,EAAM,KAAK,EAAE,MAAM,GAAG,EAAK,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,CAAI,GACxE,EAAE,cAAc,EAAE,cAAY,EAAM,KAAK,EAAE,sBAAsB;GAAE,KAAK,EAAW,EAAE,UAAU;GAAG,KAAK,EAAW,EAAE,UAAU;EAAE,CAAC,CAAC;CACxI;CACA,OAAO,EAAM,KAAK,KAAK;AACzB;AAUA,SAAgB,GAAkB,GAA2B;CAE3D,IAAI,EAAE,QAAQ;EACZ,IAAM,EAAE,WAAQ,GAAG,MAAS;EAC5B,OAAO,kBAAC,GAAD;GAAgE;GAAQ,GAAI;EAAO,GAAlE,EAAO,MAAM,EAAQ,EAAO,GAAG,IAAI,EAA+B;CAC5F;CAEA,OAAO,kBAAC,IAAD,EAAiC,GAAI,EAAI,GAAzB,EAAQ,EAAE,IAAI,CAAW;AAClD;AAEA,SAAS,GAAU,GAAwE;CACzF,IAAM,EAAE,SAAM,QAAK,UAAO,YAAS,eAAY,WAAQ,YAAS,kBAAe,aAAU,cAAW,eAAY,GAAG,MAAY,GACzH,IAAS,EAAe,GAAM,CAAO;CAC3C,OAAO,kBAAC,GAAD;EAAkB;EAAQ;EAAK;EAAO;EAAS;EAAY;EAAQ;EAAS;EAAe;EAAU;EAAW;CAAe,CAAA;AACxI;AAEA,IAAM,KAAmB;CAAE,MAAM;CAAI,IAAI;AAAG;AAE5C,SAAS,EAAW,GAA4D;CAC9E,IAAM,EAAE,WAAQ,QAAK,UAAO,YAAS,eAAY,WAAQ,aAAU,IAAS,kBAAe,aAAU,cAAW,kBAAe,GACzH,EAAE,MAAG,OAAO,MAAc,EAAY,GACtC,EAAE,WAAQ,UAAO,SAAM,eAAY;CACzC,GAAoB,UAAY;EAAE,SAAS,EAAO;EAAS,QAAQ,EAAO;EAAQ;CAAO,IAAI,CAAC,CAAM,CAAC;CACrG,IAAM,IAAO,EAAQ,WAAW,QAC1B,IAAQ,EAAO,SAAS,MAAO,EAAE,OAAO,CAAC,EAAE,IAAI,IAAI,CAAC,CAAE,GACtD,IAAS,EAAS,CAAK,GAEvB,IADQ,EAAO,QAAQ,SAAS,EAAM,MAAM,SAAS,EAAO,QAAQ,SAAS,EAAO,QAAQ,WAC1E,GAClB,IAAM,CAAC,CAAC,GAER,CAAC,GAAU,KAAe,kBAA8B,IAAI,IAAI,CAAC;CACvE,QAAgB;EACd,IAAM,IAAQ,IAAI,IAAI,EAAO,QAAQ,KAAK,MAAM,EAAE,IAAI,CAAC;EACvD,GAAa,MAAO,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,MAAM,EAAM,IAAI,CAAC,CAAC,IAAI,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,MAAM,EAAM,IAAI,CAAC,CAAC,CAAC,CAAE;CAC1G,GAAG,CAAC,EAAO,OAAO,CAAC;CACnB,IAAM,CAAC,GAAU,KAAe,EAAwB,IAAI,GACtD,IAAO,EAAc,EAAO,OAAO,IAAS,GAAU;EAAE,QAAQ,EAAQ;EAAQ,SAAS,EAAQ;EAAS,eAAe,EAAY,IAAI;CAAE,CAAC,GAC5I,IAAW,IAAW,EAAO,MAAM,MAAM,EAAE,MAAM,MAAM,MAAM,EAAE,SAAS,CAAQ,CAAC,CAAC,EAAE,OAAO,KAAA,GAC3F,CAAC,IAAU,MAAe,EAAwB,IAAI,GACtD,IAAe,GAAyB,IAAI,GAC5C,CAAC,GAAW,KAAgB,EAAwB,IAAI,GACxD,CAAC,GAAM,KAAW,EAAS,EAAK,GAEhC,KAAO;EACX,aAAa,MAAiB;GACxB,MAAQ,EAAE,aAAa,MAAM,SAAS,OAAO,MACjD,EAAE,eAAe,GACjB,EAAQ,EAAI;EACd;EACA,cAAc,MAAiB;GAC7B,AAAK,EAAE,cAAc,SAAS,EAAE,aAA4B,KAAG,EAAQ,EAAK;EAC9E;EACA,SAAS,MAAiB;GACpB,MAAQ,EAAE,aAAa,MAAM,WACjC,EAAE,eAAe,GACjB,EAAQ,EAAK,GACb,EAAO,IAAI,EAAE,aAAa,KAAK;EACjC;CACF,GAEM,KAAiB,YAAY;EACjC,IAAM,IAAQ,CAAC,GAAG,CAAQ;EACf,OAAkB,OAAe,IAAgB,MAAM,EAAc,EAAM,MAAM,IAAI,WAAW,UAAU,EAAE,wBAAwB,EAAE,OAAO,EAAM,OAAO,CAAC,CAAC,KAAK,QAE5K,MAAM,EAAO,OAAO,CAAK,CAAC,CAAC,WAAW,kBAAY,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC;CACxE,GAEM,KAAW,EAAM,MAAM,QAAQ,MAAM,EAAE,WAAW,UAAU,CAAC,CAAC,SAAS,EAAO,QAAQ,QACtF,MAAU,MACd,kBAAC,SAAD;EACE,WAAW,EACT,IACI,+NACA,+MACJ,KAAO,KAAQ,+BACf,KAAO,gCACT;EACA,aAAW,IAAM,gBAAgB;EARnC,UAAA;GAUE,kBAAC,GAAD;IAAe,MAAM;IAAgB,aAAa;IAAM,WAAW,IAAM,WAAW;GAAW,CAAA;GAC9F,IAAM,kBAAC,UAAD;IAAQ,WAAU;IAA+B,UAAA,EAAE,aAAa;GAAU,CAAA,IAAI,EAAE,YAAY;GAClG,KAAO,EAAM,SAAS,KAAK,kBAAC,QAAD;IAAM,WAAU;IAAW,UAAA,GAAc,GAAG,CAAK;GAAQ,CAAA;GACrF,kBAAC,SAAD;IACE,MAAK;IACL,UAAA;IACQ;IACR,WAAU;IACV,UAAU;IACV,aAAU;IACV,WAAW,MAAM;KAEf,AADA,EAAO,IAAI,CAAC,GAAI,EAAE,OAAO,SAAS,CAAC,CAAE,CAAC,GACtC,EAAE,OAAO,QAAQ;IACnB;GACD,CAAA;EACI;;CAGT,OACE,kBAAC,GAAD;EAA8B;EAAY,WAAW,EAAG,cAAc,CAAS;EAAG,aAAU;EAAe,aAAW,IAAO,KAAK,KAAA;EAAW,GAAI;EAAjJ,UAAA;GACE,kBAAC,OAAD;IAAK,WAAU;IAAoD,aAAU;IAA7E,UAAA,CACE,kBAAC,MAAD;KAAI,WAAU;KAAyB,UAAA,KAAS,EAAE,cAAc;IAAM,CAAA,GACtE,kBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACG,GACA,CAAC,KAAS,GAAO,EAAK,CACpB;IACF,CAAA,CAAA;;GACJ,MAAU,EAAK,QAAQ,CAAC,EAAO,QAAQ,GAAO,EAAI;GAClD,KAAS,CAAC,EAAK,QAAQ,EAAK,WAC3B,kBAAC,OAAD;IAAK,WAAU;IAAiD,aAAU;IACxE,UAAA,kBAAC,GAAD;KAAe,MAAM;KAAe,aAAa;KAAG,WAAU;IAAmC,CAAA;GAC9F,CAAA;GAGN,EAAO,QAAQ,SAAS,KACvB,kBAAC,GAAD;IAAO,SAAQ;IAAc,MAAK;IAAQ,aAAU;IAApD,UAAA,CACE,kBAAC,GAAD;KAAe,MAAM;KAAa,aAAa;IAAI,CAAA,GACnD,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,MAAD;KAAI,WAAU;KACX,UAAA,EAAO,QAAQ,KAAK,GAAG,MACtB,kBAAC,MAAD,EAAA,UAAA;MACE,kBAAC,QAAD;OAAM,WAAU;OAAe,UAAA,EAAE,KAAK;MAAW,CAAA;MAAC;MAAG,EAAU,EAAE,KAAK;KACpE,EAAA,GAFK,CAEL,CACL;IACC,CAAA,GACJ,kBAAC,GAAD;KAAQ,SAAQ;KAAU,MAAK;KAAK,WAAU;KAAa,SAAS,EAAO;KACxE,UAAA,EAAE,gBAAgB;IACb,CAAA,CACQ,EAAA,CAAA,CACb;;GAER,EAAM,WACL,kBAAC,GAAD;IAAO,SAAQ;IAAc,MAAK;IAAQ,aAAU;IAApD,UAAA;KACE,kBAAC,GAAD;MAAe,MAAM;MAAa,aAAa;KAAI,CAAA;KACnD,kBAAC,GAAD,EAAA,UAAa,EAAE,eAAe,EAAc,CAAA;KAC5C,kBAAC,GAAD,EAAA,UAAA,CACG,EAAU,EAAM,OAAO,GACxB,kBAAC,GAAD;MAAQ,SAAQ;MAAU,MAAK;MAAK,WAAU;MAAa,eAAe,EAAM,MAAM;MACnF,UAAA,EAAE,eAAe;KACZ,CAAA,CACQ,EAAA,CAAA;IACb;;GAER,EAAO,SACN,kBAAC,GAAD;IAAO,SAAQ;IAAc,MAAK;IAAQ,aAAU;IAApD,UAAA,CACE,kBAAC,GAAD;KAAe,MAAM;KAAa,aAAa;IAAI,CAAA,GACnD,kBAAC,GAAD,EAAA,UAAmB,EAAU,EAAO,KAAK,EAAoB,CAAA,CACxD;;GAGR,EAAS,OAAO,KACf,kBAAC,OAAD;IAAK,WAAU;IAA4E,aAAU;IAArG,UAAA;KACE,kBAAC,QAAD;MAAM,WAAU;MAAgB,UAAA,EAAE,mBAAmB,EAAE,OAAO,EAAS,KAAK,CAAC;KAAQ,CAAA;KACrF,kBAAC,GAAD;MAAQ,SAAQ;MAAc,MAAK;MAAK,UAAU,KAAO,EAAO;MAAU,eAAe,KAAK,GAAe;MAA7G,UAAA,CACE,kBAAC,GAAD;OAAe,MAAM;OAAc,aAAa;MAAI,CAAA,GACnD,EAAE,uBAAuB,CACpB;;KACR,kBAAC,GAAD;MAAQ,SAAQ;MAAQ,MAAK;MAAK,eAAe,kBAAY,IAAI,IAAI,CAAC;MACnE,UAAA,EAAE,uBAAuB;KACpB,CAAA;IACL;;GAGN,EAAO,KAAK,MACX,EAAE,MAAM,SACN,kBAAC,IAAD;IAEE,OAAO;IACP,QAAQ,EAAO,SAAS;IAChB;IACR,UAAU;IACA;IACV,WAAW,GAAM,MAAO,GAAa,MAAO,oBAAK,IAAI,IAAI,CAAC,GAAG,GAAG,CAAI,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,MAAM,MAAM,CAAI,CAAC,CAAE;IACzG;IACV,UAAU;IACV,QAAQ;IACR,YAAY,MAAS;KAEnB,AADA,EAAa,CAAI,GACjB,EAAa,SAAS,MAAM;IAC9B;IACY;GACb,GAfM,EAAE,IAeR,IACC,IACN;GAEC,EAAO,QAAQ,SAAS,KACvB,kBAAC,MAAD;IAAI,WAAU;IAAO,cAAY,EAAE,cAAc;IAC9C,UAAA,EAAO,QAAQ,KAAK,GAAG,MACtB,kBAAC,MAAD;KAAY,WAAU;KAAwC,aAAU;KAAY,eAAY;KAAhG,UAAA,CACE,kBAAC,GAAD,EAAO,MAAM,EAAO,EAAE,IAAI,EAAI,CAAA,GAC9B,kBAAC,OAAD;MAAK,WAAU;MAAf,UAAA,CACE,kBAAC,QAAD;OAAM,WAAU;OAAoB,UAAA,EAAE;MAAW,CAAA,GACjD,kBAAC,QAAD;OAAM,WAAU;OAAgC,aAAU;OACvD,UAAA,EAAE,eAAe;MACd,CAAA,CACH;KACH,CAAA,CAAA;IARK,GAAA,CAQL,CACL;GACC,CAAA;GAGL,EAAO,QAAQ,SAAS,KACvB,kBAAC,MAAD;IAAI,WAAU;IAAO,cAAY,EAAE,cAAc;IAAG,aAAU;IAC3D,UAAA,EAAO,QAAQ,KAAK,MACnB,kBAAC,IAAD;KAAyB,MAAM;KAAW;KAAc;KAAM,UAAU;IAAM,GAA7D,EAAE,IAA2D,CAC/E;GACC,CAAA;GAGL,EAAM,MAAM,SAAS,KACpB,kBAAC,GAAD;IACE,OAAO,EAAM;IACb,KAAK,MAAM,EAAE;IACb,OAAO,MAAM,EAAE,KAAK;IACpB,UAAU,KAAQ;IAClB,OAAO,EAAE,cAAc;IACvB,SAAS,GAAM,MAAO,EAAM,KAAK,EAAM,MAAM,EAAK,CAAE,IAAI,CAAE;IAC1D,MAAM,OAAO;KAAE,WAAW;KAAyC,aAAa;KAAa,eAAe,EAAE;IAAO;IAEnH,WAAA,GAAG,MAAW,kBAAC,IAAD;KAAU,MAAM;KAAG,QAAQ,IAAO,OAAO;KAAc;KAAc;IAAS,CAAA;GAClF,CAAA;IAGb,CAAC,KAAQ,KAAW,KAAO,KAAQ,EAAO,SAAS,KAAW,MAC/D,kBAAC,GAAD;IAAQ,WAAU;IAAQ,UAAU,KAAQ,EAAM,MAAM,SAAS,KAAK,CAAC,EAAM,SAAU,EAAO;IAAY,eAAe,KAAK,EAAO,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC;IAAG,aAAU;IAAzK,UAAA,CACG,EAAO,cAAc,kBAAC,GAAD;KAAe,MAAM;KAAe,aAAa;KAAG,WAAU;IAA4B,CAAA,GAC/G,IAAO,EAAE,oBAAoB,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAM,MAAM,QAAQ,MAAM,EAAE,WAAW,WAAW,CAAC,CAAC,SAAS,EAAO,QAAQ,OAAO,CAAC,CAC5I;;GAET;GAED,kBAAC,SAAD;IACE,KAAK;IACL,MAAK;IACG;IACR,WAAU;IACV,UAAU;IACV,eAAA;IACA,WAAW,MAAM;KACf,IAAM,IAAI,EAAE,OAAO,QAAQ;KAG3B,AAFA,EAAE,OAAO,QAAQ,IACb,KAAK,KAAW,EAAY,QAAQ,GAAW,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GACpE,EAAa,IAAI;IACnB;GACD,CAAA;GACD,kBAAC,GAAD;IACE,MAAM,CAAC,CAAC;IACR,eAAe,MAAM,CAAC,KAAK,EAAK,WAAW,YAAY,EAAY,IAAI;IACvE,QAAQ,YAAY,IAAQ,EAAK,UAAU,OAAQ;IACnD,QAAQ,GAAU,UAAU;IAC5B,SAAS,GAAU,SAAS,KAAA,IAAY;IACxC,aAAa,UAAU,IAAO,EAAK,OAAO;IAC1C,UAAU,GAAU;IACpB,OAAO,EAAE,aAAa;IACtB,MAAM,EAAK,WAAW;IACtB,OAAO,EAAK,WAAW,UAAU,EAAU,EAAK,KAAK,IAAI,KAAA;IACzD,YAAY,MAAS,KAAK,EAAK,KAAK,CAAI;GACzC,CAAA;EACe;;AAEtB;AAEA,SAAS,GAAM,EACb,UACA,WACA,WACA,aACA,aACA,aACA,aACA,aACA,WACA,cACA,iBAaC;CACD,IAAM,EAAE,SAAM,EAAY,GAEpB,IAAQ,EAAE,gBADH,EAAS,EAAM,IACI,GAAM,GAChC,IAAM,EAAM,MAAM;CACxB,OACE,kBAAC,WAAD;EAAS,WAAU;EAAa,aAAU;EAAe,aAAW,EAAM;EAA1E,UAAA,CACG,KACC,kBAAC,MAAD;GAAI,WAAU;GAAd,UAAA;IACG;IAAM;IAAI,IAAM,GAAG,EAAM,MAAM,OAAO,KAAK,MAAQ,EAAM,MAAM;GAC9D;EAEN,CAAA,GAAA,kBAAC,GAAD;GACE,OAAO,EAAM;GACb,KAAK,MAAM,EAAE;GACb,OAAO,MAAM,EAAO,GAAO,EAAE,IAAI;GACjC,UAAU,KAAY,EAAO;GAC7B,OAAO;GACP,SAAS,GAAM,MAAO,KAAK,EAAO,KAAK,EAAM,MAAM,EAAK,CAAE,MAAM,CAAE,CAAC,CAAC,YAAY,CAAC,CAAC;GAClF,MAAM,OAAO;IAAE,WAAW;IAAyC,aAAa;IAAc,aAAa,EAAE;GAAK;GAEhH,WAAA,GAAG,MACH,kBAAC,GAAD;IACE,MAAM;IACC;IACC;IACA;IACE;IACV,UAAU,EAAS,IAAI,EAAE,IAAI;IAC7B,WAAW,MAAO,EAAS,EAAE,MAAM,CAAE;IACrC,UAAU,MAAa,EAAE;IACf;IACF;IACG;IACX,SAAS,IAAa,CAAC;GACxB,CAAA;EAES,CAAA,CACP;;AAEb;AAEA,SAAS,EAAM,EAAE,SAAM,QAAK,WAAsD;CAChF,OACE,kBAAC,QAAD;EAAM,WAAU;EAAuH,aAAU;EAAjJ,UAAA,CACG,IAAM,kBAAC,OAAD;GAAK,KAAK;GAAK,KAAI;GAAG,SAAQ;GAAO,UAAS;GAAQ,WAAU;EAA0B,CAAA,IAAI,kBAAC,GAAD;GAAe,MAAM,EAAM;GAAO,aAAa;GAAM,WAAU;EAAY,CAAA,GAC/K,KAAQ,CAAC,KAAO,kBAAC,QAAD;GAAM,eAAA;GAAY,WAAU;EAAwG,CAAA,CACjJ;;AAEV;AAEA,SAAS,EAAU,EACjB,MAAM,GACN,UACA,WACA,WACA,aACA,aACA,aACA,aACA,aACA,WACA,cACA,cAcC;CACD,IAAM,EAAE,MAAG,OAAO,MAAc,EAAY,GACtC,IAAO,EAAO,EAAE,IAAI,GACpB,IAAO,EAAO,GAAO,EAAE,IAAI,GAC3B,IAAO,EAAa,CAAC,GACrB,IAAQ,QAAc,EAAY,EAAO,KAAK,MAAM,CAAC,GAAG,CAAC,EAAO,KAAK,MAAM,CAAC,CAAC,GAC7E,IAAS,KAAY,EAAO,UAC5B,IAAU,EAAE,SAAS,EAAU,EAAa,EAAE,MAAM,CAAC,IAAI,KAAA;CAC/D,OACE,kBAAA,GAAA,EAAA,UAAA;EACG;EACD,kBAAC,SAAD;GACE,MAAK;GACL,WAAU;GACV,SAAS;GACC;GACV,cAAY,EAAE,iBAAiB,EAAE,QAAK,CAAC;GACvC,WAAW,MAAM,EAAS,EAAE,OAAO,OAAO;EAC3C,CAAA;EACD,kBAAC,GAAD;GAAa;GAAM,KAAK,GAAO;GAAW;EAAO,CAAA;EACjD,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACE,kBAAC,OAAD;KAAK,WAAU;KAAf,UAAA;MACG,IACC,kBAAC,GAAD;OAAa,MAAM,EAAK,CAAI;OAAG,OAAO,EAAE,sBAAsB,EAAE,QAAK,CAAC;OAAG,SAAS,MAAQ,MAAO,OAAO,EAAS,IAAI,IAAI,EAAO,OAAO,EAAE,MAAM,CAAE,CAAC,CAAC,WAAW,EAAS,IAAI,CAAC;MAAK,CAAA,IAEjL,kBAAC,QAAD;OAAM,WAAU;OAA8B,OAAO,EAAE;OAAM,aAAU;OACpE,UAAA;MACG,CAAA;MAEP,EAAE,QACD,kBAAC,QAAD;OAAM,WAAU;OAAoF,aAAU;OAC3G,UAAA,EAAE,eAAe;MACd,CAAA;MAEP,KACC,kBAAC,QAAD;OAAM,WAAU;OAAwF,OAAO;OAAS,aAAU;OAC/H,UAAmB,EAAnB,MAAS,UAAY,uBAA0B,eAAe;MAC3D,CAAA;KAEL;;IACJ,KAAW,kBAAC,KAAD;KAAG,WAAU;KAA4B,UAAA;IAAW,CAAA;IAC/D,KAAQ,MAAS,WAAW,kBAAC,GAAD;KAAgB,UAAU,EAAE;KAAU,WAAU;IAAoB,CAAA;IAChG,KAAQ,MAAS,WAAW,kBAAC,QAAD;KAAM,WAAU;KAAiC,UAAA,EAAE,mBAAmB;IAAQ,CAAA;GACxG;;EACL,kBAAC,QAAD;GAAM,WAAU;GAAqC,aAAU;GAA/D,UAAA;IACG;IACA,MAAS,WACR,kBAAC,GAAD;KAAQ,SAAQ;KAAQ,MAAK;KAAU,cAAY,EAAE,aAAa;KAAG,OAAO,EAAE,aAAa;KAAG,UAAU,KAAU,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE;KAAM,eAAe,EAAO,EAAE,IAAI;KACnK,UAAA,kBAAC,GAAD;MAAe,MAAM;MAAU,aAAa;KAAI,CAAA;IAC1C,CAAA;IAET,CAAC,EAAM,MAAM,SACZ,kBAAC,GAAD;KAAQ,SAAQ;KAAQ,MAAK;KAAU,cAAY,EAAE,eAAe;KAAG,OAAO,EAAE,eAAe;KAAG,UAAU;KAAQ,eAAe,EAAS,EAAE,IAAI;KAChJ,UAAA,kBAAC,GAAD;MAAe,MAAM;MAAY,aAAa;KAAI,CAAA;IAC5C,CAAA;IAEV,kBAAC,GAAD;KAAQ,SAAQ;KAAQ,MAAK;KAAU,cAAY,EAAE,gBAAgB;KAAG,OAAO,EAAE,gBAAgB;KAAG,UAAU;KAAQ,eAAe,EAAU,EAAE,IAAI;KACnJ,UAAA,kBAAC,GAAD;MAAe,MAAM;MAAY,aAAa;KAAI,CAAA;IAC5C,CAAA;IACR,kBAAC,GAAD;KAAQ,SAAQ;KAAQ,MAAK;KAAU,cAAY,EAAE,eAAe;KAAG,OAAO,EAAE,eAAe;KAAG,UAAU;KAAQ,eAAe,KAAK,EAAO,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;KAC5K,UAAA,kBAAC,GAAD;MAAe,MAAM;MAAc,aAAa;KAAI,CAAA;IAC9C,CAAA;GACJ;;CACN,EAAA,CAAA;AAEN;AAEA,SAAS,EAAY,EAAE,SAAM,UAAO,aAAmF;CACrH,IAAM,CAAC,GAAO,KAAY,EAAS,CAAI,GACjC,IAAO,GAAO,EAAK,GACnB,KAAU,MAAsB;EAChC,EAAK,YACT,EAAK,UAAU,IACf,QAAQ,QAAQ,EAAO,KAAM,EAAG,KAAK,KAAK,EAAG,KAAK,MAAM,IAAO,EAAG,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,YAAa,EAAK,UAAU,EAAM;CACtH;CACA,OACE,kBAAC,SAAD;EACE,WAAA;EACA,cAAY;EACL;EACP,WAAU;EACV,WAAW,MAAM,EAAS,EAAE,OAAO,KAAK;EACxC,YAAY,MAAM;GAChB,AAAI,EAAE,QAAQ,WACZ,EAAE,eAAe,GACjB,EAAO,CAAK,KACH,EAAE,QAAQ,aACnB,EAAE,eAAe,GACjB,EAAO,IAAI;EAEf;EACA,cAAc,EAAO,CAAK;EAC1B,aAAU;CACX,CAAA;AAEL;AAGA,SAAS,GAAW,EAAE,MAAM,GAAG,WAAQ,SAAM,eAA0F;CACrI,IAAM,EAAE,MAAG,OAAO,MAAc,EAAY,GACtC,IAAO,EAAO,EAAE,IAAI,GACpB,IAAO,EAAa,CAAC,GACrB,IAAQ,QAAc,EAAY,EAAO,KAAK,MAAM,CAAC,GAAG,CAAC,EAAO,KAAK,MAAM,CAAC,CAAC,GAC7E,IAAQ,EAAE,SACZ,EAAU,EAAa,EAAE,MAAM,CAAC,IAChC,IACE,EAAE,YAAY,EAAE,SAAS,UAAU,WACjC,EAAE,4BAA4B,EAAE,SAAS,KAAK,MAAM,EAAE,SAAS,OAAO,EAAE,CAAC,IACzE,EAAE,mBAAmB,IAErB,EADF,IACI,kBACA,iBAAiB;CAC3B,OACE,kBAAC,MAAD;EAAI,WAAU;EAAwC,aAAU;EAAc,aAAW,EAAE;EAA3F,UAAA;GACE,kBAAC,GAAD;IAAa;IAAM,KAAK,GAAO;IAAW;GAAO,CAAA;GACjD,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,QAAD;KAAM,WAAU;KAAmB,OAAO,EAAE;KACzC,UAAA,EAAE,KAAK,MAAM,EAAE,KAAK,YAAY,GAAG,IAAI,CAAC;IACrC,CAAA,GACN,kBAAC,QAAD;KAAM,WAAW,EAAG,WAAW,EAAE,SAAS,qBAAqB,uBAAuB;KAAG,aAAU;KAChG,UAAA;IACG,CAAA,CACH;;GACL,kBAAC,GAAD;IAAQ,SAAQ;IAAQ,MAAK;IAAU,cAAY,EAAE,eAAe;IAAG,OAAO,EAAE,eAAe;IAAG,UAAU,KAAY,EAAO;IAAU,eAAe,KAAK,EAAO,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;IACjM,UAAA,kBAAC,GAAD;KAAe,MAAM;KAAc,aAAa;IAAI,CAAA;GAC9C,CAAA;EACN;;AAER;AAEA,SAAS,EAAW,GAAoB,GAAgC,GAAc,GAAuB;CAC3G,IAAI,EAAE,WAAW,UAAU,OAAO,EAAU,EAAE,KAAK;CACnD,IAAI,EAAE,WAAW,aAAa,OAAO,EAAc,GAAG,EAAE,QAAQ;CAChE,IAAI,EAAE,WAAW,YAAY;EAC3B,IAAM,IAAI,EAAE;EAGZ,OAFI,GAAG,SAAe,EAAU,EAAa,EAAE,MAAM,CAAC,IAClD,EAAE,cAAc,CAAC,EAAE,YAAkB,GAAG,YAAY,EAAE,SAAS,UAAU,WAAW,EAAE,4BAA4B,EAAE,SAAS,KAAK,MAAM,EAAE,SAAS,OAAO,EAAE,CAAC,IAAI,EAAE,mBAAmB,IAC5K,EAAP,IAAS,kBAAqB,iBAAiB;CACxD;CACA,OAAO,EAAE,WAAW,cAAc,EAAE,eAAe,IAAI,EAAE,eAAe;AAC1E;AAEA,SAAS,GAAS,EAAE,MAAM,GAAG,WAAQ,SAAM,aAAyF;CAClI,IAAM,EAAE,MAAG,OAAO,MAAc,EAAY,GACtC,EAAE,aAAU,GACZ,IAAO,EAAO,EAAE,KAAK,IAAI,GACzB,IAAQ,EAAW,GAAG,GAAW,GAAG,CAAI,GACxC,IAAQ,EAAE,WAAW,cAAc,EAAc,EAAE,QAAQ,IAAI,EAAE,cAAc,CAAC,EAAE,aAAa,EAAE,YAAY,WAAW,EAAE,WAAW,SAAS,UAAU;CAC9J,OACE,kBAAA,GAAA,EAAA,UAAA;EACG;EACD,kBAAC,GAAD;GAAa;GAAM,MAAM,EAAE,WAAW,eAAgB,CAAC,CAAC,EAAE,cAAc,CAAC,EAAE;EAAa,CAAA;EACxF,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACE,kBAAC,QAAD;KAAM,WAAU;KAAmB,OAAO,EAAE;KACzC,UAAA,EAAE,KAAK;IACJ,CAAA;IACL,MAAU,QAAQ,kBAAC,GAAD;KAAiB;KAAO,cAAY;KAAO,WAAU;IAAY,CAAA;IACpF,kBAAC,QAAD;KAAM,WAAW,EAAG,WAAW,EAAE,WAAW,WAAW,qBAAqB,uBAAuB;KAAG,aAAU;KAC7G,UAAA;IACG,CAAA;GACH;;EACL,kBAAC,QAAD;GAAM,WAAU;GAAhB,UAAA,CACG,EAAE,WAAW,YACZ,kBAAC,GAAD;IAAQ,SAAQ;IAAQ,MAAK;IAAU,cAAY,EAAE,cAAc;IAAG,OAAO,EAAE,cAAc;IAAG,eAAe,EAAM,MAAM,EAAE,EAAE;IAC7H,UAAA,kBAAC,GAAD;KAAe,MAAM;KAAe,aAAa;IAAI,CAAA;GAC/C,CAAA,GAEV,kBAAC,GAAD;IAAQ,SAAQ;IAAQ,MAAK;IAAU,cAAY,EAAE,eAAe;IAAG,OAAO,EAAE,eAAe;IAAG,eAAe,EAAM,OAAO,EAAE,EAAE;IAChI,UAAA,kBAAC,GAAD;KAAe,MAAM;KAAc,aAAa;IAAI,CAAA;GAC9C,CAAA,CACJ;;CACN,EAAA,CAAA;AAEN"}
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 /** Uploaded page images may be arranged as thumbnail tiles. Other groups remain lists. */\n layout?: \"list\" | \"grid\";\n /** Accessible label of the file inputs. */\n inputLabel?: string;\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, layout, inputLabel, toolbar, rowActions, footer, aspects, confirmRemove, disabled, className, appearance, ...options } = p;\n const folder = useMediaFolder(item, options);\n return <FolderView {...{ folder, ref, label, layout, inputLabel, 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, layout, inputLabel, 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 + folder.pending.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 + folder.pending.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 aria-label={inputLabel}\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 {label !== false && <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 layout={layout === \"grid\" && g.rule?.page ? \"grid\" : \"list\"}\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 {folder.pending.length > 0 && (\n <ul className=\"grid\" aria-label={t(\"folder.label\")} data-ckui=\"folder-pending\">\n {folder.pending.map((f) => (\n <PendingRow key={f.path} file={f} folder={folder} auto={auto} disabled={off} />\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.items.length > 0 && !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 + folder.pending.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 layout,\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 layout: \"list\" | \"grid\";\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 layout={layout}\n className={layout === \"grid\" ? \"grid-cols-[repeat(auto-fill,minmax(12rem,1fr))]\" : undefined}\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: layout === \"grid\" ? \"grid min-w-0 grid-cols-[auto_minmax(0,1fr)] items-start gap-2 rounded-lg border border-border bg-background p-2\" : \"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 grid={layout === \"grid\"}\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, grid, aspect }: { kind: Kind; url?: string; busy?: boolean; grid?: boolean; aspect?: number }) {\n return (\n <span className={cn(\"relative flex shrink-0 items-center justify-center overflow-hidden rounded-md bg-muted text-muted-foreground\",grid?\"col-span-2 w-full\":\"size-10\")} style={grid?{aspectRatio:aspect??0.75}:undefined} 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 grid,\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 grid?: boolean;\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} grid={grid} aspect={thumb?.w&&thumb.h?thumb.w/thumb.h:undefined} />\n <div className={cn(\"grid min-w-0 flex-1 gap-1\",grid&&\"col-span-2\")}>\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={cn(\"flex shrink-0 flex-wrap items-center gap-0.5\",grid&&\"col-span-2 justify-end\")} 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\n/** An upload on the server not yet added: an earlier visit's, kept across reloads. */\nfunction PendingRow({ file: f, folder, auto, disabled }: { file: FileInfo; folder: UseMediaFolder; auto: boolean; disabled: boolean }) {\n const { t, error: errorText } = useMessages();\n const kind = kindOf(f.type);\n const busy = isProcessing(f);\n const thumb = useMemo(() => thumbnailOf(folder.read.read, f), [folder.read.read, f]);\n const label = f.failed\n ? errorText(failureError(f.failed))\n : busy\n ? f.progress && f.progress.phase !== \"queued\"\n ? t(\"folder.processingPercent\", { percent: Math.round(f.progress.percent) })\n : t(\"folder.processing\")\n : auto\n ? t(\"folder.adding\")\n : t(\"folder.notAdded\");\n return (\n <li className=\"flex min-h-11 items-center gap-2 px-1\" data-ckui=\"pending-row\" data-path={f.path}>\n <Thumb kind={kind} url={thumb?.url} busy={busy} />\n <div className=\"grid min-w-0 flex-1 gap-1\">\n <span className=\"truncate text-sm\" title={f.path}>\n {f.path.slice(f.path.lastIndexOf(\"/\") + 1)}\n </span>\n <span className={cn(\"text-xs\", f.failed ? \"text-destructive\" : \"text-muted-foreground\")} data-ckui=\"queue-status\">\n {label}\n </span>\n </div>\n <Button variant=\"ghost\" size=\"icon-sm\" aria-label={t(\"common.remove\")} title={t(\"common.remove\")} disabled={disabled || folder.updating} onClick={() => void folder.remove([f.path]).catch(() => {})}>\n <HugeiconsIcon icon={Delete02Icon} strokeWidth={2} />\n </Button>\n </li>\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,6 +1,7 @@
1
1
  import { CSSProperties } from 'react';
2
2
  import { ContentKitUiAppearance } from '../appearance.js';
3
3
  import { HlsPlayerOptions } from '../react/gallery.js';
4
+ import { ReadingEngagement } from '../react/use-engagement.js';
4
5
  import { PlaybackProgress } from '../react/player.js';
5
6
  import { PlayerHandoff } from './video-player.js';
6
7
  export interface VideoMiniPlayerProps extends Omit<HlsPlayerOptions, "src" | "startAt" | "autoPlay" | "audioLanguage" | "subtitleLanguage" | "active"> {
@@ -15,6 +16,8 @@ export interface VideoMiniPlayerProps extends Omit<HlsPlayerOptions, "src" | "st
15
16
  time: number;
16
17
  }) => void;
17
18
  onProgress?: (progress: PlaybackProgress) => void;
19
+ /** Continue actual visible playback measurements after the full player handoff. */
20
+ engagement?: Pick<ReadingEngagement, "video">;
18
21
  /** Milliseconds. Default 10000. */
19
22
  progressInterval?: number;
20
23
  /** K, J, L and M page-wide (default), every shortcut while focus is in it, or none. */
@@ -32,4 +35,4 @@ export interface VideoMiniPlayerProps extends Omit<HlsPlayerOptions, "src" | "st
32
35
  * a seek line, expand back to the full player and close. It starts where
33
36
  * the handoff stopped, playing if it was.
34
37
  */
35
- export declare function VideoMiniPlayer({ handoff, onExpand, onClose, onProgress, progressInterval, keyboard, label, position, crossOrigin, className, style, appearance, ...options }: VideoMiniPlayerProps): import('react').JSX.Element;
38
+ export declare function VideoMiniPlayer({ handoff, onExpand, onClose, onProgress, engagement, progressInterval, keyboard, label, position, crossOrigin, className, style, appearance, ...options }: VideoMiniPlayerProps): import('react').JSX.Element;
@@ -3,9 +3,9 @@ import { publicRenditions as t } from "../client/public.js";
3
3
  import { useMessages as n } from "../i18n/context.js";
4
4
  import { ContentKitUiRoot as ee } from "../scope.js";
5
5
  import { PLAYER_VOLUME_KEY as r, playerKeyAction as i, writeVolume as a } from "../client/player.js";
6
- import { useHlsPlayer as te } from "../react/gallery.js";
7
- import { useActiveCues as ne, useMediaState as re, useProgressReports as ie } from "../react/player.js";
8
- import { Captions as ae, ControlButton as o, SeekBar as oe, Spinner as s, clock as c } from "./player-controls.js";
6
+ import { useHlsPlayer as o } from "../react/gallery.js";
7
+ import { useActiveCues as te, useMediaState as ne, useProgressReports as re } from "../react/player.js";
8
+ import { Captions as ie, ControlButton as s, SeekBar as ae, Spinner as oe, clock as c } from "./player-controls.js";
9
9
  import { SpriteFrame as l, keyAllowed as u } from "./video-player.js";
10
10
  import { useCallback as d, useEffect as f, useRef as p, useState as m } from "react";
11
11
  import { jsx as h, jsxs as g } from "react/jsx-runtime";
@@ -14,56 +14,62 @@ import { Cancel01Icon as se, GoBackward10SecIcon as ce, GoForward10SecIcon as le
14
14
  import { HugeiconsIcon as he } from "@hugeicons/react";
15
15
  //#region src/components/video-mini-player.tsx
16
16
  var ge = 2500;
17
- function v({ handoff: v, onExpand: _e, onClose: y, onProgress: b, progressInterval: ve = 1e4, keyboard: x = "global", label: S, position: ye = "bottom-right", crossOrigin: be, className: xe, style: Se, appearance: Ce, ...C }) {
18
- let { t: w } = n(), T = `${v.base}master.m3u8`, E = te({
19
- ...C,
20
- src: T,
17
+ function v({ handoff: v, onExpand: _e, onClose: ve, onProgress: ye, engagement: y, progressInterval: be = 1e4, keyboard: b = "global", label: x, position: xe = "bottom-right", crossOrigin: Se, className: Ce, style: we, appearance: Te, ...S }) {
18
+ let { t: C } = n(), w = `${v.base}master.m3u8`, T = o({
19
+ ...S,
20
+ src: w,
21
21
  startAt: v.time,
22
22
  autoPlay: v.playing,
23
23
  audioLanguage: v.audioLanguage,
24
24
  subtitleLanguage: v.subtitleLanguage,
25
25
  trackKey: null,
26
26
  qualityKey: null
27
- }), { status: D, error: O, started: k } = E, [A, we] = m(null), j = E.ref, Te = d((e) => {
28
- j(e), we(e);
29
- }, [j]), M = re(A), N = ne(A);
30
- ie(A, {
31
- enabled: k,
32
- source: k ? T : null,
33
- interval: ve,
34
- onProgress: b
27
+ }), { status: E, error: D, started: O } = T, [k, Ee] = m(null), A = T.ref, De = d((e) => {
28
+ A(e), Ee(e);
29
+ }, [A]), j = y?.video;
30
+ f(() => (j?.(O ? k : null), () => j?.(null)), [
31
+ j,
32
+ O,
33
+ k
34
+ ]);
35
+ let M = ne(k), N = te(k);
36
+ re(k, {
37
+ enabled: O,
38
+ source: O ? w : null,
39
+ interval: be,
40
+ onProgress: ye
35
41
  });
36
- let [Ee, P] = m(!0), F = p(void 0), I = d(() => {
42
+ let [Oe, P] = m(!0), F = p(void 0), I = d(() => {
37
43
  P(!0), clearTimeout(F.current), F.current = setTimeout(() => P(!1), ge);
38
44
  }, []), L = d(() => {
39
45
  clearTimeout(F.current), P(!1);
40
46
  }, []);
41
47
  f(() => () => clearTimeout(F.current), []);
42
- let [R, De] = m(!1), z = !M.paused && !M.ended, B = Ee || !z || R || !!O, V = p(!1), H = () => A?.currentTime || M.time || v.time, Oe = () => {
48
+ let [R, ke] = m(!1), z = !M.paused && !M.ended, B = Oe || !z || R || !!D, V = p(!1), H = () => k?.currentTime || M.time || v.time, Ae = () => {
43
49
  V.current || (V.current = !0, _e({
44
50
  time: H(),
45
51
  playing: z
46
52
  }));
47
- }, ke = () => {
48
- V.current || (V.current = !0, A?.pause(), y({ time: H() }));
53
+ }, je = () => {
54
+ V.current || (V.current = !0, k?.pause(), ve({ time: H() }));
49
55
  }, U = () => {
50
- A && (!k || A.paused || A.ended ? E.play() : A.pause());
56
+ k && (!O || k.paused || k.ended ? T.play() : k.pause());
51
57
  }, W = M.duration || v.duration || 0, G = (e) => {
52
- A && (A.currentTime = Math.min(W || e, Math.max(0, e)));
53
- }, Ae = C.volumeKey === void 0 ? r : C.volumeKey, K = () => {
54
- A && (A.muted = !A.muted, !A.muted && A.volume === 0 && (A.volume = 1), a(Ae, {
55
- volume: A.volume,
56
- muted: A.muted
58
+ k && (k.currentTime = Math.min(W || e, Math.max(0, e)));
59
+ }, Me = S.volumeKey === void 0 ? r : S.volumeKey, K = () => {
60
+ k && (k.muted = !k.muted, !k.muted && k.volume === 0 && (k.volume = 1), a(Me, {
61
+ volume: k.volume,
62
+ muted: k.muted
57
63
  }));
58
64
  }, q = (e, t) => {
59
- if (!A || x === "global" && !"kjlmKJLM".includes(t)) return !1;
65
+ if (!k || b === "global" && !"kjlmKJLM".includes(t)) return !1;
60
66
  switch (e.type) {
61
67
  case "toggle":
62
68
  U();
63
69
  break;
64
70
  case "seekBy":
65
- if (!k) return !1;
66
- G(A.currentTime + e.seconds);
71
+ if (!O) return !1;
72
+ G(k.currentTime + e.seconds);
67
73
  break;
68
74
  case "mute":
69
75
  K();
@@ -73,46 +79,46 @@ function v({ handoff: v, onExpand: _e, onClose: y, onProgress: b, progressInterv
73
79
  return I(), !0;
74
80
  }, J = p(q);
75
81
  J.current = q;
76
- let [Y, je] = m(null);
82
+ let [Y, Ne] = m(null);
77
83
  f(() => {
78
- if (!x || !Y) return;
79
- let e = x === "global" ? document : Y, t = (e) => {
84
+ if (!b || !Y) return;
85
+ let e = b === "global" ? document : Y, t = (e) => {
80
86
  let t = e;
81
87
  if (t.defaultPrevented) return;
82
88
  let n = i(t);
83
89
  n && u(t.target, t.key, Y) && J.current(n, t.key) && t.preventDefault();
84
90
  };
85
91
  return e.addEventListener("keydown", t), () => e.removeEventListener("keydown", t);
86
- }, [x, Y]);
87
- let X = p("mouse"), Me = (e) => {
92
+ }, [b, Y]);
93
+ let X = p("mouse"), Pe = (e) => {
88
94
  e.preventDefault(), X.current === "mouse" ? (U(), I()) : B && z ? L() : I();
89
- }, Z = v.width && v.height ? v.width / v.height : M.aspect ?? 16 / 9, Q = typeof v.poster == "string" ? [] : t(v.poster), Ne = !O && (D === "loading" || D === "buffering"), $ = "rounded-full text-white hover:bg-white/15";
95
+ }, Z = v.width && v.height ? v.width / v.height : M.aspect ?? 16 / 9, Q = typeof v.poster == "string" ? [] : t(v.poster), Fe = !D && (E === "loading" || E === "buffering"), $ = "rounded-full text-white hover:bg-white/15";
90
96
  return /* @__PURE__ */ g(ee, {
91
- ref: je,
92
- appearance: Ce,
97
+ ref: Ne,
98
+ appearance: Te,
93
99
  role: "region",
94
- "aria-label": S ? `${w("player.miniPlayer")}: ${S}` : w("player.miniPlayer"),
100
+ "aria-label": x ? `${C("player.miniPlayer")}: ${x}` : C("player.miniPlayer"),
95
101
  "data-ckui": "mini-player",
96
- "data-status": D,
97
- className: _("@container fixed bottom-4 z-50 touch-manipulation overflow-hidden rounded-md bg-black text-white shadow-lg select-none", ye === "bottom-left" ? "left-4" : "right-4", xe),
102
+ "data-status": E,
103
+ className: _("@container fixed bottom-4 z-50 touch-manipulation overflow-hidden rounded-md bg-black text-white shadow-lg select-none", xe === "bottom-left" ? "left-4" : "right-4", Ce),
98
104
  style: {
99
105
  aspectRatio: String(Z),
100
106
  width: `min(24rem, calc(100vw - 2rem), calc(60svh * ${Z}))`,
101
- ...Se
107
+ ...we
102
108
  },
103
109
  onPointerDown: (e) => X.current = e.pointerType || "mouse",
104
110
  onPointerMove: (e) => e.pointerType === "mouse" && I(),
105
111
  onPointerLeave: (e) => e.pointerType === "mouse" && !R && z && L(),
106
112
  children: [
107
113
  /* @__PURE__ */ h("video", {
108
- ref: Te,
114
+ ref: De,
109
115
  className: "absolute inset-0 size-full object-contain",
110
116
  playsInline: !0,
111
117
  preload: "none",
112
- crossOrigin: be,
113
- "aria-label": S
118
+ crossOrigin: Se,
119
+ "aria-label": x
114
120
  }),
115
- !k && (typeof v.poster == "string" ? /* @__PURE__ */ h("img", {
121
+ !O && (typeof v.poster == "string" ? /* @__PURE__ */ h("img", {
116
122
  alt: "",
117
123
  src: v.poster,
118
124
  className: "pointer-events-none absolute inset-0 size-full object-contain"
@@ -121,16 +127,16 @@ function v({ handoff: v, onExpand: _e, onClose: y, onProgress: b, progressInterv
121
127
  className: "pointer-events-none absolute inset-0 size-full object-contain"
122
128
  }) : /* @__PURE__ */ h(l, {
123
129
  vtt: `${v.base}sprite.vtt`,
124
- loader: C.loader
130
+ loader: S.loader
125
131
  })),
126
132
  /* @__PURE__ */ h("div", {
127
133
  "aria-hidden": !0,
128
134
  "data-ckui": "surface",
129
135
  className: "absolute inset-0",
130
- onClick: Me
136
+ onClick: Pe
131
137
  }),
132
- /* @__PURE__ */ h(ae, {
133
- cues: k ? N : [],
138
+ /* @__PURE__ */ h(ie, {
139
+ cues: O ? N : [],
134
140
  bottom: B ? "2.75rem" : "0.75rem"
135
141
  }),
136
142
  /* @__PURE__ */ g("div", {
@@ -139,16 +145,16 @@ function v({ handoff: v, onExpand: _e, onClose: y, onProgress: b, progressInterv
139
145
  children: [
140
146
  /* @__PURE__ */ g("div", {
141
147
  className: "absolute inset-x-0 top-0 flex items-center justify-between p-1.5",
142
- children: [/* @__PURE__ */ h(o, {
143
- label: w("player.expand"),
148
+ children: [/* @__PURE__ */ h(s, {
149
+ label: C("player.expand"),
144
150
  icon: fe,
145
- onClick: Oe,
151
+ onClick: Ae,
146
152
  className: $,
147
153
  "data-ckui": "mini-expand"
148
- }), /* @__PURE__ */ h(o, {
149
- label: w("player.close"),
154
+ }), /* @__PURE__ */ h(s, {
155
+ label: C("player.close"),
150
156
  icon: se,
151
- onClick: ke,
157
+ onClick: je,
152
158
  className: $,
153
159
  "data-ckui": "mini-close"
154
160
  })]
@@ -156,10 +162,10 @@ function v({ handoff: v, onExpand: _e, onClose: y, onProgress: b, progressInterv
156
162
  /* @__PURE__ */ g("div", {
157
163
  className: "absolute inset-0 m-auto flex h-fit w-fit items-center gap-3 @sm:gap-5",
158
164
  children: [
159
- /* @__PURE__ */ h(o, {
160
- label: w("player.seekBack", { seconds: 10 }),
165
+ /* @__PURE__ */ h(s, {
166
+ label: C("player.seekBack", { seconds: 10 }),
161
167
  icon: ce,
162
- disabled: !k,
168
+ disabled: !O,
163
169
  onClick: () => {
164
170
  G(H() - 10), I();
165
171
  },
@@ -167,24 +173,24 @@ function v({ handoff: v, onExpand: _e, onClose: y, onProgress: b, progressInterv
167
173
  }),
168
174
  /* @__PURE__ */ h("button", {
169
175
  type: "button",
170
- "aria-label": w(z ? "player.pause" : "player.resume"),
171
- title: w(z ? "player.pause" : "player.resume"),
176
+ "aria-label": C(z ? "player.pause" : "player.resume"),
177
+ title: C(z ? "player.pause" : "player.resume"),
172
178
  onClick: () => {
173
179
  U(), I();
174
180
  },
175
181
  className: _("flex size-12 cursor-pointer items-center justify-center outline-none focus-visible:ring-2 focus-visible:ring-white/80", $),
176
182
  "data-ckui": "mini-play",
177
- children: Ne && k ? /* @__PURE__ */ h(s, { className: "size-7" }) : /* @__PURE__ */ h(he, {
183
+ children: Fe && O ? /* @__PURE__ */ h(oe, { className: "size-7" }) : /* @__PURE__ */ h(he, {
178
184
  icon: z ? ue : de,
179
185
  className: "size-7 fill-current",
180
186
  strokeWidth: 1.5,
181
187
  "aria-hidden": !0
182
188
  })
183
189
  }),
184
- /* @__PURE__ */ h(o, {
185
- label: w("player.seekForward", { seconds: 10 }),
190
+ /* @__PURE__ */ h(s, {
191
+ label: C("player.seekForward", { seconds: 10 }),
186
192
  icon: le,
187
- disabled: !k,
193
+ disabled: !O,
188
194
  onClick: () => {
189
195
  G(H() + 10), I();
190
196
  },
@@ -197,8 +203,8 @@ function v({ handoff: v, onExpand: _e, onClose: y, onProgress: b, progressInterv
197
203
  children: [/* @__PURE__ */ h("span", {
198
204
  className: "text-xs font-medium tabular-nums",
199
205
  children: W > 0 ? `${c(M.time || v.time)} / ${c(W)}` : c(M.time || v.time)
200
- }), /* @__PURE__ */ h(o, {
201
- label: M.muted ? w("player.unmute") : w("player.mute"),
206
+ }), /* @__PURE__ */ h(s, {
207
+ label: M.muted ? C("player.unmute") : C("player.mute"),
202
208
  icon: M.muted ? me : pe,
203
209
  onClick: K,
204
210
  className: _($, "size-8")
@@ -208,23 +214,23 @@ function v({ handoff: v, onExpand: _e, onClose: y, onProgress: b, progressInterv
208
214
  }),
209
215
  /* @__PURE__ */ h("div", {
210
216
  className: "absolute inset-x-0 bottom-0 z-10",
211
- children: /* @__PURE__ */ h(oe, {
217
+ children: /* @__PURE__ */ h(ae, {
212
218
  thin: !0,
213
219
  time: M.time || v.time,
214
220
  duration: W,
215
221
  buffered: M.buffered,
216
222
  onSeek: G,
217
- onScrub: (e) => De(e !== null)
223
+ onScrub: (e) => ke(e !== null)
218
224
  })
219
225
  }),
220
- O && /* @__PURE__ */ g("div", {
226
+ D && /* @__PURE__ */ g("div", {
221
227
  role: "alert",
222
228
  className: "absolute inset-0 z-20 flex flex-col items-center justify-center gap-2 bg-black/80 p-3 text-center text-xs",
223
- children: [/* @__PURE__ */ h("p", { children: w(`player.errors.${O.kind}`) }), /* @__PURE__ */ h("button", {
229
+ children: [/* @__PURE__ */ h("p", { children: C(`player.errors.${D.kind}`) }), /* @__PURE__ */ h("button", {
224
230
  type: "button",
225
- onClick: E.retry,
231
+ onClick: T.retry,
226
232
  className: "rounded-md bg-white/15 px-2 py-1 font-medium hover:bg-white/25",
227
- children: w("player.retry")
233
+ children: C("player.retry")
228
234
  })]
229
235
  })
230
236
  ]