@openrails/contentkit-ui 0.0.0-placeholder → 0.68.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (367) hide show
  1. package/README.md +424 -1
  2. package/dist/appearance.d.ts +38 -0
  3. package/dist/appearance.js +15 -0
  4. package/dist/appearance.js.map +1 -0
  5. package/dist/assets/hash.worker-BYfo-7MQ.js.map +1 -0
  6. package/dist/client/aspect.d.ts +6 -0
  7. package/dist/client/aspect.js +17 -0
  8. package/dist/client/aspect.js.map +1 -0
  9. package/dist/client/client.d.ts +51 -0
  10. package/dist/client/client.js +35 -0
  11. package/dist/client/client.js.map +1 -0
  12. package/dist/client/codes.d.ts +12 -0
  13. package/dist/client/codes.js +19 -0
  14. package/dist/client/codes.js.map +1 -0
  15. package/dist/client/content/bans.d.ts +15 -0
  16. package/dist/client/content/bans.js +40 -0
  17. package/dist/client/content/bans.js.map +1 -0
  18. package/dist/client/content/comments.d.ts +36 -0
  19. package/dist/client/content/comments.js +93 -0
  20. package/dist/client/content/comments.js.map +1 -0
  21. package/dist/client/content/favorites.d.ts +14 -0
  22. package/dist/client/content/favorites.js +42 -0
  23. package/dist/client/content/favorites.js.map +1 -0
  24. package/dist/client/content/moderation.d.ts +18 -0
  25. package/dist/client/content/moderation.js +37 -0
  26. package/dist/client/content/moderation.js.map +1 -0
  27. package/dist/client/content/polls.d.ts +47 -0
  28. package/dist/client/content/polls.js +148 -0
  29. package/dist/client/content/polls.js.map +1 -0
  30. package/dist/client/content/posts.d.ts +44 -0
  31. package/dist/client/content/posts.js +91 -0
  32. package/dist/client/content/posts.js.map +1 -0
  33. package/dist/client/content/reactions.d.ts +12 -0
  34. package/dist/client/content/reactions.js +36 -0
  35. package/dist/client/content/reactions.js.map +1 -0
  36. package/dist/client/content/types.d.ts +91 -0
  37. package/dist/client/content/types.js +8 -0
  38. package/dist/client/content/types.js.map +1 -0
  39. package/dist/client/crop.d.ts +32 -0
  40. package/dist/client/crop.js +103 -0
  41. package/dist/client/crop.js.map +1 -0
  42. package/dist/client/errors.d.ts +54 -0
  43. package/dist/client/errors.js +80 -0
  44. package/dist/client/errors.js.map +1 -0
  45. package/dist/client/gallery.d.ts +43 -0
  46. package/dist/client/gallery.js +86 -0
  47. package/dist/client/gallery.js.map +1 -0
  48. package/dist/client/generated/error-codes.d.ts +5 -0
  49. package/dist/client/generated/error-codes.js +131 -0
  50. package/dist/client/generated/error-codes.js.map +1 -0
  51. package/dist/client/generated/routes.d.ts +1086 -0
  52. package/dist/client/generated/routes.js +1400 -0
  53. package/dist/client/generated/routes.js.map +1 -0
  54. package/dist/client/generated/wire.d.ts +630 -0
  55. package/dist/client/generated/wire.js +6 -0
  56. package/dist/client/generated/wire.js.map +1 -0
  57. package/dist/client/http.d.ts +79 -0
  58. package/dist/client/http.js +74 -0
  59. package/dist/client/http.js.map +1 -0
  60. package/dist/client/image.d.ts +24 -0
  61. package/dist/client/image.js +65 -0
  62. package/dist/client/image.js.map +1 -0
  63. package/dist/client/index.d.ts +33 -0
  64. package/dist/client/media/api.d.ts +36 -0
  65. package/dist/client/media/api.js +61 -0
  66. package/dist/client/media/api.js.map +1 -0
  67. package/dist/client/media/client.d.ts +247 -0
  68. package/dist/client/media/client.js +407 -0
  69. package/dist/client/media/client.js.map +1 -0
  70. package/dist/client/media/encode.d.ts +3 -0
  71. package/dist/client/media/encode.js +8 -0
  72. package/dist/client/media/encode.js.map +1 -0
  73. package/dist/client/media/hash-stream.d.ts +6 -0
  74. package/dist/client/media/hash-stream.js +16 -0
  75. package/dist/client/media/hash-stream.js.map +1 -0
  76. package/dist/client/media/hash.d.ts +12 -0
  77. package/dist/client/media/hash.js +48 -0
  78. package/dist/client/media/hash.js.map +1 -0
  79. package/dist/client/media/hash.worker-inline.js +18 -0
  80. package/dist/client/media/hash.worker-inline.js.map +1 -0
  81. package/dist/client/media/pacer.d.ts +21 -0
  82. package/dist/client/media/pacer.js +25 -0
  83. package/dist/client/media/pacer.js.map +1 -0
  84. package/dist/client/media/queue.d.ts +112 -0
  85. package/dist/client/media/queue.js +274 -0
  86. package/dist/client/media/queue.js.map +1 -0
  87. package/dist/client/media/ref.d.ts +6 -0
  88. package/dist/client/media/ref.js +10 -0
  89. package/dist/client/media/ref.js.map +1 -0
  90. package/dist/client/media/rules.d.ts +52 -0
  91. package/dist/client/media/rules.js +139 -0
  92. package/dist/client/media/rules.js.map +1 -0
  93. package/dist/client/media/transport.d.ts +13 -0
  94. package/dist/client/media/transport.js +33 -0
  95. package/dist/client/media/transport.js.map +1 -0
  96. package/dist/client/media/windows.d.ts +15 -0
  97. package/dist/client/media/windows.js +39 -0
  98. package/dist/client/media/windows.js.map +1 -0
  99. package/dist/client/playback.d.ts +200 -0
  100. package/dist/client/playback.js +142 -0
  101. package/dist/client/playback.js.map +1 -0
  102. package/dist/client/player.d.ts +102 -0
  103. package/dist/client/player.js +155 -0
  104. package/dist/client/player.js.map +1 -0
  105. package/dist/client/public.d.ts +25 -0
  106. package/dist/client/public.js +18 -0
  107. package/dist/client/public.js.map +1 -0
  108. package/dist/client/rendition.d.ts +19 -0
  109. package/dist/client/rendition.js +16 -0
  110. package/dist/client/rendition.js.map +1 -0
  111. package/dist/client/route.d.ts +39 -0
  112. package/dist/client/route.js +31 -0
  113. package/dist/client/route.js.map +1 -0
  114. package/dist/client/taxonomy.d.ts +30 -0
  115. package/dist/client/taxonomy.js +77 -0
  116. package/dist/client/taxonomy.js.map +1 -0
  117. package/dist/client.js +33 -0
  118. package/dist/components/encode-progress.d.ts +15 -0
  119. package/dist/components/encode-progress.js +49 -0
  120. package/dist/components/encode-progress.js.map +1 -0
  121. package/dist/components/hover-preview.d.ts +29 -0
  122. package/dist/components/hover-preview.js +49 -0
  123. package/dist/components/hover-preview.js.map +1 -0
  124. package/dist/components/image-crop-dialog.d.ts +48 -0
  125. package/dist/components/image-crop-dialog.js +359 -0
  126. package/dist/components/image-crop-dialog.js.map +1 -0
  127. package/dist/components/lazy-mount.d.ts +10 -0
  128. package/dist/components/lazy-mount.js +22 -0
  129. package/dist/components/lazy-mount.js.map +1 -0
  130. package/dist/components/media-folder-editor.d.ts +45 -0
  131. package/dist/components/media-folder-editor.js +564 -0
  132. package/dist/components/media-folder-editor.js.map +1 -0
  133. package/dist/components/media-gallery.d.ts +54 -0
  134. package/dist/components/media-gallery.js +597 -0
  135. package/dist/components/media-gallery.js.map +1 -0
  136. package/dist/components/media-readiness-notice.d.ts +24 -0
  137. package/dist/components/media-readiness-notice.js +61 -0
  138. package/dist/components/media-readiness-notice.js.map +1 -0
  139. package/dist/components/player-controls.d.ts +71 -0
  140. package/dist/components/player-controls.js +264 -0
  141. package/dist/components/player-controls.js.map +1 -0
  142. package/dist/components/progress.d.ts +5 -0
  143. package/dist/components/progress.js +14 -0
  144. package/dist/components/progress.js.map +1 -0
  145. package/dist/components/rendition-img.d.ts +34 -0
  146. package/dist/components/rendition-img.js +78 -0
  147. package/dist/components/rendition-img.js.map +1 -0
  148. package/dist/components/slot-editor.d.ts +95 -0
  149. package/dist/components/slot-editor.js +182 -0
  150. package/dist/components/slot-editor.js.map +1 -0
  151. package/dist/components/slot-image.d.ts +23 -0
  152. package/dist/components/slot-image.js +48 -0
  153. package/dist/components/slot-image.js.map +1 -0
  154. package/dist/components/slot-upload.d.ts +41 -0
  155. package/dist/components/slot-upload.js +213 -0
  156. package/dist/components/slot-upload.js.map +1 -0
  157. package/dist/components/social/bans.d.ts +42 -0
  158. package/dist/components/social/bans.js +300 -0
  159. package/dist/components/social/bans.js.map +1 -0
  160. package/dist/components/social/comments.d.ts +42 -0
  161. package/dist/components/social/comments.js +517 -0
  162. package/dist/components/social/comments.js.map +1 -0
  163. package/dist/components/social/engagement.d.ts +45 -0
  164. package/dist/components/social/engagement.js +129 -0
  165. package/dist/components/social/engagement.js.map +1 -0
  166. package/dist/components/social/index.d.ts +6 -0
  167. package/dist/components/social/moderation.d.ts +32 -0
  168. package/dist/components/social/moderation.js +383 -0
  169. package/dist/components/social/moderation.js.map +1 -0
  170. package/dist/components/social/parts.d.ts +50 -0
  171. package/dist/components/social/parts.js +106 -0
  172. package/dist/components/social/parts.js.map +1 -0
  173. package/dist/components/social/poll-editor.d.ts +34 -0
  174. package/dist/components/social/poll-editor.js +567 -0
  175. package/dist/components/social/poll-editor.js.map +1 -0
  176. package/dist/components/social/poll.d.ts +30 -0
  177. package/dist/components/social/poll.js +252 -0
  178. package/dist/components/social/poll.js.map +1 -0
  179. package/dist/components/sortable-list.d.ts +29 -0
  180. package/dist/components/sortable-list.js +121 -0
  181. package/dist/components/sortable-list.js.map +1 -0
  182. package/dist/components/video-mini-player.d.ts +35 -0
  183. package/dist/components/video-mini-player.js +236 -0
  184. package/dist/components/video-mini-player.js.map +1 -0
  185. package/dist/components/video-player.d.ts +146 -0
  186. package/dist/components/video-player.js +630 -0
  187. package/dist/components/video-player.js.map +1 -0
  188. package/dist/components/video-poster-picker.d.ts +59 -0
  189. package/dist/components/video-poster-picker.js +335 -0
  190. package/dist/components/video-poster-picker.js.map +1 -0
  191. package/dist/components/video-poster.d.ts +24 -0
  192. package/dist/components/video-poster.js +46 -0
  193. package/dist/components/video-poster.js.map +1 -0
  194. package/dist/i18n/context.d.ts +4 -0
  195. package/dist/i18n/context.js +11 -0
  196. package/dist/i18n/context.js.map +1 -0
  197. package/dist/i18n/messages.d.ts +40 -0
  198. package/dist/i18n/messages.js +94 -0
  199. package/dist/i18n/messages.js.map +1 -0
  200. package/dist/index.d.ts +23 -0
  201. package/dist/index.js +41 -0
  202. package/dist/locales/de.d.ts +2 -0
  203. package/dist/locales/de.js +271 -0
  204. package/dist/locales/de.js.map +1 -0
  205. package/dist/locales/en.d.ts +457 -0
  206. package/dist/locales/en.js +271 -0
  207. package/dist/locales/en.js.map +1 -0
  208. package/dist/locales/es.d.ts +2 -0
  209. package/dist/locales/es.js +271 -0
  210. package/dist/locales/es.js.map +1 -0
  211. package/dist/locales/ja.d.ts +2 -0
  212. package/dist/locales/ja.js +271 -0
  213. package/dist/locales/ja.js.map +1 -0
  214. package/dist/locales/ko.d.ts +2 -0
  215. package/dist/locales/ko.js +271 -0
  216. package/dist/locales/ko.js.map +1 -0
  217. package/dist/locales/social/de.d.ts +2 -0
  218. package/dist/locales/social/de.js +198 -0
  219. package/dist/locales/social/de.js.map +1 -0
  220. package/dist/locales/social/en.d.ts +195 -0
  221. package/dist/locales/social/en.js +198 -0
  222. package/dist/locales/social/en.js.map +1 -0
  223. package/dist/locales/social/es.d.ts +2 -0
  224. package/dist/locales/social/es.js +198 -0
  225. package/dist/locales/social/es.js.map +1 -0
  226. package/dist/locales/social/ja.d.ts +2 -0
  227. package/dist/locales/social/ja.js +198 -0
  228. package/dist/locales/social/ja.js.map +1 -0
  229. package/dist/locales/social/ko.d.ts +2 -0
  230. package/dist/locales/social/ko.js +198 -0
  231. package/dist/locales/social/ko.js.map +1 -0
  232. package/dist/locales/social/zh.d.ts +2 -0
  233. package/dist/locales/social/zh.js +198 -0
  234. package/dist/locales/social/zh.js.map +1 -0
  235. package/dist/locales/zh.d.ts +2 -0
  236. package/dist/locales/zh.js +271 -0
  237. package/dist/locales/zh.js.map +1 -0
  238. package/dist/provider.d.ts +22 -0
  239. package/dist/provider.js +59 -0
  240. package/dist/provider.js.map +1 -0
  241. package/dist/react/canonical.d.ts +33 -0
  242. package/dist/react/canonical.js +88 -0
  243. package/dist/react/canonical.js.map +1 -0
  244. package/dist/react/comments.d.ts +82 -0
  245. package/dist/react/comments.js +147 -0
  246. package/dist/react/comments.js.map +1 -0
  247. package/dist/react/config.d.ts +13 -0
  248. package/dist/react/config.js +14 -0
  249. package/dist/react/config.js.map +1 -0
  250. package/dist/react/context.d.ts +48 -0
  251. package/dist/react/context.js +37 -0
  252. package/dist/react/context.js.map +1 -0
  253. package/dist/react/crop.d.ts +49 -0
  254. package/dist/react/crop.js +107 -0
  255. package/dist/react/crop.js.map +1 -0
  256. package/dist/react/engagement.d.ts +38 -0
  257. package/dist/react/engagement.js +88 -0
  258. package/dist/react/engagement.js.map +1 -0
  259. package/dist/react/folder.d.ts +83 -0
  260. package/dist/react/folder.js +183 -0
  261. package/dist/react/folder.js.map +1 -0
  262. package/dist/react/gallery.d.ts +140 -0
  263. package/dist/react/gallery.js +477 -0
  264. package/dist/react/gallery.js.map +1 -0
  265. package/dist/react/index.d.ts +21 -0
  266. package/dist/react/inline-preview.d.ts +24 -0
  267. package/dist/react/inline-preview.js +76 -0
  268. package/dist/react/inline-preview.js.map +1 -0
  269. package/dist/react/player.d.ts +70 -0
  270. package/dist/react/player.js +214 -0
  271. package/dist/react/player.js.map +1 -0
  272. package/dist/react/polls.d.ts +74 -0
  273. package/dist/react/polls.js +176 -0
  274. package/dist/react/polls.js.map +1 -0
  275. package/dist/react/posts.d.ts +59 -0
  276. package/dist/react/posts.js +149 -0
  277. package/dist/react/posts.js.map +1 -0
  278. package/dist/react/provider.d.ts +23 -0
  279. package/dist/react/provider.js +35 -0
  280. package/dist/react/provider.js.map +1 -0
  281. package/dist/react/public.d.ts +39 -0
  282. package/dist/react/public.js +70 -0
  283. package/dist/react/public.js.map +1 -0
  284. package/dist/react/read.d.ts +52 -0
  285. package/dist/react/read.js +143 -0
  286. package/dist/react/read.js.map +1 -0
  287. package/dist/react/resources.d.ts +70 -0
  288. package/dist/react/resources.js +247 -0
  289. package/dist/react/resources.js.map +1 -0
  290. package/dist/react/slot.d.ts +102 -0
  291. package/dist/react/slot.js +181 -0
  292. package/dist/react/slot.js.map +1 -0
  293. package/dist/react/store.d.ts +51 -0
  294. package/dist/react/store.js +164 -0
  295. package/dist/react/store.js.map +1 -0
  296. package/dist/react/upload.d.ts +85 -0
  297. package/dist/react/upload.js +150 -0
  298. package/dist/react/upload.js.map +1 -0
  299. package/dist/react/use-resource.d.ts +43 -0
  300. package/dist/react/use-resource.js +66 -0
  301. package/dist/react/use-resource.js.map +1 -0
  302. package/dist/react/video.d.ts +118 -0
  303. package/dist/react/video.js +184 -0
  304. package/dist/react/video.js.map +1 -0
  305. package/dist/react/viewport.d.ts +19 -0
  306. package/dist/react/viewport.js +30 -0
  307. package/dist/react/viewport.js.map +1 -0
  308. package/dist/react.js +21 -0
  309. package/dist/scope.d.ts +14 -0
  310. package/dist/scope.js +30 -0
  311. package/dist/scope.js.map +1 -0
  312. package/dist/styles.css +3 -0
  313. package/dist/ui/alert-dialog.d.ts +18 -0
  314. package/dist/ui/alert-dialog.js +86 -0
  315. package/dist/ui/alert-dialog.js.map +1 -0
  316. package/dist/ui/alert.d.ts +10 -0
  317. package/dist/ui/alert.js +38 -0
  318. package/dist/ui/alert.js.map +1 -0
  319. package/dist/ui/avatar.d.ts +11 -0
  320. package/dist/ui/avatar.js +31 -0
  321. package/dist/ui/avatar.js.map +1 -0
  322. package/dist/ui/badge.d.ts +7 -0
  323. package/dist/ui/badge.js +31 -0
  324. package/dist/ui/badge.js.map +1 -0
  325. package/dist/ui/button.d.ts +8 -0
  326. package/dist/ui/button.js +46 -0
  327. package/dist/ui/button.js.map +1 -0
  328. package/dist/ui/dialog.d.ts +17 -0
  329. package/dist/ui/dialog.js +91 -0
  330. package/dist/ui/dialog.js.map +1 -0
  331. package/dist/ui/dropdown-menu.d.ts +15 -0
  332. package/dist/ui/dropdown-menu.js +105 -0
  333. package/dist/ui/dropdown-menu.js.map +1 -0
  334. package/dist/ui/input.d.ts +3 -0
  335. package/dist/ui/input.js +17 -0
  336. package/dist/ui/input.js.map +1 -0
  337. package/dist/ui/label.d.ts +3 -0
  338. package/dist/ui/label.js +15 -0
  339. package/dist/ui/label.js.map +1 -0
  340. package/dist/ui/progress.d.ts +7 -0
  341. package/dist/ui/progress.js +31 -0
  342. package/dist/ui/progress.js.map +1 -0
  343. package/dist/ui/select.d.ts +15 -0
  344. package/dist/ui/select.js +98 -0
  345. package/dist/ui/select.js.map +1 -0
  346. package/dist/ui/skeleton.d.ts +2 -0
  347. package/dist/ui/skeleton.js +14 -0
  348. package/dist/ui/skeleton.js.map +1 -0
  349. package/dist/ui/slider.d.ts +3 -0
  350. package/dist/ui/slider.js +35 -0
  351. package/dist/ui/slider.js.map +1 -0
  352. package/dist/ui/switch.d.ts +5 -0
  353. package/dist/ui/switch.js +20 -0
  354. package/dist/ui/switch.js.map +1 -0
  355. package/dist/ui/tabs.d.ts +10 -0
  356. package/dist/ui/tabs.js +47 -0
  357. package/dist/ui/tabs.js.map +1 -0
  358. package/dist/ui/textarea.d.ts +3 -0
  359. package/dist/ui/textarea.js +15 -0
  360. package/dist/ui/textarea.js.map +1 -0
  361. package/dist/ui/toggle-group.d.ts +5 -0
  362. package/dist/ui/toggle-group.js +23 -0
  363. package/dist/ui/toggle-group.js.map +1 -0
  364. package/dist/urls/index.d.ts +100 -0
  365. package/dist/urls.js +118 -0
  366. package/dist/urls.js.map +1 -0
  367. package/package.json +113 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-gallery.js","names":[],"sources":["../../src/components/media-gallery.tsx"],"sourcesContent":["import { Dialog as DialogPrimitive } from \"@base-ui/react/dialog\";\nimport {\n AlertCircleIcon,\n ArrowLeft01Icon,\n ArrowRight01Icon,\n Cancel01Icon,\n CarouselHorizontalIcon,\n Download01Icon,\n GridViewIcon,\n MusicNote01Icon,\n PlayIcon,\n SquareLock02Icon,\n} from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { cn } from \"cn\";\nimport { useCallback, useMemo, useState, type ReactNode } from \"react\";\nimport type { ContentKitUiAppearance } from \"../appearance.js\";\nimport { formatDuration, galleryItems, stageAspect, type GalleryItem, type GalleryLockedItem, type GalleryMediaItem } from \"../client/gallery.js\";\nimport { useCarousel, useGalleryView, useHlsPlayer, useRefreshBeforeExpiry, type GalleryViewOptions, type HlsPlayerOptions } from \"../react/gallery.js\";\nimport { useInlinePreview } from \"../react/inline-preview.js\";\nimport { useMessages } from \"../i18n/context.js\";\nimport { publicRenditions, type PublicPreset } from \"../client/public.js\";\nimport { ContentKitUiRoot, useScopeProps } from \"../scope.js\";\nimport { RenditionImg } from \"./rendition-img.js\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport type { FileInfo, ReadResult, RefBody } from \"../client/generated/wire.js\";\nimport { useOptionalContentKitClient } from \"../react/context.js\";\nimport { useMediaRead } from \"../react/read.js\";\nimport { previewStartAt, SpriteFrame, VideoPlayer } from \"./video-player.js\";\nimport { Button } from \"#ckui/ui/button\";\nimport { ToggleGroup, ToggleGroupItem } from \"#ckui/ui/toggle-group\";\n\nexport interface MediaGalleryProps extends GalleryViewOptions, Pick<HlsPlayerOptions, \"xhrSetup\" | \"refresh\" | \"abr\"> {\n /**\n * The item to show, read through the client: its read (refreshed before\n * the URLs expire, after commits), HLS bases, playlist auth and grant\n * refresh. Or pass `read` (and hlsBase, xhrSetup, refresh) yourself.\n */\n item?: RefBody;\n /** With item: only files under this path prefix. */\n prefix?: string;\n /** With item: each audio file's download name signed into its URL. */\n download?: boolean;\n /**\n * The read API result: files in manifest order with this viewer's access\n * (scope it with a prefix). A download read adds each audio file's download.\n * With `refresh`, the gallery reads again shortly before `read.expires`.\n */\n read?: ReadResult | null;\n /** A ladder's HLS folder from the read's `hls` dir: client.media.hlsBase(ref, dir). */\n hlsBase?: (dir: string) => string;\n /** The item's poster (its public preset, or a URL), drawn on the first video. */\n poster?: PublicPreset | string | null;\n /** Where the first video's preview starts, seconds (e.g. the poster's frame); default 10% in. */\n previewStart?: number;\n /** Playable videos preview muted inline (hover, or in view on touch); default the provider's. */\n inlinePreview?: boolean;\n /** The host's unlock call to action, drawn over the locked item. */\n renderLocked?: (locked: { count: number; videos: number }) => ReactNode;\n /** Below the carousel, for its current item (e.g. downloads). */\n renderDetails?: (item: GalleryItem) => ReactNode;\n /** `sizes` for carousel images. Default \"(min-width: 768px) 720px, 100vw\". */\n sizes?: string;\n /** Tallest the carousel gets; taller media letterboxes. Default \"80svh\": every slide at its native aspect, full width, never taller than the screen; \"none\" lifts it. */\n maxHeight?: string;\n label?: string;\n className?: string;\n appearance?: ContentKitUiAppearance;\n /** Overrides the provider's client (item). */\n client?: ContentKitClient;\n}\n\ninterface Ctx extends MediaGalleryProps {\n items: GalleryItem[];\n}\n\n// The item's poster and preview start belong to its first video.\nfunction videoArt(ctx: Ctx, item: GalleryMediaItem): { poster?: PublicPreset | string; start: number } {\n const first = ctx.items.find((i): i is GalleryMediaItem => i.kind === \"video\") === item;\n return { poster: first ? (ctx.poster ?? undefined) : undefined, start: previewStartAt(first ? ctx.previewStart : undefined, item.file.dur) };\n}\n\nconst baseOf = (ctx: Ctx, item: GalleryMediaItem) => (item.dir && ctx.hlsBase ? ctx.hlsBase(item.dir) : null);\n\n/**\n * A post's images and videos as a swipeable carousel or a tile grid that opens\n * a lightbox, with a view toggle. One item renders alone.\n */\nexport function MediaGallery(given: MediaGalleryProps) {\n const props = useItemRead(given);\n const { read, label, className, appearance, view: chosen, defaultView, onViewChange, storageKey } = props;\n const { t } = useMessages();\n const items = useMemo(() => galleryItems(read), [read]);\n useRefreshBeforeExpiry(read?.expires, props.refresh);\n const [view, setView] = useGalleryView({ view: chosen, defaultView, onViewChange, storageKey });\n const [index, setIndex] = useState(0);\n const [lightbox, setLightbox] = useState<number | null>(null);\n if (items.length === 0) return null;\n const ctx: Ctx = { ...props, items };\n const multi = items.length > 1;\n const current = Math.min(index, items.length - 1);\n const shown = multi ? view : \"carousel\";\n return (\n <ContentKitUiRoot appearance={appearance} className={cn(\"@container grid gap-2\", className)} data-ckui=\"media-gallery\" data-view={shown} role=\"region\" aria-label={label ?? t(\"gallery.label\")}>\n {multi && (\n <div className=\"flex items-center justify-between gap-2\" data-ckui=\"gallery-header\">\n <span className=\"text-sm text-muted-foreground tabular-nums\" data-ckui=\"gallery-count\">\n {shown === \"carousel\" ? t(\"gallery.counter\", { current: current + 1, total: items.length }) : null}\n </span>\n <ToggleGroup aria-label={t(\"gallery.view\")} value={[shown]} onValueChange={(v) => v[0] && setView(v[0] as typeof view)}>\n <ToggleGroupItem value=\"carousel\" aria-label={t(\"gallery.carousel\")} title={t(\"gallery.carousel\")}>\n <HugeiconsIcon icon={CarouselHorizontalIcon} strokeWidth={2} />\n </ToggleGroupItem>\n <ToggleGroupItem value=\"grid\" aria-label={t(\"gallery.grid\")} title={t(\"gallery.grid\")}>\n <HugeiconsIcon icon={GridViewIcon} strokeWidth={2} />\n </ToggleGroupItem>\n </ToggleGroup>\n </div>\n )}\n {shown === \"carousel\" ? (\n <>\n <Carousel ctx={ctx} index={current} onIndex={setIndex} />\n {props.renderDetails?.(items[current]!)}\n </>\n ) : (\n <Grid ctx={ctx} onOpen={setLightbox} />\n )}\n <Lightbox ctx={ctx} index={lightbox} onIndex={setLightbox} />\n </ContentKitUiRoot>\n );\n}\n\nconst NO_ITEM: RefBody = { kind: \"\", id: \"\" };\n\n// With item, the read, HLS bases, playlist auth and refresh come from the client.\nfunction useItemRead(p: MediaGalleryProps): MediaGalleryProps {\n const client = useOptionalContentKitClient(p.client);\n if (p.item && !client) throw new Error(\"contentkit-ui: MediaGallery item needs `client` or a <ContentKitProvider>\");\n // One refresh timer for the gallery and its players, keyed by r.refresh.\n const r = useMediaRead(p.item ?? NO_ITEM, { prefix: p.prefix, download: p.download, read: p.item ? p.read : null, refresh: false, client });\n const item = p.item;\n const hlsBase = useCallback((dir: string) => client!.media.hlsBase(item!, dir), [client, item]);\n if (!item || !client) return p;\n return { ...p, read: r.read, hlsBase: p.hlsBase ?? hlsBase, xhrSetup: p.xhrSetup ?? client.media.xhrSetup, refresh: p.refresh ?? r.refresh };\n}\n\nfunction Carousel({ ctx, index: given, onIndex, lightbox }: { ctx: Ctx; index: number; onIndex: (i: number) => void; lightbox?: boolean }) {\n const { t } = useMessages();\n const { items } = ctx;\n const c = useCarousel({ count: items.length, index: given, onIndexChange: onIndex });\n const { index } = c;\n const multi = items.length > 1;\n const stage = lightbox ? {} : { aspectRatio: String(stageAspect(items, index)), maxHeight: ctx.maxHeight ?? \"80svh\" };\n return (\n <div\n className={cn(\"group/carousel relative outline-none\", lightbox ? \"size-full\" : \"grid gap-2\")}\n role={multi ? \"group\" : undefined}\n aria-roledescription={multi ? \"carousel\" : undefined}\n aria-label={multi ? (ctx.label ?? t(\"gallery.label\")) : undefined}\n tabIndex={multi && !lightbox ? 0 : undefined}\n onKeyDown={multi && !lightbox ? c.onKeyDown : undefined}\n data-ckui=\"carousel\"\n >\n <div\n className={cn(\n \"relative w-full touch-pan-y overflow-hidden select-none\",\n lightbox ? \"h-full\" : \"rounded-lg bg-muted transition-[aspect-ratio] duration-300 ease-out motion-reduce:transition-none\",\n )}\n style={stage}\n data-ckui=\"stage\"\n {...(multi ? c.swipe : {})}\n >\n <div\n className={cn(\"flex h-full\", c.dragging ? \"transition-none\" : \"transition-transform duration-300 ease-out motion-reduce:transition-none\")}\n style={{ transform: `translateX(calc(${-index * 100}% + ${c.offset}px))` }}\n >\n {items.map((item, i) => {\n const near = Math.abs(i - index) <= 1;\n return (\n <div\n key={item.key}\n className=\"relative h-full w-full shrink-0 overflow-hidden\"\n role={multi ? \"group\" : undefined}\n aria-roledescription={multi ? \"slide\" : undefined}\n aria-label={multi ? t(\"gallery.slide\", { current: i + 1, total: items.length }) : undefined}\n aria-hidden={i !== index || undefined}\n inert={i !== index}\n data-ckui=\"slide\"\n data-current={i === index ? \"\" : undefined}\n >\n {near && <Slide ctx={ctx} item={item} position={i} active={i === index} lightbox={lightbox} />}\n </div>\n );\n })}\n </div>\n {multi && (\n <>\n <NavButton side=\"prev\" hidden={index === 0} last={index === 1} onClick={c.prev} label={t(\"gallery.previous\")} lightbox={lightbox} />\n <NavButton side=\"next\" hidden={index === items.length - 1} last={index === items.length - 2} onClick={c.next} label={t(\"gallery.next\")} lightbox={lightbox} />\n </>\n )}\n </div>\n {multi && !lightbox && items.length <= 12 && (\n <div className=\"flex justify-center gap-0.5\" data-ckui=\"dots\">\n {items.map((item, i) => (\n <button\n key={item.key}\n type=\"button\"\n className=\"group/dot flex size-4 items-center justify-center rounded-full outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n aria-label={t(\"gallery.goTo\", { index: i + 1 })}\n aria-current={i === index || undefined}\n onClick={() => c.go(i)}\n >\n <span className={cn(\"size-1.5 rounded-full transition-colors\", i === index ? \"bg-foreground\" : \"bg-foreground/25 group-hover/dot:bg-foreground/50\")} />\n </button>\n ))}\n </div>\n )}\n </div>\n );\n}\n\n// A strip down the stage's side, clear of a video's control bar: the stage's\n// height follows each slide's aspect, so a centred-only target would move\n// between quick clicks. A swipe may start on it. The click that reaches an end\n// removes the button, so focus moves to the carousel and the arrow keys keep working.\nfunction NavButton({ side, hidden, last, onClick, label, lightbox }: { side: \"prev\" | \"next\"; hidden: boolean; last: boolean; onClick: () => void; label: string; lightbox?: boolean }) {\n if (hidden) return null;\n return (\n <button\n type=\"button\"\n aria-label={label}\n data-ckui=\"gallery-nav\"\n data-side={side}\n onClick={(e) => {\n const root = e.currentTarget.closest<HTMLElement>(\"[data-ckui=lightbox], [data-ckui=carousel][tabindex]\");\n onClick();\n if (last && document.activeElement === e.currentTarget) root?.focus({ preventScroll: true });\n }}\n className={cn(\n \"group/nav absolute top-0 bottom-14 z-10 flex items-center outline-none\",\n lightbox ? \"w-16 sm:w-20\" : \"w-12\",\n side === \"prev\" ? (lightbox ? \"left-0 justify-start pl-3 sm:pl-5\" : \"left-0 justify-start pl-2\") : lightbox ? \"right-0 justify-end pr-3 sm:pr-5\" : \"right-0 justify-end pr-2\",\n )}\n >\n <span\n className={cn(\n \"flex items-center justify-center rounded-full backdrop-blur-sm transition-colors group-focus-visible/nav:ring-3 group-focus-visible/nav:ring-ring/60\",\n lightbox ? \"size-10 bg-white/10 text-white group-hover/nav:bg-white/20\" : \"size-8 bg-white/85 text-zinc-900 shadow-md group-hover/nav:bg-white\",\n )}\n >\n <HugeiconsIcon icon={side === \"prev\" ? ArrowLeft01Icon : ArrowRight01Icon} strokeWidth={2} className=\"size-4\" />\n </span>\n </button>\n );\n}\n\nfunction Slide({ ctx, item, position, active, lightbox }: { ctx: Ctx; item: GalleryItem; position: number; active: boolean; lightbox?: boolean }) {\n const { t } = useMessages();\n if (item.kind === \"locked\") return <Locked ctx={ctx} item={item} />;\n const f = item.file;\n if (item.kind === \"audio\") return <AudioSlide item={item} position={position} />;\n if (item.kind === \"image\") {\n if (!f.url) return f.failed ? <ImageFailed file={f} /> : <Processing>{t(\"gallery.processingImage\")}</Processing>;\n // A public teaser of a locked item carries the unlock, so no one swipes past it to find it.\n const locked = item.key.startsWith(\"preview/\") && !lightbox ? ctx.items.find((i): i is GalleryLockedItem => i.kind === \"locked\") : undefined;\n return (\n <>\n <img\n src={f.url}\n alt={t(\"gallery.image\", { index: position + 1 })}\n width={f.w}\n height={f.h}\n sizes={lightbox ? \"100vw\" : (ctx.sizes ?? \"(min-width: 768px) 720px, 100vw\")}\n loading={active ? \"eager\" : \"lazy\"}\n decoding=\"async\"\n draggable={false}\n className=\"absolute inset-0 size-full object-contain\"\n />\n {locked && <LockedBar ctx={ctx} item={locked} />}\n </>\n );\n }\n const { poster, start } = videoArt(ctx, item);\n return (\n <VideoPlayer\n inlinePreview={lightbox ? false : ctx.inlinePreview}\n previewStart={start}\n layout=\"fill\"\n base={baseOf(ctx, item)}\n poster={poster}\n width={f.w}\n height={f.h}\n duration={f.dur}\n active={active}\n xhrSetup={ctx.xhrSetup}\n refresh={ctx.refresh}\n expires={ctx.read?.expires}\n abr={ctx.abr}\n label={t(\"gallery.video\", { index: position + 1 })}\n className={lightbox ? \"bg-transparent\" : undefined}\n />\n );\n}\n\n// An audio file (a ladder's M4A): a native player, its duration and, in a\n// download read, its download.\nfunction AudioSlide({ item, position }: { item: GalleryMediaItem; position: number }) {\n const { t } = useMessages();\n const f = item.file;\n const name = (item.dir ?? f.path).replace(/\\/$/, \"\").split(\"/\").pop();\n const label = t(\"gallery.audio\", { index: position + 1 });\n return (\n <div className=\"absolute inset-0 flex flex-col items-center justify-center gap-3 bg-muted p-4\" data-ckui=\"audio\">\n <div className=\"flex min-w-0 items-center gap-2 text-sm text-muted-foreground\">\n <HugeiconsIcon icon={MusicNote01Icon} className=\"size-5 shrink-0\" strokeWidth={1.75} />\n {name && <span className=\"truncate\">{name}</span>}\n {f.dur ? <span className=\"tabular-nums\">{formatDuration(f.dur)}</span> : null}\n </div>\n {f.failed ? (\n <p className=\"text-sm text-destructive\" role=\"alert\">\n {t(\"gallery.failedAudio\")}\n </p>\n ) : f.url ? (\n <audio src={f.url} controls preload=\"metadata\" aria-label={label} className=\"w-full max-w-md\" data-ckui-noswipe=\"\" />\n ) : (\n <p className=\"text-sm text-muted-foreground\">{t(\"gallery.processingAudio\")}</p>\n )}\n {f.download && f.url && (\n <a href={f.url} download={f.download} className=\"inline-flex items-center gap-1.5 text-sm underline-offset-4 hover:underline\" data-ckui-noswipe=\"\">\n <HugeiconsIcon icon={Download01Icon} className=\"size-4\" strokeWidth={2} />\n {t(\"gallery.download\")}\n </a>\n )}\n </div>\n );\n}\n\n// Why an image cannot be shown (editors only: the read API's failed fields).\nfunction ImageFailed({ file }: { file: FileInfo }) {\n const { t, error } = useMessages();\n const f = file.failed;\n const text = f?.code ? error({ code: f.code, message: f.message, details: f.details, refusal: true }) : t(\"gallery.failedImage\");\n return (\n <div className=\"absolute inset-0 flex flex-col items-center justify-center gap-2 bg-muted p-4 text-center text-sm text-destructive\" role=\"alert\" data-ckui=\"image-failed\">\n <HugeiconsIcon icon={AlertCircleIcon} className=\"size-6\" />\n <p className=\"max-w-sm text-balance\">{text}</p>\n </div>\n );\n}\n\nfunction Processing({ children }: { children: string }) {\n return (\n <div className=\"absolute inset-0 flex items-center justify-center gap-2 bg-muted text-sm text-muted-foreground\">\n <span aria-hidden className=\"size-4 rounded-full border-2 border-current/30 border-t-current motion-safe:animate-spin\" />\n {children}\n </div>\n );\n}\n\nfunction lockedText(t: ReturnType<typeof useMessages>[\"t\"], count: number) {\n return count === 1 ? t(\"gallery.lockedOne\") : t(\"gallery.lockedMany\", { count });\n}\n\nfunction Locked({ ctx, item, tile }: { ctx: Ctx; item: GalleryLockedItem; tile?: boolean }) {\n const { t } = useMessages();\n return (\n <div className=\"absolute inset-0 overflow-hidden bg-muted\" data-ckui=\"locked\">\n {item.backdrop && <img src={item.backdrop} alt=\"\" draggable={false} className=\"absolute inset-0 size-full scale-110 object-cover blur-xl\" />}\n <div className={cn(\"absolute inset-0 flex flex-col items-center justify-center gap-3 p-4 text-center\", item.backdrop ? \"bg-black/45 text-white\" : \"text-foreground\")}>\n <HugeiconsIcon icon={SquareLock02Icon} className={tile ? \"size-6\" : \"size-8\"} strokeWidth={1.75} />\n {tile ? (\n <span className=\"text-lg font-semibold tabular-nums\">+{item.count}</span>\n ) : (\n <>\n <p className=\"text-sm font-medium text-balance\">{lockedText(t, item.count)}</p>\n {ctx.renderLocked && <div data-ckui-noswipe=\"\">{ctx.renderLocked({ count: item.count, videos: item.videos })}</div>}\n </>\n )}\n </div>\n </div>\n );\n}\n\nfunction LockedBar({ ctx, item }: { ctx: Ctx; item: GalleryLockedItem }) {\n const { t } = useMessages();\n return (\n <div\n className=\"absolute inset-x-0 bottom-0 flex flex-wrap items-center justify-between gap-x-3 gap-y-2 bg-linear-to-t from-black/75 via-black/45 to-transparent px-4 pt-10 pb-4 text-white\"\n data-ckui=\"locked-bar\"\n >\n <span className=\"flex items-center gap-2 text-sm font-medium\">\n <HugeiconsIcon icon={SquareLock02Icon} className=\"size-5 shrink-0\" strokeWidth={1.75} />\n {lockedText(t, item.count)}\n </span>\n {ctx.renderLocked && <div data-ckui-noswipe=\"\">{ctx.renderLocked({ count: item.count, videos: item.videos })}</div>}\n </div>\n );\n}\n\nfunction Grid({ ctx, onOpen }: { ctx: Ctx; onOpen: (i: number) => void }) {\n const { t } = useMessages();\n const n = ctx.items.length;\n return (\n <ul className={cn(\"grid gap-1\", n === 2 || n === 4 ? \"grid-cols-2\" : \"grid-cols-2 @md:grid-cols-3\")} data-ckui=\"grid\">\n {ctx.items.map((item, i) => (\n <li key={item.key}>\n <Tile ctx={ctx} item={item} label={t(\"gallery.open\", { index: i + 1, total: n })} onOpen={() => onOpen(i)} />\n </li>\n ))}\n </ul>\n );\n}\n\nfunction Tile({ ctx, item, label, onOpen }: { ctx: Ctx; item: GalleryItem; label: string; onOpen: () => void }) {\n const [el, setEl] = useState<HTMLButtonElement | null>(null);\n let body: ReactNode;\n if (item.kind === \"locked\") body = <Locked ctx={ctx} item={item} tile />;\n else if (item.kind === \"audio\")\n body = (\n <span className=\"absolute inset-0 flex flex-col items-center justify-center gap-1 bg-muted text-muted-foreground\">\n <HugeiconsIcon icon={item.file.failed ? AlertCircleIcon : MusicNote01Icon} className={cn(\"size-7\", item.file.failed && \"text-destructive\")} strokeWidth={1.75} />\n {item.file.dur ? <span className=\"text-[11px] font-medium tabular-nums\">{formatDuration(item.file.dur)}</span> : null}\n </span>\n );\n else if (item.kind === \"image\")\n body = item.file.url ? (\n <img src={item.file.url} alt=\"\" loading=\"lazy\" decoding=\"async\" draggable={false} className=\"absolute inset-0 size-full object-cover transition-transform duration-300 motion-safe:group-hover:scale-[1.03]\" />\n ) : item.file.failed ? (\n <span className=\"absolute inset-0 flex items-center justify-center bg-muted text-destructive\">\n <HugeiconsIcon icon={AlertCircleIcon} className=\"size-6\" />\n </span>\n ) : (\n <Processing>{\"\"}</Processing>\n );\n else {\n const f = item.file;\n const { poster, start } = videoArt(ctx, item);\n const covers = typeof poster === \"string\" ? [] : publicRenditions(poster);\n const base = baseOf(ctx, item);\n body = (\n <>\n {typeof poster === \"string\" ? (\n <img src={poster} alt=\"\" loading=\"lazy\" decoding=\"async\" className=\"absolute inset-0 size-full object-cover\" />\n ) : covers.length ? (\n <RenditionImg outputs={covers} loading=\"lazy\" className=\"absolute inset-0 size-full object-cover\" />\n ) : base ? (\n <SpriteFrame vtt={`${base}sprite.vtt`} xhrSetup={ctx.xhrSetup} fit=\"cover\" />\n ) : null}\n {base && <TilePreview ctx={ctx} base={base} start={start} target={el} />}\n {f.failed ? (\n <span className=\"absolute inset-0 flex items-center justify-center bg-muted text-destructive\">\n <HugeiconsIcon icon={AlertCircleIcon} className=\"size-6\" />\n </span>\n ) : !base ? (\n <Processing>{\"\"}</Processing>\n ) : (\n <span className=\"pointer-events-none absolute top-1/2 left-1/2 flex size-10 -translate-1/2 items-center justify-center rounded-full bg-black/55 text-white backdrop-blur-sm transition-opacity group-hover:opacity-0\">\n <HugeiconsIcon icon={PlayIcon} className=\"ml-0.5 size-5 fill-current\" strokeWidth={1.5} />\n </span>\n )}\n {f.dur ? (\n <span className=\"pointer-events-none absolute right-1.5 bottom-1.5 rounded bg-black/65 px-1.5 py-0.5 text-[11px] font-medium text-white tabular-nums\">\n {formatDuration(f.dur)}\n </span>\n ) : null}\n </>\n );\n }\n return (\n <button\n type=\"button\"\n aria-label={label}\n onClick={onOpen}\n ref={setEl}\n className=\"group relative block aspect-square w-full overflow-hidden rounded-md bg-muted outline-none focus-visible:ring-3 focus-visible:ring-ring/60\"\n data-ckui=\"tile\"\n data-kind={item.kind}\n >\n {body}\n </button>\n );\n}\n\n// A grid tile's inline preview; the tile opens the lightbox for real playback.\nfunction TilePreview({ ctx, base, start, target }: { ctx: Ctx; base: string; start: number; target: HTMLElement | null }) {\n const player = useHlsPlayer({ src: `${base}master.m3u8`, xhrSetup: ctx.xhrSetup, refresh: ctx.refresh, expires: ctx.read?.expires, abr: ctx.abr, qualityKey: null });\n useInlinePreview({ setting: ctx.inlinePreview, available: true, target, start: () => player.preview(start), stop: player.unload });\n return (\n <video\n ref={player.ref}\n muted\n playsInline\n preload=\"none\"\n aria-hidden\n tabIndex={-1}\n className={cn(\n \"pointer-events-none absolute inset-0 size-full object-cover opacity-0 transition-opacity duration-300 motion-reduce:transition-none\",\n player.previewing && player.status === \"playing\" && \"opacity-100\",\n )}\n data-ckui=\"tile-preview\"\n />\n );\n}\n\nfunction Lightbox({ ctx, index, onIndex }: { ctx: Ctx; index: number | null; onIndex: (i: number | null) => void }) {\n const { t } = useMessages();\n const scope = useScopeProps(ctx.appearance);\n const [shown, setShown] = useState(index ?? 0);\n const [prev, setPrev] = useState(index);\n if (index !== prev) {\n setPrev(index);\n if (index !== null) setShown(index);\n }\n const open = index !== null;\n const c = useCarousel({ count: ctx.items.length, index: shown, onIndexChange: setShown });\n return (\n <DialogPrimitive.Root open={open} onOpenChange={(o) => !o && onIndex(null)}>\n <DialogPrimitive.Portal {...scope} data-ckui-theme=\"dark\">\n <DialogPrimitive.Backdrop className=\"fixed inset-0 z-50 bg-black duration-150 data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0 motion-reduce:animate-none\" />\n <DialogPrimitive.Popup\n className=\"fixed inset-0 z-50 flex flex-col bg-black text-white outline-none duration-150 data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0 motion-reduce:animate-none\"\n data-ckui=\"lightbox\"\n onKeyDown={c.onKeyDown}\n >\n <DialogPrimitive.Title className=\"sr-only\">{ctx.label ?? t(\"gallery.lightbox\")}</DialogPrimitive.Title>\n <div className=\"flex h-14 shrink-0 items-center justify-between px-4\">\n <span className=\"text-sm text-white/80 tabular-nums\">{ctx.items.length > 1 ? t(\"gallery.counter\", { current: shown + 1, total: ctx.items.length }) : null}</span>\n <DialogPrimitive.Close render={<Button variant=\"ghost\" size=\"icon\" className=\"rounded-full text-white hover:bg-white/10 hover:text-white\" />}>\n <HugeiconsIcon icon={Cancel01Icon} strokeWidth={2} />\n <span className=\"sr-only\">{t(\"common.close\")}</span>\n </DialogPrimitive.Close>\n </div>\n <div className=\"min-h-0 flex-1 pb-4 sm:px-4 sm:pb-6\">\n {open && <Carousel ctx={ctx} index={shown} onIndex={setShown} lightbox />}\n </div>\n </DialogPrimitive.Popup>\n </DialogPrimitive.Portal>\n </DialogPrimitive.Root>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { ReactNode } from 'react';
2
+ import { ContentKitUiAppearance } from '../appearance.js';
3
+ import { ContentKitClient } from '../client/client.js';
4
+ import { ReadResult, RefBody } from '../client/generated/wire.js';
5
+ export interface MediaReadinessNoticeProps {
6
+ /** The item; its editor read is polled while it processes. */
7
+ item: RefBody;
8
+ /** An editor read the host already has; otherwise fetched. */
9
+ read?: ReadResult | null;
10
+ /** Only uploads under this path prefix. */
11
+ prefix?: string;
12
+ /** Replaces the processing state's second line (e.g. who can see it meanwhile). */
13
+ description?: ReactNode;
14
+ className?: string;
15
+ appearance?: ContentKitUiAppearance;
16
+ client?: ContentKitClient;
17
+ }
18
+ /**
19
+ * An item's processing state for its editors: nothing once every upload is
20
+ * processed; while some process, a notice with the first video's encode
21
+ * progress; when uploads failed, which ones (they hold the item back until
22
+ * removed).
23
+ */
24
+ export declare function MediaReadinessNotice({ item, read: given, prefix, description, className, appearance, client }: MediaReadinessNoticeProps): import('react').JSX.Element | null;
@@ -0,0 +1,61 @@
1
+ import { useMessages as e } from "../i18n/context.js";
2
+ import { ContentKitUiRoot as t } from "../scope.js";
3
+ import { EncodeProgress as n } from "./encode-progress.js";
4
+ import { isProcessing as r, processing as i } from "../client/media/windows.js";
5
+ import { useMediaRead as a } from "../react/read.js";
6
+ import { Alert as o, AlertDescription as s, AlertTitle as c } from "../ui/alert.js";
7
+ import { isVideoType as l } from "../client/gallery.js";
8
+ import { jsx as u, jsxs as d } from "react/jsx-runtime";
9
+ import { cn as f } from "cn";
10
+ import { Alert02Icon as p, Loading03Icon as m } from "@hugeicons/core-free-icons";
11
+ import { HugeiconsIcon as h } from "@hugeicons/react";
12
+ //#region src/components/media-readiness-notice.tsx
13
+ function g({ item: g, read: _, prefix: v, description: y, className: b, appearance: x, client: S }) {
14
+ let { t: C } = e(), w = a(g, {
15
+ editor: !0,
16
+ prefix: v,
17
+ read: _,
18
+ client: S
19
+ }), T = (w.read?.files ?? []).filter((e) => e.upload && !e.unattached), E = T.filter((e) => e.failed), D = i(w.read);
20
+ if (!w.read || !E.length && !D) return null;
21
+ let O = E.map((e) => e.path.split("/").pop()), k = T.find((e) => l(e.type) && r(e) && e.progress)?.progress;
22
+ return /* @__PURE__ */ u(t, {
23
+ appearance: x,
24
+ className: f("w-full", b),
25
+ "data-ckui": "readiness",
26
+ "data-state": E.length ? "failed" : "processing",
27
+ children: E.length ? /* @__PURE__ */ d(o, {
28
+ variant: "destructive",
29
+ role: "alert",
30
+ children: [
31
+ /* @__PURE__ */ u(h, {
32
+ icon: p,
33
+ strokeWidth: 2
34
+ }),
35
+ /* @__PURE__ */ u(c, { children: O.length === 1 ? C("readiness.failedOne", { name: O[0] }) : C("readiness.failedMany", {
36
+ count: O.length,
37
+ names: O.join(", ")
38
+ }) }),
39
+ /* @__PURE__ */ u(s, { children: C("readiness.failedHint") })
40
+ ]
41
+ }) : /* @__PURE__ */ d(o, {
42
+ role: "status",
43
+ children: [
44
+ /* @__PURE__ */ u(h, {
45
+ icon: m,
46
+ strokeWidth: 2,
47
+ className: "motion-safe:animate-spin"
48
+ }),
49
+ /* @__PURE__ */ u(c, { children: C("readiness.processing") }),
50
+ /* @__PURE__ */ d(s, { children: [y ?? C("readiness.processingHint"), k && /* @__PURE__ */ u(n, {
51
+ progress: k,
52
+ className: "mt-2"
53
+ })] })
54
+ ]
55
+ })
56
+ });
57
+ }
58
+ //#endregion
59
+ export { g as MediaReadinessNotice };
60
+
61
+ //# sourceMappingURL=media-readiness-notice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-readiness-notice.js","names":[],"sources":["../../src/components/media-readiness-notice.tsx"],"sourcesContent":["import { Alert02Icon, Loading03Icon } from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { cn } from \"cn\";\nimport type { ReactNode } from \"react\";\nimport type { ContentKitUiAppearance } from \"../appearance.js\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport type { ReadResult, RefBody } from \"../client/generated/wire.js\";\nimport { isVideoType } from \"../client/gallery.js\";\nimport { isProcessing, processing } from \"../client/media/windows.js\";\nimport { useMessages } from \"../i18n/context.js\";\nimport { useMediaRead } from \"../react/read.js\";\nimport { ContentKitUiRoot } from \"../scope.js\";\nimport { Alert, AlertDescription, AlertTitle } from \"#ckui/ui/alert\";\nimport { EncodeProgress } from \"./encode-progress.js\";\n\nexport interface MediaReadinessNoticeProps {\n /** The item; its editor read is polled while it processes. */\n item: RefBody;\n /** An editor read the host already has; otherwise fetched. */\n read?: ReadResult | null;\n /** Only uploads under this path prefix. */\n prefix?: string;\n /** Replaces the processing state's second line (e.g. who can see it meanwhile). */\n description?: ReactNode;\n className?: string;\n appearance?: ContentKitUiAppearance;\n client?: ContentKitClient;\n}\n\n/**\n * An item's processing state for its editors: nothing once every upload is\n * processed; while some process, a notice with the first video's encode\n * progress; when uploads failed, which ones (they hold the item back until\n * removed).\n */\nexport function MediaReadinessNotice({ item, read: given, prefix, description, className, appearance, client }: MediaReadinessNoticeProps) {\n const { t } = useMessages();\n const r = useMediaRead(item, { editor: true, prefix, read: given, client });\n const uploads = (r.read?.files ?? []).filter((f) => f.upload && !f.unattached);\n const failed = uploads.filter((f) => f.failed);\n const busy = processing(r.read);\n if (!r.read || (!failed.length && !busy)) return null;\n const names = failed.map((f) => f.path.split(\"/\").pop()!);\n const progress = uploads.find((f) => isVideoType(f.type) && isProcessing(f) && f.progress)?.progress;\n return (\n <ContentKitUiRoot appearance={appearance} className={cn(\"w-full\", className)} data-ckui=\"readiness\" data-state={failed.length ? \"failed\" : \"processing\"}>\n {failed.length ? (\n <Alert variant=\"destructive\" role=\"alert\">\n <HugeiconsIcon icon={Alert02Icon} strokeWidth={2} />\n <AlertTitle>{names.length === 1 ? t(\"readiness.failedOne\", { name: names[0]! }) : t(\"readiness.failedMany\", { count: names.length, names: names.join(\", \") })}</AlertTitle>\n <AlertDescription>{t(\"readiness.failedHint\")}</AlertDescription>\n </Alert>\n ) : (\n <Alert role=\"status\">\n <HugeiconsIcon icon={Loading03Icon} strokeWidth={2} className=\"motion-safe:animate-spin\" />\n <AlertTitle>{t(\"readiness.processing\")}</AlertTitle>\n <AlertDescription>\n {description ?? t(\"readiness.processingHint\")}\n {progress && <EncodeProgress progress={progress} className=\"mt-2\" />}\n </AlertDescription>\n </Alert>\n )}\n </ContentKitUiRoot>\n );\n}\n"],"mappings":";;;;;;;;;;;;AAmCA,SAAgB,EAAqB,EAAE,SAAM,MAAM,GAAO,WAAQ,gBAAa,cAAW,eAAY,aAAqC;CACzI,IAAM,EAAE,SAAM,EAAY,GACpB,IAAI,EAAa,GAAM;EAAE,QAAQ;EAAM;EAAQ,MAAM;EAAO;CAAO,CAAC,GACpE,KAAW,EAAE,MAAM,SAAS,CAAC,EAAA,CAAG,QAAQ,MAAM,EAAE,UAAU,CAAC,EAAE,UAAU,GACvE,IAAS,EAAQ,QAAQ,MAAM,EAAE,MAAM,GACvC,IAAO,EAAW,EAAE,IAAI;CAC9B,IAAI,CAAC,EAAE,QAAS,CAAC,EAAO,UAAU,CAAC,GAAO,OAAO;CACjD,IAAM,IAAQ,EAAO,KAAK,MAAM,EAAE,KAAK,MAAM,GAAG,CAAC,CAAC,IAAI,CAAE,GAClD,IAAW,EAAQ,MAAM,MAAM,EAAY,EAAE,IAAI,KAAK,EAAa,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE;CAC5F,OACE,kBAAC,GAAD;EAA8B;EAAY,WAAW,EAAG,UAAU,CAAS;EAAG,aAAU;EAAY,cAAY,EAAO,SAAS,WAAW;EACxI,UAAA,EAAO,SACN,kBAAC,GAAD;GAAO,SAAQ;GAAc,MAAK;GAAlC,UAAA;IACE,kBAAC,GAAD;KAAe,MAAM;KAAa,aAAa;IAAI,CAAA;IACnD,kBAAC,GAAD,EAAA,UAAa,EAAM,WAAW,IAAI,EAAE,uBAAuB,EAAE,MAAM,EAAM,GAAI,CAAC,IAAI,EAAE,wBAAwB;KAAE,OAAO,EAAM;KAAQ,OAAO,EAAM,KAAK,IAAI;IAAE,CAAC,EAAc,CAAA;IAC1K,kBAAC,GAAD,EAAA,UAAmB,EAAE,sBAAsB,EAAoB,CAAA;GAC1D;EAEP,CAAA,IAAA,kBAAC,GAAD;GAAO,MAAK;GAAZ,UAAA;IACE,kBAAC,GAAD;KAAe,MAAM;KAAe,aAAa;KAAG,WAAU;IAA4B,CAAA;IAC1F,kBAAC,GAAD,EAAA,UAAa,EAAE,sBAAsB,EAAc,CAAA;IACnD,kBAAC,GAAD,EAAA,UAAA,CACG,KAAe,EAAE,0BAA0B,GAC3C,KAAY,kBAAC,GAAD;KAA0B;KAAU,WAAU;IAAQ,CAAA,CACnD,EAAA,CAAA;GACb;;CAEO,CAAA;AAEtB"}
@@ -0,0 +1,71 @@
1
+ import { IconSvgElement } from '@hugeicons/react';
2
+ import { ComponentProps } from 'react';
3
+ import { Sprite } from '../react/player.js';
4
+ /** The class of every control-bar button; a host's slotted buttons can share it. */
5
+ export declare const playerButtonClass = "inline-flex size-9 shrink-0 cursor-pointer items-center justify-center rounded-full text-white outline-none transition-colors hover:bg-white/15 focus-visible:ring-2 focus-visible:ring-white/80 motion-reduce:transition-none data-popup-open:bg-white/15 [&_svg]:size-5 relative aria-pressed:after:absolute aria-pressed:after:bottom-1 aria-pressed:after:h-0.5 aria-pressed:after:w-4 aria-pressed:after:rounded-full aria-pressed:after:bg-player-accent";
6
+ export declare const clock: (s: number) => string;
7
+ export declare function ControlButton({ label, shortcut, icon, className, ...props }: Omit<ComponentProps<"button">, "children"> & {
8
+ label: string;
9
+ shortcut?: string;
10
+ icon: IconSvgElement;
11
+ }): import('react').JSX.Element;
12
+ export interface SeekBarProps {
13
+ time: number;
14
+ duration: number;
15
+ buffered?: number;
16
+ onSeek: (time: number) => void;
17
+ /** The position being dragged to, or null when the drag ends. */
18
+ onScrub?: (time: number | null) => void;
19
+ sprite?: Sprite | null;
20
+ /** The mini player's hairline along its bottom edge. */
21
+ thin?: boolean;
22
+ className?: string;
23
+ }
24
+ /** The seek slider: buffered range, drag to seek on release, keys in 5 s steps, a sprite and time preview on hover. */
25
+ export declare function SeekBar({ time, duration, buffered, onSeek, onScrub, sprite, thin, className }: SeekBarProps): import('react').JSX.Element;
26
+ export declare function VolumeControl({ volume, muted, onVolume, onMute }: {
27
+ volume: number;
28
+ muted: boolean;
29
+ onVolume: (v: number) => void;
30
+ onMute: () => void;
31
+ }): import('react').JSX.Element;
32
+ export interface MenuOption {
33
+ value: string;
34
+ label: string;
35
+ }
36
+ /** One settings row: its current value, and a submenu choosing it. */
37
+ export interface MenuSection {
38
+ key: string;
39
+ label: string;
40
+ value: string;
41
+ options: readonly MenuOption[];
42
+ onChange: (value: string) => void;
43
+ }
44
+ export declare function SettingsMenu({ icon, label, sections, actions, container, onOpenChange, }: {
45
+ icon: IconSvgElement;
46
+ label: string;
47
+ sections: MenuSection[];
48
+ actions?: {
49
+ label: string;
50
+ onSelect: () => void;
51
+ }[];
52
+ container?: HTMLElement;
53
+ onOpenChange?: (open: boolean) => void;
54
+ }): import('react').JSX.Element;
55
+ /** The showing subtitle cues, drawn above the controls; markup comes from the browser's cue parser. */
56
+ export declare function Captions({ cues, bottom }: {
57
+ cues: readonly VTTCue[];
58
+ bottom: string;
59
+ }): import('react').JSX.Element | null;
60
+ export interface SeekFlashState {
61
+ direction: -1 | 1;
62
+ /** The burst's total, e.g. 30 after three taps. */
63
+ seconds: number;
64
+ }
65
+ /** The "10 seconds" bubble for keyboard and double-tap seeks. */
66
+ export declare function SeekFlash({ flash }: {
67
+ flash: SeekFlashState | null;
68
+ }): import('react').JSX.Element | null;
69
+ export declare function Spinner({ className }: {
70
+ className?: string;
71
+ }): import('react').JSX.Element;
@@ -0,0 +1,264 @@
1
+ import { useMessages as e } from "../i18n/context.js";
2
+ import { AppearanceContext as t } from "../scope.js";
3
+ import { DropdownMenu as n, DropdownMenuContent as r, DropdownMenuItem as i, DropdownMenuRadioGroup as a, DropdownMenuRadioItem as o, DropdownMenuSeparator as s, DropdownMenuSub as c, DropdownMenuSubContent as l, DropdownMenuSubTrigger as u, DropdownMenuTrigger as d } from "../ui/dropdown-menu.js";
4
+ import { formatDuration as f } from "../client/gallery.js";
5
+ import { spriteCueAt as p } from "../client/player.js";
6
+ import { useContext as m, useLayoutEffect as h, useRef as g, useState as _ } from "react";
7
+ import { Fragment as v, jsx as y, jsxs as b } from "react/jsx-runtime";
8
+ import { cn as x } from "cn";
9
+ import { ArrowLeft01Icon as S, ArrowRight01Icon as C, VolumeHighIcon as w, VolumeLowIcon as T, VolumeOffIcon as E } from "@hugeicons/core-free-icons";
10
+ import { HugeiconsIcon as D } from "@hugeicons/react";
11
+ import { Slider as O } from "@base-ui/react/slider";
12
+ //#region src/components/player-controls.tsx
13
+ var k = "inline-flex size-9 shrink-0 cursor-pointer items-center justify-center rounded-full text-white outline-none transition-colors hover:bg-white/15 focus-visible:ring-2 focus-visible:ring-white/80 motion-reduce:transition-none data-popup-open:bg-white/15 [&_svg]:size-5 relative aria-pressed:after:absolute aria-pressed:after:bottom-1 aria-pressed:after:h-0.5 aria-pressed:after:w-4 aria-pressed:after:rounded-full aria-pressed:after:bg-player-accent", A = (e) => f(Math.floor(e));
14
+ function j({ label: e, shortcut: t, icon: n, className: r, ...i }) {
15
+ return /* @__PURE__ */ y("button", {
16
+ type: "button",
17
+ "aria-label": e,
18
+ title: t ? `${e} (${t})` : e,
19
+ className: x(k, r),
20
+ ...i,
21
+ children: /* @__PURE__ */ y(D, {
22
+ icon: n,
23
+ strokeWidth: 1.75,
24
+ "aria-hidden": !0
25
+ })
26
+ });
27
+ }
28
+ var M = {
29
+ ArrowLeft: (e) => e - 5,
30
+ ArrowDown: (e) => e - 5,
31
+ ArrowRight: (e) => e + 5,
32
+ ArrowUp: (e) => e + 5,
33
+ PageDown: (e, t) => e - t / 10,
34
+ PageUp: (e, t) => e + t / 10,
35
+ Home: () => 0,
36
+ End: (e, t) => t
37
+ };
38
+ function N({ time: t, duration: n, buffered: r = 0, onSeek: i, onScrub: a, sprite: o, thin: s, className: c }) {
39
+ let { t: l } = e(), [u, d] = _(null), [f, p] = _(null), m = g(null), h = u ?? Math.min(t, n || t), v = (e) => n > 0 ? `${Math.min(100, e / n * 100)}%` : "0%", S = (e) => {
40
+ let t = m.current?.getBoundingClientRect();
41
+ if (!t || !t.width || !n) return null;
42
+ let r = Math.min(t.width, Math.max(0, e - t.left));
43
+ return {
44
+ time: r / t.width * n,
45
+ x: r,
46
+ width: t.width
47
+ };
48
+ }, C = (e) => {
49
+ d(e), a?.(e);
50
+ }, w = (e) => {
51
+ let r = M[e.key];
52
+ r && n && (e.preventDefault(), e.stopPropagation(), i(Math.min(n, Math.max(0, r(t, n)))));
53
+ }, T = u === null ? f : {
54
+ time: u,
55
+ x: u / (n || 1) * (m.current?.clientWidth ?? 0),
56
+ width: m.current?.clientWidth ?? 0
57
+ };
58
+ return /* @__PURE__ */ b(O.Root, {
59
+ value: h,
60
+ min: 0,
61
+ max: n || 1,
62
+ step: .01,
63
+ disabled: !n,
64
+ thumbAlignment: "center",
65
+ onValueChange: (e) => C(e),
66
+ onValueCommitted: (e) => {
67
+ C(null), i(e);
68
+ },
69
+ onKeyDownCapture: w,
70
+ className: x("relative w-full", c),
71
+ "data-ckui": "seek",
72
+ children: [/* @__PURE__ */ b(O.Control, {
73
+ className: x("group/seek relative flex w-full cursor-pointer touch-none items-center select-none", s ? "h-3 items-end" : "h-4"),
74
+ onPointerMove: (e) => e.pointerType === "mouse" && p(S(e.clientX)),
75
+ onPointerLeave: () => p(null),
76
+ children: [/* @__PURE__ */ b(O.Track, {
77
+ ref: m,
78
+ className: x("relative w-full overflow-hidden bg-white/30 transition-[height] motion-reduce:transition-none", s ? "h-[3px] group-hover/seek:h-[5px]" : "h-1 rounded-full group-hover/seek:h-1.5", u !== null && (s ? "h-[5px]" : "h-1.5")),
79
+ children: [/* @__PURE__ */ y("div", {
80
+ "aria-hidden": !0,
81
+ className: "absolute inset-y-0 left-0 bg-white/40",
82
+ style: { width: v(r) }
83
+ }), /* @__PURE__ */ y(O.Indicator, { className: "bg-player-accent" })]
84
+ }), /* @__PURE__ */ y(O.Thumb, {
85
+ "aria-label": l("player.seek"),
86
+ getAriaValueText: (e, t) => l("player.time", {
87
+ current: A(t),
88
+ duration: A(n)
89
+ }),
90
+ className: x("size-3 rounded-full bg-player-accent opacity-0 shadow transition-opacity outline-none group-hover/seek:opacity-100 focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-white/80 motion-reduce:transition-none", u !== null && "opacity-100", s && "mb-[-4px]")
91
+ })]
92
+ }), T && !s && /* @__PURE__ */ y(P, {
93
+ sprite: o,
94
+ ...T
95
+ })]
96
+ });
97
+ }
98
+ function P({ sprite: e, time: t, x: n, width: r }) {
99
+ let i = e ? p(e.cues, t) : void 0, a = i ? Math.min(160, Math.max(96, r * .3)) : 0, o = i ? a / i.w : 0, s = Math.max(a, 48), c = Math.min(Math.max(0, n - s / 2), Math.max(0, r - s));
100
+ return /* @__PURE__ */ b("div", {
101
+ "aria-hidden": !0,
102
+ "data-ckui": "seek-preview",
103
+ className: "pointer-events-none absolute bottom-full mb-2 flex flex-col items-center gap-1",
104
+ style: {
105
+ left: c,
106
+ width: s
107
+ },
108
+ children: [i && e && /* @__PURE__ */ y("div", {
109
+ "data-ckui": "seek-sprite",
110
+ className: "rounded-md bg-black bg-no-repeat shadow-lg ring-1 ring-white/30",
111
+ style: {
112
+ width: a,
113
+ height: i.h * o,
114
+ backgroundImage: `url("${i.url}")`,
115
+ backgroundPosition: `${-i.x * o}px ${-i.y * o}px`,
116
+ backgroundSize: `${e.width * o}px ${e.height * o}px`
117
+ }
118
+ }), /* @__PURE__ */ y("span", {
119
+ className: "rounded bg-black/75 px-1.5 py-0.5 text-xs font-medium text-white tabular-nums",
120
+ children: A(t)
121
+ })]
122
+ });
123
+ }
124
+ function F({ volume: t, muted: n, onVolume: r, onMute: i }) {
125
+ let { t: a } = e(), o = n || t === 0;
126
+ return /* @__PURE__ */ b("div", {
127
+ className: "group/volume flex items-center",
128
+ "data-ckui": "volume",
129
+ children: [/* @__PURE__ */ y(j, {
130
+ label: a(o ? "player.unmute" : "player.mute"),
131
+ shortcut: "m",
132
+ icon: o ? E : t < .5 ? T : w,
133
+ onClick: i
134
+ }), /* @__PURE__ */ y("div", {
135
+ className: "w-0 overflow-hidden opacity-0 transition-[width,opacity] group-focus-within/volume:w-20 group-focus-within/volume:opacity-100 group-hover/volume:w-20 group-hover/volume:opacity-100 motion-reduce:transition-none pointer-coarse:hidden",
136
+ children: /* @__PURE__ */ y(O.Root, {
137
+ value: o ? 0 : t,
138
+ min: 0,
139
+ max: 1,
140
+ step: .05,
141
+ onValueChange: (e) => r(e),
142
+ className: "px-2",
143
+ children: /* @__PURE__ */ b(O.Control, {
144
+ className: "relative flex h-6 w-full cursor-pointer touch-none items-center select-none",
145
+ children: [/* @__PURE__ */ y(O.Track, {
146
+ className: "relative h-1 w-full overflow-hidden rounded-full bg-white/30",
147
+ children: /* @__PURE__ */ y(O.Indicator, { className: "bg-white" })
148
+ }), /* @__PURE__ */ y(O.Thumb, {
149
+ "aria-label": a("player.volume"),
150
+ getAriaValueText: (e, t) => `${Math.round(t * 100)}%`,
151
+ className: "size-3 rounded-full bg-white outline-none focus-visible:ring-2 focus-visible:ring-white/80"
152
+ })]
153
+ })
154
+ })
155
+ })]
156
+ });
157
+ }
158
+ function I({ icon: e, label: f, sections: p, actions: h, container: g, onOpenChange: _ }) {
159
+ let x = m(t);
160
+ return /* @__PURE__ */ y(t.Provider, {
161
+ value: {
162
+ ...x,
163
+ theme: "dark"
164
+ },
165
+ children: /* @__PURE__ */ b(n, {
166
+ onOpenChange: _,
167
+ children: [/* @__PURE__ */ y(d, {
168
+ "aria-label": f,
169
+ title: f,
170
+ className: k,
171
+ "data-ckui": "settings",
172
+ children: /* @__PURE__ */ y(D, {
173
+ icon: e,
174
+ strokeWidth: 1.75,
175
+ "aria-hidden": !0
176
+ })
177
+ }), /* @__PURE__ */ b(r, {
178
+ side: "top",
179
+ align: "end",
180
+ sideOffset: 8,
181
+ container: g,
182
+ className: "min-w-56",
183
+ "data-ckui": "settings-menu",
184
+ children: [p.map((e) => /* @__PURE__ */ b(c, { children: [/* @__PURE__ */ b(u, {
185
+ "data-ckui": `settings-${e.key}`,
186
+ children: [/* @__PURE__ */ y("span", { children: e.label }), /* @__PURE__ */ y("span", {
187
+ className: "ml-auto max-w-32 truncate pl-4 text-muted-foreground",
188
+ children: e.options.find((t) => t.value === e.value)?.label
189
+ })]
190
+ }), /* @__PURE__ */ y(l, {
191
+ side: "left",
192
+ align: "end",
193
+ alignOffset: -4,
194
+ container: g,
195
+ className: "min-w-40",
196
+ "data-ckui": `${e.key}-menu`,
197
+ children: /* @__PURE__ */ y(a, {
198
+ value: e.value,
199
+ onValueChange: (t) => t !== e.value && e.onChange(String(t)),
200
+ children: e.options.map((e) => /* @__PURE__ */ y(o, {
201
+ value: e.value,
202
+ closeOnClick: !0,
203
+ children: e.label
204
+ }, e.value))
205
+ })
206
+ })] }, e.key)), h?.length ? /* @__PURE__ */ b(v, { children: [p.length > 0 && /* @__PURE__ */ y(s, {}), h.map((e) => /* @__PURE__ */ y(i, {
207
+ onClick: e.onSelect,
208
+ children: e.label
209
+ }, e.label))] }) : null]
210
+ })]
211
+ })
212
+ });
213
+ }
214
+ function L({ cues: e, bottom: t }) {
215
+ return e.length ? /* @__PURE__ */ y("div", {
216
+ "data-ckui": "captions",
217
+ className: "pointer-events-none absolute inset-x-0 z-[5] flex flex-col items-center gap-1 px-[5%] text-center transition-[bottom] duration-200 motion-reduce:transition-none",
218
+ style: { bottom: t },
219
+ children: e.map((e, t) => /* @__PURE__ */ y(R, { cue: e }, `${e.startTime}:${t}`))
220
+ }) : null;
221
+ }
222
+ function R({ cue: e }) {
223
+ let t = g(null);
224
+ return h(() => {
225
+ let n = t.current;
226
+ if (!n) return;
227
+ let r = typeof e.getCueAsHTML == "function" ? e.getCueAsHTML() : null;
228
+ n.replaceChildren(r ?? document.createTextNode(e.text));
229
+ }, [e]), /* @__PURE__ */ y("span", {
230
+ ref: t,
231
+ className: "rounded bg-black/75 px-2 py-0.5 text-[clamp(0.8rem,3.2cqw,2rem)] leading-snug whitespace-pre-line text-white"
232
+ });
233
+ }
234
+ function z({ flash: t }) {
235
+ let { t: n } = e();
236
+ if (!t) return null;
237
+ let r = t.direction < 0;
238
+ return /* @__PURE__ */ y("div", {
239
+ "aria-hidden": !0,
240
+ "data-ckui": "seek-flash",
241
+ className: x("pointer-events-none absolute top-1/2 z-[6] -translate-y-1/2 duration-200 animate-in fade-in zoom-in-90 motion-reduce:animate-none", r ? "left-[8%]" : "right-[8%]"),
242
+ children: /* @__PURE__ */ b("div", {
243
+ className: "flex size-20 flex-col items-center justify-center gap-0.5 rounded-full bg-black/50 text-white sm:size-24",
244
+ children: [/* @__PURE__ */ y(D, {
245
+ icon: r ? S : C,
246
+ className: "size-7",
247
+ strokeWidth: 2.5
248
+ }), /* @__PURE__ */ y("span", {
249
+ className: "text-xs font-semibold tabular-nums",
250
+ children: n("player.seconds", { seconds: t.seconds })
251
+ })]
252
+ })
253
+ }, t.direction);
254
+ }
255
+ function B({ className: e }) {
256
+ return /* @__PURE__ */ y("span", {
257
+ "aria-hidden": !0,
258
+ className: x("size-6 rounded-full border-2 border-white/30 border-t-white motion-safe:animate-spin", e)
259
+ });
260
+ }
261
+ //#endregion
262
+ export { L as Captions, j as ControlButton, N as SeekBar, z as SeekFlash, I as SettingsMenu, B as Spinner, F as VolumeControl, A as clock, k as playerButtonClass };
263
+
264
+ //# sourceMappingURL=player-controls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"player-controls.js","names":[],"sources":["../../src/components/player-controls.tsx"],"sourcesContent":["import { ArrowLeft01Icon, ArrowRight01Icon, VolumeHighIcon, VolumeLowIcon, VolumeOffIcon } from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon, type IconSvgElement } from \"@hugeicons/react\";\nimport { Slider as SliderPrimitive } from \"@base-ui/react/slider\";\nimport { cn } from \"cn\";\nimport { useContext, useLayoutEffect, useRef, useState, type ComponentProps, type KeyboardEvent, type PointerEvent } from \"react\";\nimport { formatDuration } from \"../client/gallery.js\";\nimport { ARROW_SEEK, spriteCueAt } from \"../client/player.js\";\nimport { useMessages } from \"../i18n/context.js\";\nimport type { Sprite } from \"../react/player.js\";\nimport { AppearanceContext } from \"../scope.js\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuTrigger,\n} from \"#ckui/ui/dropdown-menu\";\n\n/** The class of every control-bar button; a host's slotted buttons can share it. */\nexport const playerButtonClass =\n \"inline-flex size-9 shrink-0 cursor-pointer items-center justify-center rounded-full text-white outline-none transition-colors hover:bg-white/15 focus-visible:ring-2 focus-visible:ring-white/80 motion-reduce:transition-none data-popup-open:bg-white/15 [&_svg]:size-5 relative aria-pressed:after:absolute aria-pressed:after:bottom-1 aria-pressed:after:h-0.5 aria-pressed:after:w-4 aria-pressed:after:rounded-full aria-pressed:after:bg-player-accent\";\n\nexport const clock = (s: number) => formatDuration(Math.floor(s));\n\nexport function ControlButton({\n label,\n shortcut,\n icon,\n className,\n ...props\n}: Omit<ComponentProps<\"button\">, \"children\"> & { label: string; shortcut?: string; icon: IconSvgElement }) {\n return (\n <button type=\"button\" aria-label={label} title={shortcut ? `${label} (${shortcut})` : label} className={cn(playerButtonClass, className)} {...props}>\n <HugeiconsIcon icon={icon} strokeWidth={1.75} aria-hidden />\n </button>\n );\n}\n\nconst SEEK_KEYS: Record<string, (time: number, duration: number) => number> = {\n ArrowLeft: (t) => t - ARROW_SEEK,\n ArrowDown: (t) => t - ARROW_SEEK,\n ArrowRight: (t) => t + ARROW_SEEK,\n ArrowUp: (t) => t + ARROW_SEEK,\n PageDown: (t, d) => t - d / 10,\n PageUp: (t, d) => t + d / 10,\n Home: () => 0,\n End: (_, d) => d,\n};\n\nexport interface SeekBarProps {\n time: number;\n duration: number;\n buffered?: number;\n onSeek: (time: number) => void;\n /** The position being dragged to, or null when the drag ends. */\n onScrub?: (time: number | null) => void;\n sprite?: Sprite | null;\n /** The mini player's hairline along its bottom edge. */\n thin?: boolean;\n className?: string;\n}\n\n/** The seek slider: buffered range, drag to seek on release, keys in 5 s steps, a sprite and time preview on hover. */\nexport function SeekBar({ time, duration, buffered = 0, onSeek, onScrub, sprite, thin, className }: SeekBarProps) {\n const { t } = useMessages();\n const [scrub, setScrub] = useState<number | null>(null);\n const [hover, setHover] = useState<{ time: number; x: number; width: number } | null>(null);\n const track = useRef<HTMLDivElement>(null);\n const value = scrub ?? Math.min(time, duration || time);\n const pct = (v: number) => (duration > 0 ? `${Math.min(100, (v / duration) * 100)}%` : \"0%\");\n const at = (clientX: number) => {\n const r = track.current?.getBoundingClientRect();\n if (!r || !r.width || !duration) return null;\n const x = Math.min(r.width, Math.max(0, clientX - r.left));\n return { time: (x / r.width) * duration, x, width: r.width };\n };\n const scrubTo = (v: number | null) => {\n setScrub(v);\n onScrub?.(v);\n };\n const onKeyDownCapture = (e: KeyboardEvent) => {\n const to = SEEK_KEYS[e.key];\n if (!to || !duration) return;\n // The slider's own steps are tiny; these are the player's.\n e.preventDefault();\n e.stopPropagation();\n onSeek(Math.min(duration, Math.max(0, to(time, duration))));\n };\n const preview = scrub !== null ? { time: scrub, x: (scrub / (duration || 1)) * (track.current?.clientWidth ?? 0), width: track.current?.clientWidth ?? 0 } : hover;\n return (\n <SliderPrimitive.Root\n value={value}\n min={0}\n max={duration || 1}\n step={0.01}\n disabled={!duration}\n thumbAlignment=\"center\"\n onValueChange={(v) => scrubTo(v)}\n onValueCommitted={(v) => {\n scrubTo(null);\n onSeek(v);\n }}\n onKeyDownCapture={onKeyDownCapture}\n className={cn(\"relative w-full\", className)}\n data-ckui=\"seek\"\n >\n <SliderPrimitive.Control\n className={cn(\"group/seek relative flex w-full cursor-pointer touch-none items-center select-none\", thin ? \"h-3 items-end\" : \"h-4\")}\n onPointerMove={(e: PointerEvent) => e.pointerType === \"mouse\" && setHover(at(e.clientX))}\n onPointerLeave={() => setHover(null)}\n >\n <SliderPrimitive.Track\n ref={track}\n className={cn(\n \"relative w-full overflow-hidden bg-white/30 transition-[height] motion-reduce:transition-none\",\n thin ? \"h-[3px] group-hover/seek:h-[5px]\" : \"h-1 rounded-full group-hover/seek:h-1.5\",\n scrub !== null && (thin ? \"h-[5px]\" : \"h-1.5\"),\n )}\n >\n <div aria-hidden className=\"absolute inset-y-0 left-0 bg-white/40\" style={{ width: pct(buffered) }} />\n <SliderPrimitive.Indicator className=\"bg-player-accent\" />\n </SliderPrimitive.Track>\n <SliderPrimitive.Thumb\n aria-label={t(\"player.seek\")}\n getAriaValueText={(_, v) => t(\"player.time\", { current: clock(v), duration: clock(duration) })}\n className={cn(\n \"size-3 rounded-full bg-player-accent opacity-0 shadow transition-opacity outline-none group-hover/seek:opacity-100 focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-white/80 motion-reduce:transition-none\",\n scrub !== null && \"opacity-100\",\n thin && \"mb-[-4px]\",\n )}\n />\n </SliderPrimitive.Control>\n {preview && !thin && <SeekPreview sprite={sprite} {...preview} />}\n </SliderPrimitive.Root>\n );\n}\n\nfunction SeekPreview({ sprite, time, x, width }: { sprite?: Sprite | null; time: number; x: number; width: number }) {\n const cue = sprite ? spriteCueAt(sprite.cues, time) : undefined;\n const w = cue ? Math.min(160, Math.max(96, width * 0.3)) : 0;\n const s = cue ? w / cue.w : 0;\n const boxW = Math.max(w, 48);\n const left = Math.min(Math.max(0, x - boxW / 2), Math.max(0, width - boxW));\n return (\n <div aria-hidden data-ckui=\"seek-preview\" className=\"pointer-events-none absolute bottom-full mb-2 flex flex-col items-center gap-1\" style={{ left, width: boxW }}>\n {cue && sprite && (\n <div\n data-ckui=\"seek-sprite\"\n className=\"rounded-md bg-black bg-no-repeat shadow-lg ring-1 ring-white/30\"\n style={{\n width: w,\n height: cue.h * s,\n backgroundImage: `url(\"${cue.url}\")`,\n backgroundPosition: `${-cue.x * s}px ${-cue.y * s}px`,\n backgroundSize: `${sprite.width * s}px ${sprite.height * s}px`,\n }}\n />\n )}\n <span className=\"rounded bg-black/75 px-1.5 py-0.5 text-xs font-medium text-white tabular-nums\">{clock(time)}</span>\n </div>\n );\n}\n\nexport function VolumeControl({ volume, muted, onVolume, onMute }: { volume: number; muted: boolean; onVolume: (v: number) => void; onMute: () => void }) {\n const { t } = useMessages();\n const silent = muted || volume === 0;\n return (\n <div className=\"group/volume flex items-center\" data-ckui=\"volume\">\n <ControlButton label={silent ? t(\"player.unmute\") : t(\"player.mute\")} shortcut=\"m\" icon={silent ? VolumeOffIcon : volume < 0.5 ? VolumeLowIcon : VolumeHighIcon} onClick={onMute} />\n <div className=\"w-0 overflow-hidden opacity-0 transition-[width,opacity] group-focus-within/volume:w-20 group-focus-within/volume:opacity-100 group-hover/volume:w-20 group-hover/volume:opacity-100 motion-reduce:transition-none pointer-coarse:hidden\">\n <SliderPrimitive.Root value={silent ? 0 : volume} min={0} max={1} step={0.05} onValueChange={(v) => onVolume(v)} className=\"px-2\">\n <SliderPrimitive.Control className=\"relative flex h-6 w-full cursor-pointer touch-none items-center select-none\">\n <SliderPrimitive.Track className=\"relative h-1 w-full overflow-hidden rounded-full bg-white/30\">\n <SliderPrimitive.Indicator className=\"bg-white\" />\n </SliderPrimitive.Track>\n <SliderPrimitive.Thumb\n aria-label={t(\"player.volume\")}\n getAriaValueText={(_, v) => `${Math.round(v * 100)}%`}\n className=\"size-3 rounded-full bg-white outline-none focus-visible:ring-2 focus-visible:ring-white/80\"\n />\n </SliderPrimitive.Control>\n </SliderPrimitive.Root>\n </div>\n </div>\n );\n}\n\nexport interface MenuOption {\n value: string;\n label: string;\n}\n\n/** One settings row: its current value, and a submenu choosing it. */\nexport interface MenuSection {\n key: string;\n label: string;\n value: string;\n options: readonly MenuOption[];\n onChange: (value: string) => void;\n}\n\nexport function SettingsMenu({\n icon,\n label,\n sections,\n actions,\n container,\n onOpenChange,\n}: {\n icon: IconSvgElement;\n label: string;\n sections: MenuSection[];\n actions?: { label: string; onSelect: () => void }[];\n container?: HTMLElement;\n onOpenChange?: (open: boolean) => void;\n}) {\n // Menus over video are dark, whatever the page's theme.\n const appearance = useContext(AppearanceContext);\n return (\n <AppearanceContext.Provider value={{ ...appearance, theme: \"dark\" }}>\n <DropdownMenu onOpenChange={onOpenChange}>\n <DropdownMenuTrigger aria-label={label} title={label} className={playerButtonClass} data-ckui=\"settings\">\n <HugeiconsIcon icon={icon} strokeWidth={1.75} aria-hidden />\n </DropdownMenuTrigger>\n <DropdownMenuContent side=\"top\" align=\"end\" sideOffset={8} container={container} className=\"min-w-56\" data-ckui=\"settings-menu\">\n {sections.map((s) => (\n <DropdownMenuSub key={s.key}>\n <DropdownMenuSubTrigger data-ckui={`settings-${s.key}`}>\n <span>{s.label}</span>\n <span className=\"ml-auto max-w-32 truncate pl-4 text-muted-foreground\">{s.options.find((o) => o.value === s.value)?.label}</span>\n </DropdownMenuSubTrigger>\n <DropdownMenuSubContent side=\"left\" align=\"end\" alignOffset={-4} container={container} className=\"min-w-40\" data-ckui={`${s.key}-menu`}>\n <DropdownMenuRadioGroup value={s.value} onValueChange={(v) => v !== s.value && s.onChange(String(v))}>\n {s.options.map((o) => (\n <DropdownMenuRadioItem key={o.value} value={o.value} closeOnClick>\n {o.label}\n </DropdownMenuRadioItem>\n ))}\n </DropdownMenuRadioGroup>\n </DropdownMenuSubContent>\n </DropdownMenuSub>\n ))}\n {actions?.length ? (\n <>\n {sections.length > 0 && <DropdownMenuSeparator />}\n {actions.map((a) => (\n <DropdownMenuItem key={a.label} onClick={a.onSelect}>\n {a.label}\n </DropdownMenuItem>\n ))}\n </>\n ) : null}\n </DropdownMenuContent>\n </DropdownMenu>\n </AppearanceContext.Provider>\n );\n}\n\n/** The showing subtitle cues, drawn above the controls; markup comes from the browser's cue parser. */\nexport function Captions({ cues, bottom }: { cues: readonly VTTCue[]; bottom: string }) {\n if (!cues.length) return null;\n return (\n <div\n data-ckui=\"captions\"\n className=\"pointer-events-none absolute inset-x-0 z-[5] flex flex-col items-center gap-1 px-[5%] text-center transition-[bottom] duration-200 motion-reduce:transition-none\"\n style={{ bottom }}\n >\n {cues.map((c, i) => (\n <Cue key={`${c.startTime}:${i}`} cue={c} />\n ))}\n </div>\n );\n}\n\nfunction Cue({ cue }: { cue: VTTCue }) {\n const ref = useRef<HTMLSpanElement>(null);\n useLayoutEffect(() => {\n const el = ref.current;\n if (!el) return;\n const html = typeof cue.getCueAsHTML === \"function\" ? cue.getCueAsHTML() : null;\n el.replaceChildren(html ?? document.createTextNode(cue.text));\n }, [cue]);\n return <span ref={ref} className=\"rounded bg-black/75 px-2 py-0.5 text-[clamp(0.8rem,3.2cqw,2rem)] leading-snug whitespace-pre-line text-white\" />;\n}\n\nexport interface SeekFlashState {\n direction: -1 | 1;\n /** The burst's total, e.g. 30 after three taps. */\n seconds: number;\n}\n\n/** The \"10 seconds\" bubble for keyboard and double-tap seeks. */\nexport function SeekFlash({ flash }: { flash: SeekFlashState | null }) {\n const { t } = useMessages();\n if (!flash) return null;\n const back = flash.direction < 0;\n return (\n <div\n key={flash.direction}\n aria-hidden\n data-ckui=\"seek-flash\"\n className={cn(\n \"pointer-events-none absolute top-1/2 z-[6] -translate-y-1/2 duration-200 animate-in fade-in zoom-in-90 motion-reduce:animate-none\",\n back ? \"left-[8%]\" : \"right-[8%]\",\n )}\n >\n <div className=\"flex size-20 flex-col items-center justify-center gap-0.5 rounded-full bg-black/50 text-white sm:size-24\">\n <HugeiconsIcon icon={back ? ArrowLeft01Icon : ArrowRight01Icon} className=\"size-7\" strokeWidth={2.5} />\n <span className=\"text-xs font-semibold tabular-nums\">{t(\"player.seconds\", { seconds: flash.seconds })}</span>\n </div>\n </div>\n );\n}\n\nexport function Spinner({ className }: { className?: string }) {\n return <span aria-hidden className={cn(\"size-6 rounded-full border-2 border-white/30 border-t-white motion-safe:animate-spin\", className)} />;\n}\n\n"],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { Progress } from '../client/media/client.js';
2
+ import { Translator } from '../i18n/messages.js';
3
+ /** Hashing and uploading fill 0–90 %, completing the rest; processing is indeterminate. */
4
+ export declare function progressValue(p: Progress | undefined, rendering?: boolean): number | null;
5
+ export declare function progressLabel(t: Translator["t"], p: Progress | undefined, rendering?: boolean): string;
@@ -0,0 +1,14 @@
1
+ //#region src/components/progress.ts
2
+ function e(e, t) {
3
+ if (t || e?.phase === "processing") return null;
4
+ if (!e) return 0;
5
+ let n = e.total > 0 ? e.loaded / e.total : 0;
6
+ return e.phase === "hashing" ? Math.round(n * 10) : e.phase === "uploading" ? 10 + Math.round(n * 80) : 95;
7
+ }
8
+ function t(e, t, n) {
9
+ return n || t?.phase === "processing" ? e("progress.rendering") : t ? t.phase === "uploading" ? e("progress.uploading", { percent: t.total > 0 ? Math.round(t.loaded / t.total * 100) : 0 }) : e(t.phase === "hashing" ? "progress.hashing" : "progress.completing") : e("progress.hashing");
10
+ }
11
+ //#endregion
12
+ export { t as progressLabel, e as progressValue };
13
+
14
+ //# sourceMappingURL=progress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress.js","names":[],"sources":["../../src/components/progress.ts"],"sourcesContent":["import type { Progress } from \"../client/media/client.js\";\nimport type { Translator } from \"../i18n/messages.js\";\n\n/** Hashing and uploading fill 0–90 %, completing the rest; processing is indeterminate. */\nexport function progressValue(p: Progress | undefined, rendering?: boolean): number | null {\n if (rendering || p?.phase === \"processing\") return null;\n if (!p) return 0;\n const f = p.total > 0 ? p.loaded / p.total : 0;\n if (p.phase === \"hashing\") return Math.round(f * 10);\n if (p.phase === \"uploading\") return 10 + Math.round(f * 80);\n return 95;\n}\n\nexport function progressLabel(t: Translator[\"t\"], p: Progress | undefined, rendering?: boolean): string {\n if (rendering || p?.phase === \"processing\") return t(\"progress.rendering\");\n if (!p) return t(\"progress.hashing\");\n if (p.phase === \"uploading\") return t(\"progress.uploading\", { percent: p.total > 0 ? Math.round((p.loaded / p.total) * 100) : 0 });\n return t(p.phase === \"hashing\" ? \"progress.hashing\" : \"progress.completing\");\n}\n"],"mappings":";AAIA,SAAgB,EAAc,GAAyB,GAAoC;CACzF,IAAI,KAAa,GAAG,UAAU,cAAc,OAAO;CACnD,IAAI,CAAC,GAAG,OAAO;CACf,IAAM,IAAI,EAAE,QAAQ,IAAI,EAAE,SAAS,EAAE,QAAQ;CAG7C,OAFI,EAAE,UAAU,YAAkB,KAAK,MAAM,IAAI,EAAE,IAC/C,EAAE,UAAU,cAAoB,KAAK,KAAK,MAAM,IAAI,EAAE,IACnD;AACT;AAEA,SAAgB,EAAc,GAAoB,GAAyB,GAA6B;CAItG,OAHI,KAAa,GAAG,UAAU,eAAqB,EAAE,oBAAoB,IACpE,IACD,EAAE,UAAU,cAAoB,EAAE,sBAAsB,EAAE,SAAS,EAAE,QAAQ,IAAI,KAAK,MAAO,EAAE,SAAS,EAAE,QAAS,GAAG,IAAI,EAAE,CAAC,IAC1H,EAAE,EAAE,UAAU,YAAY,qBAAqB,qBAAqB,IAF5D,EAAE,kBAAkB;AAGrC"}