@openrails/contentkit-ui 0.104.0-rc.1 → 0.104.0-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/dist/client/beacons.js +4 -1
- package/dist/client/beacons.js.map +1 -1
- package/dist/client/contents.d.ts +9 -1
- package/dist/client/contents.js +73 -55
- package/dist/client/contents.js.map +1 -1
- package/dist/client/discovery.d.ts +6 -2
- package/dist/client/discovery.js +1 -1
- package/dist/client/discovery.js.map +1 -1
- package/dist/client/generated/error-codes.d.ts +1 -1
- package/dist/client/generated/error-codes.js +4 -0
- package/dist/client/generated/error-codes.js.map +1 -1
- package/dist/client/generated/routes.d.ts +43 -30
- package/dist/client/generated/routes.js +70 -63
- package/dist/client/generated/routes.js.map +1 -1
- package/dist/client/generated/wire.d.ts +36 -74
- package/dist/client/generated/wire.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/media/windows.d.ts +2 -0
- package/dist/client/media/windows.js +4 -1
- package/dist/client/media/windows.js.map +1 -1
- package/dist/client/stats.d.ts +4 -20
- package/dist/client/stats.js +0 -11
- package/dist/client/stats.js.map +1 -1
- package/dist/client/versions.d.ts +8 -6
- package/dist/client/versions.js +15 -10
- package/dist/client/versions.js.map +1 -1
- package/dist/components/admin/bulk-drafts.d.ts +17 -0
- package/dist/components/admin/bulk-drafts.js +41 -0
- package/dist/components/admin/bulk-drafts.js.map +1 -0
- package/dist/components/admin/content-admin.d.ts +1 -1
- package/dist/components/admin/content-admin.js.map +1 -1
- package/dist/components/admin/content-manager.d.ts +11 -3
- package/dist/components/admin/content-manager.js +739 -380
- package/dist/components/admin/content-manager.js.map +1 -1
- package/dist/components/admin/group-manager.d.ts +8 -3
- package/dist/components/admin/group-manager.js +218 -146
- package/dist/components/admin/group-manager.js.map +1 -1
- package/dist/components/admin/page-notices.d.ts +16 -0
- package/dist/components/admin/page-notices.js +113 -0
- package/dist/components/admin/page-notices.js.map +1 -0
- package/dist/components/admin/page-picker.d.ts +38 -0
- package/dist/components/admin/page-picker.js +159 -0
- package/dist/components/admin/page-picker.js.map +1 -0
- package/dist/components/admin/reader-content-editor.js +537 -500
- package/dist/components/admin/reader-content-editor.js.map +1 -1
- package/dist/components/admin/reader-manifest.js +181 -179
- package/dist/components/admin/reader-manifest.js.map +1 -1
- package/dist/components/admin/shell.d.ts +10 -2
- package/dist/components/admin/shell.js +114 -42
- package/dist/components/admin/shell.js.map +1 -1
- package/dist/components/admin/stats-dashboard.d.ts +4 -9
- package/dist/components/admin/stats-dashboard.js +300 -202
- package/dist/components/admin/stats-dashboard.js.map +1 -1
- package/dist/components/admin/upload-queue.d.ts +14 -0
- package/dist/components/admin/upload-queue.js +115 -98
- package/dist/components/admin/upload-queue.js.map +1 -1
- package/dist/components/content/card.d.ts +31 -3
- package/dist/components/content/card.js +324 -158
- package/dist/components/content/card.js.map +1 -1
- package/dist/components/content/daily-releases.js +14 -12
- package/dist/components/content/daily-releases.js.map +1 -1
- package/dist/components/content/editor-save.js +27 -25
- package/dist/components/content/editor-save.js.map +1 -1
- package/dist/components/content/editors.js +274 -253
- package/dist/components/content/editors.js.map +1 -1
- package/dist/components/content/favorites.d.ts +1 -1
- package/dist/components/content/favorites.js +36 -22
- package/dist/components/content/favorites.js.map +1 -1
- package/dist/components/content/grid.d.ts +11 -4
- package/dist/components/content/grid.js +52 -43
- package/dist/components/content/grid.js.map +1 -1
- package/dist/components/content/history.js +83 -63
- package/dist/components/content/history.js.map +1 -1
- package/dist/components/content/index.d.ts +5 -3
- package/dist/components/content/listing.d.ts +14 -3
- package/dist/components/content/listing.js +65 -56
- package/dist/components/content/listing.js.map +1 -1
- package/dist/components/content/offer-fields.js +6 -6
- package/dist/components/content/paged-grid.d.ts +10 -0
- package/dist/components/content/paged-grid.js +116 -0
- package/dist/components/content/paged-grid.js.map +1 -0
- package/dist/components/content/pagination.d.ts +19 -0
- package/dist/components/content/pagination.js +97 -0
- package/dist/components/content/pagination.js.map +1 -0
- package/dist/components/content/paywall.d.ts +9 -0
- package/dist/components/content/paywall.js +27 -3
- package/dist/components/content/paywall.js.map +1 -1
- package/dist/components/content/post-list.d.ts +37 -0
- package/dist/components/content/post-list.js +203 -0
- package/dist/components/content/post-list.js.map +1 -0
- package/dist/components/content/reader-settings.d.ts +2 -0
- package/dist/components/content/reader-settings.js +1 -1
- package/dist/components/content/reader-settings.js.map +1 -1
- package/dist/components/groups/banner.d.ts +6 -2
- package/dist/components/groups/banner.js +79 -61
- package/dist/components/groups/banner.js.map +1 -1
- package/dist/components/groups/directory.d.ts +12 -2
- package/dist/components/groups/directory.js +168 -105
- package/dist/components/groups/directory.js.map +1 -1
- package/dist/components/groups/editor.js +10 -10
- package/dist/components/groups/editor.js.map +1 -1
- package/dist/components/groups/entity-chips.d.ts +61 -0
- package/dist/components/groups/entity-chips.js +382 -0
- package/dist/components/groups/entity-chips.js.map +1 -0
- package/dist/components/groups/group-members.d.ts +29 -0
- package/dist/components/groups/group-members.js +474 -0
- package/dist/components/groups/group-members.js.map +1 -0
- package/dist/components/groups/header.js +53 -45
- package/dist/components/groups/header.js.map +1 -1
- package/dist/components/groups/index.d.ts +3 -1
- package/dist/components/groups/memberships.d.ts +3 -36
- package/dist/components/groups/memberships.js +105 -480
- package/dist/components/groups/memberships.js.map +1 -1
- package/dist/components/groups/scoped.d.ts +23 -0
- package/dist/components/groups/scoped.js +92 -0
- package/dist/components/groups/scoped.js.map +1 -0
- package/dist/components/media-folder-editor.d.ts +5 -0
- package/dist/components/media-folder-editor.js +418 -230
- package/dist/components/media-folder-editor.js.map +1 -1
- package/dist/components/social/poll.js +57 -48
- package/dist/components/social/poll.js.map +1 -1
- package/dist/components/sortable-list.d.ts +5 -1
- package/dist/components/sortable-list.js +97 -81
- package/dist/components/sortable-list.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +41 -37
- package/dist/locales/admin/de.js +78 -45
- package/dist/locales/admin/de.js.map +1 -1
- package/dist/locales/admin/en.d.ts +74 -41
- package/dist/locales/admin/en.js +78 -45
- package/dist/locales/admin/en.js.map +1 -1
- package/dist/locales/admin/es.js +78 -45
- package/dist/locales/admin/es.js.map +1 -1
- package/dist/locales/admin/ja.js +78 -45
- package/dist/locales/admin/ja.js.map +1 -1
- package/dist/locales/admin/ko.js +78 -45
- package/dist/locales/admin/ko.js.map +1 -1
- package/dist/locales/admin/zh.js +78 -45
- package/dist/locales/admin/zh.js.map +1 -1
- package/dist/locales/de.js +2 -0
- package/dist/locales/de.js.map +1 -1
- package/dist/locales/discovery/de.js +25 -1
- package/dist/locales/discovery/de.js.map +1 -1
- package/dist/locales/discovery/en.d.ts +24 -0
- package/dist/locales/discovery/en.js +25 -1
- package/dist/locales/discovery/en.js.map +1 -1
- package/dist/locales/discovery/es.js +25 -1
- package/dist/locales/discovery/es.js.map +1 -1
- package/dist/locales/discovery/ja.js +25 -1
- package/dist/locales/discovery/ja.js.map +1 -1
- package/dist/locales/discovery/ko.js +25 -1
- package/dist/locales/discovery/ko.js.map +1 -1
- package/dist/locales/discovery/zh.js +25 -1
- package/dist/locales/discovery/zh.js.map +1 -1
- package/dist/locales/en.d.ts +120 -43
- package/dist/locales/en.js +2 -0
- package/dist/locales/en.js.map +1 -1
- package/dist/locales/es.js +2 -0
- package/dist/locales/es.js.map +1 -1
- package/dist/locales/groups/de.js +22 -4
- package/dist/locales/groups/de.js.map +1 -1
- package/dist/locales/groups/en.d.ts +20 -2
- package/dist/locales/groups/en.js +22 -4
- package/dist/locales/groups/en.js.map +1 -1
- package/dist/locales/groups/es.js +22 -4
- package/dist/locales/groups/es.js.map +1 -1
- package/dist/locales/groups/ja.js +22 -4
- package/dist/locales/groups/ja.js.map +1 -1
- package/dist/locales/groups/ko.js +22 -4
- package/dist/locales/groups/ko.js.map +1 -1
- package/dist/locales/groups/zh.js +22 -4
- package/dist/locales/groups/zh.js.map +1 -1
- package/dist/locales/ja.js +2 -0
- package/dist/locales/ja.js.map +1 -1
- package/dist/locales/ko.js +2 -0
- package/dist/locales/ko.js.map +1 -1
- package/dist/locales/zh.js +2 -0
- package/dist/locales/zh.js.map +1 -1
- package/dist/react/contents.js +1 -1
- package/dist/react/contents.js.map +1 -1
- package/dist/react/discovery.d.ts +16 -0
- package/dist/react/discovery.js +69 -37
- package/dist/react/discovery.js.map +1 -1
- package/dist/react/groups.d.ts +19 -3
- package/dist/react/groups.js +49 -22
- package/dist/react/groups.js.map +1 -1
- package/dist/react/index.d.ts +6 -4
- package/dist/react/page-notices.d.ts +13 -0
- package/dist/react/page-notices.js +38 -0
- package/dist/react/page-notices.js.map +1 -0
- package/dist/react/post-reads.d.ts +23 -0
- package/dist/react/post-reads.js +90 -0
- package/dist/react/post-reads.js.map +1 -0
- package/dist/react/remembered-sort.d.ts +5 -0
- package/dist/react/remembered-sort.js +29 -0
- package/dist/react/remembered-sort.js.map +1 -0
- package/dist/react/resources.js +2 -2
- package/dist/react/resources.js.map +1 -1
- package/dist/react/stats.d.ts +3 -7
- package/dist/react/stats.js +2 -6
- package/dist/react/stats.js.map +1 -1
- package/dist/react/use-engagement.d.ts +2 -0
- package/dist/react/use-engagement.js +40 -34
- package/dist/react/use-engagement.js.map +1 -1
- package/dist/react.js +29 -27
- package/dist/styles.css +1 -1
- package/dist/urls/index.d.ts +1 -1
- package/dist/urls.js +2 -2
- package/dist/urls.js.map +1 -1
- package/package.json +1 -1
- package/dist/components/admin/page-review.d.ts +0 -13
- package/dist/components/admin/page-review.js +0 -225
- package/dist/components/admin/page-review.js.map +0 -1
- package/dist/react/page-review.d.ts +0 -14
- package/dist/react/page-review.js +0 -37
- package/dist/react/page-review.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media-folder-editor.js","names":[],"sources":["../../src/components/media-folder-editor.tsx"],"sourcesContent":["import {\n Alert02Icon,\n CropIcon,\n Delete02Icon,\n Edit02Icon,\n File01Icon,\n Image01Icon,\n ImageAdd01Icon,\n Loading03Icon,\n MusicNote01Icon,\n Refresh01Icon,\n RepeatIcon,\n Video01Icon,\n} from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon, type IconSvgElement } from \"@hugeicons/react\";\nimport { 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
|
+
{"version":3,"file":"media-folder-editor.js","names":[],"sources":["../../src/components/media-folder-editor.tsx"],"sourcesContent":["import {\n Alert02Icon,\n Cancel01Icon,\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, ruleFor } from \"../client/media/rules.js\";\nimport { isProcessing, pageRemoved } 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 /** The page tile chosen in a grid (e.g. to set a thumbnail from); clicking a tile reports it, again clears it. */\n selectedPage?: string | null;\n onSelectPage?: (file: FileInfo | null) => void;\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, selectedPage, onSelectPage, ...options } = p;\n const folder = useMediaFolder(item, options);\n return <FolderView {...{ folder, ref, label, layout, inputLabel, toolbar, rowActions, footer, aspects, confirmRemove, disabled, className, appearance, selectedPage, onSelectPage }} />;\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, selectedPage, onSelectPage } = 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 // Page uploads in flight join the page grid as tiles; the rest stay listed.\n const pageGroup = layout === \"grid\" ? groups.find((g) => g.rule?.page) : undefined;\n const inPages = (path: string) => !!pageGroup && ruleFor(rules, path)?.path === pageGroup.rule!.path;\n const pageQueue = queue.items.filter((i) => inPages(i.path));\n const otherQueue = queue.items.filter((i) => !inPages(i.path));\n const pagePending = folder.pending.filter((f) => inPages(f.path));\n const otherPending = folder.pending.filter((f) => !inPages(f.path));\n const pageWaiting = pageGroup ? folder.waiting.filter((f) => isImageType(f.type)) : [];\n const otherWaiting = pageGroup ? folder.waiting.filter((f) => !isImageType(f.type)) : folder.waiting;\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 === pageGroup ? (\n g.files.length + pageQueue.length + pagePending.length + pageWaiting.length > 0 && (\n <PageGrid\n key={g.path}\n group={g}\n folder={folder}\n disabled={off}\n auto={auto}\n selected={selectedPage ?? null}\n onSelect={(f) => onSelectPage?.(f)}\n queued={pageQueue}\n pending={pagePending}\n waiting={pageWaiting}\n />\n )\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 {otherWaiting.length > 0 && (\n <ul className=\"grid\" aria-label={t(\"folder.label\")}>\n {otherWaiting.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 {otherPending.length > 0 && (\n <ul className=\"grid\" aria-label={t(\"folder.label\")} data-ckui=\"folder-pending\">\n {otherPending.map((f) => (\n <PendingRow key={f.path} file={f} folder={folder} auto={auto} disabled={off} />\n ))}\n </ul>\n )}\n\n {otherQueue.length > 0 && (\n <SortableList\n items={otherQueue}\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(otherQueue[from]!.id, queue.items.indexOf(otherQueue[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\n/** A page's name from its place: zero-padded to at least two digits, keeping its extension. */\nexport function positionalName(position: number, count: number, path: string): string {\n const dot = path.lastIndexOf(\".\");\n const ext = dot > path.lastIndexOf(\"/\") ? path.slice(dot).toLowerCase() : \"\";\n return String(position).padStart(Math.max(2, String(count).length), \"0\") + ext;\n}\n\nconst TILE = \"group relative grid min-w-0 content-start gap-1 rounded-lg border bg-background p-1.5 outline-none focus-visible:ring-2 focus-visible:ring-ring\";\n\nfunction RemoveTile({ label, disabled, onRemove }: { label: string; disabled?: boolean; onRemove: () => void }) {\n return (\n <button\n type=\"button\"\n aria-label={label}\n title={label}\n disabled={disabled}\n className=\"absolute end-2 top-2 inline-flex size-6 items-center justify-center rounded-full bg-background/90 text-muted-foreground opacity-0 shadow-sm transition-opacity hover:text-foreground focus-visible:opacity-100 group-hover:opacity-100 group-focus-within:opacity-100 disabled:hidden\"\n onPointerDown={(e) => e.stopPropagation()}\n onKeyDown={(e) => e.stopPropagation()}\n onClick={(e) => {\n e.stopPropagation();\n onRemove();\n }}\n data-ckui=\"tile-remove\"\n >\n <HugeiconsIcon icon={Cancel01Icon} strokeWidth={2} className=\"size-3.5\" />\n </button>\n );\n}\n\nfunction TileImage({ url, aspect, busy }: { url?: string; aspect?: number; busy?: boolean }) {\n return (\n <span className=\"relative block w-full overflow-hidden rounded-md bg-muted\" style={{ aspectRatio: aspect ?? 0.75 }}>\n {url && <img src={url} alt=\"\" loading=\"lazy\" decoding=\"async\" draggable={false} className={cn(\"size-full object-cover\", busy && \"opacity-70\")} />}\n {busy && !url && <span aria-hidden className=\"absolute inset-[40%] rounded-full border-2 border-current/25 border-t-current text-muted-foreground motion-safe:animate-spin\" />}\n </span>\n );\n}\n\n/**\n * Pages as one grid: committed pages (drag anywhere on a tile to reorder;\n * names follow position) followed by uploads still on their way, shown from\n * their local files. Pages automatic processing removed are left out.\n */\nfunction PageGrid({\n group,\n folder,\n disabled,\n auto,\n selected,\n onSelect,\n queued,\n pending,\n waiting,\n}: {\n group: FolderGroup;\n folder: UseMediaFolder;\n disabled: boolean;\n auto: boolean;\n selected: string | null;\n onSelect: (file: FileInfo | null) => void;\n queued: readonly QueueItem[];\n pending: readonly FileInfo[];\n waiting: readonly File[];\n}) {\n const { t, error: errorText } = useMessages();\n const pages = useMemo(() => group.files.filter((f) => !pageRemoved(f)), [group.files]);\n const total = pages.length + pending.length + queued.length + waiting.length;\n // Local previews bridge an upload until the server's thumbnail arrives.\n const previews = useRef(new Map<string, string>());\n for (const i of queued) if (!previews.current.has(i.path)) previews.current.set(i.path, URL.createObjectURL(i.file));\n useEffect(() => {\n const urls = previews.current;\n return () => urls.forEach((url) => URL.revokeObjectURL(url));\n }, []);\n const locked = disabled || folder.updating;\n const choose = (f: FileInfo) => onSelect(selected === f.path ? null : f);\n return (\n <section className=\"grid gap-1\" data-ckui=\"folder-group\" data-path={group.path}>\n <SortableList\n layout=\"grid\"\n wholeItem\n className=\"grid-cols-[repeat(auto-fill,minmax(8.5rem,1fr))]\"\n items={pages}\n id={(f) => f.path}\n name={(f) => positionalName(pages.indexOf(f) + 1, total, f.path)}\n disabled={locked}\n label={t(`folder.kinds.${ruleKind(group.rule)}`)}\n onMove={(from, to) => void folder.move(pages[from]!.path, group.files.findIndex((f) => f.path === pages[to]!.path)).catch(() => {})}\n row={(f) => ({\n className: cn(TILE, \"cursor-grab active:cursor-grabbing\", selected === f.path ? \"border-primary ring-1 ring-primary/40\" : \"border-border\"),\n \"data-ckui\": \"page-tile\",\n \"data-path\": f.path,\n \"data-selected\": selected === f.path || undefined,\n \"aria-pressed\": selected === f.path,\n onClick: () => choose(f),\n onKeyDown: (e) => {\n if (e.key !== \"Enter\") return;\n e.preventDefault();\n choose(f);\n },\n })}\n trailing={\n <>\n {pending.map((f, i) => {\n const thumb = thumbnailOf(folder.read.read, f);\n return (\n <li key={f.path} className={cn(TILE, \"border-dashed border-border\")} data-ckui=\"page-tile-pending\">\n <TileImage url={thumb?.url ?? previews.current.get(f.path)} busy={isProcessing(f)} />\n <span className=\"truncate px-0.5 text-xs text-muted-foreground tabular-nums\">\n {positionalName(pages.length + i + 1, total, f.path)} · {f.failed ? errorText(failureError(f.failed)) : auto ? t(\"folder.adding\") : t(\"folder.notAdded\")}\n </span>\n <RemoveTile label={t(\"common.remove\")} disabled={locked} onRemove={() => void folder.remove([f.path]).catch(() => {})} />\n </li>\n );\n })}\n {queued.map((i, n) => {\n const value = i.status === \"uploading\" ? progressValue(i.progress) : null;\n return (\n <li key={i.id} className={cn(TILE, \"border-dashed border-border\")} data-ckui=\"page-tile-upload\" data-status={i.status}>\n <TileImage url={previews.current.get(i.path)} busy />\n {value !== null && <Progress value={value} aria-label={queueLabel(t, errorText, i, auto)} className=\"h-1\" />}\n <span className={cn(\"truncate px-0.5 text-xs tabular-nums\", i.status === \"failed\" ? \"text-destructive\" : \"text-muted-foreground\")} title={i.file.name}>\n {positionalName(pages.length + pending.length + n + 1, total, i.path)} · {queueLabel(t, errorText, i, auto)}\n </span>\n <RemoveTile label={t(\"common.remove\")} onRemove={() => folder.queue.remove(i.id)} />\n </li>\n );\n })}\n {waiting.map((f, n) => (\n <li key={`waiting-${n}`} className={cn(TILE, \"border-dashed border-border\")} data-ckui=\"page-tile-waiting\">\n <TileImage busy />\n <span className=\"truncate px-0.5 text-xs text-muted-foreground\" title={f.name}>\n {t(\"folder.queued\")}\n </span>\n </li>\n ))}\n </>\n }\n >\n {(f, _handle, index) => {\n const busy = isProcessing(f);\n const thumb = thumbnailOf(folder.read.read, f);\n const failure = f.failed ? errorText(failureError(f.failed)) : undefined;\n return (\n <>\n <TileImage url={thumb?.url ?? previews.current.get(f.path)} aspect={thumb?.w && thumb.h ? thumb.w / thumb.h : undefined} busy={busy} />\n <span className=\"flex min-w-0 items-center justify-between gap-1 px-0.5 text-xs text-muted-foreground tabular-nums\">\n <span className=\"truncate\" data-ckui=\"upload-name\" title={f.path}>\n {positionalName(index + 1, total, f.path)}\n </span>\n {failure ? (\n <span className=\"truncate text-destructive\" title={failure} data-ckui=\"failed\">\n {t(\"folder.failed\")}\n </span>\n ) : (\n busy && <span>{t(\"folder.processing\")}</span>\n )}\n </span>\n <RemoveTile label={t(\"common.remove\")} disabled={locked} onRemove={() => void folder.remove([f.path]).catch(() => {})} />\n </>\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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"}
|
|
@@ -21,7 +21,7 @@ function x(c) {
|
|
|
21
21
|
client: c.client
|
|
22
22
|
}), T = i(c.onError), [E, D] = m(null), { config: O } = o({ client: c.client }), k = c.onSignIn ?? b?.onSignIn, A = b?.viewer === null && O?.anonymous.votes === !1, j = (e) => /* @__PURE__ */ g(n, {
|
|
23
23
|
appearance: c.appearance,
|
|
24
|
-
className: v("grid gap-3 rounded-xl border border-border bg-card p-4 text-sm text-card-foreground", c.className),
|
|
24
|
+
className: v("grid content-start gap-3 rounded-xl border border-border bg-card p-4 text-sm text-card-foreground", c.className),
|
|
25
25
|
"data-ckui": "poll",
|
|
26
26
|
children: e
|
|
27
27
|
});
|
|
@@ -60,7 +60,7 @@ function x(c) {
|
|
|
60
60
|
loading: "lazy"
|
|
61
61
|
}),
|
|
62
62
|
/* @__PURE__ */ g("h3", {
|
|
63
|
-
className: "text-base font-semibold",
|
|
63
|
+
className: "border-b border-border pb-2 text-base font-semibold",
|
|
64
64
|
id: `poll-${M.id}`,
|
|
65
65
|
children: M.question
|
|
66
66
|
}),
|
|
@@ -94,12 +94,18 @@ function x(c) {
|
|
|
94
94
|
] }));
|
|
95
95
|
}
|
|
96
96
|
function S({ poll: e, results: n, canVote: r, onVote: i }) {
|
|
97
|
-
let
|
|
97
|
+
let a = t(), { t: o } = a, s = [...e.options].sort((e, t) => e.position - t.position), c = s.some((e) => e.image_url), l = e.total_votes || s.reduce((e, t) => e + t.vote_count, 0), d = Math.max(1, ...s.map((e) => e.vote_count));
|
|
98
98
|
return /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("ul", {
|
|
99
|
-
className: v("grid gap-
|
|
99
|
+
className: v("grid gap-3", c && "grid-cols-2"),
|
|
100
100
|
"aria-labelledby": `poll-${e.id}`,
|
|
101
|
-
children:
|
|
102
|
-
let
|
|
101
|
+
children: s.map((t) => {
|
|
102
|
+
let s = e.my_option === t.id, c = l ? Math.round(t.vote_count / l * 100) : 0, u = r ? () => i(t.id) : void 0, f = n && !u ? {
|
|
103
|
+
role: "meter",
|
|
104
|
+
"aria-valuemin": 0,
|
|
105
|
+
"aria-valuemax": 100,
|
|
106
|
+
"aria-valuenow": c,
|
|
107
|
+
"aria-label": t.label
|
|
108
|
+
} : {}, p = /* @__PURE__ */ _(h, { children: [
|
|
103
109
|
t.image_url && /* @__PURE__ */ g("img", {
|
|
104
110
|
src: t.image_url,
|
|
105
111
|
alt: "",
|
|
@@ -107,58 +113,61 @@ function S({ poll: e, results: n, canVote: r, onVote: i }) {
|
|
|
107
113
|
loading: "lazy"
|
|
108
114
|
}),
|
|
109
115
|
/* @__PURE__ */ _("span", {
|
|
110
|
-
className: "
|
|
111
|
-
children: [
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
116
|
+
className: "flex w-full items-baseline gap-2",
|
|
117
|
+
children: [
|
|
118
|
+
s && /* @__PURE__ */ g(b, {
|
|
119
|
+
icon: y,
|
|
120
|
+
strokeWidth: 2.5,
|
|
121
|
+
className: "size-4 shrink-0 self-center text-primary",
|
|
122
|
+
"aria-label": o("poll.yourVote")
|
|
123
|
+
}),
|
|
124
|
+
/* @__PURE__ */ g("span", {
|
|
125
|
+
className: "min-w-0 flex-1 break-words text-start font-medium",
|
|
126
|
+
children: t.label
|
|
127
|
+
}),
|
|
128
|
+
n && /* @__PURE__ */ _("span", {
|
|
129
|
+
className: "shrink-0 text-xs tabular-nums text-muted-foreground",
|
|
130
|
+
children: [
|
|
131
|
+
/* @__PURE__ */ _("span", {
|
|
132
|
+
className: "font-semibold text-foreground",
|
|
133
|
+
children: [c, "%"]
|
|
134
|
+
}),
|
|
135
|
+
" · ",
|
|
136
|
+
a.plural("poll.votes", t.vote_count)
|
|
137
|
+
]
|
|
138
|
+
})
|
|
139
|
+
]
|
|
134
140
|
}),
|
|
135
141
|
n && /* @__PURE__ */ g("span", {
|
|
136
|
-
|
|
137
|
-
|
|
142
|
+
"aria-hidden": !0,
|
|
143
|
+
className: "block h-2 w-full overflow-hidden rounded-full bg-muted",
|
|
144
|
+
children: /* @__PURE__ */ g("span", {
|
|
145
|
+
className: v("block h-full rounded-full transition-[width] duration-500 motion-reduce:transition-none", s ? "bg-primary" : "bg-foreground/40"),
|
|
146
|
+
style: { width: `${t.vote_count / d * 100}%` }
|
|
147
|
+
})
|
|
138
148
|
})
|
|
139
149
|
] });
|
|
140
150
|
return /* @__PURE__ */ g("li", {
|
|
141
151
|
"data-option": t.id,
|
|
142
|
-
"data-mine":
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
152
|
+
"data-mine": s || void 0,
|
|
153
|
+
...f,
|
|
154
|
+
children: u ? /* @__PURE__ */ g("button", {
|
|
155
|
+
type: "button",
|
|
156
|
+
className: "grid w-full gap-1.5 rounded-md p-1.5 text-start hover:bg-muted/60 focus-visible:outline-2 focus-visible:outline-ring",
|
|
157
|
+
onClick: u,
|
|
158
|
+
children: p
|
|
148
159
|
}) : /* @__PURE__ */ g("div", {
|
|
149
|
-
className: "grid gap-1.5
|
|
150
|
-
|
|
151
|
-
"aria-valuemin": 0,
|
|
152
|
-
"aria-valuemax": 100,
|
|
153
|
-
"aria-valuenow": l,
|
|
154
|
-
"aria-label": t.label,
|
|
155
|
-
children: f
|
|
160
|
+
className: "grid gap-1.5 p-1.5",
|
|
161
|
+
children: p
|
|
156
162
|
})
|
|
157
163
|
}, t.id);
|
|
158
164
|
})
|
|
159
|
-
}),
|
|
160
|
-
className: "text-xs text-muted-foreground",
|
|
161
|
-
children:
|
|
165
|
+
}), /* @__PURE__ */ _("p", {
|
|
166
|
+
className: "flex justify-between gap-2 border-t border-border pt-2 text-xs tabular-nums text-muted-foreground",
|
|
167
|
+
children: [/* @__PURE__ */ g("time", {
|
|
168
|
+
dateTime: e.live_at,
|
|
169
|
+
children: u(a, e.live_at, !1)
|
|
170
|
+
}), n && /* @__PURE__ */ g("span", { children: a.plural("poll.votes", l) })]
|
|
162
171
|
})] });
|
|
163
172
|
}
|
|
164
173
|
function C({ poll: e, pending: n, maxLength: r, results: i, onAnswer: o }) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"poll.js","names":[],"sources":["../../../src/components/social/poll.tsx"],"sourcesContent":["import { Tick02Icon } from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { cn } from \"cn\";\nimport { useContext, useId, useState, type ReactNode } from \"react\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport { toContentKitError, type ContentKitError } from \"../../client/errors.js\";\nimport type { Poll as PollData } from \"../../client/generated/wire.js\";\nimport type { ContentKitUiAppearance } from \"../../appearance.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport { ContentKitContext, useErrorReporter, type ContentKitErrorHandler } from \"../../react/context.js\";\nimport { useContentConfig } from \"../../react/config.js\";\nimport { usePoll } from \"../../react/polls.js\";\nimport { ContentKitUiRoot } from \"../../scope.js\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Skeleton } from \"#ckui/ui/skeleton\";\nimport { Textarea } from \"#ckui/ui/textarea\";\nimport { ErrorLine, formatDate } from \"./parts.js\";\n\nexport interface PollProps {\n /** A poll id, or the poll the host already has; none shows the newest live poll (in language). */\n poll?: string | PollData;\n language?: string;\n /** When results show: once the visitor voted (default), or always. A closed poll always shows them. */\n results?: \"voted\" | \"always\";\n /** Asks a signed-out visitor to sign in where the server takes no anonymous votes (default the provider's). */\n onSignIn?: () => void;\n /** Shown when there is no live poll; default nothing. */\n empty?: ReactNode;\n /** Longest free-text answer. Default 280. */\n maxLength?: number;\n client?: ContentKitClient;\n onError?: ContentKitErrorHandler;\n className?: string;\n appearance?: ContentKitUiAppearance;\n}\n\n/**\n * A poll: vote (at once, final) and results scaled to the leading option, or a\n * free-text answer and its groups. Question and option images, the closing\n * date and the closed state come from the poll. Signed out, visitors vote\n * where the server allows it (`Config.anonymous.votes`) and are asked to sign\n * in elsewhere; free-text answers always need a signed-in visitor.\n */\nexport function Poll(p: PollProps) {\n const m = useMessages();\n const { t } = m;\n const ctx = useContext(ContentKitContext);\n const id = typeof p.poll === \"string\" ? p.poll : p.poll?.id;\n const r = usePoll(id ?? null, { initial: typeof p.poll === \"object\" ? p.poll : undefined, language: p.language, client: p.client });\n const report = useErrorReporter(p.onError);\n const [error, setError] = useState<ContentKitError | null>(null);\n const { config } = useContentConfig({ client: p.client });\n const signIn = p.onSignIn ?? ctx?.onSignIn;\n const signedOut = ctx?.viewer === null;\n // Signed out where the server takes no anonymous votes.\n const mustSignIn = signedOut && config?.anonymous.votes === false;\n const root = (children: ReactNode) => (\n <ContentKitUiRoot appearance={p.appearance} className={cn(\"grid gap-3 rounded-xl border border-border bg-card p-4 text-sm text-card-foreground\", p.className)} data-ckui=\"poll\">\n {children}\n </ContentKitUiRoot>\n );\n if (r.loading && !r.poll) {\n return root(\n <div className=\"grid gap-2\" aria-busy>\n <Skeleton className=\"h-5 w-2/3\" />\n <Skeleton className=\"h-9 w-full\" />\n <Skeleton className=\"h-9 w-full\" />\n </div>,\n );\n }\n if (r.error && !r.poll) {\n return root(\n <div className=\"grid justify-items-start gap-2\">\n <ErrorLine>{t(\"poll.loadFailed\")}</ErrorLine>\n <Button size=\"sm\" variant=\"outline\" onClick={r.reload}>\n {t(\"common.retry\")}\n </Button>\n </div>,\n );\n }\n const poll = r.poll;\n if (!poll) return p.empty ? <>{p.empty}</> : null;\n\n const fail = (e: unknown, op: \"poll.vote\" | \"poll.answer\") => {\n const err = toContentKitError(e);\n if (err.code === \"unauthorized\" && signIn) return signIn();\n setError(err);\n report(err, op);\n };\n const vote = (option: string) => {\n if (mustSignIn) return signIn?.();\n setError(null);\n r.vote(option).catch((e) => fail(e, \"poll.vote\"));\n };\n const header = (\n <>\n {poll.image_url && <img src={poll.image_url} alt=\"\" className=\"aspect-video w-full rounded-lg object-cover\" loading=\"lazy\" />}\n <h3 className=\"text-base font-semibold\" id={`poll-${poll.id}`}>\n {poll.question}\n </h3>\n {poll.closed ? (\n <p className=\"text-muted-foreground\">{t(\"poll.closed\")}</p>\n ) : (\n poll.closes_at && <p className=\"text-muted-foreground\">{t(\"poll.closes\", { date: formatDate(m, poll.closes_at) })}</p>\n )}\n </>\n );\n return root(\n <>\n {header}\n {poll.kind === \"free_text\" ? (\n <FreeText poll={poll} pending={r.pending} maxLength={p.maxLength ?? 280} results={p.results} onAnswer={(text) =>\n r.answer(text).then(\n () => true,\n (e) => (fail(e, \"poll.answer\"), false),\n )\n }\n />\n ) : (\n <Choices poll={poll} results={p.results === \"always\" || poll.voted || poll.closed} canVote={!poll.voted && !poll.closed && !r.pending && (!mustSignIn || !!signIn)} onVote={vote} />\n )}\n <ErrorLine error={error} />\n {!poll.voted && !poll.closed && mustSignIn && poll.kind !== \"free_text\" && <p className=\"text-xs text-muted-foreground\">{t(\"poll.signIn\")}</p>}\n </>,\n );\n}\n\nfunction Choices({ poll, results, canVote, onVote }: { poll: PollData; results: boolean; canVote: boolean; onVote: (option: string) => void }) {\n const m = useMessages();\n const { t } = m;\n const options = [...poll.options].sort((a, b) => a.position - b.position);\n const images = options.some((o) => o.image_url);\n const total = poll.total_votes || options.reduce((n, o) => n + o.vote_count, 0);\n const lead = Math.max(1, ...options.map((o) => o.vote_count));\n return (\n <>\n <ul className={cn(\"grid gap-2\", images && \"grid-cols-2\")} aria-labelledby={`poll-${poll.id}`}>\n {options.map((o) => {\n const mine = poll.my_option === o.id;\n const percent = total ? Math.round((o.vote_count / total) * 100) : 0;\n const body = (\n <>\n {o.image_url && <img src={o.image_url} alt=\"\" className=\"aspect-[4/3] w-full rounded-md bg-muted object-contain\" loading=\"lazy\" />}\n <span className=\"relative flex w-full items-center gap-2\">\n {results && (\n <span\n aria-hidden\n className={cn(\"absolute inset-y-0 start-0 rounded-md transition-[width] duration-500 motion-reduce:transition-none\", mine ? \"bg-primary/25\" : \"bg-muted\")}\n style={{ width: `${(o.vote_count / lead) * 100}%` }}\n />\n )}\n <span className=\"relative flex min-w-0 flex-1 items-center gap-2 px-2 py-1.5\">\n {mine && <HugeiconsIcon icon={Tick02Icon} strokeWidth={2.5} className=\"size-4 shrink-0 text-primary\" aria-label={t(\"poll.yourVote\")} />}\n <span className=\"min-w-0 flex-1 break-words text-start\">{o.label}</span>\n {results && <span className=\"shrink-0 tabular-nums font-medium\">{percent}%</span>}\n </span>\n </span>\n {results && <span className=\"sr-only\">{m.plural(\"poll.votes\", o.vote_count)}</span>}\n </>\n );\n return (\n <li key={o.id} data-option={o.id} data-mine={mine || undefined}>\n {canVote ? (\n <Button variant=\"outline\" className=\"h-auto w-full flex-col items-stretch gap-1.5 p-1 whitespace-normal\" onClick={() => onVote(o.id)}>\n {body}\n </Button>\n ) : (\n <div\n className=\"grid gap-1.5 rounded-md border border-border p-1\"\n role=\"meter\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={percent}\n aria-label={o.label}\n >\n {body}\n </div>\n )}\n </li>\n );\n })}\n </ul>\n {results && <p className=\"text-xs text-muted-foreground\">{m.plural(\"poll.votes\", total)}</p>}\n </>\n );\n}\n\nfunction FreeText({ poll, pending, maxLength, results, onAnswer }: { poll: PollData; pending: boolean; maxLength: number; results?: \"voted\" | \"always\"; onAnswer: (text: string) => Promise<boolean> }) {\n const m = useMessages();\n const { t } = m;\n const ids = useId();\n const mine = poll.my_answer;\n const [editing, setEditing] = useState(false);\n const [text, setText] = useState(mine?.text ?? \"\");\n const open = !poll.closed;\n const groups = [...(poll.groups ?? [])].sort((a, b) => b.count - a.count);\n const lead = Math.max(1, ...groups.map((g) => g.count));\n const showGroups = groups.length > 0 && (!!mine || poll.closed || results === \"always\");\n return (\n <>\n {open && (!mine || editing) ? (\n <form\n className=\"grid gap-2\"\n onSubmit={(e) => {\n e.preventDefault();\n if (!text.trim()) return;\n void onAnswer(text.trim()).then((ok) => ok && setEditing(false));\n }}\n >\n <label htmlFor={`${ids}-answer`} className=\"sr-only\">\n {t(\"poll.answerPlaceholder\")}\n </label>\n <Textarea id={`${ids}-answer`} rows={2} maxLength={maxLength} placeholder={t(\"poll.answerPlaceholder\")} value={text} disabled={pending} onChange={(e) => setText(e.target.value)} />\n <div className=\"flex justify-end gap-2\">\n {editing && (\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={() => setEditing(false)}>\n {t(\"common.cancel\")}\n </Button>\n )}\n <Button type=\"submit\" size=\"sm\" disabled={pending || !text.trim()}>\n {t(mine ? \"poll.updateAnswer\" : \"poll.answer\")}\n </Button>\n </div>\n </form>\n ) : (\n mine && (\n <div className=\"grid gap-1 rounded-md bg-muted p-3\">\n <p className=\"text-xs text-muted-foreground\">{t(\"poll.yourAnswer\")}</p>\n <p className=\"break-words whitespace-pre-wrap\">{mine.text}</p>\n {open && (\n <Button\n variant=\"link\"\n size=\"xs\"\n className=\"justify-self-start px-0\"\n onClick={() => {\n setText(mine.text);\n setEditing(true);\n }}\n >\n {t(\"poll.editAnswer\")}\n </Button>\n )}\n </div>\n )\n )}\n {showGroups && (\n <>\n <ul className=\"grid gap-2\" aria-labelledby={`poll-${poll.id}`}>\n {groups.map((g) => (\n <li key={g.id} className=\"relative flex items-center gap-2 rounded-md px-2 py-1.5\">\n <span aria-hidden className=\"absolute inset-y-0 start-0 rounded-md bg-muted\" style={{ width: `${(g.count / lead) * 100}%` }} />\n <span className=\"relative min-w-0 flex-1 break-words\">{g.label}</span>\n <span className=\"relative tabular-nums text-muted-foreground\">{m.plural(\"poll.answers\", g.count)}</span>\n </li>\n ))}\n </ul>\n {poll.answer_count !== undefined && <p className=\"text-xs text-muted-foreground\">{m.plural(\"poll.answers\", poll.answer_count)}</p>}\n </>\n )}\n </>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA2CA,SAAgB,EAAK,GAAc;CACjC,IAAM,IAAI,EAAY,GAChB,EAAE,SAAM,GACR,IAAM,EAAW,CAAiB,GAClC,IAAK,OAAO,EAAE,QAAS,WAAW,EAAE,OAAO,EAAE,MAAM,IACnD,IAAI,EAAQ,KAAM,MAAM;EAAE,SAAS,OAAO,EAAE,QAAS,WAAW,EAAE,OAAO,KAAA;EAAW,UAAU,EAAE;EAAU,QAAQ,EAAE;CAAO,CAAC,GAC5H,IAAS,EAAiB,EAAE,OAAO,GACnC,CAAC,GAAO,KAAY,EAAiC,IAAI,GACzD,EAAE,cAAW,EAAiB,EAAE,QAAQ,EAAE,OAAO,CAAC,GAClD,IAAS,EAAE,YAAY,GAAK,UAG5B,IAFY,GAAK,WAAW,QAEF,GAAQ,UAAU,UAAU,IACtD,KAAQ,MACZ,kBAAC,GAAD;EAAkB,YAAY,EAAE;EAAY,WAAW,EAAG,uFAAuF,EAAE,SAAS;EAAG,aAAU;EACtK;CACe,CAAA;CAEpB,IAAI,EAAE,WAAW,CAAC,EAAE,MAClB,OAAO,EACL,kBAAC,OAAD;EAAK,WAAU;EAAa,aAAA;EAA5B,UAAA;GACE,kBAAC,GAAD,EAAU,WAAU,YAAa,CAAA;GACjC,kBAAC,GAAD,EAAU,WAAU,aAAc,CAAA;GAClC,kBAAC,GAAD,EAAU,WAAU,aAAc,CAAA;EAC/B;CACP,CAAA,CAAA;CAEF,IAAI,EAAE,SAAS,CAAC,EAAE,MAChB,OAAO,EACL,kBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACE,kBAAC,GAAD,EAAA,UAAY,EAAE,iBAAiB,EAAa,CAAA,GAC5C,kBAAC,GAAD;GAAQ,MAAK;GAAK,SAAQ;GAAU,SAAS,EAAE;GAC5C,UAAA,EAAE,cAAc;EACX,CAAA,CACL;CACP,CAAA,CAAA;CAEF,IAAM,IAAO,EAAE;CACf,IAAI,CAAC,GAAM,OAAO,EAAE,QAAQ,kBAAA,GAAA,EAAA,UAAG,EAAE,MAAQ,CAAA,IAAI;CAE7C,IAAM,KAAQ,GAAY,MAAoC;EAC5D,IAAM,IAAM,EAAkB,CAAC;EAC/B,IAAI,EAAI,SAAS,kBAAkB,GAAQ,OAAO,EAAO;EAEzD,AADA,EAAS,CAAG,GACZ,EAAO,GAAK,CAAE;CAChB,GACM,KAAQ,MAAmB;EAC/B,IAAI,GAAY,OAAO,IAAS;EAEhC,AADA,EAAS,IAAI,GACb,EAAE,KAAK,CAAM,CAAC,CAAC,OAAO,MAAM,EAAK,GAAG,WAAW,CAAC;CAClD,GACM,IACJ,kBAAA,GAAA,EAAA,UAAA;EACG,EAAK,aAAa,kBAAC,OAAD;GAAK,KAAK,EAAK;GAAW,KAAI;GAAG,WAAU;GAA8C,SAAQ;EAAQ,CAAA;EAC5H,kBAAC,MAAD;GAAI,WAAU;GAA0B,IAAI,QAAQ,EAAK;GACtD,UAAA,EAAK;EACJ,CAAA;EACH,EAAK,SACJ,kBAAC,KAAD;GAAG,WAAU;GAAyB,UAAA,EAAE,aAAa;EAAK,CAAA,IAE1D,EAAK,aAAa,kBAAC,KAAD;GAAG,WAAU;GAAyB,UAAA,EAAE,eAAe,EAAE,MAAM,EAAW,GAAG,EAAK,SAAS,EAAE,CAAC;EAAK,CAAA;CAEvH,EAAA,CAAA;CAEJ,OAAO,EACL,kBAAA,GAAA,EAAA,UAAA;EACG;EACA,EAAK,SAAS,cACb,kBAAC,GAAD;GAAgB;GAAM,SAAS,EAAE;GAAS,WAAW,EAAE,aAAa;GAAK,SAAS,EAAE;GAAS,WAAW,MACpG,EAAE,OAAO,CAAI,CAAC,CAAC,WACP,KACL,OAAO,EAAK,GAAG,aAAa,GAAG,GAClC;EAEH,CAAA,IAED,kBAAC,GAAD;GAAe;GAAM,SAAS,EAAE,YAAY,YAAY,EAAK,SAAS,EAAK;GAAQ,SAAS,CAAC,EAAK,SAAS,CAAC,EAAK,UAAU,CAAC,EAAE,YAAY,CAAC,KAAc,CAAC,CAAC;GAAS,QAAQ;EAAO,CAAA;EAErL,kBAAC,GAAD,EAAkB,SAAQ,CAAA;EACzB,CAAC,EAAK,SAAS,CAAC,EAAK,UAAU,KAAc,EAAK,SAAS,eAAe,kBAAC,KAAD;GAAG,WAAU;GAAiC,UAAA,EAAE,aAAa;EAAK,CAAA;CAC7I,EAAA,CAAA,CACJ;AACF;AAEA,SAAS,EAAQ,EAAE,SAAM,YAAS,YAAS,aAAoG;CAC7I,IAAM,IAAI,EAAY,GAChB,EAAE,SAAM,GACR,IAAU,CAAC,GAAG,EAAK,OAAO,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ,GAClE,IAAS,EAAQ,MAAM,MAAM,EAAE,SAAS,GACxC,IAAQ,EAAK,eAAe,EAAQ,QAAQ,GAAG,MAAM,IAAI,EAAE,YAAY,CAAC,GACxE,IAAO,KAAK,IAAI,GAAG,GAAG,EAAQ,KAAK,MAAM,EAAE,UAAU,CAAC;CAC5D,OACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,MAAD;EAAI,WAAW,EAAG,cAAc,KAAU,aAAa;EAAG,mBAAiB,QAAQ,EAAK;EACrF,UAAA,EAAQ,KAAK,MAAM;GAClB,IAAM,IAAO,EAAK,cAAc,EAAE,IAC5B,IAAU,IAAQ,KAAK,MAAO,EAAE,aAAa,IAAS,GAAG,IAAI,GAC7D,IACJ,kBAAA,GAAA,EAAA,UAAA;IACG,EAAE,aAAa,kBAAC,OAAD;KAAK,KAAK,EAAE;KAAW,KAAI;KAAG,WAAU;KAAyD,SAAQ;IAAQ,CAAA;IACjI,kBAAC,QAAD;KAAM,WAAU;KAAhB,UAAA,CACG,KACC,kBAAC,QAAD;MACE,eAAA;MACA,WAAW,EAAG,uGAAuG,IAAO,kBAAkB,UAAU;MACxJ,OAAO,EAAE,OAAO,GAAI,EAAE,aAAa,IAAQ,IAAI,GAAG;KACnD,CAAA,GAEH,kBAAC,QAAD;MAAM,WAAU;MAAhB,UAAA;OACG,KAAQ,kBAAC,GAAD;QAAe,MAAM;QAAY,aAAa;QAAK,WAAU;QAA+B,cAAY,EAAE,eAAe;OAAI,CAAA;OACtI,kBAAC,QAAD;QAAM,WAAU;QAAyC,UAAA,EAAE;OAAY,CAAA;OACtE,KAAW,kBAAC,QAAD;QAAM,WAAU;QAAhB,UAAA,CAAqD,GAAQ,GAAO;;MAC5E;KACF,CAAA,CAAA;;IACL,KAAW,kBAAC,QAAD;KAAM,WAAU;KAAW,UAAA,EAAE,OAAO,cAAc,EAAE,UAAU;IAAQ,CAAA;GAClF,EAAA,CAAA;GAEJ,OACE,kBAAC,MAAD;IAAe,eAAa,EAAE;IAAI,aAAW,KAAQ,KAAA;IAClD,UAAA,IACC,kBAAC,GAAD;KAAQ,SAAQ;KAAU,WAAU;KAAqE,eAAe,EAAO,EAAE,EAAE;KAChI,UAAA;IACK,CAAA,IAER,kBAAC,OAAD;KACE,WAAU;KACV,MAAK;KACL,iBAAe;KACf,iBAAe;KACf,iBAAe;KACf,cAAY,EAAE;KAEb,UAAA;IACE,CAAA;GAEL,GAjBK,EAAE,EAiBP;EAER,CAAC;CACC,CAAA,GACH,KAAW,kBAAC,KAAD;EAAG,WAAU;EAAiC,UAAA,EAAE,OAAO,cAAc,CAAK;CAAK,CAAA,CAC3F,EAAA,CAAA;AAEN;AAEA,SAAS,EAAS,EAAE,SAAM,YAAS,cAAW,YAAS,eAAiJ;CACtM,IAAM,IAAI,EAAY,GAChB,EAAE,SAAM,GACR,IAAM,EAAM,GACZ,IAAO,EAAK,WACZ,CAAC,GAAS,KAAc,EAAS,EAAK,GACtC,CAAC,GAAM,KAAW,EAAS,GAAM,QAAQ,EAAE,GAC3C,IAAO,CAAC,EAAK,QACb,IAAS,CAAC,GAAI,EAAK,UAAU,CAAC,CAAE,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,GAClE,IAAO,KAAK,IAAI,GAAG,GAAG,EAAO,KAAK,MAAM,EAAE,KAAK,CAAC,GAChD,IAAa,EAAO,SAAS,MAAM,CAAC,CAAC,KAAQ,EAAK,UAAU,MAAY;CAC9E,OACE,kBAAA,GAAA,EAAA,UAAA,CACG,MAAS,CAAC,KAAQ,KACjB,kBAAC,QAAD;EACE,WAAU;EACV,WAAW,MAAM;GACf,EAAE,eAAe,GACZ,EAAK,KAAK,KACf,EAAc,EAAK,KAAK,CAAC,CAAC,CAAC,MAAM,MAAO,KAAM,EAAW,EAAK,CAAC;EACjE;EANF,UAAA;GAQE,kBAAC,SAAD;IAAO,SAAS,GAAG,EAAI;IAAU,WAAU;IACxC,UAAA,EAAE,wBAAwB;GACtB,CAAA;GACP,kBAAC,GAAD;IAAU,IAAI,GAAG,EAAI;IAAU,MAAM;IAAc;IAAW,aAAa,EAAE,wBAAwB;IAAG,OAAO;IAAM,UAAU;IAAS,WAAW,MAAM,EAAQ,EAAE,OAAO,KAAK;GAAI,CAAA;GACnL,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACG,KACC,kBAAC,GAAD;KAAQ,MAAK;KAAS,SAAQ;KAAQ,MAAK;KAAK,eAAe,EAAW,EAAK;KAC5E,UAAA,EAAE,eAAe;IACZ,CAAA,GAEV,kBAAC,GAAD;KAAQ,MAAK;KAAS,MAAK;KAAK,UAAU,KAAW,CAAC,EAAK,KAAK;KAC7D,UAAA,EAAE,IAAO,sBAAsB,aAAa;IACvC,CAAA,CACL;;EACD;CAEN,CAAA,IAAA,KACE,kBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACE,kBAAC,KAAD;IAAG,WAAU;IAAiC,UAAA,EAAE,iBAAiB;GAAK,CAAA;GACtE,kBAAC,KAAD;IAAG,WAAU;IAAmC,UAAA,EAAK;GAAQ,CAAA;GAC5D,KACC,kBAAC,GAAD;IACE,SAAQ;IACR,MAAK;IACL,WAAU;IACV,eAAe;KAEb,AADA,EAAQ,EAAK,IAAI,GACjB,EAAW,EAAI;IACjB;IAEC,UAAA,EAAE,iBAAiB;GACd,CAAA;EAEP;CAGR,CAAA,GAAA,KACC,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,MAAD;EAAI,WAAU;EAAa,mBAAiB,QAAQ,EAAK;EACtD,UAAA,EAAO,KAAK,MACX,kBAAC,MAAD;GAAe,WAAU;GAAzB,UAAA;IACE,kBAAC,QAAD;KAAM,eAAA;KAAY,WAAU;KAAiD,OAAO,EAAE,OAAO,GAAI,EAAE,QAAQ,IAAQ,IAAI,GAAG;IAAI,CAAA;IAC9H,kBAAC,QAAD;KAAM,WAAU;KAAuC,UAAA,EAAE;IAAY,CAAA;IACrE,kBAAC,QAAD;KAAM,WAAU;KAA+C,UAAA,EAAE,OAAO,gBAAgB,EAAE,KAAK;IAAQ,CAAA;GACrG;EAJK,GAAA,EAAE,EAIP,CACL;CACC,CAAA,GACH,EAAK,iBAAiB,KAAA,KAAa,kBAAC,KAAD;EAAG,WAAU;EAAiC,UAAA,EAAE,OAAO,gBAAgB,EAAK,YAAY;CAAK,CAAA,CACjI,EAAA,CAAA,CAEJ,EAAA,CAAA;AAEN"}
|
|
1
|
+
{"version":3,"file":"poll.js","names":[],"sources":["../../../src/components/social/poll.tsx"],"sourcesContent":["import { Tick02Icon } from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { cn } from \"cn\";\nimport { useContext, useId, useState, type ReactNode } from \"react\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport { toContentKitError, type ContentKitError } from \"../../client/errors.js\";\nimport type { Poll as PollData } from \"../../client/generated/wire.js\";\nimport type { ContentKitUiAppearance } from \"../../appearance.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport { ContentKitContext, useErrorReporter, type ContentKitErrorHandler } from \"../../react/context.js\";\nimport { useContentConfig } from \"../../react/config.js\";\nimport { usePoll } from \"../../react/polls.js\";\nimport { ContentKitUiRoot } from \"../../scope.js\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Skeleton } from \"#ckui/ui/skeleton\";\nimport { Textarea } from \"#ckui/ui/textarea\";\nimport { ErrorLine, formatDate } from \"./parts.js\";\n\nexport interface PollProps {\n /** A poll id, or the poll the host already has; none shows the newest live poll (in language). */\n poll?: string | PollData;\n language?: string;\n /** When results show: once the visitor voted (default), or always. A closed poll always shows them. */\n results?: \"voted\" | \"always\";\n /** Asks a signed-out visitor to sign in where the server takes no anonymous votes (default the provider's). */\n onSignIn?: () => void;\n /** Shown when there is no live poll; default nothing. */\n empty?: ReactNode;\n /** Longest free-text answer. Default 280. */\n maxLength?: number;\n client?: ContentKitClient;\n onError?: ContentKitErrorHandler;\n className?: string;\n appearance?: ContentKitUiAppearance;\n}\n\n/**\n * A poll: vote (at once, final) and results scaled to the leading option, or a\n * free-text answer and its groups. Question and option images, the closing\n * date and the closed state come from the poll. Signed out, visitors vote\n * where the server allows it (`Config.anonymous.votes`) and are asked to sign\n * in elsewhere; free-text answers always need a signed-in visitor.\n */\nexport function Poll(p: PollProps) {\n const m = useMessages();\n const { t } = m;\n const ctx = useContext(ContentKitContext);\n const id = typeof p.poll === \"string\" ? p.poll : p.poll?.id;\n const r = usePoll(id ?? null, { initial: typeof p.poll === \"object\" ? p.poll : undefined, language: p.language, client: p.client });\n const report = useErrorReporter(p.onError);\n const [error, setError] = useState<ContentKitError | null>(null);\n const { config } = useContentConfig({ client: p.client });\n const signIn = p.onSignIn ?? ctx?.onSignIn;\n const signedOut = ctx?.viewer === null;\n // Signed out where the server takes no anonymous votes.\n const mustSignIn = signedOut && config?.anonymous.votes === false;\n const root = (children: ReactNode) => (\n <ContentKitUiRoot appearance={p.appearance} className={cn(\"grid content-start gap-3 rounded-xl border border-border bg-card p-4 text-sm text-card-foreground\", p.className)} data-ckui=\"poll\">\n {children}\n </ContentKitUiRoot>\n );\n if (r.loading && !r.poll) {\n return root(\n <div className=\"grid gap-2\" aria-busy>\n <Skeleton className=\"h-5 w-2/3\" />\n <Skeleton className=\"h-9 w-full\" />\n <Skeleton className=\"h-9 w-full\" />\n </div>,\n );\n }\n if (r.error && !r.poll) {\n return root(\n <div className=\"grid justify-items-start gap-2\">\n <ErrorLine>{t(\"poll.loadFailed\")}</ErrorLine>\n <Button size=\"sm\" variant=\"outline\" onClick={r.reload}>\n {t(\"common.retry\")}\n </Button>\n </div>,\n );\n }\n const poll = r.poll;\n if (!poll) return p.empty ? <>{p.empty}</> : null;\n\n const fail = (e: unknown, op: \"poll.vote\" | \"poll.answer\") => {\n const err = toContentKitError(e);\n if (err.code === \"unauthorized\" && signIn) return signIn();\n setError(err);\n report(err, op);\n };\n const vote = (option: string) => {\n if (mustSignIn) return signIn?.();\n setError(null);\n r.vote(option).catch((e) => fail(e, \"poll.vote\"));\n };\n const header = (\n <>\n {poll.image_url && <img src={poll.image_url} alt=\"\" className=\"aspect-video w-full rounded-lg object-cover\" loading=\"lazy\" />}\n <h3 className=\"border-b border-border pb-2 text-base font-semibold\" id={`poll-${poll.id}`}>\n {poll.question}\n </h3>\n {poll.closed ? (\n <p className=\"text-muted-foreground\">{t(\"poll.closed\")}</p>\n ) : (\n poll.closes_at && <p className=\"text-muted-foreground\">{t(\"poll.closes\", { date: formatDate(m, poll.closes_at) })}</p>\n )}\n </>\n );\n return root(\n <>\n {header}\n {poll.kind === \"free_text\" ? (\n <FreeText poll={poll} pending={r.pending} maxLength={p.maxLength ?? 280} results={p.results} onAnswer={(text) =>\n r.answer(text).then(\n () => true,\n (e) => (fail(e, \"poll.answer\"), false),\n )\n }\n />\n ) : (\n <Choices\n poll={poll}\n results={p.results === \"always\" || poll.voted || poll.closed}\n canVote={!poll.voted && !poll.closed && !r.pending && (!mustSignIn || !!signIn)}\n onVote={vote}\n />\n )}\n <ErrorLine error={error} />\n {!poll.voted && !poll.closed && mustSignIn && poll.kind !== \"free_text\" && <p className=\"text-xs text-muted-foreground\">{t(\"poll.signIn\")}</p>}\n </>,\n );\n}\n\nfunction Choices({ poll, results, canVote, onVote }: { poll: PollData; results: boolean; canVote: boolean; onVote: (option: string) => void }) {\n const m = useMessages();\n const { t } = m;\n const options = [...poll.options].sort((a, b) => a.position - b.position);\n const images = options.some((o) => o.image_url);\n const total = poll.total_votes || options.reduce((n, o) => n + o.vote_count, 0);\n // Bars scale to the leading option, which spans the full width.\n const lead = Math.max(1, ...options.map((o) => o.vote_count));\n return (\n <>\n <ul className={cn(\"grid gap-3\", images && \"grid-cols-2\")} aria-labelledby={`poll-${poll.id}`}>\n {options.map((o) => {\n const mine = poll.my_option === o.id;\n const percent = total ? Math.round((o.vote_count / total) * 100) : 0;\n const choose = canVote ? () => onVote(o.id) : undefined;\n const meter = results && !choose ? { role: \"meter\", \"aria-valuemin\": 0, \"aria-valuemax\": 100, \"aria-valuenow\": percent, \"aria-label\": o.label } : {};\n const body = (\n <>\n {o.image_url && <img src={o.image_url} alt=\"\" className=\"aspect-[4/3] w-full rounded-md bg-muted object-contain\" loading=\"lazy\" />}\n <span className=\"flex w-full items-baseline gap-2\">\n {mine && <HugeiconsIcon icon={Tick02Icon} strokeWidth={2.5} className=\"size-4 shrink-0 self-center text-primary\" aria-label={t(\"poll.yourVote\")} />}\n <span className=\"min-w-0 flex-1 break-words text-start font-medium\">{o.label}</span>\n {results && (\n <span className=\"shrink-0 text-xs tabular-nums text-muted-foreground\">\n <span className=\"font-semibold text-foreground\">{percent}%</span> · {m.plural(\"poll.votes\", o.vote_count)}\n </span>\n )}\n </span>\n {results && (\n <span aria-hidden className=\"block h-2 w-full overflow-hidden rounded-full bg-muted\">\n <span className={cn(\"block h-full rounded-full transition-[width] duration-500 motion-reduce:transition-none\", mine ? \"bg-primary\" : \"bg-foreground/40\")} style={{ width: `${(o.vote_count / lead) * 100}%` }} />\n </span>\n )}\n </>\n );\n return (\n <li key={o.id} data-option={o.id} data-mine={mine || undefined} {...meter}>\n {choose ? (\n <button type=\"button\" className=\"grid w-full gap-1.5 rounded-md p-1.5 text-start hover:bg-muted/60 focus-visible:outline-2 focus-visible:outline-ring\" onClick={choose}>\n {body}\n </button>\n ) : (\n <div className=\"grid gap-1.5 p-1.5\">{body}</div>\n )}\n </li>\n );\n })}\n </ul>\n <p className=\"flex justify-between gap-2 border-t border-border pt-2 text-xs tabular-nums text-muted-foreground\">\n <time dateTime={poll.live_at}>{formatDate(m, poll.live_at, false)}</time>\n {results && <span>{m.plural(\"poll.votes\", total)}</span>}\n </p>\n </>\n );\n}\n\nfunction FreeText({ poll, pending, maxLength, results, onAnswer }: { poll: PollData; pending: boolean; maxLength: number; results?: \"voted\" | \"always\"; onAnswer: (text: string) => Promise<boolean> }) {\n const m = useMessages();\n const { t } = m;\n const ids = useId();\n const mine = poll.my_answer;\n const [editing, setEditing] = useState(false);\n const [text, setText] = useState(mine?.text ?? \"\");\n const open = !poll.closed;\n const groups = [...(poll.groups ?? [])].sort((a, b) => b.count - a.count);\n const lead = Math.max(1, ...groups.map((g) => g.count));\n const showGroups = groups.length > 0 && (!!mine || poll.closed || results === \"always\");\n return (\n <>\n {open && (!mine || editing) ? (\n <form\n className=\"grid gap-2\"\n onSubmit={(e) => {\n e.preventDefault();\n if (!text.trim()) return;\n void onAnswer(text.trim()).then((ok) => ok && setEditing(false));\n }}\n >\n <label htmlFor={`${ids}-answer`} className=\"sr-only\">\n {t(\"poll.answerPlaceholder\")}\n </label>\n <Textarea id={`${ids}-answer`} rows={2} maxLength={maxLength} placeholder={t(\"poll.answerPlaceholder\")} value={text} disabled={pending} onChange={(e) => setText(e.target.value)} />\n <div className=\"flex justify-end gap-2\">\n {editing && (\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={() => setEditing(false)}>\n {t(\"common.cancel\")}\n </Button>\n )}\n <Button type=\"submit\" size=\"sm\" disabled={pending || !text.trim()}>\n {t(mine ? \"poll.updateAnswer\" : \"poll.answer\")}\n </Button>\n </div>\n </form>\n ) : (\n mine && (\n <div className=\"grid gap-1 rounded-md bg-muted p-3\">\n <p className=\"text-xs text-muted-foreground\">{t(\"poll.yourAnswer\")}</p>\n <p className=\"break-words whitespace-pre-wrap\">{mine.text}</p>\n {open && (\n <Button\n variant=\"link\"\n size=\"xs\"\n className=\"justify-self-start px-0\"\n onClick={() => {\n setText(mine.text);\n setEditing(true);\n }}\n >\n {t(\"poll.editAnswer\")}\n </Button>\n )}\n </div>\n )\n )}\n {showGroups && (\n <>\n <ul className=\"grid gap-2\" aria-labelledby={`poll-${poll.id}`}>\n {groups.map((g) => (\n <li key={g.id} className=\"relative flex items-center gap-2 rounded-md px-2 py-1.5\">\n <span aria-hidden className=\"absolute inset-y-0 start-0 rounded-md bg-muted\" style={{ width: `${(g.count / lead) * 100}%` }} />\n <span className=\"relative min-w-0 flex-1 break-words\">{g.label}</span>\n <span className=\"relative tabular-nums text-muted-foreground\">{m.plural(\"poll.answers\", g.count)}</span>\n </li>\n ))}\n </ul>\n {poll.answer_count !== undefined && <p className=\"text-xs text-muted-foreground\">{m.plural(\"poll.answers\", poll.answer_count)}</p>}\n </>\n )}\n </>\n );\n}\n"],"mappings":"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"}
|
|
@@ -18,6 +18,10 @@ export interface SortableListProps<T> {
|
|
|
18
18
|
className?: string;
|
|
19
19
|
/** Accessible name of the list. */
|
|
20
20
|
label?: string;
|
|
21
|
+
/** The whole item is the drag handle (Space lifts and drops; Enter is left to the item). */
|
|
22
|
+
wholeItem?: boolean;
|
|
23
|
+
/** Unsortable entries after the items, in the same list (e.g. uploads in progress). */
|
|
24
|
+
trailing?: ReactNode;
|
|
21
25
|
appearance?: ContentKitUiAppearance;
|
|
22
26
|
}
|
|
23
27
|
/**
|
|
@@ -26,4 +30,4 @@ export interface SortableListProps<T> {
|
|
|
26
30
|
* or Enter drops, Escape cancels), with localized screen reader
|
|
27
31
|
* announcements. onMove gets the old and new index once, on drop.
|
|
28
32
|
*/
|
|
29
|
-
export declare function SortableList<T>({ items, id, name, onMove, layout, disabled, row, children, className, label, appearance }: SortableListProps<T>): import('react').JSX.Element;
|
|
33
|
+
export declare function SortableList<T>({ items, id, name, onMove, layout, disabled, row, children, className, label, appearance, wholeItem, trailing }: SortableListProps<T>): import('react').JSX.Element;
|