@codingfactory/mediables-vue 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (367) hide show
  1. package/dist/PixiFrameExporter-BTU38EVl.cjs +2 -0
  2. package/dist/PixiFrameExporter-BTU38EVl.cjs.map +1 -0
  3. package/dist/PixiFrameExporter-Bb3QNWP-.js +199 -0
  4. package/dist/PixiFrameExporter-Bb3QNWP-.js.map +1 -0
  5. package/dist/adapters/MediablesAdapter.d.ts +19 -0
  6. package/dist/adapters/SpatieAdapter.d.ts +18 -0
  7. package/dist/adapters/index.d.ts +18 -0
  8. package/dist/components/AdminMediaBrowser.vue.d.ts +11 -0
  9. package/dist/components/AdminMediaBrowserExample.vue.d.ts +2 -0
  10. package/dist/components/AdminMediaBulkActionsToolbar.vue.d.ts +2 -0
  11. package/dist/components/AdminMediaGrid.vue.d.ts +17 -0
  12. package/dist/components/AdminMediaListItem.vue.d.ts +10 -0
  13. package/dist/components/AdminMediaManager.vue.d.ts +25 -0
  14. package/dist/components/AdminMediaUploader.vue.d.ts +11 -0
  15. package/dist/components/AlbumBrowser.vue.d.ts +17 -0
  16. package/dist/components/AlbumManager.vue.d.ts +16 -0
  17. package/dist/components/AlbumMediaGrid.vue.d.ts +28 -0
  18. package/dist/components/AlbumTree.vue.d.ts +35 -0
  19. package/dist/components/BulkActionsToolbar.vue.d.ts +2 -0
  20. package/dist/components/ConversionProgressIndicator.vue.d.ts +2 -0
  21. package/dist/components/Editor.vue.d.ts +29 -0
  22. package/dist/components/ExampleGridAndList.vue.d.ts +2 -0
  23. package/dist/components/ExampleUsage.vue.d.ts +2 -0
  24. package/dist/components/Grid.vue.d.ts +2 -0
  25. package/dist/components/ImageEditor/ImageEditor.vue.d.ts +3 -0
  26. package/dist/components/ImageEditorModal.vue.d.ts +16 -0
  27. package/dist/components/ImagePicker.vue.d.ts +32 -0
  28. package/dist/components/ImageUploadZone.vue.d.ts +7 -0
  29. package/dist/components/Item.vue.d.ts +2 -0
  30. package/dist/components/Library.vue.d.ts +2 -0
  31. package/dist/components/ManagedMediaGallery.vue.d.ts +12 -0
  32. package/dist/components/MediaAttacher.vue.d.ts +21 -0
  33. package/dist/components/MediaBrowser.vue.d.ts +2 -0
  34. package/dist/components/MediaCard.vue.d.ts +2 -0
  35. package/dist/components/MediaFilters.vue.d.ts +2 -0
  36. package/dist/components/MediaGrid.vue.d.ts +31 -0
  37. package/dist/components/MediaInfoEditor.vue.d.ts +7 -0
  38. package/dist/components/MediaManager.vue.d.ts +2 -0
  39. package/dist/components/MediaUploadWithProgress.vue.d.ts +2 -0
  40. package/dist/components/MediaUploader.vue.d.ts +2 -0
  41. package/dist/components/MediaWorkspace.vue.d.ts +19 -0
  42. package/dist/components/Modal.vue.d.ts +2 -0
  43. package/dist/components/ModelMediaManager.vue.d.ts +80 -0
  44. package/dist/components/Pagination.vue.d.ts +2 -0
  45. package/dist/components/Search.vue.d.ts +2 -0
  46. package/dist/components/VideoEditorSimple.vue.d.ts +2 -0
  47. package/dist/components/VideoExportPanel.vue.d.ts +2 -0
  48. package/dist/components/VideoTimeline.vue.d.ts +2 -0
  49. package/dist/components/VideoTimelineSimple.vue.d.ts +2 -0
  50. package/dist/components/VideoToolsPanel.vue.d.ts +2 -0
  51. package/dist/components/albums/AlbumTreeNode.vue.d.ts +23 -0
  52. package/dist/components/attachment/MediaAttachment.vue.d.ts +23 -0
  53. package/dist/components/attachment/index.d.ts +4 -0
  54. package/dist/components/collection/MediaCollection.vue.d.ts +27 -0
  55. package/dist/components/collection/MediaCollectionDropzone.vue.d.ts +18 -0
  56. package/dist/components/collection/MediaCollectionItem.vue.d.ts +2 -0
  57. package/dist/components/collection/index.d.ts +6 -0
  58. package/dist/components/form/MediaHiddenFields.vue.d.ts +2 -0
  59. package/dist/components/form/index.d.ts +4 -0
  60. package/dist/components/image/ImageEditor.vue.d.ts +2 -0
  61. package/dist/components/image/ImageItem.vue.d.ts +2 -0
  62. package/dist/components/renderless/MediaAttachmentProvider.vue.d.ts +12 -0
  63. package/dist/components/renderless/MediaCollectionProvider.vue.d.ts +12 -0
  64. package/dist/components/renderless/index.d.ts +7 -0
  65. package/dist/components/timeline/TimeRuler.vue.d.ts +2 -0
  66. package/dist/components/timeline/VideoTrack.vue.d.ts +2 -0
  67. package/dist/components/tools/VideoFiltersPanel.vue.d.ts +7 -0
  68. package/dist/components/tools/VideoTextPanel.vue.d.ts +2 -0
  69. package/dist/components/video/AudioTrackManager.vue.d.ts +2 -0
  70. package/dist/components/video/EditorControls.vue.d.ts +2 -0
  71. package/dist/components/video/ExportPanel.vue.d.ts +2 -0
  72. package/dist/components/video/FilterSelector.vue.d.ts +2 -0
  73. package/dist/components/video/LiveStreamManager.vue.d.ts +2 -0
  74. package/dist/components/video/StreamCredentials.vue.d.ts +2 -0
  75. package/dist/components/video/StreamStatus.vue.d.ts +2 -0
  76. package/dist/components/video/TextOverlayPanel.vue.d.ts +2 -0
  77. package/dist/components/video/ThumbnailPicker.vue.d.ts +2 -0
  78. package/dist/components/video/TimelineClip.vue.d.ts +2 -0
  79. package/dist/components/video/TimelineControls.vue.d.ts +2 -0
  80. package/dist/components/video/TransitionSelector.vue.d.ts +2 -0
  81. package/dist/components/video/VideoControls.vue.d.ts +2 -0
  82. package/dist/components/video/VideoEditor.vue.d.ts +8 -0
  83. package/dist/components/video/VideoEditorDialog.vue.d.ts +12 -0
  84. package/dist/components/video/VideoFilterCarousel.vue.d.ts +2 -0
  85. package/dist/components/video/VideoFilterPreview.vue.d.ts +18 -0
  86. package/dist/components/video/VideoPlayer.vue.d.ts +2 -0
  87. package/dist/components/video/VideoPreview.vue.d.ts +3 -0
  88. package/dist/components/video/VideoPreviewCSS.vue.d.ts +2 -0
  89. package/dist/components/video/VideoPreviewEngine.vue.d.ts +3 -0
  90. package/dist/components/video/VideoTimeline.vue.d.ts +2 -0
  91. package/dist/components/video/VideoUploadProgress.vue.d.ts +2 -0
  92. package/dist/components/video/VideoUploader.vue.d.ts +29 -0
  93. package/dist/components/video/index.d.ts +19 -0
  94. package/dist/composables/useAccordion.d.ts +138 -0
  95. package/dist/composables/useAlbumDragDrop.d.ts +24 -0
  96. package/dist/composables/useAlbums.d.ts +17 -0
  97. package/dist/composables/useFloatingPills.d.ts +111 -0
  98. package/dist/composables/useHaptic.d.ts +10 -0
  99. package/dist/composables/useImageEditorModal.d.ts +277 -0
  100. package/dist/composables/useLiveStream.d.ts +66 -0
  101. package/dist/composables/useMediaAttachment.d.ts +105 -0
  102. package/dist/composables/useMediaCollection.d.ts +122 -0
  103. package/dist/composables/useMediaConversionProgress.d.ts +31 -0
  104. package/dist/composables/useMediaDragSort.d.ts +56 -0
  105. package/dist/composables/useMediaSelection.d.ts +27 -0
  106. package/dist/composables/useMediaUploadQueue.d.ts +61 -0
  107. package/dist/composables/useMediaValidation.d.ts +59 -0
  108. package/dist/composables/useRadialMenu.d.ts +116 -0
  109. package/dist/composables/useSanctumClient.d.ts +31 -0
  110. package/dist/composables/useTheme.d.ts +7 -0
  111. package/dist/composables/useToast.d.ts +25 -0
  112. package/dist/composables/useVideoEditor.d.ts +127 -0
  113. package/dist/composables/useVideoFilters.d.ts +176 -0
  114. package/dist/composables/useVideoPlayer.d.ts +50 -0
  115. package/dist/composables/useVideoUpload.d.ts +134 -0
  116. package/dist/filters/controlMapping.d.ts +31 -0
  117. package/dist/filters/css-registry.d.ts +83 -0
  118. package/dist/filters/definitions/adjustment.d.ts +2 -0
  119. package/dist/filters/definitions/adjustmentAdvanced.d.ts +2 -0
  120. package/dist/filters/definitions/advancedBloom.d.ts +2 -0
  121. package/dist/filters/definitions/alpha.d.ts +2 -0
  122. package/dist/filters/definitions/ascii.d.ts +2 -0
  123. package/dist/filters/definitions/backdropBlur.d.ts +2 -0
  124. package/dist/filters/definitions/bevel.d.ts +2 -0
  125. package/dist/filters/definitions/bloom.d.ts +2 -0
  126. package/dist/filters/definitions/blur.d.ts +2 -0
  127. package/dist/filters/definitions/bulgePinch.d.ts +2 -0
  128. package/dist/filters/definitions/colorGradient.d.ts +2 -0
  129. package/dist/filters/definitions/colorMap.d.ts +2 -0
  130. package/dist/filters/definitions/colorMatrix.d.ts +2 -0
  131. package/dist/filters/definitions/colorOverlay.d.ts +2 -0
  132. package/dist/filters/definitions/colorReplace.d.ts +2 -0
  133. package/dist/filters/definitions/convolution.d.ts +2 -0
  134. package/dist/filters/definitions/crossHatch.d.ts +2 -0
  135. package/dist/filters/definitions/crt.d.ts +2 -0
  136. package/dist/filters/definitions/displacement.d.ts +2 -0
  137. package/dist/filters/definitions/dot.d.ts +2 -0
  138. package/dist/filters/definitions/dropShadow.d.ts +2 -0
  139. package/dist/filters/definitions/emboss.d.ts +2 -0
  140. package/dist/filters/definitions/glitch.d.ts +2 -0
  141. package/dist/filters/definitions/glow.d.ts +2 -0
  142. package/dist/filters/definitions/godray.d.ts +2 -0
  143. package/dist/filters/definitions/grayscale.d.ts +2 -0
  144. package/dist/filters/definitions/hslAdjustment.d.ts +2 -0
  145. package/dist/filters/definitions/kawaseBlur.d.ts +2 -0
  146. package/dist/filters/definitions/lightmap.d.ts +2 -0
  147. package/dist/filters/definitions/motionBlur.d.ts +2 -0
  148. package/dist/filters/definitions/multiColorReplace.d.ts +2 -0
  149. package/dist/filters/definitions/noise.d.ts +2 -0
  150. package/dist/filters/definitions/oldFilm.d.ts +2 -0
  151. package/dist/filters/definitions/outline.d.ts +2 -0
  152. package/dist/filters/definitions/pixelate.d.ts +2 -0
  153. package/dist/filters/definitions/radialBlur.d.ts +2 -0
  154. package/dist/filters/definitions/reflection.d.ts +2 -0
  155. package/dist/filters/definitions/rgbSplit.d.ts +2 -0
  156. package/dist/filters/definitions/shockwave.d.ts +2 -0
  157. package/dist/filters/definitions/simplexNoise.d.ts +2 -0
  158. package/dist/filters/definitions/tiltShift.d.ts +2 -0
  159. package/dist/filters/definitions/twist.d.ts +2 -0
  160. package/dist/filters/definitions/vignette.d.ts +2 -0
  161. package/dist/filters/definitions/zoomBlur.d.ts +2 -0
  162. package/dist/filters/factory.d.ts +38 -0
  163. package/dist/filters/filters/controlMapping.d.ts +31 -0
  164. package/dist/filters/filters/definitions/adjustment.d.ts +2 -0
  165. package/dist/filters/filters/definitions/adjustmentAdvanced.d.ts +2 -0
  166. package/dist/filters/filters/definitions/advancedBloom.d.ts +2 -0
  167. package/dist/filters/filters/definitions/alpha.d.ts +2 -0
  168. package/dist/filters/filters/definitions/ascii.d.ts +2 -0
  169. package/dist/filters/filters/definitions/backdropBlur.d.ts +2 -0
  170. package/dist/filters/filters/definitions/bevel.d.ts +2 -0
  171. package/dist/filters/filters/definitions/bloom.d.ts +2 -0
  172. package/dist/filters/filters/definitions/blur.d.ts +2 -0
  173. package/dist/filters/filters/definitions/bulgePinch.d.ts +2 -0
  174. package/dist/filters/filters/definitions/colorGradient.d.ts +2 -0
  175. package/dist/filters/filters/definitions/colorMap.d.ts +2 -0
  176. package/dist/filters/filters/definitions/colorMatrix.d.ts +2 -0
  177. package/dist/filters/filters/definitions/colorOverlay.d.ts +2 -0
  178. package/dist/filters/filters/definitions/colorReplace.d.ts +2 -0
  179. package/dist/filters/filters/definitions/convolution.d.ts +2 -0
  180. package/dist/filters/filters/definitions/crossHatch.d.ts +2 -0
  181. package/dist/filters/filters/definitions/crt.d.ts +2 -0
  182. package/dist/filters/filters/definitions/displacement.d.ts +2 -0
  183. package/dist/filters/filters/definitions/dot.d.ts +2 -0
  184. package/dist/filters/filters/definitions/dropShadow.d.ts +2 -0
  185. package/dist/filters/filters/definitions/emboss.d.ts +2 -0
  186. package/dist/filters/filters/definitions/glitch.d.ts +2 -0
  187. package/dist/filters/filters/definitions/glow.d.ts +2 -0
  188. package/dist/filters/filters/definitions/godray.d.ts +2 -0
  189. package/dist/filters/filters/definitions/grayscale.d.ts +2 -0
  190. package/dist/filters/filters/definitions/hslAdjustment.d.ts +2 -0
  191. package/dist/filters/filters/definitions/kawaseBlur.d.ts +2 -0
  192. package/dist/filters/filters/definitions/lightmap.d.ts +2 -0
  193. package/dist/filters/filters/definitions/motionBlur.d.ts +2 -0
  194. package/dist/filters/filters/definitions/multiColorReplace.d.ts +2 -0
  195. package/dist/filters/filters/definitions/noise.d.ts +2 -0
  196. package/dist/filters/filters/definitions/oldFilm.d.ts +2 -0
  197. package/dist/filters/filters/definitions/outline.d.ts +2 -0
  198. package/dist/filters/filters/definitions/pixelate.d.ts +2 -0
  199. package/dist/filters/filters/definitions/radialBlur.d.ts +2 -0
  200. package/dist/filters/filters/definitions/reflection.d.ts +2 -0
  201. package/dist/filters/filters/definitions/rgbSplit.d.ts +2 -0
  202. package/dist/filters/filters/definitions/shockwave.d.ts +2 -0
  203. package/dist/filters/filters/definitions/simplexNoise.d.ts +2 -0
  204. package/dist/filters/filters/definitions/tiltShift.d.ts +2 -0
  205. package/dist/filters/filters/definitions/twist.d.ts +2 -0
  206. package/dist/filters/filters/definitions/vignette.d.ts +2 -0
  207. package/dist/filters/filters/definitions/zoomBlur.d.ts +2 -0
  208. package/dist/filters/filters/factory.d.ts +36 -0
  209. package/dist/filters/filters/index.d.ts +93 -0
  210. package/dist/filters/filters/registry.d.ts +89 -0
  211. package/dist/filters/index.d.ts +93 -0
  212. package/dist/filters/registry.d.ts +89 -0
  213. package/dist/filters/video-compatible.d.ts +77 -0
  214. package/dist/filters/video-css-filters.d.ts +153 -0
  215. package/dist/index-6yUGA--H.cjs +42 -0
  216. package/dist/index-6yUGA--H.cjs.map +1 -0
  217. package/dist/index-CcGWfCCV.js +7799 -0
  218. package/dist/index-CcGWfCCV.js.map +1 -0
  219. package/dist/index-DTUgsw7J.cjs +76 -0
  220. package/dist/index-DTUgsw7J.cjs.map +1 -0
  221. package/dist/index-VrUG0lmk.js +28655 -0
  222. package/dist/index-VrUG0lmk.js.map +1 -0
  223. package/dist/index.d.ts +62 -0
  224. package/dist/js/workers/material-color-extractor.js +215 -0
  225. package/dist/mediables-vanilla.cjs +2 -0
  226. package/dist/mediables-vanilla.cjs.map +1 -0
  227. package/dist/mediables-vanilla.mjs +12 -0
  228. package/dist/mediables-vanilla.mjs.map +1 -0
  229. package/dist/mediables-vue.cjs +2 -0
  230. package/dist/mediables-vue.cjs.map +1 -0
  231. package/dist/mediables-vue.mjs +67 -0
  232. package/dist/mediables-vue.mjs.map +1 -0
  233. package/dist/render-page/assets/index-hBfvGPpt.js +48933 -0
  234. package/dist/render-page/index.html +18 -0
  235. package/dist/services/VideoJobClient.d.ts +79 -0
  236. package/dist/stores/albumStore.d.ts +4 -0
  237. package/dist/stores/mediaVariantStore.d.ts +1 -0
  238. package/dist/stores/useAdminMediaStore.d.ts +16 -0
  239. package/dist/stores/useMediaStore.d.ts +25 -0
  240. package/dist/stores/useVideoStore.d.ts +21 -0
  241. package/dist/stores/variantPollStore.d.ts +5 -0
  242. package/dist/stores/video.d.ts +1 -0
  243. package/dist/style.css +1 -0
  244. package/dist/types/adapter.d.ts +181 -0
  245. package/dist/types/album.d.ts +28 -0
  246. package/dist/types/api.d.ts +88 -0
  247. package/dist/types/collection.d.ts +306 -0
  248. package/dist/types/editor.d.ts +172 -0
  249. package/dist/types/image.d.ts +210 -0
  250. package/dist/types/index.d.ts +5 -0
  251. package/dist/types/media.d.ts +107 -0
  252. package/dist/types/types/address.d.ts +66 -0
  253. package/dist/types/types/admin/intelligent-po.d.ts +47 -0
  254. package/dist/types/types/admin/products/index.d.ts +17 -0
  255. package/dist/types/types/admin/purchase-order.d.ts +50 -0
  256. package/dist/types/types/admin/receipt.d.ts +86 -0
  257. package/dist/types/types/admin/vendor.d.ts +61 -0
  258. package/dist/types/types/ai.d.ts +63 -0
  259. package/dist/types/types/aiActions.d.ts +42 -0
  260. package/dist/types/types/aiDesigner.d.ts +77 -0
  261. package/dist/types/types/api-errors.d.ts +6 -0
  262. package/dist/types/types/api.d.ts +109 -0
  263. package/dist/types/types/bundle.d.ts +131 -0
  264. package/dist/types/types/bundles/analytics.d.ts +64 -0
  265. package/dist/types/types/bundles.d.ts +108 -0
  266. package/dist/types/types/cart.d.ts +81 -0
  267. package/dist/types/types/checkout.d.ts +40 -0
  268. package/dist/types/types/component-config.d.ts +26 -0
  269. package/dist/types/types/components.d.ts +32 -0
  270. package/dist/types/types/content.d.ts +138 -0
  271. package/dist/types/types/coupon.d.ts +32 -0
  272. package/dist/types/types/customer-product-history.d.ts +210 -0
  273. package/dist/types/types/drag-contracts.d.ts +40 -0
  274. package/dist/types/types/drag-drop.d.ts +19 -0
  275. package/dist/types/types/editor.d.ts +127 -0
  276. package/dist/types/types/errors.d.ts +36 -0
  277. package/dist/types/types/feedback.d.ts +122 -0
  278. package/dist/types/types/image.d.ts +210 -0
  279. package/dist/types/types/index.d.ts +62 -0
  280. package/dist/types/types/instagram.d.ts +86 -0
  281. package/dist/types/types/ionic-components.d.ts +152 -0
  282. package/dist/types/types/layout.d.ts +127 -0
  283. package/dist/types/types/media-gateway.d.ts +34 -0
  284. package/dist/types/types/media.d.ts +178 -0
  285. package/dist/types/types/notifications.d.ts +123 -0
  286. package/dist/types/types/order-management.d.ts +245 -0
  287. package/dist/types/types/pageBuilder/block.d.ts +34 -0
  288. package/dist/types/types/pageBuilder/blocks.d.ts +82 -0
  289. package/dist/types/types/pageBuilder/cache.d.ts +33 -0
  290. package/dist/types/types/pageBuilder/editor.d.ts +15 -0
  291. package/dist/types/types/pageBuilder/field.d.ts +11 -0
  292. package/dist/types/types/pageBuilder/index.d.ts +24 -0
  293. package/dist/types/types/pageBuilder/revisions.d.ts +40 -0
  294. package/dist/types/types/pageBuilder/templates.d.ts +62 -0
  295. package/dist/types/types/pattern.d.ts +40 -0
  296. package/dist/types/types/payment.d.ts +21 -0
  297. package/dist/types/types/payments.d.ts +10 -0
  298. package/dist/types/types/pipeline.d.ts +12 -0
  299. package/dist/types/types/pixi/filter-args.d.ts +274 -0
  300. package/dist/types/types/pixi/filters-extended.d.ts +157 -0
  301. package/dist/types/types/pixi/filters.d.ts +38 -0
  302. package/dist/types/types/preview.d.ts +36 -0
  303. package/dist/types/types/pricing.d.ts +31 -0
  304. package/dist/types/types/quickbooks.d.ts +43 -0
  305. package/dist/types/types/receipt.d.ts +121 -0
  306. package/dist/types/types/rewards.d.ts +110 -0
  307. package/dist/types/types/saved-cart.d.ts +51 -0
  308. package/dist/types/types/settings.d.ts +63 -0
  309. package/dist/types/types/shipment.d.ts +62 -0
  310. package/dist/types/types/shipping.d.ts +98 -0
  311. package/dist/types/types/sidebar-variations.d.ts +226 -0
  312. package/dist/types/types/slots.d.ts +2 -0
  313. package/dist/types/types/specification-types.d.ts +70 -0
  314. package/dist/types/types/specifications.d.ts +163 -0
  315. package/dist/types/types/store.d.ts +64 -0
  316. package/dist/types/types/template.d.ts +8 -0
  317. package/dist/types/types/user.d.ts +47 -0
  318. package/dist/types/types/variant-groups.d.ts +158 -0
  319. package/dist/types/types/wishlist.d.ts +73 -0
  320. package/dist/types/types/workflow-wizard.d.ts +12 -0
  321. package/dist/types/video.d.ts +449 -0
  322. package/dist/utils/category-tree-constants.d.ts +42 -0
  323. package/dist/utils/cookies.d.ts +3 -0
  324. package/dist/utils/crypto-polyfill.d.ts +4 -0
  325. package/dist/utils/datetime.d.ts +43 -0
  326. package/dist/utils/debounce.d.ts +10 -0
  327. package/dist/utils/debugConsole.d.ts +69 -0
  328. package/dist/utils/editor/argHelpers.d.ts +6 -0
  329. package/dist/utils/formatters.d.ts +105 -0
  330. package/dist/utils/isPresignedAwsUrl.d.ts +67 -0
  331. package/dist/utils/media-helpers.d.ts +34 -0
  332. package/dist/utils/normalisePricing.d.ts +11 -0
  333. package/dist/utils/recipe-generator.d.ts +34 -0
  334. package/dist/utils/string.d.ts +29 -0
  335. package/dist/utils/unwrapApiResponse.d.ts +5 -0
  336. package/dist/utils/uuid.d.ts +30 -0
  337. package/dist/utils/validators.d.ts +28 -0
  338. package/dist/utils/video-export.d.ts +60 -0
  339. package/dist/v3-ionic-1-demo.html +440 -0
  340. package/dist/video-engine/VideoEngine.d.ts +267 -0
  341. package/dist/video-engine/adapters/AudioManager.d.ts +106 -0
  342. package/dist/video-engine/adapters/CSSFilterAdapter.d.ts +106 -0
  343. package/dist/video-engine/adapters/ExportManager.d.ts +88 -0
  344. package/dist/video-engine/adapters/FilterBridge.d.ts +96 -0
  345. package/dist/video-engine/adapters/MediablesCompositionAdapter.d.ts +56 -0
  346. package/dist/video-engine/adapters/PixiFrameExporter.d.ts +52 -0
  347. package/dist/video-engine/adapters/RenderQueue.d.ts +119 -0
  348. package/dist/video-engine/adapters/TextOverlayManager.d.ts +93 -0
  349. package/dist/video-engine/adapters/TimelineAdapter.d.ts +58 -0
  350. package/dist/video-engine/adapters/TransitionManager.d.ts +76 -0
  351. package/dist/video-engine/adapters/WebCodecsExport.d.ts +36 -0
  352. package/dist/video-engine/compositions/examples/example.d.ts +2 -0
  353. package/dist/video-engine/filters/CSSFilterSystem.d.ts +213 -0
  354. package/dist/video-engine/index.d.ts +14 -0
  355. package/dist/video-engine/presets/ExportPresets.d.ts +70 -0
  356. package/dist/video-engine/types/index.d.ts +96 -0
  357. package/dist/video-engine/types.d.ts +1 -0
  358. package/dist/video-engine/utils/EventEmitter.d.ts +12 -0
  359. package/dist/video-engine/utils/MediaSourceResolver.d.ts +9 -0
  360. package/dist/video-engine/utils/error-reporter.d.ts +159 -0
  361. package/dist/video-engine/utils/keyboard-shortcuts.d.ts +120 -0
  362. package/dist/video-engine/utils/pixi-video-fallback.d.ts +2 -0
  363. package/docs/video-subsystem/README.md +490 -0
  364. package/docs/video-subsystem/api-reference.md +747 -0
  365. package/docs/video-subsystem/component-examples.md +1477 -0
  366. package/docs/video-subsystem/integration-guide.md +1021 -0
  367. package/package.json +102 -0
@@ -0,0 +1,1477 @@
1
+ # Video Component Usage Examples
2
+
3
+ This guide provides practical examples of using the Mediables video components in your Vue application.
4
+
5
+ ## Table of Contents
6
+
7
+ 1. [Basic Examples](#basic-examples)
8
+ 2. [Advanced Examples](#advanced-examples)
9
+ 3. [Integration Patterns](#integration-patterns)
10
+ 4. [Mobile Optimizations](#mobile-optimizations)
11
+ 5. [Error Handling](#error-handling)
12
+ 6. [Performance Tips](#performance-tips)
13
+
14
+ ## Basic Examples
15
+
16
+ ### Simple Video Upload
17
+
18
+ ```vue
19
+ <template>
20
+ <div class="video-upload-container">
21
+ <VideoUploader
22
+ @uploaded="onVideoUploaded"
23
+ @error="onUploadError"
24
+ />
25
+
26
+ <div v-if="uploadedVideo" class="mt-4">
27
+ <p>Video uploaded successfully!</p>
28
+ <VideoPlayer :media="uploadedVideo" />
29
+ </div>
30
+ </div>
31
+ </template>
32
+
33
+ <script setup lang="ts">
34
+ import { ref } from 'vue'
35
+ import { VideoUploader, VideoPlayer } from '@mediables/vue'
36
+
37
+ const uploadedVideo = ref(null)
38
+
39
+ function onVideoUploaded(media) {
40
+ uploadedVideo.value = media
41
+ console.log('Video ready:', media.uuid)
42
+ }
43
+
44
+ function onUploadError(error) {
45
+ console.error('Upload failed:', error)
46
+ }
47
+ </script>
48
+ ```
49
+
50
+ ### Basic Video Player
51
+
52
+ ```vue
53
+ <template>
54
+ <VideoPlayer
55
+ :playback-url="videoUrl"
56
+ :controls="true"
57
+ :autoplay="false"
58
+ :muted="false"
59
+ />
60
+ </template>
61
+
62
+ <script setup lang="ts">
63
+ import { VideoPlayer } from '@mediables/vue'
64
+
65
+ const videoUrl = 'https://your-cdn.b-cdn.net/your-library-id/play_video-guid-abc123/playlist.m3u8'
66
+ </script>
67
+ ```
68
+
69
+ ### Simple Video Editor
70
+
71
+ ```vue
72
+ <template>
73
+ <VideoEditor
74
+ :media-uuid="videoId"
75
+ @export="handleExport"
76
+ />
77
+ </template>
78
+
79
+ <script setup lang="ts">
80
+ import { VideoEditor } from '@mediables/vue'
81
+
82
+ const videoId = 'your-video-uuid-here'
83
+
84
+ async function handleExport(recipe) {
85
+ console.log('Exporting with recipe:', recipe)
86
+ // Send recipe to backend for processing
87
+ }
88
+ </script>
89
+ ```
90
+
91
+ ## Advanced Examples
92
+
93
+ ### Upload with Progress and Validation
94
+
95
+ ```vue
96
+ <template>
97
+ <div class="advanced-upload">
98
+ <VideoUploader
99
+ :multiple="true"
100
+ :max-size="maxFileSize"
101
+ :accepted-formats="acceptedFormats"
102
+ :collection="'project-videos'"
103
+ @before-upload="validateUpload"
104
+ @progress="updateProgress"
105
+ @uploaded="handleUploaded"
106
+ @error="handleError"
107
+ >
108
+ <template #trigger>
109
+ <div class="custom-upload-button">
110
+ <IonIcon :icon="cloudUploadOutline" />
111
+ <span>Drop videos here or click to browse</span>
112
+ <small>MP4, MOV, WebM up to 2GB</small>
113
+ </div>
114
+ </template>
115
+ </VideoUploader>
116
+
117
+ <!-- Progress indicators -->
118
+ <div v-if="uploads.length > 0" class="upload-queue mt-4">
119
+ <div v-for="upload in uploads" :key="upload.id" class="upload-item">
120
+ <div class="flex items-center justify-between">
121
+ <span>{{ upload.filename }}</span>
122
+ <span>{{ upload.progress }}%</span>
123
+ </div>
124
+ <IonProgressBar :value="upload.progress / 100" />
125
+ <button v-if="!upload.completed" @click="cancelUpload(upload.id)">
126
+ Cancel
127
+ </button>
128
+ </div>
129
+ </div>
130
+ </div>
131
+ </template>
132
+
133
+ <script setup lang="ts">
134
+ import { ref, reactive } from 'vue'
135
+ import { IonIcon, IonProgressBar, useIonToast } from '@ionic/vue'
136
+ import { cloudUploadOutline } from 'ionicons/icons'
137
+ import { VideoUploader } from '@mediables/vue'
138
+
139
+ const [presentToast] = useIonToast()
140
+
141
+ const maxFileSize = 2 * 1024 * 1024 * 1024 // 2GB
142
+ const acceptedFormats = ['video/mp4', 'video/quicktime', 'video/webm']
143
+ const uploads = reactive([])
144
+
145
+ function validateUpload(file) {
146
+ // Custom validation
147
+ if (file.name.includes('temp')) {
148
+ presentToast({
149
+ message: 'Temporary files not allowed',
150
+ color: 'warning'
151
+ })
152
+ return false
153
+ }
154
+
155
+ // Check duration (if available)
156
+ return new Promise((resolve) => {
157
+ const video = document.createElement('video')
158
+ video.preload = 'metadata'
159
+
160
+ video.onloadedmetadata = () => {
161
+ if (video.duration > 600) { // 10 minutes max
162
+ presentToast({
163
+ message: 'Video must be less than 10 minutes',
164
+ color: 'warning'
165
+ })
166
+ resolve(false)
167
+ } else {
168
+ resolve(true)
169
+ }
170
+ }
171
+
172
+ video.src = URL.createObjectURL(file)
173
+ })
174
+ }
175
+
176
+ function updateProgress(data) {
177
+ const upload = uploads.find(u => u.id === data.uploadId)
178
+ if (upload) {
179
+ upload.progress = data.progress
180
+ } else {
181
+ uploads.push({
182
+ id: data.uploadId,
183
+ filename: data.filename,
184
+ progress: data.progress,
185
+ completed: false
186
+ })
187
+ }
188
+ }
189
+
190
+ function handleUploaded(media) {
191
+ const upload = uploads.find(u => u.id === media.upload_id)
192
+ if (upload) {
193
+ upload.completed = true
194
+ upload.progress = 100
195
+ }
196
+ }
197
+
198
+ function handleError(error) {
199
+ presentToast({
200
+ message: `Upload failed: ${error.message}`,
201
+ color: 'danger',
202
+ duration: 5000
203
+ })
204
+ }
205
+
206
+ function cancelUpload(uploadId) {
207
+ // Implementation depends on your upload mechanism
208
+ const index = uploads.findIndex(u => u.id === uploadId)
209
+ if (index !== -1) {
210
+ uploads.splice(index, 1)
211
+ }
212
+ }
213
+ </script>
214
+
215
+ <style scoped>
216
+ .custom-upload-button {
217
+ border: 2px dashed var(--ion-color-medium);
218
+ border-radius: 8px;
219
+ padding: 3rem;
220
+ text-align: center;
221
+ cursor: pointer;
222
+ transition: all 0.3s;
223
+ }
224
+
225
+ .custom-upload-button:hover {
226
+ border-color: var(--ion-color-primary);
227
+ background: var(--ion-color-primary-tint);
228
+ }
229
+
230
+ .upload-item {
231
+ padding: 1rem;
232
+ border: 1px solid var(--ion-color-light);
233
+ border-radius: 4px;
234
+ margin-bottom: 0.5rem;
235
+ }
236
+ </style>
237
+ ```
238
+
239
+ ### Player with Custom Controls
240
+
241
+ ```vue
242
+ <template>
243
+ <div class="custom-player">
244
+ <VideoPlayer
245
+ ref="playerRef"
246
+ :media="media"
247
+ :controls="false"
248
+ @play="isPlaying = true"
249
+ @pause="isPlaying = false"
250
+ @timeupdate="updateTime"
251
+ @ended="handleEnded"
252
+ />
253
+
254
+ <!-- Custom control bar -->
255
+ <div class="controls">
256
+ <button @click="togglePlay">
257
+ <IonIcon :icon="isPlaying ? pauseOutline : playOutline" />
258
+ </button>
259
+
260
+ <div class="time-display">
261
+ {{ formatTime(currentTime) }} / {{ formatTime(duration) }}
262
+ </div>
263
+
264
+ <input
265
+ type="range"
266
+ :value="currentTime"
267
+ :max="duration"
268
+ @input="seek($event.target.value)"
269
+ class="seek-bar"
270
+ />
271
+
272
+ <button @click="toggleMute">
273
+ <IonIcon :icon="isMuted ? volumeMuteOutline : volumeHighOutline" />
274
+ </button>
275
+
276
+ <button @click="toggleFullscreen">
277
+ <IonIcon :icon="expandOutline" />
278
+ </button>
279
+
280
+ <select @change="changeQuality($event.target.value)">
281
+ <option value="auto">Auto</option>
282
+ <option value="1080p">1080p</option>
283
+ <option value="720p">720p</option>
284
+ <option value="480p">480p</option>
285
+ </select>
286
+ </div>
287
+
288
+ <!-- Overlay for loading/buffering -->
289
+ <div v-if="isBuffering" class="overlay">
290
+ <IonSpinner />
291
+ </div>
292
+ </div>
293
+ </template>
294
+
295
+ <script setup lang="ts">
296
+ import { ref, computed } from 'vue'
297
+ import { IonIcon, IonSpinner } from '@ionic/vue'
298
+ import {
299
+ playOutline,
300
+ pauseOutline,
301
+ volumeHighOutline,
302
+ volumeMuteOutline,
303
+ expandOutline
304
+ } from 'ionicons/icons'
305
+ import { VideoPlayer } from '@mediables/vue'
306
+
307
+ const props = defineProps({
308
+ media: Object
309
+ })
310
+
311
+ const playerRef = ref()
312
+ const isPlaying = ref(false)
313
+ const isMuted = ref(false)
314
+ const isBuffering = ref(false)
315
+ const currentTime = ref(0)
316
+ const duration = ref(0)
317
+
318
+ function togglePlay() {
319
+ if (isPlaying.value) {
320
+ playerRef.value.pause()
321
+ } else {
322
+ playerRef.value.play()
323
+ }
324
+ }
325
+
326
+ function seek(time) {
327
+ playerRef.value.seek(Number(time))
328
+ }
329
+
330
+ function toggleMute() {
331
+ isMuted.value = !isMuted.value
332
+ playerRef.value.setMuted(isMuted.value)
333
+ }
334
+
335
+ function toggleFullscreen() {
336
+ playerRef.value.requestFullscreen()
337
+ }
338
+
339
+ function changeQuality(quality) {
340
+ playerRef.value.setQuality(quality)
341
+ }
342
+
343
+ function updateTime(event) {
344
+ currentTime.value = event.currentTime
345
+ duration.value = event.duration
346
+ }
347
+
348
+ function handleEnded() {
349
+ isPlaying.value = false
350
+ // Maybe show related videos or replay button
351
+ }
352
+
353
+ function formatTime(seconds) {
354
+ const mins = Math.floor(seconds / 60)
355
+ const secs = Math.floor(seconds % 60)
356
+ return `${mins}:${secs.toString().padStart(2, '0')}`
357
+ }
358
+ </script>
359
+
360
+ <style scoped>
361
+ .custom-player {
362
+ position: relative;
363
+ background: black;
364
+ }
365
+
366
+ .controls {
367
+ position: absolute;
368
+ bottom: 0;
369
+ left: 0;
370
+ right: 0;
371
+ display: flex;
372
+ align-items: center;
373
+ gap: 1rem;
374
+ padding: 1rem;
375
+ background: linear-gradient(transparent, rgba(0,0,0,0.8));
376
+ color: white;
377
+ }
378
+
379
+ .seek-bar {
380
+ flex: 1;
381
+ }
382
+
383
+ .overlay {
384
+ position: absolute;
385
+ inset: 0;
386
+ display: flex;
387
+ align-items: center;
388
+ justify-content: center;
389
+ background: rgba(0,0,0,0.5);
390
+ }
391
+ </style>
392
+ ```
393
+
394
+ ### Advanced Video Editor with Timeline
395
+
396
+ ```vue
397
+ <template>
398
+ <div class="advanced-editor">
399
+ <VideoEditor
400
+ ref="editorRef"
401
+ :media-uuid="videoId"
402
+ :initial-recipe="savedRecipe"
403
+ @change="handleChange"
404
+ @export="handleExport"
405
+ >
406
+ <template #toolbar>
407
+ <div class="editor-toolbar">
408
+ <button @click="undo" :disabled="!canUndo">
409
+ <IonIcon :icon="arrowUndoOutline" />
410
+ Undo
411
+ </button>
412
+
413
+ <button @click="redo" :disabled="!canRedo">
414
+ <IonIcon :icon="arrowRedoOutline" />
415
+ Redo
416
+ </button>
417
+
418
+ <div class="separator" />
419
+
420
+ <button @click="splitAtPlayhead">
421
+ <IonIcon :icon="cutOutline" />
422
+ Split
423
+ </button>
424
+
425
+ <button @click="deleteSelected" :disabled="!hasSelection">
426
+ <IonIcon :icon="trashOutline" />
427
+ Delete
428
+ </button>
429
+
430
+ <div class="separator" />
431
+
432
+ <button @click="addTextOverlay">
433
+ <IonIcon :icon="textOutline" />
434
+ Add Text
435
+ </button>
436
+
437
+ <button @click="addTransition">
438
+ <IonIcon :icon="shuffleOutline" />
439
+ Transition
440
+ </button>
441
+ </div>
442
+ </template>
443
+
444
+ <template #sidebar>
445
+ <div class="editor-sidebar">
446
+ <!-- Filter presets -->
447
+ <div class="section">
448
+ <h3>Quick Filters</h3>
449
+ <div class="filter-grid">
450
+ <button
451
+ v-for="preset in filterPresets"
452
+ :key="preset.id"
453
+ @click="applyPreset(preset)"
454
+ class="filter-preset"
455
+ >
456
+ <img :src="preset.thumbnail" :alt="preset.name" />
457
+ <span>{{ preset.name }}</span>
458
+ </button>
459
+ </div>
460
+ </div>
461
+
462
+ <!-- Audio controls -->
463
+ <div class="section">
464
+ <h3>Audio</h3>
465
+ <label>
466
+ Volume
467
+ <input
468
+ type="range"
469
+ min="0"
470
+ max="200"
471
+ v-model="audioVolume"
472
+ @change="updateAudio"
473
+ />
474
+ <span>{{ audioVolume }}%</span>
475
+ </label>
476
+
477
+ <label>
478
+ <input type="checkbox" v-model="removeAudio" />
479
+ Remove audio
480
+ </label>
481
+ </div>
482
+
483
+ <!-- Export settings -->
484
+ <div class="section">
485
+ <h3>Export Settings</h3>
486
+ <select v-model="exportQuality">
487
+ <option value="2160p">4K (2160p)</option>
488
+ <option value="1080p">Full HD (1080p)</option>
489
+ <option value="720p">HD (720p)</option>
490
+ <option value="480p">SD (480p)</option>
491
+ </select>
492
+
493
+ <select v-model="exportFormat">
494
+ <option value="mp4">MP4 (H.264)</option>
495
+ <option value="webm">WebM (VP9)</option>
496
+ </select>
497
+ </div>
498
+ </div>
499
+ </template>
500
+ </VideoEditor>
501
+
502
+ <!-- Export progress modal -->
503
+ <IonModal :is-open="exporting">
504
+ <IonHeader>
505
+ <IonToolbar>
506
+ <IonTitle>Exporting Video</IonTitle>
507
+ </IonToolbar>
508
+ </IonHeader>
509
+
510
+ <IonContent>
511
+ <div class="export-progress">
512
+ <IonProgressBar :value="exportProgress / 100" />
513
+ <p>{{ exportProgress }}% complete</p>
514
+ <p class="text-sm">{{ exportStatus }}</p>
515
+ </div>
516
+ </IonContent>
517
+ </IonModal>
518
+ </div>
519
+ </template>
520
+
521
+ <script setup lang="ts">
522
+ import { ref, reactive, computed } from 'vue'
523
+ import {
524
+ IonIcon,
525
+ IonModal,
526
+ IonHeader,
527
+ IonToolbar,
528
+ IonTitle,
529
+ IonContent,
530
+ IonProgressBar
531
+ } from '@ionic/vue'
532
+ import {
533
+ arrowUndoOutline,
534
+ arrowRedoOutline,
535
+ cutOutline,
536
+ trashOutline,
537
+ textOutline,
538
+ shuffleOutline
539
+ } from 'ionicons/icons'
540
+ import { VideoEditor } from '@mediables/vue'
541
+ import { useVideoEditorStore } from '@/stores/videoEditor'
542
+
543
+ const props = defineProps({
544
+ videoId: String,
545
+ savedRecipe: Object
546
+ })
547
+
548
+ const editorRef = ref()
549
+ const editorStore = useVideoEditorStore()
550
+
551
+ const canUndo = computed(() => editorStore.canUndo)
552
+ const canRedo = computed(() => editorStore.canRedo)
553
+ const hasSelection = computed(() => editorStore.hasSelection)
554
+
555
+ const audioVolume = ref(100)
556
+ const removeAudio = ref(false)
557
+ const exportQuality = ref('1080p')
558
+ const exportFormat = ref('mp4')
559
+ const exporting = ref(false)
560
+ const exportProgress = ref(0)
561
+ const exportStatus = ref('')
562
+
563
+ const filterPresets = [
564
+ { id: 'vintage', name: 'Vintage', thumbnail: '/filters/vintage.jpg' },
565
+ { id: 'cinematic', name: 'Cinematic', thumbnail: '/filters/cinematic.jpg' },
566
+ { id: 'vibrant', name: 'Vibrant', thumbnail: '/filters/vibrant.jpg' },
567
+ { id: 'noir', name: 'Noir', thumbnail: '/filters/noir.jpg' }
568
+ ]
569
+
570
+ function undo() {
571
+ editorRef.value.undo()
572
+ }
573
+
574
+ function redo() {
575
+ editorRef.value.redo()
576
+ }
577
+
578
+ function splitAtPlayhead() {
579
+ editorRef.value.splitAtPlayhead()
580
+ }
581
+
582
+ function deleteSelected() {
583
+ editorRef.value.deleteSelected()
584
+ }
585
+
586
+ function addTextOverlay() {
587
+ editorRef.value.addLayer({
588
+ type: 'text',
589
+ content: 'Your text here',
590
+ position: { x: 50, y: 50 },
591
+ style: {
592
+ fontSize: 24,
593
+ color: '#ffffff',
594
+ fontFamily: 'Arial'
595
+ }
596
+ })
597
+ }
598
+
599
+ function addTransition() {
600
+ editorRef.value.addTransition({
601
+ type: 'crossfade',
602
+ duration: 1
603
+ })
604
+ }
605
+
606
+ function applyPreset(preset) {
607
+ const filters = getPresetFilters(preset.id)
608
+ editorRef.value.applyFilters(filters)
609
+ }
610
+
611
+ function updateAudio() {
612
+ editorRef.value.setAudioVolume(audioVolume.value / 100)
613
+ }
614
+
615
+ function handleChange(state) {
616
+ editorStore.updateState(state)
617
+ // Auto-save draft every 30 seconds
618
+ editorStore.saveDraft()
619
+ }
620
+
621
+ async function handleExport(recipe) {
622
+ exporting.value = true
623
+ exportProgress.value = 0
624
+
625
+ try {
626
+ // Add export settings to recipe
627
+ const fullRecipe = {
628
+ ...recipe,
629
+ audio: {
630
+ ...recipe.audio,
631
+ volume: removeAudio.value ? 0 : audioVolume.value / 100
632
+ },
633
+ output: {
634
+ format: exportFormat.value,
635
+ quality: exportQuality.value,
636
+ codec: exportFormat.value === 'mp4' ? 'h264' : 'vp9'
637
+ }
638
+ }
639
+
640
+ const response = await api.post(`/video/${props.videoId}/export`, {
641
+ recipe: fullRecipe
642
+ })
643
+
644
+ // Poll for progress
645
+ const jobId = response.data.job_id
646
+ const interval = setInterval(async () => {
647
+ const status = await api.get(`/video/exports/${jobId}`)
648
+
649
+ exportProgress.value = status.data.progress
650
+ exportStatus.value = status.data.status
651
+
652
+ if (status.data.status === 'completed') {
653
+ clearInterval(interval)
654
+ exporting.value = false
655
+ // Navigate to result
656
+ router.push(`/video/export/${jobId}/complete`)
657
+ } else if (status.data.status === 'failed') {
658
+ clearInterval(interval)
659
+ exporting.value = false
660
+ // Show error
661
+ }
662
+ }, 2000)
663
+
664
+ } catch (error) {
665
+ exporting.value = false
666
+ console.error('Export failed:', error)
667
+ }
668
+ }
669
+
670
+ function getPresetFilters(presetId) {
671
+ const presets = {
672
+ vintage: [
673
+ { id: 'sepia', intensity: 0.3 },
674
+ { id: 'vignette', intensity: 0.5 }
675
+ ],
676
+ cinematic: [
677
+ { id: 'contrast', params: { value: 1.2 } },
678
+ { id: 'saturation', params: { value: 0.8 } }
679
+ ],
680
+ vibrant: [
681
+ { id: 'saturation', params: { value: 1.5 } },
682
+ { id: 'brightness', params: { value: 0.1 } }
683
+ ],
684
+ noir: [
685
+ { id: 'grayscale', intensity: 1 },
686
+ { id: 'contrast', params: { value: 1.3 } }
687
+ ]
688
+ }
689
+
690
+ return presets[presetId] || []
691
+ }
692
+ </script>
693
+
694
+ <style scoped>
695
+ .advanced-editor {
696
+ height: 100vh;
697
+ display: flex;
698
+ flex-direction: column;
699
+ }
700
+
701
+ .editor-toolbar {
702
+ display: flex;
703
+ align-items: center;
704
+ gap: 0.5rem;
705
+ padding: 0.5rem;
706
+ background: var(--ion-color-light);
707
+ border-bottom: 1px solid var(--ion-color-medium);
708
+ }
709
+
710
+ .separator {
711
+ width: 1px;
712
+ height: 24px;
713
+ background: var(--ion-color-medium);
714
+ margin: 0 0.5rem;
715
+ }
716
+
717
+ .editor-sidebar {
718
+ width: 300px;
719
+ padding: 1rem;
720
+ background: var(--ion-color-light-shade);
721
+ overflow-y: auto;
722
+ }
723
+
724
+ .section {
725
+ margin-bottom: 2rem;
726
+ }
727
+
728
+ .section h3 {
729
+ font-size: 1rem;
730
+ font-weight: 600;
731
+ margin-bottom: 0.5rem;
732
+ }
733
+
734
+ .filter-grid {
735
+ display: grid;
736
+ grid-template-columns: repeat(2, 1fr);
737
+ gap: 0.5rem;
738
+ }
739
+
740
+ .filter-preset {
741
+ display: flex;
742
+ flex-direction: column;
743
+ align-items: center;
744
+ padding: 0.5rem;
745
+ border: 1px solid var(--ion-color-medium);
746
+ border-radius: 4px;
747
+ cursor: pointer;
748
+ }
749
+
750
+ .filter-preset img {
751
+ width: 60px;
752
+ height: 60px;
753
+ object-fit: cover;
754
+ border-radius: 4px;
755
+ margin-bottom: 0.25rem;
756
+ }
757
+
758
+ .export-progress {
759
+ padding: 2rem;
760
+ text-align: center;
761
+ }
762
+ </style>
763
+ ```
764
+
765
+ ## Integration Patterns
766
+
767
+ ### With Pinia Store
768
+
769
+ ```typescript
770
+ // stores/video.ts
771
+ import { defineStore } from 'pinia'
772
+ import { ref, computed } from 'vue'
773
+ import api from '@/services/api'
774
+
775
+ export const useVideoStore = defineStore('video', () => {
776
+ const videos = ref([])
777
+ const currentVideo = ref(null)
778
+ const isUploading = ref(false)
779
+ const uploadProgress = ref(0)
780
+
781
+ const sortedVideos = computed(() => {
782
+ return [...videos.value].sort((a, b) =>
783
+ new Date(b.created_at) - new Date(a.created_at)
784
+ )
785
+ })
786
+
787
+ async function fetchVideos() {
788
+ const response = await api.get('/videos')
789
+ videos.value = response.data.data
790
+ }
791
+
792
+ async function uploadVideo(file) {
793
+ isUploading.value = true
794
+ uploadProgress.value = 0
795
+
796
+ try {
797
+ // Request upload URL
798
+ const uploadResponse = await api.post('/video/upload', {
799
+ filename: file.name,
800
+ size: file.size,
801
+ mime_type: file.type
802
+ })
803
+
804
+ // Upload to provider
805
+ const xhr = new XMLHttpRequest()
806
+
807
+ xhr.upload.addEventListener('progress', (e) => {
808
+ if (e.lengthComputable) {
809
+ uploadProgress.value = Math.round((e.loaded / e.total) * 100)
810
+ }
811
+ })
812
+
813
+ return new Promise((resolve, reject) => {
814
+ xhr.onload = () => {
815
+ if (xhr.status === 200) {
816
+ const media = { uuid: uploadResponse.data.media_uuid }
817
+ videos.value.unshift(media)
818
+ resolve(media)
819
+ } else {
820
+ reject(new Error('Upload failed'))
821
+ }
822
+ }
823
+
824
+ xhr.onerror = () => reject(new Error('Upload failed'))
825
+
826
+ xhr.open('PUT', uploadResponse.data.upload_url)
827
+ xhr.send(file)
828
+ })
829
+
830
+ } finally {
831
+ isUploading.value = false
832
+ uploadProgress.value = 0
833
+ }
834
+ }
835
+
836
+ async function deleteVideo(uuid) {
837
+ await api.delete(`/videos/${uuid}`)
838
+ const index = videos.value.findIndex(v => v.uuid === uuid)
839
+ if (index !== -1) {
840
+ videos.value.splice(index, 1)
841
+ }
842
+ }
843
+
844
+ return {
845
+ videos,
846
+ currentVideo,
847
+ isUploading,
848
+ uploadProgress,
849
+ sortedVideos,
850
+ fetchVideos,
851
+ uploadVideo,
852
+ deleteVideo
853
+ }
854
+ })
855
+ ```
856
+
857
+ ### With Vue Router
858
+
859
+ ```typescript
860
+ // router/video-routes.ts
861
+ export const videoRoutes = [
862
+ {
863
+ path: '/videos',
864
+ component: () => import('@/views/VideoList.vue'),
865
+ meta: { requiresAuth: true }
866
+ },
867
+ {
868
+ path: '/videos/upload',
869
+ component: () => import('@/views/VideoUpload.vue'),
870
+ meta: { requiresAuth: true }
871
+ },
872
+ {
873
+ path: '/videos/:uuid',
874
+ component: () => import('@/views/VideoPlayer.vue'),
875
+ props: true
876
+ },
877
+ {
878
+ path: '/videos/:uuid/edit',
879
+ component: () => import('@/views/VideoEditor.vue'),
880
+ props: true,
881
+ meta: { requiresAuth: true }
882
+ },
883
+ {
884
+ path: '/live',
885
+ component: () => import('@/views/LiveStream.vue'),
886
+ meta: { requiresAuth: true }
887
+ }
888
+ ]
889
+ ```
890
+
891
+ ## Mobile Optimizations
892
+
893
+ ### Responsive Video Player
894
+
895
+ ```vue
896
+ <template>
897
+ <div class="mobile-player" :class="{ 'fullscreen': isFullscreen }">
898
+ <VideoPlayer
899
+ ref="player"
900
+ :media="media"
901
+ :controls="!showCustomControls"
902
+ @click="toggleControls"
903
+ @touchstart="handleTouchStart"
904
+ @touchend="handleTouchEnd"
905
+ />
906
+
907
+ <!-- Mobile gesture overlay -->
908
+ <div v-if="showCustomControls" class="gesture-overlay">
909
+ <!-- Tap zones for seek -->
910
+ <div class="tap-zone left" @click="seekBackward">
911
+ <transition name="feedback">
912
+ <div v-if="showSeekFeedback === 'back'" class="seek-feedback">
913
+ -10s
914
+ </div>
915
+ </transition>
916
+ </div>
917
+
918
+ <div class="tap-zone center" @click="togglePlay">
919
+ <transition name="fade">
920
+ <IonIcon
921
+ v-if="showPlayPause"
922
+ :icon="isPlaying ? pauseCircleOutline : playCircleOutline"
923
+ class="play-icon"
924
+ />
925
+ </transition>
926
+ </div>
927
+
928
+ <div class="tap-zone right" @click="seekForward">
929
+ <transition name="feedback">
930
+ <div v-if="showSeekFeedback === 'forward'" class="seek-feedback">
931
+ +10s
932
+ </div>
933
+ </transition>
934
+ </div>
935
+ </div>
936
+
937
+ <!-- Mobile controls (bottom) -->
938
+ <transition name="slide-up">
939
+ <div v-if="showCustomControls" class="mobile-controls">
940
+ <div class="progress-bar" @click="seekToPosition">
941
+ <div class="progress-fill" :style="{ width: progressPercent + '%' }" />
942
+ <div class="progress-thumb" :style="{ left: progressPercent + '%' }" />
943
+ </div>
944
+
945
+ <div class="control-buttons">
946
+ <button @click="togglePlay">
947
+ <IonIcon :icon="isPlaying ? pauseOutline : playOutline" />
948
+ </button>
949
+
950
+ <span class="time">
951
+ {{ formatTime(currentTime) }} / {{ formatTime(duration) }}
952
+ </span>
953
+
954
+ <button @click="toggleFullscreen">
955
+ <IonIcon :icon="isFullscreen ? contractOutline : expandOutline" />
956
+ </button>
957
+ </div>
958
+ </div>
959
+ </transition>
960
+ </div>
961
+ </template>
962
+
963
+ <script setup lang="ts">
964
+ import { ref, computed, onMounted, onUnmounted } from 'vue'
965
+ import { IonIcon } from '@ionic/vue'
966
+ import {
967
+ playOutline,
968
+ pauseOutline,
969
+ playCircleOutline,
970
+ pauseCircleOutline,
971
+ expandOutline,
972
+ contractOutline
973
+ } from 'ionicons/icons'
974
+ import { VideoPlayer } from '@mediables/vue'
975
+ import { Haptics, ImpactStyle } from '@capacitor/haptics'
976
+
977
+ const props = defineProps({
978
+ media: Object
979
+ })
980
+
981
+ const player = ref()
982
+ const isPlaying = ref(false)
983
+ const isFullscreen = ref(false)
984
+ const showCustomControls = ref(true)
985
+ const showPlayPause = ref(false)
986
+ const showSeekFeedback = ref(null)
987
+ const currentTime = ref(0)
988
+ const duration = ref(0)
989
+
990
+ const progressPercent = computed(() => {
991
+ if (!duration.value) return 0
992
+ return (currentTime.value / duration.value) * 100
993
+ })
994
+
995
+ let controlsTimeout = null
996
+
997
+ function toggleControls() {
998
+ showCustomControls.value = !showCustomControls.value
999
+ resetControlsTimeout()
1000
+ }
1001
+
1002
+ function resetControlsTimeout() {
1003
+ clearTimeout(controlsTimeout)
1004
+ controlsTimeout = setTimeout(() => {
1005
+ if (isPlaying.value) {
1006
+ showCustomControls.value = false
1007
+ }
1008
+ }, 3000)
1009
+ }
1010
+
1011
+ function togglePlay() {
1012
+ if (isPlaying.value) {
1013
+ player.value.pause()
1014
+ } else {
1015
+ player.value.play()
1016
+ }
1017
+
1018
+ showPlayPause.value = true
1019
+ setTimeout(() => {
1020
+ showPlayPause.value = false
1021
+ }, 600)
1022
+
1023
+ // Haptic feedback
1024
+ Haptics.impact({ style: ImpactStyle.Light })
1025
+ }
1026
+
1027
+ function seekForward() {
1028
+ player.value.seek(currentTime.value + 10)
1029
+ showSeekFeedback.value = 'forward'
1030
+ setTimeout(() => {
1031
+ showSeekFeedback.value = null
1032
+ }, 600)
1033
+
1034
+ Haptics.impact({ style: ImpactStyle.Light })
1035
+ }
1036
+
1037
+ function seekBackward() {
1038
+ player.value.seek(Math.max(0, currentTime.value - 10))
1039
+ showSeekFeedback.value = 'back'
1040
+ setTimeout(() => {
1041
+ showSeekFeedback.value = null
1042
+ }, 600)
1043
+
1044
+ Haptics.impact({ style: ImpactStyle.Light })
1045
+ }
1046
+
1047
+ function seekToPosition(event) {
1048
+ const rect = event.currentTarget.getBoundingClientRect()
1049
+ const percent = (event.clientX - rect.left) / rect.width
1050
+ player.value.seek(duration.value * percent)
1051
+ }
1052
+
1053
+ function toggleFullscreen() {
1054
+ if (isFullscreen.value) {
1055
+ document.exitFullscreen()
1056
+ } else {
1057
+ player.value.$el.requestFullscreen()
1058
+ }
1059
+ isFullscreen.value = !isFullscreen.value
1060
+ }
1061
+
1062
+ // Gesture handling
1063
+ let touchStartX = 0
1064
+ let touchStartTime = 0
1065
+
1066
+ function handleTouchStart(event) {
1067
+ touchStartX = event.touches[0].clientX
1068
+ touchStartTime = currentTime.value
1069
+ }
1070
+
1071
+ function handleTouchEnd(event) {
1072
+ const touchEndX = event.changedTouches[0].clientX
1073
+ const deltaX = touchEndX - touchStartX
1074
+
1075
+ // Horizontal swipe for seek
1076
+ if (Math.abs(deltaX) > 50) {
1077
+ const seekAmount = (deltaX / window.innerWidth) * 30 // Max 30s seek
1078
+ player.value.seek(touchStartTime + seekAmount)
1079
+ }
1080
+ }
1081
+
1082
+ function formatTime(seconds) {
1083
+ const mins = Math.floor(seconds / 60)
1084
+ const secs = Math.floor(seconds % 60)
1085
+ return `${mins}:${secs.toString().padStart(2, '0')}`
1086
+ }
1087
+
1088
+ // Clean up on unmount
1089
+ onUnmounted(() => {
1090
+ clearTimeout(controlsTimeout)
1091
+ })
1092
+ </script>
1093
+
1094
+ <style scoped>
1095
+ .mobile-player {
1096
+ position: relative;
1097
+ width: 100%;
1098
+ background: black;
1099
+ }
1100
+
1101
+ .mobile-player.fullscreen {
1102
+ position: fixed;
1103
+ inset: 0;
1104
+ z-index: 9999;
1105
+ }
1106
+
1107
+ .gesture-overlay {
1108
+ position: absolute;
1109
+ inset: 0;
1110
+ display: flex;
1111
+ }
1112
+
1113
+ .tap-zone {
1114
+ flex: 1;
1115
+ display: flex;
1116
+ align-items: center;
1117
+ justify-content: center;
1118
+ }
1119
+
1120
+ .tap-zone.left,
1121
+ .tap-zone.right {
1122
+ flex: 0.3;
1123
+ }
1124
+
1125
+ .seek-feedback {
1126
+ padding: 0.5rem 1rem;
1127
+ background: rgba(0,0,0,0.7);
1128
+ color: white;
1129
+ border-radius: 20px;
1130
+ font-weight: bold;
1131
+ }
1132
+
1133
+ .play-icon {
1134
+ font-size: 64px;
1135
+ color: white;
1136
+ opacity: 0.9;
1137
+ }
1138
+
1139
+ .mobile-controls {
1140
+ position: absolute;
1141
+ bottom: 0;
1142
+ left: 0;
1143
+ right: 0;
1144
+ padding: 1rem;
1145
+ background: linear-gradient(transparent, rgba(0,0,0,0.9));
1146
+ }
1147
+
1148
+ .progress-bar {
1149
+ position: relative;
1150
+ height: 4px;
1151
+ background: rgba(255,255,255,0.3);
1152
+ border-radius: 2px;
1153
+ margin-bottom: 1rem;
1154
+ cursor: pointer;
1155
+ }
1156
+
1157
+ .progress-fill {
1158
+ position: absolute;
1159
+ top: 0;
1160
+ left: 0;
1161
+ height: 100%;
1162
+ background: var(--ion-color-primary);
1163
+ border-radius: 2px;
1164
+ }
1165
+
1166
+ .progress-thumb {
1167
+ position: absolute;
1168
+ top: -6px;
1169
+ width: 16px;
1170
+ height: 16px;
1171
+ background: white;
1172
+ border-radius: 50%;
1173
+ transform: translateX(-50%);
1174
+ }
1175
+
1176
+ .control-buttons {
1177
+ display: flex;
1178
+ align-items: center;
1179
+ justify-content: space-between;
1180
+ color: white;
1181
+ }
1182
+
1183
+ .control-buttons button {
1184
+ background: none;
1185
+ border: none;
1186
+ color: white;
1187
+ font-size: 24px;
1188
+ padding: 0.5rem;
1189
+ }
1190
+
1191
+ .time {
1192
+ font-size: 14px;
1193
+ }
1194
+
1195
+ /* Animations */
1196
+ .fade-enter-active,
1197
+ .fade-leave-active {
1198
+ transition: opacity 0.3s;
1199
+ }
1200
+
1201
+ .fade-enter-from,
1202
+ .fade-leave-to {
1203
+ opacity: 0;
1204
+ }
1205
+
1206
+ .feedback-enter-active {
1207
+ animation: bounce 0.6s;
1208
+ }
1209
+
1210
+ @keyframes bounce {
1211
+ 0%, 100% { transform: scale(1); }
1212
+ 50% { transform: scale(1.2); }
1213
+ }
1214
+
1215
+ .slide-up-enter-active,
1216
+ .slide-up-leave-active {
1217
+ transition: transform 0.3s;
1218
+ }
1219
+
1220
+ .slide-up-enter-from,
1221
+ .slide-up-leave-to {
1222
+ transform: translateY(100%);
1223
+ }
1224
+ </style>
1225
+ ```
1226
+
1227
+ ## Error Handling
1228
+
1229
+ ### Comprehensive Error Management
1230
+
1231
+ ```vue
1232
+ <template>
1233
+ <div class="video-container">
1234
+ <VideoUploader
1235
+ v-if="!hasError"
1236
+ @uploaded="handleUploaded"
1237
+ @error="handleError"
1238
+ />
1239
+
1240
+ <!-- Error display -->
1241
+ <IonCard v-if="hasError" color="danger">
1242
+ <IonCardHeader>
1243
+ <IonCardTitle>Upload Error</IonCardTitle>
1244
+ </IonCardHeader>
1245
+ <IonCardContent>
1246
+ <p>{{ errorMessage }}</p>
1247
+
1248
+ <div v-if="errorDetails" class="error-details">
1249
+ <h4>Details:</h4>
1250
+ <ul>
1251
+ <li v-for="(detail, key) in errorDetails" :key="key">
1252
+ <strong>{{ key }}:</strong> {{ detail }}
1253
+ </li>
1254
+ </ul>
1255
+ </div>
1256
+
1257
+ <IonButton @click="retry" fill="outline" color="light">
1258
+ Try Again
1259
+ </IonButton>
1260
+ </IonCardContent>
1261
+ </IonCard>
1262
+ </div>
1263
+ </template>
1264
+
1265
+ <script setup lang="ts">
1266
+ import { ref, computed } from 'vue'
1267
+ import {
1268
+ IonCard,
1269
+ IonCardHeader,
1270
+ IonCardTitle,
1271
+ IonCardContent,
1272
+ IonButton
1273
+ } from '@ionic/vue'
1274
+ import { VideoUploader } from '@mediables/vue'
1275
+
1276
+ const error = ref(null)
1277
+ const hasError = computed(() => !!error.value)
1278
+ const errorMessage = computed(() => {
1279
+ if (!error.value) return ''
1280
+
1281
+ // Map common errors to user-friendly messages
1282
+ const errorMap = {
1283
+ 'UPLOAD_TOO_LARGE': 'Video file is too large. Maximum size is 5GB.',
1284
+ 'UNSUPPORTED_FORMAT': 'Video format not supported. Please use MP4, MOV, or WebM.',
1285
+ 'NETWORK_ERROR': 'Network connection lost. Please check your internet and try again.',
1286
+ 'QUOTA_EXCEEDED': 'Storage quota exceeded. Please delete some videos first.',
1287
+ 'PROCESSING_FAILED': 'Video processing failed. The file may be corrupted.',
1288
+ 'UNAUTHORIZED': 'Session expired. Please log in again.',
1289
+ 'RATE_LIMITED': 'Too many uploads. Please wait a moment and try again.'
1290
+ }
1291
+
1292
+ return errorMap[error.value.code] || error.value.message || 'An unexpected error occurred'
1293
+ })
1294
+
1295
+ const errorDetails = computed(() => {
1296
+ if (!error.value?.details) return null
1297
+ return error.value.details
1298
+ })
1299
+
1300
+ function handleUploaded(media) {
1301
+ console.log('Upload successful:', media)
1302
+ error.value = null
1303
+ }
1304
+
1305
+ function handleError(uploadError) {
1306
+ console.error('Upload error:', uploadError)
1307
+
1308
+ // Parse error response
1309
+ if (uploadError.response?.data?.error) {
1310
+ error.value = uploadError.response.data.error
1311
+ } else if (uploadError.code === 'ERR_NETWORK') {
1312
+ error.value = {
1313
+ code: 'NETWORK_ERROR',
1314
+ message: 'Network connection failed'
1315
+ }
1316
+ } else {
1317
+ error.value = {
1318
+ code: 'UNKNOWN',
1319
+ message: uploadError.message || 'Upload failed',
1320
+ details: {
1321
+ status: uploadError.response?.status,
1322
+ statusText: uploadError.response?.statusText
1323
+ }
1324
+ }
1325
+ }
1326
+
1327
+ // Log to error tracking service
1328
+ if (window.Sentry) {
1329
+ window.Sentry.captureException(uploadError, {
1330
+ contexts: {
1331
+ upload: {
1332
+ error_code: error.value.code,
1333
+ error_message: error.value.message
1334
+ }
1335
+ }
1336
+ })
1337
+ }
1338
+ }
1339
+
1340
+ function retry() {
1341
+ error.value = null
1342
+ }
1343
+ </script>
1344
+
1345
+ <style scoped>
1346
+ .error-details {
1347
+ margin-top: 1rem;
1348
+ padding: 1rem;
1349
+ background: rgba(0,0,0,0.1);
1350
+ border-radius: 4px;
1351
+ }
1352
+
1353
+ .error-details ul {
1354
+ list-style: none;
1355
+ padding: 0;
1356
+ margin: 0.5rem 0 0 0;
1357
+ }
1358
+
1359
+ .error-details li {
1360
+ padding: 0.25rem 0;
1361
+ }
1362
+ </style>
1363
+ ```
1364
+
1365
+ ## Performance Tips
1366
+
1367
+ ### 1. Lazy Load Components
1368
+
1369
+ ```typescript
1370
+ // Only load video components when needed
1371
+ const VideoEditor = defineAsyncComponent(() =>
1372
+ import('@mediables/vue').then(m => m.VideoEditor)
1373
+ )
1374
+
1375
+ const VideoPlayer = defineAsyncComponent(() =>
1376
+ import('@mediables/vue').then(m => m.VideoPlayer)
1377
+ )
1378
+ ```
1379
+
1380
+ ### 2. Optimize Thumbnails
1381
+
1382
+ ```vue
1383
+ <script setup>
1384
+ // Generate multiple thumbnail sizes
1385
+ const thumbnailSizes = {
1386
+ small: { width: 320, height: 180 },
1387
+ medium: { width: 640, height: 360 },
1388
+ large: { width: 1280, height: 720 }
1389
+ }
1390
+
1391
+ function getThumbnailUrl(media, size = 'medium') {
1392
+ const { width, height } = thumbnailSizes[size]
1393
+ return `${media.thumbnail_base}?w=${width}&h=${height}&fit=cover`
1394
+ }
1395
+ </script>
1396
+ ```
1397
+
1398
+ ### 3. Implement Virtual Scrolling
1399
+
1400
+ ```vue
1401
+ <template>
1402
+ <RecycleScroller
1403
+ class="video-list"
1404
+ :items="videos"
1405
+ :item-size="120"
1406
+ key-field="uuid"
1407
+ v-slot="{ item }"
1408
+ >
1409
+ <VideoListItem :video="item" />
1410
+ </RecycleScroller>
1411
+ </template>
1412
+
1413
+ <script setup>
1414
+ import { RecycleScroller } from 'vue-virtual-scroller'
1415
+ import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
1416
+ </script>
1417
+ ```
1418
+
1419
+ ### 4. Cache Playback URLs
1420
+
1421
+ ```typescript
1422
+ // Use a simple LRU cache for playback URLs
1423
+ import lru from 'tiny-lru'
1424
+
1425
+ const playbackCache = lru(100, 3600000) // 100 items, 1 hour TTL
1426
+
1427
+ async function getPlaybackUrl(uuid) {
1428
+ const cached = playbackCache.get(uuid)
1429
+ if (cached && cached.expiresAt > Date.now()) {
1430
+ return cached.url
1431
+ }
1432
+
1433
+ const response = await api.get(`/video/${uuid}/playback`)
1434
+ playbackCache.set(uuid, {
1435
+ url: response.data.playback_url,
1436
+ expiresAt: new Date(response.data.token_expires_at).getTime()
1437
+ })
1438
+
1439
+ return response.data.playback_url
1440
+ }
1441
+ ```
1442
+
1443
+ ### 5. Debounce Editor Operations
1444
+
1445
+ ```typescript
1446
+ import { debounce } from 'lodash-es'
1447
+
1448
+ const saveRecipe = debounce(async (recipe) => {
1449
+ await api.post('/video/draft', { recipe })
1450
+ }, 1000)
1451
+
1452
+ const updateTimeline = debounce((changes) => {
1453
+ editorStore.updateTimeline(changes)
1454
+ }, 100)
1455
+ ```
1456
+
1457
+ ## Best Practices
1458
+
1459
+ 1. **Always handle loading states** - Show spinners or skeletons
1460
+ 2. **Provide feedback** - Acknowledge user actions immediately
1461
+ 3. **Test on real devices** - Especially for mobile gestures
1462
+ 4. **Monitor performance** - Track video load times and errors
1463
+ 5. **Implement retry logic** - For network failures
1464
+ 6. **Use appropriate video formats** - MP4 for compatibility
1465
+ 7. **Optimize for mobile data** - Offer quality settings
1466
+ 8. **Cache aggressively** - But respect token expiry
1467
+ 9. **Handle edge cases** - No network, low storage, etc.
1468
+ 10. **Accessibility** - Captions, keyboard controls, ARIA labels
1469
+
1470
+ ## Support
1471
+
1472
+ For more examples and support:
1473
+
1474
+ - **GitHub Examples**: https://github.com/mediables/examples
1475
+ - **CodeSandbox Demos**: https://codesandbox.io/u/mediables
1476
+ - **Video Tutorials**: https://youtube.com/@mediables
1477
+ - **Discord Community**: https://discord.gg/mediables