@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":"player.js","names":[],"sources":["../../src/client/player.ts"],"sourcesContent":["// Player logic without the DOM: the keyboard map, resume points, seek-sprite\n// cues, track choice, played time and the viewer's remembered settings.\n\n/** What a key does to the player. */\nexport type PlayerAction =\n | { type: \"toggle\" }\n | { type: \"seekBy\"; seconds: number }\n /** A fraction of the duration: Home 0, End 1, digit n n/10. */\n | { type: \"seekTo\"; fraction: number }\n | { type: \"volumeBy\"; delta: number }\n | { type: \"mute\" }\n | { type: \"captions\" }\n | { type: \"fullscreen\" }\n | { type: \"theater\" }\n | { type: \"miniPlayer\" }\n | { type: \"speed\"; step: 1 | -1 };\n\nexport interface KeyLike {\n key: string;\n altKey?: boolean;\n ctrlKey?: boolean;\n metaKey?: boolean;\n}\n\n/** Seconds the arrow keys seek; J and L, and a double tap, seek twice as far. */\nexport const ARROW_SEEK = 5;\nexport const JUMP_SEEK = 10;\nexport const VOLUME_STEP = 0.05;\nexport const PLAYBACK_SPEEDS = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2] as const;\n\n/**\n * The shortcut for a key, as on YouTube: Space/K play, ←/→ 5 s, J/L 10 s,\n * ↑/↓ volume, M mute, C subtitles, F fullscreen, T theater, I mini player,\n * 0–9 a tenth of the way, Home/End, `<`/`>` (or `,`/`.`) speed. Keys with\n * Alt, Ctrl or Meta belong to the browser.\n */\nexport function playerKeyAction(e: KeyLike): PlayerAction | null {\n if (e.altKey || e.ctrlKey || e.metaKey) return null;\n const key = e.key.length === 1 ? e.key.toLowerCase() : e.key;\n switch (key) {\n case \" \":\n case \"k\":\n return { type: \"toggle\" };\n case \"ArrowLeft\":\n return { type: \"seekBy\", seconds: -ARROW_SEEK };\n case \"ArrowRight\":\n return { type: \"seekBy\", seconds: ARROW_SEEK };\n case \"j\":\n return { type: \"seekBy\", seconds: -JUMP_SEEK };\n case \"l\":\n return { type: \"seekBy\", seconds: JUMP_SEEK };\n case \"ArrowUp\":\n return { type: \"volumeBy\", delta: VOLUME_STEP };\n case \"ArrowDown\":\n return { type: \"volumeBy\", delta: -VOLUME_STEP };\n case \"m\":\n return { type: \"mute\" };\n case \"c\":\n return { type: \"captions\" };\n case \"f\":\n return { type: \"fullscreen\" };\n case \"t\":\n return { type: \"theater\" };\n case \"i\":\n return { type: \"miniPlayer\" };\n case \"Home\":\n return { type: \"seekTo\", fraction: 0 };\n case \"End\":\n return { type: \"seekTo\", fraction: 1 };\n case \"<\":\n case \",\":\n return { type: \"speed\", step: -1 };\n case \">\":\n case \".\":\n return { type: \"speed\", step: 1 };\n }\n return /^[0-9]$/.test(key) ? { type: \"seekTo\", fraction: Number(key) / 10 } : null;\n}\n\n/** The next playback speed up or down from rate (a rate off the list snaps to its nearest). */\nexport function nextSpeed(rate: number, step: 1 | -1): number {\n let at = 0;\n PLAYBACK_SPEEDS.forEach((s, i) => {\n if (Math.abs(s - rate) < Math.abs(PLAYBACK_SPEEDS[at]! - rate)) at = i;\n });\n return PLAYBACK_SPEEDS[Math.min(PLAYBACK_SPEEDS.length - 1, Math.max(0, at + step))]!;\n}\n\n/**\n * Where playback starts for a resume point: 0 without one, or when it is in\n * the last few seconds (the viewer finished; start over).\n */\nexport function resumeAt(startAt: number | undefined, duration?: number): number {\n if (!startAt || !Number.isFinite(startAt) || startAt <= 0) return 0;\n if (duration && duration > 0 && startAt >= duration - Math.max(3, duration * 0.02)) return 0;\n return startAt;\n}\n\n/** One cue of a seek sprite: a tile of the sprite image for [start, end). */\nexport interface SpriteCue {\n start: number;\n end: number;\n url: string;\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nfunction vttSeconds(s: string): number {\n const parts = s.trim().split(\":\").map(Number);\n return parts.reduce((acc, p) => acc * 60 + p, 0);\n}\n\n/** The cues of a sprite.vtt; tile URLs resolve against the cue sheet's. */\nexport function parseSpriteVtt(text: string, base: string): SpriteCue[] {\n const cues: SpriteCue[] = [];\n const lines = text.split(/\\r?\\n/);\n for (let i = 0; i < lines.length - 1; i++) {\n const timing = lines[i]!.match(/^\\s*([\\d:.]+)\\s+-->\\s+([\\d:.]+)/);\n const tile = timing && lines[i + 1]!.trim().match(/^(\\S+)#xywh=(\\d+),(\\d+),(\\d+),(\\d+)$/);\n if (!timing || !tile) continue;\n const [x, y, w, h] = tile.slice(2).map(Number) as [number, number, number, number];\n cues.push({ start: vttSeconds(timing[1]!), end: vttSeconds(timing[2]!), url: new URL(tile[1]!, base).href, x, y, w, h });\n }\n return cues;\n}\n\n/** The cue showing at time t (cues ascend): the last that starts at or before it. */\nexport function spriteCueAt(cues: readonly SpriteCue[], t: number): SpriteCue | undefined {\n let lo = 0;\n let hi = cues.length - 1;\n let found: SpriteCue | undefined;\n while (lo <= hi) {\n const mid = (lo + hi) >> 1;\n if (cues[mid]!.start <= t) {\n found = cues[mid];\n lo = mid + 1;\n } else hi = mid - 1;\n }\n return found ?? cues[0];\n}\n\n/** A selectable audio or subtitle track. */\nexport interface PlayerTrack {\n index: number;\n /** The playlist's NAME, else its language. */\n label: string;\n /** BCP 47. */\n lang?: string;\n forced?: boolean;\n}\n\n/** The track for a BCP 47 tag: an exact match, else the same primary language; -1 for none. */\nexport function pickTrack(tracks: readonly { lang?: string }[], lang: string | null | undefined): number {\n if (!lang) return -1;\n const want = lang.toLowerCase();\n const exact = tracks.findIndex((t) => t.lang?.toLowerCase() === want);\n if (exact >= 0) return exact;\n const primary = want.split(\"-\")[0];\n return tracks.findIndex((t) => t.lang?.toLowerCase().split(\"-\")[0] === primary);\n}\n\n/** A playhead sample: wall-clock ms and media seconds. */\nexport interface PlaySample {\n at: number;\n pos: number;\n}\n\n/** Seconds actually played between two samples: time that both elapsed and advanced the playhead (a seek adds nothing). */\nexport function playedBetween(a: PlaySample, b: PlaySample): number {\n return Math.max(0, Math.min((b.at - a.at) / 1000, b.pos - a.pos));\n}\n\nexport const PLAYER_VOLUME_KEY = \"ckui.player.volume\";\nexport const PLAYER_TRACKS_KEY = \"ckui.player.tracks\";\n\nexport interface VolumePrefs {\n volume: number;\n muted: boolean;\n}\n\n/** Audio and subtitle languages the viewer chose; subtitles \"off\" when they turned them off. */\nexport interface TrackPrefs {\n audio?: string;\n subtitles?: string;\n}\n\nfunction readJSON(key: string | null | undefined): Record<string, unknown> {\n if (!key) return {};\n try {\n const v: unknown = JSON.parse(globalThis.localStorage?.getItem(key) ?? \"{}\");\n return v && typeof v === \"object\" ? (v as Record<string, unknown>) : {};\n } catch {\n return {};\n }\n}\n\nfunction writeJSON(key: string | null | undefined, value: object) {\n if (!key) return;\n try {\n globalThis.localStorage?.setItem(key, JSON.stringify({ ...readJSON(key), ...value }));\n } catch {\n // private mode or blocked storage: the choice lasts this page\n }\n}\n\nexport function readVolume(key: string | null | undefined): VolumePrefs {\n const v = readJSON(key);\n const volume = typeof v.volume === \"number\" && Number.isFinite(v.volume) ? Math.min(1, Math.max(0, v.volume)) : 1;\n return { volume, muted: v.muted === true };\n}\n\nexport const writeVolume = (key: string | null | undefined, prefs: Partial<VolumePrefs>) => writeJSON(key, prefs);\n\nexport function readTrackPrefs(key: string | null | undefined): TrackPrefs {\n const v = readJSON(key);\n return { audio: typeof v.audio === \"string\" ? v.audio : undefined, subtitles: typeof v.subtitles === \"string\" ? v.subtitles : undefined };\n}\n\nexport const writeTrackPrefs = (key: string | null | undefined, prefs: TrackPrefs) => writeJSON(key, prefs);\n"],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { AspectRatio } from './aspect.js';
2
+ import { Rendition } from './rendition.js';
3
+ /**
4
+ * A public file's URL, as media.PublicURL: `{base}/v1/{namespace}/{kind}/{id}/public/{name}`.
5
+ * Pass an actual published name, not a preset template for a current image.
6
+ */
7
+ export declare function publicURL(base: string, namespace: string, kind: string, id: string, name: string): string;
8
+ /** Each `{key}` of template replaced by vars[key] ("" when missing), as the registry's templates fill. */
9
+ export declare function fill(template: string, vars: Record<string, string | number>): string;
10
+ /** A srcset from published URLs and their actual encoded widths. */
11
+ export declare function srcSet(renditions: readonly Rendition[]): string;
12
+ /**
13
+ * A public preset at an item: what a slot or poster shows, with its current
14
+ * renditions (from a read's `public`, or a host's authorized listing).
15
+ */
16
+ export interface PublicPreset {
17
+ preset: string;
18
+ renditions: readonly Rendition[];
19
+ /** The preset's "W:H"; "" or omitted is the source's own. */
20
+ aspect?: AspectRatio;
21
+ }
22
+ /** Published files, narrowest first; sizes and filenames are never inferred. */
23
+ export declare function publicRenditions(p: PublicPreset | {
24
+ renditions: readonly Rendition[];
25
+ } | null | undefined): Rendition[];
@@ -0,0 +1,18 @@
1
+ import { sortRenditions as e } from "./rendition.js";
2
+ //#region src/client/public.ts
3
+ function t(e, t, n, r, i) {
4
+ return `${e.replace(/\/+$/, "")}/v1/${t}/${n}/${r}/public/${i}`;
5
+ }
6
+ function n(e, t) {
7
+ return e.replace(/\{([^}]*)\}/g, (e, n) => n in t ? String(t[n]) : "");
8
+ }
9
+ function r(t) {
10
+ return e(t).filter((e, t, n) => t === 0 || e.w !== n[t - 1].w).map((e) => `${e.url} ${e.w}w`).join(", ");
11
+ }
12
+ function i(t) {
13
+ return t ? e(t.renditions) : [];
14
+ }
15
+ //#endregion
16
+ export { n as fill, i as publicRenditions, t as publicURL, r as srcSet };
17
+
18
+ //# sourceMappingURL=public.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public.js","names":[],"sources":["../../src/client/public.ts"],"sourcesContent":["import type { AspectRatio } from \"./aspect.js\";\nimport { sortRenditions, type Rendition } from \"./rendition.js\";\n\n/**\n * A public file's URL, as media.PublicURL: `{base}/v1/{namespace}/{kind}/{id}/public/{name}`.\n * Pass an actual published name, not a preset template for a current image.\n */\nexport function publicURL(base: string, namespace: string, kind: string, id: string, name: string): string {\n return `${base.replace(/\\/+$/, \"\")}/v1/${namespace}/${kind}/${id}/public/${name}`;\n}\n\n/** Each `{key}` of template replaced by vars[key] (\"\" when missing), as the registry's templates fill. */\nexport function fill(template: string, vars: Record<string, string | number>): string {\n return template.replace(/\\{([^}]*)\\}/g, (_, k: string) => (k in vars ? String(vars[k]) : \"\"));\n}\n\n/** A srcset from published URLs and their actual encoded widths. */\nexport function srcSet(renditions: readonly Rendition[]): string {\n return sortRenditions(renditions)\n .filter((r, i, all) => i === 0 || r.w !== all[i - 1]!.w)\n .map((r) => `${r.url} ${r.w}w`).join(\", \");\n}\n\n/**\n * A public preset at an item: what a slot or poster shows, with its current\n * renditions (from a read's `public`, or a host's authorized listing).\n */\nexport interface PublicPreset {\n preset: string;\n renditions: readonly Rendition[];\n /** The preset's \"W:H\"; \"\" or omitted is the source's own. */\n aspect?: AspectRatio;\n}\n\n/** Published files, narrowest first; sizes and filenames are never inferred. */\nexport function publicRenditions(p: PublicPreset | { renditions: readonly Rendition[] } | null | undefined): Rendition[] {\n if (!p) return [];\n return sortRenditions(p.renditions);\n}\n"],"mappings":";;AAOA,SAAgB,EAAU,GAAc,GAAmB,GAAc,GAAY,GAAsB;CACzG,OAAO,GAAG,EAAK,QAAQ,QAAQ,EAAE,EAAE,MAAM,EAAU,GAAG,EAAK,GAAG,EAAG,UAAU;AAC7E;AAGA,SAAgB,EAAK,GAAkB,GAA+C;CACpF,OAAO,EAAS,QAAQ,iBAAiB,GAAG,MAAe,KAAK,IAAO,OAAO,EAAK,EAAE,IAAI,EAAG;AAC9F;AAGA,SAAgB,EAAO,GAA0C;CAC/D,OAAO,EAAe,CAAU,CAAC,CAC9B,QAAQ,GAAG,GAAG,MAAQ,MAAM,KAAK,EAAE,MAAM,EAAI,IAAI,EAAE,CAAE,CAAC,CAAC,CACvD,KAAK,MAAM,GAAG,EAAE,IAAI,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI;AAC7C;AAcA,SAAgB,EAAiB,GAAwF;CAEvH,OADK,IACE,EAAe,EAAE,UAAU,IADnB,CAAC;AAElB"}
@@ -0,0 +1,19 @@
1
+ /** One rendered width of an image, e.g. a public preset's file at one of its widths. */
2
+ export interface Rendition {
3
+ w: number;
4
+ /** Its height when known (the preset's aspect). */
5
+ h?: number;
6
+ url: string;
7
+ }
8
+ /** Device-pixel density range renditions target: even 1× screens get 2×, 3× phones 3×. */
9
+ export type DensityRange = readonly [min: number, max: number];
10
+ export declare const DEFAULT_DENSITY: DensityRange;
11
+ /** devicePixelRatio clamped into range. */
12
+ export declare function densityFor(range?: DensityRange, dpr?: number): number;
13
+ /** Renditions with a URL and width, narrowest first. */
14
+ export declare function sortRenditions<T extends Rendition>(outputs: readonly T[] | null | undefined): T[];
15
+ /**
16
+ * The narrowest rendition at least cssWidth × density device pixels wide
17
+ * (the widest when none is), e.g. 400 CSS px at 2× picks ≥ 800 px.
18
+ */
19
+ export declare function pickRendition<T extends Rendition>(outputs: readonly T[] | null | undefined, cssWidth: number, density?: number): T | undefined;
@@ -0,0 +1,16 @@
1
+ //#region src/client/rendition.ts
2
+ var e = [2, 3];
3
+ function t(t = e, n = typeof devicePixelRatio == "number" ? devicePixelRatio : 1) {
4
+ return Math.min(t[1], Math.max(t[0], n || 1));
5
+ }
6
+ function n(e) {
7
+ return [...e ?? []].filter((e) => e.url && e.w > 0).sort((e, t) => e.w - t.w);
8
+ }
9
+ function r(e, r, i = t()) {
10
+ let a = n(e), o = r * i;
11
+ return a.find((e) => e.w >= o) ?? a.at(-1);
12
+ }
13
+ //#endregion
14
+ export { e as DEFAULT_DENSITY, t as densityFor, r as pickRendition, n as sortRenditions };
15
+
16
+ //# sourceMappingURL=rendition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rendition.js","names":[],"sources":["../../src/client/rendition.ts"],"sourcesContent":["/** One rendered width of an image, e.g. a public preset's file at one of its widths. */\nexport interface Rendition {\n w: number;\n /** Its height when known (the preset's aspect). */\n h?: number;\n url: string;\n}\n\n/** Device-pixel density range renditions target: even 1× screens get 2×, 3× phones 3×. */\nexport type DensityRange = readonly [min: number, max: number];\n\nexport const DEFAULT_DENSITY: DensityRange = [2, 3];\n\n/** devicePixelRatio clamped into range. */\nexport function densityFor(range: DensityRange = DEFAULT_DENSITY, dpr = typeof devicePixelRatio === \"number\" ? devicePixelRatio : 1): number {\n return Math.min(range[1], Math.max(range[0], dpr || 1));\n}\n\n/** Renditions with a URL and width, narrowest first. */\nexport function sortRenditions<T extends Rendition>(outputs: readonly T[] | null | undefined): T[] {\n return [...(outputs ?? [])].filter((o) => o.url && o.w > 0).sort((a, b) => a.w - b.w);\n}\n\n/**\n * The narrowest rendition at least cssWidth × density device pixels wide\n * (the widest when none is), e.g. 400 CSS px at 2× picks ≥ 800 px.\n */\nexport function pickRendition<T extends Rendition>(outputs: readonly T[] | null | undefined, cssWidth: number, density = densityFor()): T | undefined {\n const sorted = sortRenditions(outputs);\n const want = cssWidth * density;\n return sorted.find((o) => o.w >= want) ?? sorted.at(-1);\n}\n"],"mappings":";AAWA,IAAa,IAAgC,CAAC,GAAG,CAAC;AAGlD,SAAgB,EAAW,IAAsB,GAAiB,IAAM,OAAO,oBAAqB,WAAW,mBAAmB,GAAW;CAC3I,OAAO,KAAK,IAAI,EAAM,IAAI,KAAK,IAAI,EAAM,IAAI,KAAO,CAAC,CAAC;AACxD;AAGA,SAAgB,EAAoC,GAA+C;CACjG,OAAO,CAAC,GAAI,KAAW,CAAC,CAAE,CAAC,CAAC,QAAQ,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,CAAC;AACtF;AAMA,SAAgB,EAAmC,GAA0C,GAAkB,IAAU,EAAW,GAAkB;CACpJ,IAAM,IAAS,EAAe,CAAO,GAC/B,IAAO,IAAW;CACxB,OAAO,EAAO,MAAM,MAAM,EAAE,KAAK,CAAI,KAAK,EAAO,GAAG,EAAE;AACxD"}
@@ -0,0 +1,39 @@
1
+ import { CONTENTKIT_ROUTES } from './generated/routes.js';
2
+ import { Http } from './http.js';
3
+ type AnyRoute = (typeof CONTENTKIT_ROUTES)[number];
4
+ export type Method = AnyRoute["method"];
5
+ /** A route path the catalog declares for the method. */
6
+ export type RoutePath<M extends Method> = Extract<AnyRoute, {
7
+ method: M;
8
+ }>["path"];
9
+ type RouteOf<M extends Method, P extends string> = Extract<AnyRoute, {
10
+ method: M;
11
+ path: P;
12
+ }>;
13
+ type ParamNames<P extends string> = P extends `${string}{${infer K}}${infer R}` ? (K extends `${infer N}...` ? N : K) | ParamNames<R> : never;
14
+ /** The path's {wildcards}, each a string value. */
15
+ export type PathParams<P extends string> = {
16
+ [K in ParamNames<P>]: string;
17
+ };
18
+ /** The query parameters the route declares. */
19
+ export type RouteQuery<M extends Method, P extends string> = Partial<Record<RouteOf<M, P>["query"][number], QueryValue>>;
20
+ type QueryValue = string | number | boolean | null | undefined | readonly string[];
21
+ export interface CallOptions<M extends Method, P extends string> {
22
+ params?: PathParams<P>;
23
+ query?: RouteQuery<M, P>;
24
+ body?: unknown;
25
+ signal?: AbortSignal;
26
+ }
27
+ /** The URL of a catalog route: its module's mount, the path with params filled, then the query. */
28
+ export declare function routeURL<M extends Method, P extends RoutePath<M>>(http: Http, method: M, path: P, o?: Pick<CallOptions<M, P>, "params" | "query">): string;
29
+ /**
30
+ * Calls a catalog route and resolves with its JSON body (undefined for 204);
31
+ * the caller's declared type names it.
32
+ */
33
+ export declare function call<M extends Method, P extends RoutePath<M>, T = any>(http: Http, method: M, path: P, o?: CallOptions<M, P>): Promise<T>;
34
+ /** A page of a limit/offset list. */
35
+ export interface PageQuery {
36
+ limit?: number;
37
+ offset?: number;
38
+ }
39
+ export {};
@@ -0,0 +1,31 @@
1
+ import { CONTENTKIT_ROUTES as e } from "./generated/routes.js";
2
+ //#region src/client/route.ts
3
+ var t = new Map(e.map((e) => [`${e.method} ${e.path}`, e]));
4
+ function n(e, t, n, r = {}) {
5
+ return i(e, t, n, r.params, r.query);
6
+ }
7
+ function r(e, t, n, r = {}) {
8
+ let a = i(e, t, n, r.params, r.query);
9
+ return e.request(a, {
10
+ method: t,
11
+ body: r.body,
12
+ signal: r.signal
13
+ });
14
+ }
15
+ function i(e, n, r, i = {}, a = {}) {
16
+ let o = t.get(`${n} ${r}`);
17
+ if (!o) throw Error(`contentkit: no route ${n} ${r}`);
18
+ let s = r.replace(/\{(\w+)(\.\.\.)?\}/g, (e, t, a) => {
19
+ let o = i[t];
20
+ if (o === void 0 || o === "") throw Error(`contentkit: ${n} ${r} needs ${t}`);
21
+ return a ? o.split("/").map(encodeURIComponent).join("/") : encodeURIComponent(o);
22
+ }), c = new URLSearchParams();
23
+ for (let [e, t] of Object.entries(a)) if (Array.isArray(t)) for (let n of t) c.append(e, n);
24
+ else t != null && t !== "" && c.set(e, String(t));
25
+ let l = c.toString();
26
+ return e.mount(o.module) + s + (l ? `?${l}` : "");
27
+ }
28
+ //#endregion
29
+ export { r as call, n as routeURL };
30
+
31
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.js","names":[],"sources":["../../src/client/route.ts"],"sourcesContent":["import { CONTENTKIT_ROUTES } from \"./generated/routes.js\";\nimport type { Http } from \"./http.js\";\n\ntype AnyRoute = (typeof CONTENTKIT_ROUTES)[number];\nexport type Method = AnyRoute[\"method\"];\n/** A route path the catalog declares for the method. */\nexport type RoutePath<M extends Method> = Extract<AnyRoute, { method: M }>[\"path\"];\ntype RouteOf<M extends Method, P extends string> = Extract<AnyRoute, { method: M; path: P }>;\n\ntype ParamNames<P extends string> = P extends `${string}{${infer K}}${infer R}` ? (K extends `${infer N}...` ? N : K) | ParamNames<R> : never;\n/** The path's {wildcards}, each a string value. */\nexport type PathParams<P extends string> = { [K in ParamNames<P>]: string };\n/** The query parameters the route declares. */\nexport type RouteQuery<M extends Method, P extends string> = Partial<Record<RouteOf<M, P>[\"query\"][number], QueryValue>>;\ntype QueryValue = string | number | boolean | null | undefined | readonly string[];\n\nexport interface CallOptions<M extends Method, P extends string> {\n params?: PathParams<P>;\n query?: RouteQuery<M, P>;\n body?: unknown;\n signal?: AbortSignal;\n}\n\nconst index = new Map<string, AnyRoute>(CONTENTKIT_ROUTES.map((r) => [`${r.method} ${r.path}`, r]));\n\n/** The URL of a catalog route: its module's mount, the path with params filled, then the query. */\nexport function routeURL<M extends Method, P extends RoutePath<M>>(http: Http, method: M, path: P, o: Pick<CallOptions<M, P>, \"params\" | \"query\"> = {}): string {\n return build(http, method, path, o.params as Record<string, string> | undefined, o.query as Record<string, QueryValue> | undefined);\n}\n\n/**\n * Calls a catalog route and resolves with its JSON body (undefined for 204);\n * the caller's declared type names it.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function call<M extends Method, P extends RoutePath<M>, T = any>(http: Http, method: M, path: P, o: CallOptions<M, P> = {}): Promise<T> {\n const url = build(http, method, path, o.params as Record<string, string> | undefined, o.query as Record<string, QueryValue> | undefined);\n return http.request<T>(url, { method, body: o.body, signal: o.signal });\n}\n\nfunction build(http: Http, method: string, path: string, params: Record<string, string> = {}, query: Record<string, QueryValue> = {}): string {\n const r = index.get(`${method} ${path}`);\n if (!r) throw new Error(`contentkit: no route ${method} ${path}`);\n const filled = path.replace(/\\{(\\w+)(\\.\\.\\.)?\\}/g, (_, name: string, rest?: string) => {\n const v = params[name];\n if (v === undefined || v === \"\") throw new Error(`contentkit: ${method} ${path} needs ${name}`);\n return rest ? v.split(\"/\").map(encodeURIComponent).join(\"/\") : encodeURIComponent(v);\n });\n const q = new URLSearchParams();\n for (const [k, v] of Object.entries(query)) {\n if (Array.isArray(v)) for (const x of v) q.append(k, x);\n else if (v !== undefined && v !== null && v !== \"\") q.set(k, String(v));\n }\n const s = q.toString();\n return http.mount(r.module) + filled + (s ? `?${s}` : \"\");\n}\n\n/** A page of a limit/offset list. */\nexport interface PageQuery {\n limit?: number;\n offset?: number;\n}\n"],"mappings":";;AAuBA,IAAM,IAAQ,IAAI,IAAsB,EAAkB,KAAK,MAAM,CAAC,GAAG,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;AAGlG,SAAgB,EAAmD,GAAY,GAAW,GAAS,IAAiD,CAAC,GAAW;CAC9J,OAAO,EAAM,GAAM,GAAQ,GAAM,EAAE,QAA8C,EAAE,KAA+C;AACpI;AAOA,SAAgB,EAAwD,GAAY,GAAW,GAAS,IAAuB,CAAC,GAAe;CAC7I,IAAM,IAAM,EAAM,GAAM,GAAQ,GAAM,EAAE,QAA8C,EAAE,KAA+C;CACvI,OAAO,EAAK,QAAW,GAAK;EAAE;EAAQ,MAAM,EAAE;EAAM,QAAQ,EAAE;CAAO,CAAC;AACxE;AAEA,SAAS,EAAM,GAAY,GAAgB,GAAc,IAAiC,CAAC,GAAG,IAAoC,CAAC,GAAW;CAC5I,IAAM,IAAI,EAAM,IAAI,GAAG,EAAO,GAAG,GAAM;CACvC,IAAI,CAAC,GAAG,MAAU,MAAM,wBAAwB,EAAO,GAAG,GAAM;CAChE,IAAM,IAAS,EAAK,QAAQ,wBAAwB,GAAG,GAAc,MAAkB;EACrF,IAAM,IAAI,EAAO;EACjB,IAAI,MAAM,KAAA,KAAa,MAAM,IAAI,MAAU,MAAM,eAAe,EAAO,GAAG,EAAK,SAAS,GAAM;EAC9F,OAAO,IAAO,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,kBAAkB,CAAC,CAAC,KAAK,GAAG,IAAI,mBAAmB,CAAC;CACrF,CAAC,GACK,IAAI,IAAI,gBAAgB;CAC9B,KAAK,IAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,CAAK,GACvC,IAAI,MAAM,QAAQ,CAAC,GAAG,KAAK,IAAM,KAAK,GAAG,EAAE,OAAO,GAAG,CAAC;MACjD,AAAI,KAAyB,QAAQ,MAAM,MAAI,EAAE,IAAI,GAAG,OAAO,CAAC,CAAC;CAExE,IAAM,IAAI,EAAE,SAAS;CACrB,OAAO,EAAK,MAAM,EAAE,MAAM,IAAI,KAAU,IAAI,IAAI,MAAM;AACxD"}
@@ -0,0 +1,30 @@
1
+ import { Assignment, AssignmentsWritten, ContentRef, Count, CountsRebuilt, Edge, EdgesWritten, EffectiveTagsOf, MergeReport, Name, Node, NodeDetail, NodeInput, NodePage, NodeUpdate } from './generated/wire.js';
2
+ import { Http } from './http.js';
3
+ import { RouteQuery } from './route.js';
4
+ /** GET /taxonomy/nodes filters, as the route names them. */
5
+ export type NodeQuery = RouteQuery<"GET", "/nodes">;
6
+ /** The taxonomy admin API (Taxonomy permission). */
7
+ export declare class TaxonomyClient {
8
+ private readonly http;
9
+ constructor(http: Http);
10
+ nodes(q?: NodeQuery, signal?: AbortSignal): Promise<NodePage>;
11
+ node(id: string, signal?: AbortSignal): Promise<NodeDetail>;
12
+ createNodes(nodes: NodeInput[]): Promise<Node[]>;
13
+ updateNode(id: string, patch: NodeUpdate): Promise<Node>;
14
+ /** Marks the node deleted. */
15
+ deleteNode(id: string): Promise<Node>;
16
+ /** Replaces, adds or removes names. */
17
+ names(id: string, op: "set" | "add" | "remove", names: Name[]): Promise<NodeDetail>;
18
+ merge(id: string, into: string): Promise<MergeReport>;
19
+ edges(op: "add" | "remove", edges: Edge[]): Promise<EdgesWritten>;
20
+ /** Assigns or unassigns nodes; suppressCounts skips count upkeep (rebuildCounts afterwards). */
21
+ assignments(op: "add" | "remove", assignments: Assignment[], o?: {
22
+ suppressCounts?: boolean;
23
+ }): Promise<AssignmentsWritten>;
24
+ /** The effective tags (work and version) of each content. */
25
+ effective(refs: ContentRef[], signal?: AbortSignal): Promise<EffectiveTagsOf[]>;
26
+ /** Content counts of nodes, by taxonomy id. */
27
+ counts(ids: readonly string[], signal?: AbortSignal): Promise<Record<string, Count[]>>;
28
+ rebuildCounts(): Promise<CountsRebuilt>;
29
+ private write;
30
+ }
@@ -0,0 +1,77 @@
1
+ import { call as e } from "./route.js";
2
+ //#region src/client/taxonomy.ts
3
+ var t = class {
4
+ http;
5
+ constructor(e) {
6
+ this.http = e;
7
+ }
8
+ nodes(t = {}, n) {
9
+ return e(this.http, "GET", "/nodes", {
10
+ query: t,
11
+ signal: n
12
+ });
13
+ }
14
+ node(t, n) {
15
+ return e(this.http, "GET", "/nodes/{id}", {
16
+ params: { id: t },
17
+ signal: n
18
+ });
19
+ }
20
+ createNodes(t) {
21
+ return this.write(e(this.http, "POST", "/nodes", { body: t }));
22
+ }
23
+ updateNode(t, n) {
24
+ return this.write(e(this.http, "PATCH", "/nodes/{id}", {
25
+ params: { id: t },
26
+ body: n
27
+ }));
28
+ }
29
+ deleteNode(t) {
30
+ return this.write(e(this.http, "DELETE", "/nodes/{id}", { params: { id: t } }));
31
+ }
32
+ names(t, n, r) {
33
+ let i = n === "set" ? "PUT" : n === "add" ? "POST" : "DELETE";
34
+ return this.write(e(this.http, i, "/nodes/{id}/names", {
35
+ params: { id: t },
36
+ body: r
37
+ }));
38
+ }
39
+ merge(t, n) {
40
+ return this.write(e(this.http, "POST", "/nodes/{id}/merge", {
41
+ params: { id: t },
42
+ body: { into_taxonomy_id: n }
43
+ }));
44
+ }
45
+ edges(t, n) {
46
+ return this.write(e(this.http, t === "add" ? "POST" : "DELETE", "/edges", { body: n }));
47
+ }
48
+ assignments(t, n, r = {}) {
49
+ return this.write(e(this.http, t === "add" ? "POST" : "DELETE", "/assignments", {
50
+ body: n,
51
+ query: { suppress_counts: r.suppressCounts }
52
+ }));
53
+ }
54
+ effective(t, n) {
55
+ return e(this.http, "POST", "/effective", {
56
+ body: t,
57
+ signal: n
58
+ });
59
+ }
60
+ counts(t, n) {
61
+ return e(this.http, "GET", "/counts", {
62
+ query: { taxonomy_id: t },
63
+ signal: n
64
+ });
65
+ }
66
+ rebuildCounts() {
67
+ return this.write(e(this.http, "POST", "/counts/rebuild"));
68
+ }
69
+ async write(e) {
70
+ let t = await e;
71
+ return this.http.emit({ type: "taxonomy.changed" }), t;
72
+ }
73
+ };
74
+ //#endregion
75
+ export { t as TaxonomyClient };
76
+
77
+ //# sourceMappingURL=taxonomy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"taxonomy.js","names":[],"sources":["../../src/client/taxonomy.ts"],"sourcesContent":["import type {\n Assignment,\n AssignmentsWritten,\n ContentRef,\n Count,\n CountsRebuilt,\n Edge,\n EdgesWritten,\n EffectiveTagsOf,\n MergeReport,\n Name,\n Node,\n NodeDetail,\n NodeInput,\n NodePage,\n NodeUpdate,\n} from \"./generated/wire.js\";\nimport type { Http } from \"./http.js\";\nimport { call, type RouteQuery } from \"./route.js\";\n\n/** GET /taxonomy/nodes filters, as the route names them. */\nexport type NodeQuery = RouteQuery<\"GET\", \"/nodes\">;\n\n/** The taxonomy admin API (Taxonomy permission). */\nexport class TaxonomyClient {\n constructor(private readonly http: Http) {}\n\n nodes(q: NodeQuery = {}, signal?: AbortSignal): Promise<NodePage> {\n return call(this.http, \"GET\", \"/nodes\", { query: q, signal });\n }\n node(id: string, signal?: AbortSignal): Promise<NodeDetail> {\n return call(this.http, \"GET\", \"/nodes/{id}\", { params: { id }, signal });\n }\n createNodes(nodes: NodeInput[]): Promise<Node[]> {\n return this.write(call(this.http, \"POST\", \"/nodes\", { body: nodes }));\n }\n updateNode(id: string, patch: NodeUpdate): Promise<Node> {\n return this.write(call(this.http, \"PATCH\", \"/nodes/{id}\", { params: { id }, body: patch }));\n }\n /** Marks the node deleted. */\n deleteNode(id: string): Promise<Node> {\n return this.write(call(this.http, \"DELETE\", \"/nodes/{id}\", { params: { id } }));\n }\n /** Replaces, adds or removes names. */\n names(id: string, op: \"set\" | \"add\" | \"remove\", names: Name[]): Promise<NodeDetail> {\n const method = op === \"set\" ? \"PUT\" : op === \"add\" ? \"POST\" : \"DELETE\";\n return this.write(call(this.http, method, \"/nodes/{id}/names\", { params: { id }, body: names }));\n }\n merge(id: string, into: string): Promise<MergeReport> {\n return this.write(call(this.http, \"POST\", \"/nodes/{id}/merge\", { params: { id }, body: { into_taxonomy_id: into } }));\n }\n edges(op: \"add\" | \"remove\", edges: Edge[]): Promise<EdgesWritten> {\n return this.write(call(this.http, op === \"add\" ? \"POST\" : \"DELETE\", \"/edges\", { body: edges }));\n }\n /** Assigns or unassigns nodes; suppressCounts skips count upkeep (rebuildCounts afterwards). */\n assignments(op: \"add\" | \"remove\", assignments: Assignment[], o: { suppressCounts?: boolean } = {}): Promise<AssignmentsWritten> {\n return this.write(call(this.http, op === \"add\" ? \"POST\" : \"DELETE\", \"/assignments\", { body: assignments, query: { suppress_counts: o.suppressCounts } }));\n }\n /** The effective tags (work and version) of each content. */\n effective(refs: ContentRef[], signal?: AbortSignal): Promise<EffectiveTagsOf[]> {\n return call(this.http, \"POST\", \"/effective\", { body: refs, signal });\n }\n /** Content counts of nodes, by taxonomy id. */\n counts(ids: readonly string[], signal?: AbortSignal): Promise<Record<string, Count[]>> {\n return call(this.http, \"GET\", \"/counts\", { query: { taxonomy_id: ids }, signal });\n }\n rebuildCounts(): Promise<CountsRebuilt> {\n return this.write(call(this.http, \"POST\", \"/counts/rebuild\"));\n }\n\n private async write<T>(p: Promise<T>): Promise<T> {\n const out = await p;\n this.http.emit({ type: \"taxonomy.changed\" });\n return out;\n }\n}\n"],"mappings":";;AAwBA,IAAa,IAAb,MAA4B;CACG;CAA7B,YAAY,GAA6B;EAAZ,KAAA,OAAA;CAAa;CAE1C,MAAM,IAAe,CAAC,GAAG,GAAyC;EAChE,OAAO,EAAK,KAAK,MAAM,OAAO,UAAU;GAAE,OAAO;GAAG;EAAO,CAAC;CAC9D;CACA,KAAK,GAAY,GAA2C;EAC1D,OAAO,EAAK,KAAK,MAAM,OAAO,eAAe;GAAE,QAAQ,EAAE,MAAG;GAAG;EAAO,CAAC;CACzE;CACA,YAAY,GAAqC;EAC/C,OAAO,KAAK,MAAM,EAAK,KAAK,MAAM,QAAQ,UAAU,EAAE,MAAM,EAAM,CAAC,CAAC;CACtE;CACA,WAAW,GAAY,GAAkC;EACvD,OAAO,KAAK,MAAM,EAAK,KAAK,MAAM,SAAS,eAAe;GAAE,QAAQ,EAAE,MAAG;GAAG,MAAM;EAAM,CAAC,CAAC;CAC5F;CAEA,WAAW,GAA2B;EACpC,OAAO,KAAK,MAAM,EAAK,KAAK,MAAM,UAAU,eAAe,EAAE,QAAQ,EAAE,MAAG,EAAE,CAAC,CAAC;CAChF;CAEA,MAAM,GAAY,GAA8B,GAAoC;EAClF,IAAM,IAAS,MAAO,QAAQ,QAAQ,MAAO,QAAQ,SAAS;EAC9D,OAAO,KAAK,MAAM,EAAK,KAAK,MAAM,GAAQ,qBAAqB;GAAE,QAAQ,EAAE,MAAG;GAAG,MAAM;EAAM,CAAC,CAAC;CACjG;CACA,MAAM,GAAY,GAAoC;EACpD,OAAO,KAAK,MAAM,EAAK,KAAK,MAAM,QAAQ,qBAAqB;GAAE,QAAQ,EAAE,MAAG;GAAG,MAAM,EAAE,kBAAkB,EAAK;EAAE,CAAC,CAAC;CACtH;CACA,MAAM,GAAsB,GAAsC;EAChE,OAAO,KAAK,MAAM,EAAK,KAAK,MAAM,MAAO,QAAQ,SAAS,UAAU,UAAU,EAAE,MAAM,EAAM,CAAC,CAAC;CAChG;CAEA,YAAY,GAAsB,GAA2B,IAAkC,CAAC,GAAgC;EAC9H,OAAO,KAAK,MAAM,EAAK,KAAK,MAAM,MAAO,QAAQ,SAAS,UAAU,gBAAgB;GAAE,MAAM;GAAa,OAAO,EAAE,iBAAiB,EAAE,eAAe;EAAE,CAAC,CAAC;CAC1J;CAEA,UAAU,GAAoB,GAAkD;EAC9E,OAAO,EAAK,KAAK,MAAM,QAAQ,cAAc;GAAE,MAAM;GAAM;EAAO,CAAC;CACrE;CAEA,OAAO,GAAwB,GAAwD;EACrF,OAAO,EAAK,KAAK,MAAM,OAAO,WAAW;GAAE,OAAO,EAAE,aAAa,EAAI;GAAG;EAAO,CAAC;CAClF;CACA,gBAAwC;EACtC,OAAO,KAAK,MAAM,EAAK,KAAK,MAAM,QAAQ,iBAAiB,CAAC;CAC9D;CAEA,MAAc,MAAS,GAA2B;EAChD,IAAM,IAAM,MAAM;EAElB,OADA,KAAK,KAAK,KAAK,EAAE,MAAM,mBAAmB,CAAC,GACpC;CACT;AACF"}
package/dist/client.js ADDED
@@ -0,0 +1,33 @@
1
+ import { DEFAULT_DENSITY as e, densityFor as t, pickRendition as n, sortRenditions as r } from "./client/rendition.js";
2
+ import { CLIENT_ERROR_CODES as i, ContentKitError as a, ERROR_CODES as o, failureError as s, isContentKitError as c, readContentKitError as l, toContentKitError as u } from "./client/errors.js";
3
+ import { fill as d, publicRenditions as f, publicURL as p, srcSet as m } from "./client/public.js";
4
+ import { aspectOf as h, ratio as g } from "./client/aspect.js";
5
+ import { call as _, routeURL as v } from "./client/route.js";
6
+ import { checkRef as y, isContentId as b } from "./client/media/ref.js";
7
+ import { MediaApi as x } from "./client/media/api.js";
8
+ import { MAX_PART_SIZE as S, MAX_SINGLE_PUT as C, MIN_PART_SIZE as w } from "./client/generated/wire.js";
9
+ import { sha256Hex as T } from "./client/media/hash.js";
10
+ import { Pacer as E } from "./client/media/pacer.js";
11
+ import { defaultTransport as D, fetchTransport as O, xhrTransport as k } from "./client/media/transport.js";
12
+ import { MediaClient as A, backoff as j, samePath as M, stem as N } from "./client/media/client.js";
13
+ import { acceptOf as P, defaultImage as F, filesFor as I, isPattern as L, ratioLabel as R, ruleDir as z, ruleFor as B, screenFiles as V, uniqueName as H, uploadRules as U, withMediaType as W } from "./client/media/rules.js";
14
+ import { centeredCrop as G, constrainCrop as K, editOf as q, editedSize as J, fromRotated as Y, rotation as X, sameEdit as Z, toOriginal as Q, toRotated as $ } from "./client/crop.js";
15
+ import { encodeRemaining as ee } from "./client/media/encode.js";
16
+ import { UploadQueue as te } from "./client/media/queue.js";
17
+ import { decodeImage as ne, isAnimatedImage as re } from "./client/image.js";
18
+ import { READ_CHUNK as ie, chunkOffsets as ae, isProcessing as oe, mergeReads as se, processing as ce } from "./client/media/windows.js";
19
+ import { ABR_DEFAULTS as le, NETWORK_FAILURES_BEFORE_ERROR as ue, REFRESH_BEFORE_EXPIRY as de, abrHlsConfig as fe, capRung as pe, classifyHlsError as me, classifyMediaError as he, expiryDelay as ge, hlsConfig as _e, initialEstimate as ve, refreshable as ye, startRung as be, statusKind as xe } from "./client/playback.js";
20
+ import { formatDuration as Se, galleryItems as Ce, isAudioType as we, isImageType as Te, isSubtitleType as Ee, isVideoType as De, stageAspect as Oe } from "./client/gallery.js";
21
+ import { PLAYBACK_SPEEDS as ke, PLAYER_TRACKS_KEY as Ae, PLAYER_VOLUME_KEY as je, parseSpriteVtt as Me, playerKeyAction as Ne, resumeAt as Pe } from "./client/player.js";
22
+ import { CodesClient as Fe } from "./client/codes.js";
23
+ import { BansClient as Ie } from "./client/content/bans.js";
24
+ import { reactionVerb as Le } from "./client/content/types.js";
25
+ import { CommentsClient as Re } from "./client/content/comments.js";
26
+ import { FavoritesClient as ze } from "./client/content/favorites.js";
27
+ import { ModerationClient as Be } from "./client/content/moderation.js";
28
+ import { PollsClient as Ve } from "./client/content/polls.js";
29
+ import { PostsClient as He } from "./client/content/posts.js";
30
+ import { ReactionsClient as Ue } from "./client/content/reactions.js";
31
+ import { TaxonomyClient as We } from "./client/taxonomy.js";
32
+ import { createContentKitClient as Ge } from "./client/client.js";
33
+ export { le as ABR_DEFAULTS, Ie as BansClient, i as CLIENT_ERROR_CODES, Fe as CodesClient, Re as CommentsClient, a as ContentKitError, e as DEFAULT_DENSITY, o as ERROR_CODES, ze as FavoritesClient, S as MAX_PART_SIZE, C as MAX_SINGLE_PUT, w as MIN_PART_SIZE, x as MediaApi, A as MediaClient, Be as ModerationClient, ue as NETWORK_FAILURES_BEFORE_ERROR, ke as PLAYBACK_SPEEDS, Ae as PLAYER_TRACKS_KEY, je as PLAYER_VOLUME_KEY, E as Pacer, Ve as PollsClient, He as PostsClient, ie as READ_CHUNK, de as REFRESH_BEFORE_EXPIRY, Ue as ReactionsClient, We as TaxonomyClient, te as UploadQueue, fe as abrHlsConfig, P as acceptOf, h as aspectOf, j as backoff, _ as call, pe as capRung, G as centeredCrop, y as checkRef, ae as chunkOffsets, me as classifyHlsError, he as classifyMediaError, K as constrainCrop, Ge as createContentKitClient, ne as decodeImage, F as defaultImage, D as defaultTransport, t as densityFor, q as editOf, J as editedSize, ee as encodeRemaining, ge as expiryDelay, s as failureError, O as fetchTransport, I as filesFor, d as fill, Se as formatDuration, Y as fromRotated, Ce as galleryItems, _e as hlsConfig, ve as initialEstimate, re as isAnimatedImage, we as isAudioType, b as isContentId, c as isContentKitError, Te as isImageType, L as isPattern, oe as isProcessing, Ee as isSubtitleType, De as isVideoType, se as mergeReads, Me as parseSpriteVtt, n as pickRendition, Ne as playerKeyAction, ce as processing, f as publicRenditions, p as publicURL, g as ratio, R as ratioLabel, Le as reactionVerb, l as readContentKitError, ye as refreshable, Pe as resumeAt, X as rotation, v as routeURL, z as ruleDir, B as ruleFor, Z as sameEdit, M as samePath, V as screenFiles, T as sha256Hex, r as sortRenditions, m as srcSet, Oe as stageAspect, be as startRung, xe as statusKind, N as stem, u as toContentKitError, Q as toOriginal, $ as toRotated, H as uniqueName, U as uploadRules, W as withMediaType, k as xhrTransport };
@@ -0,0 +1,15 @@
1
+ import { ContentKitUiAppearance } from '../appearance.js';
2
+ import { Translator } from '../i18n/messages.js';
3
+ import { EncodeProgress as Progress } from '../client/generated/wire.js';
4
+ export interface EncodeProgressProps {
5
+ /** `files[i].progress` from the read API; absent renders a plain "Processing video" state. */
6
+ progress?: Progress | null;
7
+ className?: string;
8
+ appearance?: ContentKitUiAppearance;
9
+ }
10
+ /** "~40 s left", "~3 min left", "~1 h 5 min left"; "almost done" under 5 s. */
11
+ export declare function formatRemaining(t: Translator["t"], seconds: number): string;
12
+ /** The status line: phase · segment n / N · time left, or the queue position. */
13
+ export declare function encodeLabel(t: Translator["t"], p: Progress | undefined, remaining?: number): string;
14
+ /** A pending video's encode: progress bar, phase, segments and time left. Motion is limited to the bar's width, off under reduced motion. */
15
+ export declare function EncodeProgress({ progress, className, appearance }: EncodeProgressProps): import('react').JSX.Element;
@@ -0,0 +1,49 @@
1
+ import { useMessages as e } from "../i18n/context.js";
2
+ import { ContentKitUiRoot as t } from "../scope.js";
3
+ import { useEncodeProgress as n } from "../react/upload.js";
4
+ import { Progress as r } from "../ui/progress.js";
5
+ import { jsx as i, jsxs as a } from "react/jsx-runtime";
6
+ import { cn as o } from "cn";
7
+ //#region src/components/encode-progress.tsx
8
+ function s(e, t) {
9
+ if (t < 5) return e("encode.almostDone");
10
+ if (t < 55) return e("encode.remainingSeconds", { seconds: t < 20 ? Math.ceil(t) : Math.ceil(t / 5) * 5 });
11
+ let n = Math.ceil(t / 60);
12
+ return n < 60 ? e("encode.remainingMinutes", { minutes: n }) : e("encode.remainingHours", {
13
+ hours: Math.floor(n / 60),
14
+ minutes: n % 60
15
+ });
16
+ }
17
+ function c(e, t, n) {
18
+ if (!t) return e("encode.processing");
19
+ if (t.stalled) return e("encode.stalled");
20
+ let r = t.stage && t.stage > 1 ? [e("encode.higherQualities")] : [];
21
+ if (t.phase === "queued") return [...r, t.queue_position ? e("encode.queuedPosition", { position: t.queue_position }) : e("encode.queued")].join(" · ");
22
+ let i = [...r, e(`encode.phase.${t.phase}`)];
23
+ return t.phase === "encoding" && t.segments_total && i.push(e("encode.segments", {
24
+ done: t.segments_done ?? 0,
25
+ total: t.segments_total
26
+ })), n === void 0 ? t.phase === "encoding" && i.push(e("encode.estimating")) : i.push(s(e, n)), i.join(" · ");
27
+ }
28
+ function l({ progress: s, className: l, appearance: u }) {
29
+ let { t: d } = e(), { progress: f, remaining: p } = n(s), m = c(d, f, p), h = f && f.percent > 0 ? Math.min(100, f.percent) : null;
30
+ return /* @__PURE__ */ a(t, {
31
+ appearance: u,
32
+ className: o("grid w-full gap-1.5 text-sm", l),
33
+ "data-ckui": "encode-progress",
34
+ "data-phase": f?.phase,
35
+ children: [/* @__PURE__ */ i("p", {
36
+ className: "text-muted-foreground tabular-nums",
37
+ children: m
38
+ }), /* @__PURE__ */ i(r, {
39
+ value: h,
40
+ "aria-label": d("encode.processing"),
41
+ "aria-valuetext": h === null ? m : `${Math.round(h)}% · ${m}`,
42
+ className: "[&_[data-slot=progress-indicator]]:motion-reduce:transition-none [&[data-indeterminate]_[data-slot=progress-track]]:motion-safe:animate-pulse"
43
+ })]
44
+ });
45
+ }
46
+ //#endregion
47
+ export { l as EncodeProgress, c as encodeLabel, s as formatRemaining };
48
+
49
+ //# sourceMappingURL=encode-progress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encode-progress.js","names":[],"sources":["../../src/components/encode-progress.tsx"],"sourcesContent":["import { cn } from \"cn\";\nimport type { ContentKitUiAppearance } from \"../appearance.js\";\nimport { useMessages } from \"../i18n/context.js\";\nimport type { Translator } from \"../i18n/messages.js\";\nimport { useEncodeProgress } from \"../react/upload.js\";\nimport { ContentKitUiRoot } from \"../scope.js\";\nimport type { EncodeProgress as Progress } from \"../client/generated/wire.js\";\nimport { Progress as Bar } from \"#ckui/ui/progress\";\n\nexport interface EncodeProgressProps {\n /** `files[i].progress` from the read API; absent renders a plain \"Processing video\" state. */\n progress?: Progress | null;\n className?: string;\n appearance?: ContentKitUiAppearance;\n}\n\n/** \"~40 s left\", \"~3 min left\", \"~1 h 5 min left\"; \"almost done\" under 5 s. */\nexport function formatRemaining(t: Translator[\"t\"], seconds: number): string {\n if (seconds < 5) return t(\"encode.almostDone\");\n if (seconds < 55) return t(\"encode.remainingSeconds\", { seconds: seconds < 20 ? Math.ceil(seconds) : Math.ceil(seconds / 5) * 5 });\n const minutes = Math.ceil(seconds / 60);\n if (minutes < 60) return t(\"encode.remainingMinutes\", { minutes });\n return t(\"encode.remainingHours\", { hours: Math.floor(minutes / 60), minutes: minutes % 60 });\n}\n\n/** The status line: phase · segment n / N · time left, or the queue position. */\nexport function encodeLabel(t: Translator[\"t\"], p: Progress | undefined, remaining?: number): string {\n if (!p) return t(\"encode.processing\");\n if (p.stalled) return t(\"encode.stalled\");\n // A second stage adds the rungs above 1080 to a video that already plays.\n const stage = p.stage && p.stage > 1 ? [t(\"encode.higherQualities\")] : [];\n if (p.phase === \"queued\")\n return [...stage, p.queue_position ? t(\"encode.queuedPosition\", { position: p.queue_position }) : t(\"encode.queued\")].join(\" · \");\n const parts = [...stage, t(`encode.phase.${p.phase}`)];\n if (p.phase === \"encoding\" && p.segments_total) parts.push(t(\"encode.segments\", { done: p.segments_done ?? 0, total: p.segments_total }));\n if (remaining !== undefined) parts.push(formatRemaining(t, remaining));\n else if (p.phase === \"encoding\") parts.push(t(\"encode.estimating\"));\n return parts.join(\" · \");\n}\n\n/** A pending video's encode: progress bar, phase, segments and time left. Motion is limited to the bar's width, off under reduced motion. */\nexport function EncodeProgress({ progress, className, appearance }: EncodeProgressProps) {\n const { t } = useMessages();\n const { progress: p, remaining } = useEncodeProgress(progress);\n const label = encodeLabel(t, p, remaining);\n const value = p && p.percent > 0 ? Math.min(100, p.percent) : null;\n return (\n <ContentKitUiRoot appearance={appearance} className={cn(\"grid w-full gap-1.5 text-sm\", className)} data-ckui=\"encode-progress\" data-phase={p?.phase}>\n <p className=\"text-muted-foreground tabular-nums\">\n {label}\n </p>\n <Bar\n value={value}\n aria-label={t(\"encode.processing\")}\n aria-valuetext={value === null ? label : `${Math.round(value)}% · ${label}`}\n className=\"[&_[data-slot=progress-indicator]]:motion-reduce:transition-none [&[data-indeterminate]_[data-slot=progress-track]]:motion-safe:animate-pulse\"\n />\n </ContentKitUiRoot>\n );\n}\n"],"mappings":";;;;;;;AAiBA,SAAgB,EAAgB,GAAoB,GAAyB;CAC3E,IAAI,IAAU,GAAG,OAAO,EAAE,mBAAmB;CAC7C,IAAI,IAAU,IAAI,OAAO,EAAE,2BAA2B,EAAE,SAAS,IAAU,KAAK,KAAK,KAAK,CAAO,IAAI,KAAK,KAAK,IAAU,CAAC,IAAI,EAAE,CAAC;CACjI,IAAM,IAAU,KAAK,KAAK,IAAU,EAAE;CAEtC,OADI,IAAU,KAAW,EAAE,2BAA2B,EAAE,WAAQ,CAAC,IAC1D,EAAE,yBAAyB;EAAE,OAAO,KAAK,MAAM,IAAU,EAAE;EAAG,SAAS,IAAU;CAAG,CAAC;AAC9F;AAGA,SAAgB,EAAY,GAAoB,GAAyB,GAA4B;CACnG,IAAI,CAAC,GAAG,OAAO,EAAE,mBAAmB;CACpC,IAAI,EAAE,SAAS,OAAO,EAAE,gBAAgB;CAExC,IAAM,IAAQ,EAAE,SAAS,EAAE,QAAQ,IAAI,CAAC,EAAE,wBAAwB,CAAC,IAAI,CAAC;CACxE,IAAI,EAAE,UAAU,UACd,OAAO,CAAC,GAAG,GAAO,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,UAAU,EAAE,eAAe,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,KAAK,KAAK;CAClI,IAAM,IAAQ,CAAC,GAAG,GAAO,EAAE,gBAAgB,EAAE,OAAO,CAAC;CAIrD,OAHI,EAAE,UAAU,cAAc,EAAE,kBAAgB,EAAM,KAAK,EAAE,mBAAmB;EAAE,MAAM,EAAE,iBAAiB;EAAG,OAAO,EAAE;CAAe,CAAC,CAAC,GACpI,MAAc,KAAA,IACT,EAAE,UAAU,cAAY,EAAM,KAAK,EAAE,mBAAmB,CAAC,IADrC,EAAM,KAAK,EAAgB,GAAG,CAAS,CAAC,GAE9D,EAAM,KAAK,KAAK;AACzB;AAGA,SAAgB,EAAe,EAAE,aAAU,cAAW,iBAAmC;CACvF,IAAM,EAAE,SAAM,EAAY,GACpB,EAAE,UAAU,GAAG,iBAAc,EAAkB,CAAQ,GACvD,IAAQ,EAAY,GAAG,GAAG,CAAS,GACnC,IAAQ,KAAK,EAAE,UAAU,IAAI,KAAK,IAAI,KAAK,EAAE,OAAO,IAAI;CAC9D,OACE,kBAAC,GAAD;EAA8B;EAAY,WAAW,EAAG,+BAA+B,CAAS;EAAG,aAAU;EAAkB,cAAY,GAAG;EAA9I,UAAA,CACE,kBAAC,KAAD;GAAG,WAAU;GACV,UAAA;EACA,CAAA,GACH,kBAAC,GAAD;GACS;GACP,cAAY,EAAE,mBAAmB;GACjC,kBAAgB,MAAU,OAAO,IAAQ,GAAG,KAAK,MAAM,CAAK,EAAE,MAAM;GACpE,WAAU;EACX,CAAA,CACe;;AAEtB"}
@@ -0,0 +1,29 @@
1
+ import { ContentKitClient } from '../client/client.js';
2
+ import { RefBody } from '../client/generated/wire.js';
3
+ import { HlsPlayerOptions } from '../react/gallery.js';
4
+ export interface HoverPreviewProps extends Pick<HlsPlayerOptions, "abr"> {
5
+ /** The video item. */
6
+ item: RefBody;
7
+ /** Its HLS folder (a read's `hls` entry). Default "hls/". */
8
+ dir?: string;
9
+ /** Seconds; the preview starts 10% in. */
10
+ duration?: number;
11
+ /** Where the preview starts, seconds; overrides the 10% default. */
12
+ start?: number;
13
+ /** The viewer may play it (free, or entitled). Default true. */
14
+ available?: boolean;
15
+ /** What is hovered (fine pointers) or watched for visibility (touch); default the preview's parent, the card. */
16
+ target?: HTMLElement | null;
17
+ /** Previews on; default the provider's `inlinePreview`. */
18
+ enabled?: boolean;
19
+ className?: string;
20
+ client?: ContentKitClient;
21
+ }
22
+ /**
23
+ * A card's muted inline preview: the item's real HLS stream through the
24
+ * client (its base and playlist auth) at the lowest rendition, fading in over
25
+ * the card's thumbnail on hover, or while it is the most visible card on
26
+ * touch screens. One plays page-wide; none with reduced motion or Save-Data.
27
+ * Place it inside the card, which must be positioned.
28
+ */
29
+ export declare function HoverPreview({ item, dir, duration, start, available, target, enabled, abr, className, client: own }: HoverPreviewProps): import('react').JSX.Element;
@@ -0,0 +1,49 @@
1
+ import { useInlinePreview as e } from "../react/inline-preview.js";
2
+ import { useContentKitClient as t } from "../react/context.js";
3
+ import { useHlsPlayer as n } from "../react/gallery.js";
4
+ import { useCallback as r, useState as i } from "react";
5
+ import { jsx as a } from "react/jsx-runtime";
6
+ //#region src/components/hover-preview.tsx
7
+ function o({ item: o, dir: s = "hls/", duration: c, start: l, available: u = !0, target: d, enabled: f, abr: p, className: m, client: h }) {
8
+ let { media: g } = t(h), [_, v] = i(null), y = n({
9
+ src: `${g.hlsBase(o, s)}master.m3u8`,
10
+ xhrSetup: g.xhrSetup,
11
+ abr: p,
12
+ qualityKey: null
13
+ }), b = c ?? 0, x = Math.max(0, l ?? (b > 1 ? Math.min(b * .1, b - 1) : 0));
14
+ e({
15
+ setting: f,
16
+ available: u,
17
+ target: d ?? _?.parentElement ?? null,
18
+ start: () => y.preview(x),
19
+ stop: y.unload
20
+ });
21
+ let S = y.ref, C = r((e) => {
22
+ S(e), v(e);
23
+ }, [S]);
24
+ return /* @__PURE__ */ a("video", {
25
+ ref: C,
26
+ muted: !0,
27
+ playsInline: !0,
28
+ preload: "none",
29
+ "aria-hidden": !0,
30
+ tabIndex: -1,
31
+ className: m,
32
+ style: {
33
+ position: "absolute",
34
+ inset: 0,
35
+ width: "100%",
36
+ height: "100%",
37
+ objectFit: "cover",
38
+ pointerEvents: "none",
39
+ opacity: y.previewing && y.status === "playing" ? 1 : 0,
40
+ transition: "opacity 200ms"
41
+ },
42
+ "data-ckui": "hover-preview",
43
+ "data-playing": y.previewing && y.status === "playing" ? "" : void 0
44
+ });
45
+ }
46
+ //#endregion
47
+ export { o as HoverPreview };
48
+
49
+ //# sourceMappingURL=hover-preview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hover-preview.js","names":[],"sources":["../../src/components/hover-preview.tsx"],"sourcesContent":["import { useCallback, useState } from \"react\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport type { RefBody } from \"../client/generated/wire.js\";\nimport { useContentKitClient } from \"../react/context.js\";\nimport { useHlsPlayer, type HlsPlayerOptions } from \"../react/gallery.js\";\nimport { useInlinePreview } from \"../react/inline-preview.js\";\n\nexport interface HoverPreviewProps extends Pick<HlsPlayerOptions, \"abr\"> {\n /** The video item. */\n item: RefBody;\n /** Its HLS folder (a read's `hls` entry). Default \"hls/\". */\n dir?: string;\n /** Seconds; the preview starts 10% in. */\n duration?: number;\n /** Where the preview starts, seconds; overrides the 10% default. */\n start?: number;\n /** The viewer may play it (free, or entitled). Default true. */\n available?: boolean;\n /** What is hovered (fine pointers) or watched for visibility (touch); default the preview's parent, the card. */\n target?: HTMLElement | null;\n /** Previews on; default the provider's `inlinePreview`. */\n enabled?: boolean;\n className?: string;\n client?: ContentKitClient;\n}\n\n/**\n * A card's muted inline preview: the item's real HLS stream through the\n * client (its base and playlist auth) at the lowest rendition, fading in over\n * the card's thumbnail on hover, or while it is the most visible card on\n * touch screens. One plays page-wide; none with reduced motion or Save-Data.\n * Place it inside the card, which must be positioned.\n */\nexport function HoverPreview({ item, dir = \"hls/\", duration, start, available = true, target, enabled, abr, className, client: own }: HoverPreviewProps) {\n const { media } = useContentKitClient(own);\n const [el, setEl] = useState<HTMLVideoElement | null>(null);\n const player = useHlsPlayer({ src: `${media.hlsBase(item, dir)}master.m3u8`, xhrSetup: media.xhrSetup, abr, qualityKey: null });\n const d = duration ?? 0;\n const at = Math.max(0, start ?? (d > 1 ? Math.min(d * 0.1, d - 1) : 0));\n useInlinePreview({ setting: enabled, available, target: target ?? el?.parentElement ?? null, start: () => player.preview(at), stop: player.unload });\n const attach = player.ref;\n const ref = useCallback(\n (v: HTMLVideoElement | null) => {\n attach(v);\n setEl(v);\n },\n [attach],\n );\n return (\n <video\n ref={ref}\n muted\n playsInline\n preload=\"none\"\n aria-hidden\n tabIndex={-1}\n className={className}\n style={{\n position: \"absolute\",\n inset: 0,\n width: \"100%\",\n height: \"100%\",\n objectFit: \"cover\",\n pointerEvents: \"none\",\n opacity: player.previewing && player.status === \"playing\" ? 1 : 0,\n transition: \"opacity 200ms\",\n }}\n data-ckui=\"hover-preview\"\n data-playing={player.previewing && player.status === \"playing\" ? \"\" : undefined}\n />\n );\n}\n"],"mappings":";;;;;;AAiCA,SAAgB,EAAa,EAAE,SAAM,SAAM,QAAQ,aAAU,UAAO,eAAY,IAAM,WAAQ,YAAS,QAAK,cAAW,QAAQ,KAA0B;CACvJ,IAAM,EAAE,aAAU,EAAoB,CAAG,GACnC,CAAC,GAAI,KAAS,EAAkC,IAAI,GACpD,IAAS,EAAa;EAAE,KAAK,GAAG,EAAM,QAAQ,GAAM,CAAG,EAAE;EAAc,UAAU,EAAM;EAAU;EAAK,YAAY;CAAK,CAAC,GACxH,IAAI,KAAY,GAChB,IAAK,KAAK,IAAI,GAAG,MAAU,IAAI,IAAI,KAAK,IAAI,IAAI,IAAK,IAAI,CAAC,IAAI,EAAE;CACtE,EAAiB;EAAE,SAAS;EAAS;EAAW,QAAQ,KAAU,GAAI,iBAAiB;EAAM,aAAa,EAAO,QAAQ,CAAE;EAAG,MAAM,EAAO;CAAO,CAAC;CACnJ,IAAM,IAAS,EAAO,KAChB,IAAM,GACT,MAA+B;EAE9B,AADA,EAAO,CAAC,GACR,EAAM,CAAC;CACT,GACA,CAAC,CAAM,CACT;CACA,OACE,kBAAC,SAAD;EACO;EACL,OAAA;EACA,aAAA;EACA,SAAQ;EACR,eAAA;EACA,UAAU;EACC;EACX,OAAO;GACL,UAAU;GACV,OAAO;GACP,OAAO;GACP,QAAQ;GACR,WAAW;GACX,eAAe;GACf,SAAS,EAAO,cAAc,EAAO,WAAW,YAAY,IAAI;GAChE,YAAY;EACd;EACA,aAAU;EACV,gBAAc,EAAO,cAAc,EAAO,WAAW,YAAY,KAAK,KAAA;CACvE,CAAA;AAEL"}
@@ -0,0 +1,48 @@
1
+ import { AspectRatio } from '../client/aspect.js';
2
+ import { ReactNode } from 'react';
3
+ import { Progress as UploadProgress } from '../client/media/client.js';
4
+ import { CropSource } from '../client/image.js';
5
+ import { Edit } from '../client/generated/wire.js';
6
+ export interface ImageCropDialogProps {
7
+ open: boolean;
8
+ /** Closing (Esc, the close button, Cancel) reports false. */
9
+ onOpenChange: (open: boolean) => void;
10
+ /** The image and its EXIF-oriented original size; edits are in those pixels. */
11
+ source: CropSource | null;
12
+ /** The output's "W:H" (after rotation); "" keeps the image's own shape. */
13
+ aspect: AspectRatio;
14
+ /**
15
+ * Shapes to choose from, "" being the original's (e.g. ["", "1:1", "4:5",
16
+ * "16:9"]). The chooser starts at aspect when listed, else the first.
17
+ */
18
+ aspects?: readonly AspectRatio[];
19
+ /** A small preview of the result beside the controls. Default true. */
20
+ preview?: boolean;
21
+ /** Circular mask (avatars); the saved crop is still the square around it. */
22
+ round?: boolean;
23
+ /** Offer 90° rotation. Default true. */
24
+ rotatable?: boolean;
25
+ /** Starting edit (re-crop); default centred at aspect, unrotated. */
26
+ initialEdit?: Edit | null;
27
+ /** Called with the edit on open and whenever its value changes (safe to pass a state setter). */
28
+ onEditChange?: (edit: Edit | null) => void;
29
+ /** The chosen edit; null is the full centred crop, unrotated. */
30
+ onConfirm: (edit: Edit | null) => void;
31
+ /** Warns when the output is narrower than this many source pixels. */
32
+ targetWidth?: number;
33
+ /** The narrowest edit the server accepts (the preset's Image.MinWidth): zoom stops there, and a smaller image cannot be confirmed. */
34
+ minWidth?: number;
35
+ title?: ReactNode;
36
+ description?: ReactNode;
37
+ confirmLabel?: ReactNode;
38
+ /** A save is running: controls lock and progress shows. */
39
+ busy?: boolean;
40
+ progress?: UploadProgress;
41
+ /** The worker is rendering the outputs (indeterminate progress). */
42
+ rendering?: boolean;
43
+ /** Shown above the footer, e.g. a mapped ContentKitError. */
44
+ error?: ReactNode;
45
+ className?: string;
46
+ }
47
+ /** Pan, zoom (slider, wheel, pinch, keyboard), rotate and confirm a fixed-aspect edit. */
48
+ export declare function ImageCropDialog(p: ImageCropDialogProps): import('react').JSX.Element;