@djangocfg/ui-tools 2.1.404 → 2.1.408

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 (336) hide show
  1. package/README.md +9 -11
  2. package/dist/file-icon/index.cjs +449 -61
  3. package/dist/file-icon/index.cjs.map +1 -1
  4. package/dist/file-icon/index.d.cts +56 -18
  5. package/dist/file-icon/index.d.ts +56 -18
  6. package/dist/file-icon/index.mjs +448 -62
  7. package/dist/file-icon/index.mjs.map +1 -1
  8. package/dist/tree/index.cjs +49 -22
  9. package/dist/tree/index.cjs.map +1 -1
  10. package/dist/tree/index.d.cts +9 -3
  11. package/dist/tree/index.d.ts +9 -3
  12. package/dist/tree/index.mjs +49 -22
  13. package/dist/tree/index.mjs.map +1 -1
  14. package/dist/{types-B_zhyAqR.d.cts → types-eEu8SeiQ.d.cts} +4 -0
  15. package/dist/{types-B_zhyAqR.d.ts → types-eEu8SeiQ.d.ts} +4 -0
  16. package/package.json +13 -16
  17. package/src/components/FloatingToolbar/index.tsx +37 -3
  18. package/src/lib/page-snapshot/__tests__/capture-integration.test.ts +85 -0
  19. package/src/lib/page-snapshot/__tests__/engine.test.ts +36 -0
  20. package/src/lib/page-snapshot/__tests__/redaction-integration.test.ts +99 -0
  21. package/src/lib/page-snapshot/__tests__/tokens.test.ts +17 -0
  22. package/src/lib/page-snapshot/capture/__tests__/budget.test.ts +49 -0
  23. package/src/lib/page-snapshot/capture/__tests__/chrome-filter.test.ts +47 -0
  24. package/src/lib/page-snapshot/capture/__tests__/fold.test.ts +66 -0
  25. package/src/lib/page-snapshot/capture/__tests__/scope.test.ts +74 -0
  26. package/src/lib/page-snapshot/capture/__tests__/walk.test.ts +129 -0
  27. package/src/lib/page-snapshot/capture/accessible-name.ts +73 -0
  28. package/src/lib/page-snapshot/capture/budget.ts +95 -0
  29. package/src/lib/page-snapshot/capture/chrome-filter.ts +81 -0
  30. package/src/lib/page-snapshot/capture/classify.ts +111 -0
  31. package/src/lib/page-snapshot/capture/dom-utils.ts +111 -0
  32. package/src/lib/page-snapshot/capture/fold.ts +96 -0
  33. package/src/lib/page-snapshot/capture/scope.ts +169 -0
  34. package/src/lib/page-snapshot/capture/walk.ts +250 -0
  35. package/src/lib/page-snapshot/cst/__tests__/serialize.test.ts +50 -0
  36. package/src/lib/page-snapshot/cst/directives.ts +47 -0
  37. package/src/lib/page-snapshot/cst/payload.ts +50 -0
  38. package/src/lib/page-snapshot/cst/serialize.ts +84 -0
  39. package/src/lib/page-snapshot/cst/types.ts +115 -0
  40. package/src/lib/page-snapshot/engine.ts +176 -0
  41. package/src/lib/page-snapshot/index.ts +93 -0
  42. package/src/lib/page-snapshot/react/PageSnapshotChip.tsx +72 -0
  43. package/src/lib/page-snapshot/react/PageSnapshotPreview.tsx +78 -0
  44. package/src/lib/page-snapshot/react/__tests__/PageSnapshotChip.test.tsx +54 -0
  45. package/src/lib/page-snapshot/react/__tests__/provider.test.tsx +103 -0
  46. package/src/lib/page-snapshot/react/__tests__/use-page-snapshot-toggle.test.tsx +62 -0
  47. package/src/lib/page-snapshot/react/provider.tsx +162 -0
  48. package/src/lib/page-snapshot/react/use-page-snapshot-toggle.ts +47 -0
  49. package/src/lib/page-snapshot/react/use-page-snapshot.ts +67 -0
  50. package/src/lib/page-snapshot/redaction/__tests__/audit.test.ts +25 -0
  51. package/src/lib/page-snapshot/redaction/__tests__/heuristics.test.ts +73 -0
  52. package/src/lib/page-snapshot/redaction/__tests__/luhn.test.ts +26 -0
  53. package/src/lib/page-snapshot/redaction/__tests__/patterns.test.ts +60 -0
  54. package/src/lib/page-snapshot/redaction/audit.ts +58 -0
  55. package/src/lib/page-snapshot/redaction/heuristics.ts +75 -0
  56. package/src/lib/page-snapshot/redaction/index.ts +75 -0
  57. package/src/lib/page-snapshot/redaction/luhn.ts +25 -0
  58. package/src/lib/page-snapshot/redaction/patterns.ts +111 -0
  59. package/src/lib/page-snapshot/refs/__tests__/registry.test.ts +24 -0
  60. package/src/lib/page-snapshot/refs/registry.ts +46 -0
  61. package/src/lib/page-snapshot/staleness/__tests__/hash.test.ts +34 -0
  62. package/src/lib/page-snapshot/staleness/hash.ts +20 -0
  63. package/src/lib/page-snapshot/tokens.ts +15 -0
  64. package/src/tools/AudioPlayer/context/PlayerProvider.tsx +13 -14
  65. package/src/tools/AudioPlayer/hooks/useAudioElementEvents.ts +55 -6
  66. package/src/tools/AudioPlayer/lazy.tsx +13 -27
  67. package/src/tools/AudioPlayer/parts/Meta/TimeDisplay.tsx +2 -5
  68. package/src/tools/Chat/README.md +267 -39
  69. package/src/tools/Chat/composer/Composer.tsx +471 -0
  70. package/src/tools/Chat/composer/ComposerActionBar.tsx +65 -0
  71. package/src/tools/Chat/composer/ComposerBanner.tsx +128 -0
  72. package/src/tools/Chat/composer/ComposerButton.tsx +64 -0
  73. package/src/tools/Chat/composer/ComposerFooter.tsx +90 -0
  74. package/src/tools/Chat/composer/ComposerMenuButton.tsx +62 -0
  75. package/src/tools/Chat/composer/ComposerModelPicker.tsx +104 -0
  76. package/src/tools/Chat/composer/ComposerRichTextarea.tsx +88 -0
  77. package/src/tools/Chat/composer/ComposerToolPill.tsx +95 -0
  78. package/src/tools/Chat/composer/index.ts +45 -0
  79. package/src/tools/Chat/composer/size-context.tsx +26 -0
  80. package/src/tools/Chat/composer/types.ts +143 -0
  81. package/src/tools/Chat/composer/useComposerActions.tsx +164 -0
  82. package/src/tools/Chat/context/ChatProvider.tsx +54 -3
  83. package/src/tools/Chat/core/__tests__/metadata.test.ts +69 -0
  84. package/src/tools/Chat/core/index.ts +23 -1
  85. package/src/tools/Chat/core/markdown.ts +1 -1
  86. package/src/tools/Chat/core/metadata.ts +47 -0
  87. package/src/tools/Chat/core/payload-dispatch.ts +1 -1
  88. package/src/tools/Chat/core/transport/http.ts +71 -32
  89. package/src/tools/Chat/core/transport/sse.ts +18 -10
  90. package/src/tools/Chat/highlight/HighlightOverlay.tsx +101 -0
  91. package/src/tools/Chat/highlight/README.md +103 -0
  92. package/src/tools/Chat/highlight/SpotlightCanvas.tsx +153 -0
  93. package/src/tools/Chat/highlight/__tests__/HighlightOverlay.test.tsx +112 -0
  94. package/src/tools/Chat/highlight/__tests__/resolveRef.test.ts +55 -0
  95. package/src/tools/Chat/highlight/index.ts +21 -0
  96. package/src/tools/Chat/highlight/resolveRef.ts +42 -0
  97. package/src/tools/Chat/highlight/types.ts +49 -0
  98. package/src/tools/Chat/highlight/useHighlightTargets.ts +128 -0
  99. package/src/tools/Chat/hooks/index.ts +0 -5
  100. package/src/tools/Chat/hooks/useAutoFocusOnStreamEnd.ts +28 -47
  101. package/src/tools/Chat/hooks/useChat.ts +47 -14
  102. package/src/tools/Chat/hooks/useChatComposer.ts +2 -2
  103. package/src/tools/Chat/hooks/useChatLayout.ts +1 -1
  104. package/src/tools/Chat/hooks/useStreamEndFocus.ts +54 -0
  105. package/src/tools/Chat/index.ts +25 -219
  106. package/src/tools/Chat/launcher/ChatDock.tsx +1 -1
  107. package/src/tools/Chat/launcher/ChatLauncher.tsx +1 -1
  108. package/src/tools/Chat/launcher/{ChatHeader.tsx → header/ChatHeader.tsx} +24 -11
  109. package/src/tools/Chat/launcher/{ChatHeaderActionButton.tsx → header/ChatHeaderActionButton.tsx} +34 -3
  110. package/src/tools/Chat/launcher/{ChatHeaderLanguageButton.tsx → header/ChatHeaderLanguageButton.tsx} +2 -2
  111. package/src/tools/Chat/launcher/{ChatHeaderModeToggle.tsx → header/ChatHeaderModeToggle.tsx} +1 -1
  112. package/src/tools/Chat/launcher/{ChatHeaderResetButton.tsx → header/ChatHeaderResetButton.tsx} +2 -1
  113. package/src/tools/Chat/launcher/{HeaderSlots.tsx → header/HeaderSlots.tsx} +3 -3
  114. package/src/tools/Chat/launcher/header/index.ts +26 -0
  115. package/src/tools/Chat/launcher/index.ts +3 -10
  116. package/src/tools/Chat/lazy.tsx +38 -284
  117. package/src/tools/Chat/{components → messages}/MessageBubble.tsx +58 -5
  118. package/src/tools/Chat/{components → messages}/MessageList.tsx +8 -25
  119. package/src/tools/Chat/messages/blocks/MessageBlocks.tsx +131 -0
  120. package/src/tools/Chat/messages/blocks/builtin.tsx +91 -0
  121. package/src/tools/Chat/messages/blocks/index.ts +12 -0
  122. package/src/tools/Chat/messages/blocks/registry.tsx +42 -0
  123. package/src/tools/Chat/messages/blocks/renderers/AudioBlock.tsx +20 -0
  124. package/src/tools/Chat/messages/blocks/renderers/CodeBlock.tsx +19 -0
  125. package/src/tools/Chat/messages/blocks/renderers/GalleryBlock.tsx +26 -0
  126. package/src/tools/Chat/messages/blocks/renderers/ImageBlock.tsx +27 -0
  127. package/src/tools/Chat/messages/blocks/renderers/JsonBlock.tsx +12 -0
  128. package/src/tools/Chat/messages/blocks/renderers/LottieBlock.tsx +11 -0
  129. package/src/tools/Chat/messages/blocks/renderers/MapBlock.tsx +36 -0
  130. package/src/tools/Chat/messages/blocks/renderers/MermaidBlock.tsx +11 -0
  131. package/src/tools/Chat/messages/blocks/renderers/VideoBlock.tsx +24 -0
  132. package/src/tools/Chat/messages/blocks/renderers/types.ts +8 -0
  133. package/src/tools/Chat/{components → messages}/index.ts +11 -5
  134. package/src/tools/Chat/public.ts +212 -0
  135. package/src/tools/Chat/shell/ChatRoot.tsx +326 -0
  136. package/src/tools/Chat/{components → shell}/EmptyState.tsx +4 -2
  137. package/src/tools/Chat/shell/index.ts +15 -0
  138. package/src/tools/Chat/types/block.ts +120 -0
  139. package/src/tools/Chat/types/config.ts +0 -5
  140. package/src/tools/Chat/types/index.ts +17 -0
  141. package/src/tools/Chat/types/message.ts +3 -0
  142. package/src/tools/Chat/utils/index.ts +4 -0
  143. package/src/tools/CodeEditor/README.md +4 -6
  144. package/src/tools/CodeEditor/components/DiffEditor.tsx +48 -13
  145. package/src/tools/CodeEditor/components/Editor.tsx +96 -44
  146. package/src/tools/CodeEditor/context/EditorProvider.tsx +34 -17
  147. package/src/tools/CodeEditor/hooks/useEditorTheme.ts +92 -99
  148. package/src/tools/CodeEditor/hooks/useMonaco.ts +37 -22
  149. package/src/tools/CodeEditor/lazy.tsx +6 -0
  150. package/src/tools/CodeEditor/lib/index.ts +1 -1
  151. package/src/tools/CodeEditor/lib/themes.ts +3 -39
  152. package/src/tools/CronScheduler/CronScheduler.client.tsx +230 -61
  153. package/src/tools/CronScheduler/components/CustomInput.tsx +21 -4
  154. package/src/tools/CronScheduler/components/DayChips.tsx +13 -11
  155. package/src/tools/CronScheduler/components/MonthDayGrid.tsx +4 -4
  156. package/src/tools/CronScheduler/components/SchedulePreview.tsx +7 -3
  157. package/src/tools/CronScheduler/components/TimeSelector.tsx +1 -1
  158. package/src/tools/CronScheduler/index.tsx +1 -1
  159. package/src/tools/CronScheduler/types/index.ts +8 -3
  160. package/src/tools/CronScheduler/utils/cron-humanize.ts +61 -16
  161. package/src/tools/CronScheduler/utils/cron-parser.ts +13 -4
  162. package/src/tools/FileIcon/FileIcon.tsx +24 -39
  163. package/src/tools/FileIcon/get-file-icon.ts +73 -0
  164. package/src/tools/FileIcon/icons/icon-data.ts +399 -0
  165. package/src/tools/FileIcon/index.ts +4 -0
  166. package/src/tools/FileIcon/loader.ts +17 -35
  167. package/src/tools/FileIcon/specialFolders.ts +18 -0
  168. package/src/tools/Gallery/components/lightbox/GalleryLightbox.tsx +112 -35
  169. package/src/tools/Gallery/components/media/GalleryVideo.tsx +21 -2
  170. package/src/tools/Gallery/components/preview/GalleryCarousel.tsx +11 -1
  171. package/src/tools/Gallery/hooks/usePreloadImages.ts +54 -7
  172. package/src/tools/ImageViewer/components/ImageInfo.tsx +12 -1
  173. package/src/tools/ImageViewer/components/ImageToolbar.tsx +51 -43
  174. package/src/tools/ImageViewer/components/ImageViewer.tsx +106 -26
  175. package/src/tools/ImageViewer/hooks/useImageLoading.ts +13 -0
  176. package/src/tools/ImageViewer/utils/constants.ts +3 -0
  177. package/src/tools/ImageViewer/utils/index.ts +1 -0
  178. package/src/tools/JsonForm/JsonSchemaForm.tsx +4 -1
  179. package/src/tools/JsonForm/templates/ArrayFieldTemplate.tsx +5 -3
  180. package/src/tools/JsonForm/templates/BaseInputTemplate.tsx +7 -4
  181. package/src/tools/JsonForm/templates/ErrorListTemplate.tsx +3 -1
  182. package/src/tools/JsonForm/templates/ObjectFieldTemplate.tsx +23 -3
  183. package/src/tools/JsonForm/widgets/ColorWidget.tsx +20 -12
  184. package/src/tools/JsonForm/widgets/NumberWidget.tsx +14 -9
  185. package/src/tools/JsonForm/widgets/RadioWidget.tsx +78 -0
  186. package/src/tools/JsonForm/widgets/SelectWidget.tsx +1 -0
  187. package/src/tools/JsonForm/widgets/SliderWidget.tsx +7 -4
  188. package/src/tools/JsonForm/widgets/TextWidget.tsx +41 -17
  189. package/src/tools/JsonForm/widgets/index.ts +1 -0
  190. package/src/tools/JsonTree/components/JsonContent.tsx +115 -40
  191. package/src/tools/LottiePlayer/LottiePlayer.client.tsx +177 -72
  192. package/src/tools/LottiePlayer/index.tsx +14 -4
  193. package/src/tools/LottiePlayer/lazy.tsx +11 -3
  194. package/src/tools/LottiePlayer/types.ts +31 -1
  195. package/src/tools/LottiePlayer/useLottie.ts +32 -9
  196. package/src/tools/LottiePlayer/usePrefersReducedMotion.ts +46 -0
  197. package/src/tools/Map/components/LayerSwitcher.tsx +54 -21
  198. package/src/tools/Map/components/MapCluster.tsx +28 -21
  199. package/src/tools/Map/components/MapContainer.tsx +11 -4
  200. package/src/tools/Map/components/MapLegend.tsx +46 -15
  201. package/src/tools/Map/components/MapMarker.tsx +31 -2
  202. package/src/tools/Map/hooks/useMapEvents.ts +64 -105
  203. package/src/tools/MarkdownEditor/MarkdownEditor.tsx +61 -6
  204. package/src/tools/MarkdownEditor/MentionList.tsx +37 -4
  205. package/src/tools/MarkdownEditor/createMentionSuggestion.ts +11 -0
  206. package/src/tools/MarkdownEditor/lazy.tsx +32 -7
  207. package/src/tools/MarkdownEditor/styles.css +13 -0
  208. package/src/tools/MarkdownMessage/CodeBlock.tsx +40 -17
  209. package/src/tools/MarkdownMessage/MarkdownMessage.tsx +26 -6
  210. package/src/tools/MarkdownMessage/components.tsx +22 -9
  211. package/src/tools/MarkdownMessage/types.ts +24 -1
  212. package/src/tools/Mermaid/Mermaid.client.tsx +27 -5
  213. package/src/tools/Mermaid/components/MermaidErrorPanel.tsx +31 -0
  214. package/src/tools/Mermaid/components/MermaidFullscreenModal.tsx +14 -17
  215. package/src/tools/Mermaid/hooks/useMermaidRenderer.ts +264 -168
  216. package/src/tools/Mermaid/hooks/useMermaidValidation.ts +76 -10
  217. package/src/tools/Mermaid/index.tsx +6 -0
  218. package/src/tools/Mermaid/utils/mermaid-helpers.ts +141 -18
  219. package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/SchemaFields/FieldRow.tsx +11 -1
  220. package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/SchemaFields/buildTree.ts +49 -20
  221. package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/index.tsx +7 -0
  222. package/src/tools/OpenapiViewer/components/DocsLayout/grouping.ts +7 -4
  223. package/src/tools/OpenapiViewer/constants.ts +3 -0
  224. package/src/tools/OpenapiViewer/hooks/useOpenApiSchema.ts +73 -11
  225. package/src/tools/OpenapiViewer/utils/schemaExport.ts +26 -6
  226. package/src/tools/PrettyCode/PrettyCode.client.tsx +23 -16
  227. package/src/tools/PrettyCode/lazy.tsx +1 -1
  228. package/src/tools/SpeechRecognition/README.md +1 -1
  229. package/src/tools/SpeechRecognition/__tests__/language.test.ts +9 -3
  230. package/src/tools/SpeechRecognition/components/RecordingPulse.tsx +59 -0
  231. package/src/tools/SpeechRecognition/components/index.ts +2 -0
  232. package/src/tools/SpeechRecognition/core/engine/external.ts +24 -7
  233. package/src/tools/SpeechRecognition/core/language.ts +23 -6
  234. package/src/tools/SpeechRecognition/hooks/usePushToTalk.ts +36 -5
  235. package/src/tools/SpeechRecognition/hooks/useSpeechRecognition.ts +18 -11
  236. package/src/tools/SpeechRecognition/widgets/VoiceComposerSlot.tsx +94 -26
  237. package/src/tools/SpeechRecognition/widgets/index.ts +1 -1
  238. package/src/tools/Tree/README.md +4 -8
  239. package/src/tools/Tree/TreeRoot.tsx +22 -10
  240. package/src/tools/Tree/components/TreeContent.tsx +24 -4
  241. package/src/tools/Tree/components/TreeLabel.tsx +8 -2
  242. package/src/tools/Tree/components/TreeRow.tsx +16 -6
  243. package/src/tools/Tree/data/flatten.ts +10 -4
  244. package/src/tools/Tree/types.ts +4 -0
  245. package/src/tools/Uploader/components/UploadAddButton.tsx +29 -6
  246. package/src/tools/Uploader/components/UploadDropzone.tsx +63 -7
  247. package/src/tools/Uploader/components/UploadPageDropOverlay.tsx +19 -5
  248. package/src/tools/Uploader/components/UploadPreviewItem.tsx +47 -17
  249. package/src/tools/Uploader/components/UploadPreviewList.tsx +24 -12
  250. package/src/tools/Uploader/utils/formatters.ts +8 -3
  251. package/src/tools/VideoPlayer/README.md +87 -230
  252. package/src/tools/VideoPlayer/VideoPlayer.tsx +82 -0
  253. package/src/tools/VideoPlayer/canvas/canvas-dispatcher.tsx +34 -0
  254. package/src/tools/VideoPlayer/canvas/hls-canvas.tsx +39 -0
  255. package/src/tools/VideoPlayer/canvas/iframe-canvas.tsx +33 -0
  256. package/src/tools/VideoPlayer/canvas/index.ts +12 -0
  257. package/src/tools/VideoPlayer/canvas/jsx-augmentation.ts +47 -0
  258. package/src/tools/VideoPlayer/canvas/native-canvas.tsx +38 -0
  259. package/src/tools/VideoPlayer/canvas/vimeo-canvas.tsx +40 -0
  260. package/src/tools/VideoPlayer/canvas/youtube-canvas.tsx +78 -0
  261. package/src/tools/VideoPlayer/index.ts +51 -65
  262. package/src/tools/VideoPlayer/lazy.tsx +11 -54
  263. package/src/tools/VideoPlayer/parts/controls-bar.tsx +35 -0
  264. package/src/tools/VideoPlayer/parts/fullscreen.tsx +19 -0
  265. package/src/tools/VideoPlayer/parts/index.ts +15 -0
  266. package/src/tools/VideoPlayer/parts/pip.tsx +19 -0
  267. package/src/tools/VideoPlayer/parts/play-button.tsx +19 -0
  268. package/src/tools/VideoPlayer/parts/playback-rate.tsx +31 -0
  269. package/src/tools/VideoPlayer/parts/poster.tsx +3 -0
  270. package/src/tools/VideoPlayer/parts/seek-bar.tsx +26 -0
  271. package/src/tools/VideoPlayer/parts/volume.tsx +32 -0
  272. package/src/tools/VideoPlayer/styles/video-player.css +141 -0
  273. package/src/tools/VideoPlayer/types.ts +82 -0
  274. package/src/tools/VideoPlayer/utils/parse-embed-url.ts +70 -0
  275. package/src/tools/VideoPlayer/utils/vimeo-id.ts +24 -0
  276. package/src/tools/VideoPlayer/utils/youtube-id.ts +64 -0
  277. package/src/tools/index.ts +37 -29
  278. package/src/tools/Chat/components/AudioToggle.tsx +0 -78
  279. package/src/tools/Chat/components/ChatRoot.tsx +0 -305
  280. package/src/tools/Chat/components/Composer.tsx +0 -216
  281. package/src/tools/Chat/hooks/useChatScroll.ts +0 -145
  282. package/src/tools/Chat/types.ts +0 -9
  283. package/src/tools/JsonTree/components/JsonToolbar.tsx +0 -95
  284. package/src/tools/JsonTree/hooks/useElementCorner.ts +0 -84
  285. package/src/tools/JsonTree/hooks/useNavbarHeight.ts +0 -83
  286. package/src/tools/OpenapiViewer/components/DocsLayout/schemaFields.ts +0 -121
  287. package/src/tools/Tour/README.md +0 -373
  288. package/src/tools/Tour/components/Tour.tsx +0 -12
  289. package/src/tools/Tour/components/TourContent.tsx +0 -171
  290. package/src/tools/Tour/components/TourNavigation.tsx +0 -77
  291. package/src/tools/Tour/components/TourProgress.tsx +0 -88
  292. package/src/tools/Tour/components/TourSpotlight.tsx +0 -199
  293. package/src/tools/Tour/components/index.ts +0 -5
  294. package/src/tools/Tour/context/TourContext.ts +0 -19
  295. package/src/tools/Tour/context/TourProvider.tsx +0 -292
  296. package/src/tools/Tour/context/index.ts +0 -2
  297. package/src/tools/Tour/hooks/index.ts +0 -3
  298. package/src/tools/Tour/hooks/useKeyboardNavigation.ts +0 -59
  299. package/src/tools/Tour/hooks/useStepTarget.ts +0 -121
  300. package/src/tools/Tour/hooks/useTour.ts +0 -42
  301. package/src/tools/Tour/index.ts +0 -38
  302. package/src/tools/Tour/types/index.ts +0 -224
  303. package/src/tools/Tour/utils/dom.ts +0 -98
  304. package/src/tools/Tour/utils/index.ts +0 -3
  305. package/src/tools/Tour/utils/logger.ts +0 -3
  306. package/src/tools/Tour/utils/scrollIntoView.ts +0 -24
  307. package/src/tools/VideoPlayer/components/VideoControls.tsx +0 -138
  308. package/src/tools/VideoPlayer/components/VideoErrorFallback.tsx +0 -172
  309. package/src/tools/VideoPlayer/components/VideoPlayer.tsx +0 -201
  310. package/src/tools/VideoPlayer/components/index.ts +0 -14
  311. package/src/tools/VideoPlayer/context/VideoPlayerContext.tsx +0 -52
  312. package/src/tools/VideoPlayer/context/index.ts +0 -8
  313. package/src/tools/VideoPlayer/hooks/index.ts +0 -12
  314. package/src/tools/VideoPlayer/hooks/useVideoPlayerSettings.ts +0 -71
  315. package/src/tools/VideoPlayer/hooks/useVideoPositionCache.ts +0 -117
  316. package/src/tools/VideoPlayer/providers/NativeProvider.tsx +0 -284
  317. package/src/tools/VideoPlayer/providers/StreamProvider.tsx +0 -505
  318. package/src/tools/VideoPlayer/providers/VidstackProvider.tsx +0 -397
  319. package/src/tools/VideoPlayer/providers/index.ts +0 -8
  320. package/src/tools/VideoPlayer/types/index.ts +0 -38
  321. package/src/tools/VideoPlayer/types/player.ts +0 -116
  322. package/src/tools/VideoPlayer/types/provider.ts +0 -93
  323. package/src/tools/VideoPlayer/types/sources.ts +0 -97
  324. package/src/tools/VideoPlayer/utils/debug.ts +0 -14
  325. package/src/tools/VideoPlayer/utils/fileSource.ts +0 -78
  326. package/src/tools/VideoPlayer/utils/index.ts +0 -12
  327. package/src/tools/VideoPlayer/utils/resolvers.ts +0 -75
  328. /package/src/tools/Chat/{config.ts → constants.ts} +0 -0
  329. /package/src/tools/Chat/launcher/{ChatHeaderAudioToggle.tsx → header/ChatHeaderAudioToggle.tsx} +0 -0
  330. /package/src/tools/Chat/{components → messages}/Attachments.tsx +0 -0
  331. /package/src/tools/Chat/{components → messages}/JumpToLatest.tsx +0 -0
  332. /package/src/tools/Chat/{components → messages}/MessageActions.tsx +0 -0
  333. /package/src/tools/Chat/{components → messages}/Sources.tsx +0 -0
  334. /package/src/tools/Chat/{components → messages}/StreamingIndicator.tsx +0 -0
  335. /package/src/tools/Chat/{components → messages}/ToolCalls.tsx +0 -0
  336. /package/src/tools/Chat/{components → shell}/ErrorBanner.tsx +0 -0
@@ -1,121 +0,0 @@
1
- 'use client';
2
-
3
- import { useState, useEffect, useCallback, useRef } from 'react';
4
- import { findTargetElements, getElementBorderRadius } from '../utils/dom';
5
- import { scrollToElement } from '../utils/scrollIntoView';
6
- import type { SpotlightTarget } from '../types';
7
-
8
- interface UseStepTargetOptions {
9
- scrollToTarget?: boolean;
10
- scrollBehavior?: ScrollBehavior;
11
- spotlightPadding?: number;
12
- }
13
-
14
- interface UseStepTargetReturn {
15
- targets: SpotlightTarget[];
16
- isReady: boolean;
17
- }
18
-
19
- /**
20
- * Hook to track target elements for current tour step.
21
- * Handles scroll, resize, and DOM mutations.
22
- */
23
- export function useStepTarget(
24
- target: string | undefined,
25
- stepId: string | undefined,
26
- options: UseStepTargetOptions = {}
27
- ): UseStepTargetReturn {
28
- const {
29
- scrollToTarget = true,
30
- scrollBehavior = 'smooth',
31
- spotlightPadding = 8,
32
- } = options;
33
-
34
- const [targets, setTargets] = useState<SpotlightTarget[]>([]);
35
- const [isReady, setIsReady] = useState(false);
36
- const hasScrolledRef = useRef(false);
37
- const updateTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
38
-
39
- const updateTargets = useCallback(() => {
40
- if (!stepId) {
41
- setTargets([]);
42
- setIsReady(false);
43
- return;
44
- }
45
-
46
- const elements = findTargetElements(target, stepId);
47
- if (elements.length === 0) {
48
- setTargets([]);
49
- setIsReady(false);
50
- return;
51
- }
52
-
53
- const newTargets: SpotlightTarget[] = elements.map((element) => ({
54
- element,
55
- rect: element.getBoundingClientRect(),
56
- padding: spotlightPadding,
57
- radius: getElementBorderRadius(element),
58
- }));
59
-
60
- setTargets(newTargets);
61
- setIsReady(true);
62
-
63
- // Scroll to first target on initial render
64
- if (scrollToTarget && !hasScrolledRef.current && elements[0]) {
65
- scrollToElement(elements[0], scrollBehavior);
66
- hasScrolledRef.current = true;
67
- }
68
- }, [target, stepId, scrollToTarget, scrollBehavior, spotlightPadding]);
69
-
70
- // Debounced update for performance
71
- const debouncedUpdate = useCallback(() => {
72
- if (updateTimeoutRef.current) {
73
- clearTimeout(updateTimeoutRef.current);
74
- }
75
- updateTimeoutRef.current = setTimeout(updateTargets, 16);
76
- }, [updateTargets]);
77
-
78
- // Reset scroll flag when step changes
79
- useEffect(() => {
80
- hasScrolledRef.current = false;
81
- }, [stepId]);
82
-
83
- // Initial update and event listeners
84
- useEffect(() => {
85
- if (!stepId) return;
86
-
87
- // Initial update
88
- updateTargets();
89
-
90
- // Resize listener
91
- window.addEventListener('resize', debouncedUpdate);
92
-
93
- // Scroll listener (capture phase to catch all scrolls)
94
- window.addEventListener('scroll', debouncedUpdate, true);
95
-
96
- // Mutation observer for DOM changes
97
- const observer = new MutationObserver(debouncedUpdate);
98
- observer.observe(document.body, {
99
- childList: true,
100
- subtree: true,
101
- attributes: true,
102
- attributeFilter: ['style', 'class'],
103
- });
104
-
105
- // ResizeObserver for element size changes
106
- const resizeObserver = new ResizeObserver(debouncedUpdate);
107
- resizeObserver.observe(document.body);
108
-
109
- return () => {
110
- window.removeEventListener('resize', debouncedUpdate);
111
- window.removeEventListener('scroll', debouncedUpdate, true);
112
- observer.disconnect();
113
- resizeObserver.disconnect();
114
- if (updateTimeoutRef.current) {
115
- clearTimeout(updateTimeoutRef.current);
116
- }
117
- };
118
- }, [stepId, updateTargets, debouncedUpdate]);
119
-
120
- return { targets, isReady };
121
- }
@@ -1,42 +0,0 @@
1
- 'use client';
2
-
3
- import { useTourContext } from '../context/TourContext';
4
- import type { UseTourReturn } from '../types';
5
-
6
- /**
7
- * Hook to control the tour.
8
- * Must be used within a TourProvider.
9
- */
10
- export function useTour(): UseTourReturn {
11
- const {
12
- start,
13
- next,
14
- previous,
15
- goTo,
16
- close,
17
- isActive,
18
- activeTourId,
19
- currentStep,
20
- currentStepIndex,
21
- totalSteps,
22
- isFirstStep,
23
- isLastStep,
24
- progress,
25
- } = useTourContext();
26
-
27
- return {
28
- start,
29
- next,
30
- previous,
31
- goTo,
32
- close,
33
- isActive,
34
- activeTourId,
35
- currentStep,
36
- currentStepIndex,
37
- totalSteps,
38
- isFirstStep,
39
- isLastStep,
40
- progress,
41
- };
42
- }
@@ -1,38 +0,0 @@
1
- // Components
2
- export { Tour } from './components/Tour';
3
- export { TourSpotlight } from './components/TourSpotlight';
4
- export { TourProgress } from './components/TourProgress';
5
- export { TourNavigation } from './components/TourNavigation';
6
- export { TourContent } from './components/TourContent';
7
-
8
- // Context
9
- export { TourProvider } from './context';
10
-
11
- // Hooks
12
- export { useTour } from './hooks/useTour';
13
- export { useStepTarget } from './hooks/useStepTarget';
14
- export { useKeyboardNavigation } from './hooks/useKeyboardNavigation';
15
-
16
- // Utils
17
- export { findTargetElements, isElementInViewport } from './utils/dom';
18
- export { scrollToElement } from './utils/scrollIntoView';
19
-
20
- // Types
21
- export type {
22
- Tour as TourConfig,
23
- TourStep,
24
- TourAction,
25
- TourState,
26
- TourPosition,
27
- TourAlign,
28
- ProgressVariant,
29
- TourCallbacks,
30
- TourProviderProps,
31
- TourProps,
32
- TourContentProps,
33
- TourSpotlightProps,
34
- TourProgressProps,
35
- TourNavigationProps,
36
- SpotlightTarget,
37
- UseTourReturn,
38
- } from './types';
@@ -1,224 +0,0 @@
1
- import type { ReactNode } from 'react';
2
-
3
- // Position & Alignment
4
- export type TourPosition = 'top' | 'bottom' | 'left' | 'right' | 'auto';
5
- export type TourAlign = 'start' | 'center' | 'end';
6
- export type ProgressVariant = 'dots' | 'bar' | 'fraction' | 'none';
7
-
8
- // Step Action
9
- export interface TourAction {
10
- label: ReactNode;
11
- onClick: () => void;
12
- variant?: 'default' | 'outline' | 'ghost' | 'destructive';
13
- }
14
-
15
- // Step Definition
16
- export interface TourStep {
17
- /** Unique step identifier */
18
- id: string;
19
- /** CSS selector or data-tour-step-id value to find target element */
20
- target?: string;
21
- /** Step title */
22
- title: ReactNode;
23
- /** Step description/content */
24
- content: ReactNode;
25
- /** Popover position relative to target */
26
- position?: TourPosition;
27
- /** Offset from target in pixels */
28
- offset?: number;
29
- /** Alignment along the position axis */
30
- align?: TourAlign;
31
- /** Alignment offset in pixels */
32
- alignOffset?: number;
33
- /** Custom class for this step's popover */
34
- className?: string;
35
- /** Route to navigate on Next (for multi-page tours) */
36
- nextRoute?: string;
37
- /** Route to navigate on Previous */
38
- previousRoute?: string;
39
- /** Custom Next button label */
40
- nextLabel?: ReactNode;
41
- /** Custom Previous button label */
42
- previousLabel?: ReactNode;
43
- /** Disable spotlight for this step */
44
- disableSpotlight?: boolean;
45
- /** Spotlight padding around target */
46
- spotlightPadding?: number;
47
- /** Custom spotlight border radius */
48
- spotlightRadius?: number;
49
- /** Allow interaction with target while step is active */
50
- allowTargetInteraction?: boolean;
51
- /** Auto-advance after delay (ms) */
52
- autoAdvance?: number;
53
- /** Custom action buttons */
54
- actions?: TourAction[];
55
- /** Called before step shows, return false to skip */
56
- onBeforeShow?: () => boolean | Promise<boolean>;
57
- /** Called after step renders */
58
- onShow?: () => void;
59
- /** Called before step hides */
60
- onHide?: () => void;
61
- }
62
-
63
- // Tour Definition
64
- export interface Tour {
65
- id: string;
66
- steps: TourStep[];
67
- /** Tour-level defaults for steps */
68
- defaults?: Partial<TourStep>;
69
- }
70
-
71
- // State
72
- export interface TourState {
73
- isActive: boolean;
74
- activeTourId: string | null;
75
- currentStepIndex: number;
76
- isTransitioning: boolean;
77
- direction: 'forward' | 'backward';
78
- }
79
-
80
- // Callbacks
81
- export interface TourCallbacks {
82
- /** Called when tour starts */
83
- onStart?: (tourId: string) => void;
84
- /** Called when tour completes (last step finished) */
85
- onComplete?: (tourId: string) => void;
86
- /** Called when tour is skipped/closed early */
87
- onSkip?: (tourId: string, stepIndex: number) => void;
88
- /** Called on step change */
89
- onStepChange?: (stepIndex: number, step: TourStep, direction: 'forward' | 'backward') => void;
90
- /** Called before step transition, return false to cancel */
91
- onBeforeStepChange?: (currentIndex: number, nextIndex: number) => boolean | Promise<boolean>;
92
- }
93
-
94
- // Provider Props
95
- export interface TourProviderProps extends TourCallbacks {
96
- tours: Tour[];
97
- children: ReactNode;
98
- /** Enable spotlight (default: true) */
99
- spotlight?: boolean;
100
- /** Spotlight opacity 0-1 (default: 0.5) */
101
- spotlightOpacity?: number;
102
- /** Spotlight blur amount in pixels (default: 0) */
103
- spotlightBlur?: number;
104
- /** Enable spotlight animations (default: true) */
105
- animated?: boolean;
106
- /** Show pulsing ring around target (default: false) */
107
- pulseRing?: boolean;
108
- /** Show arrow pointing to target (default: false) */
109
- showArrow?: boolean;
110
- /** Enable keyboard navigation (default: true) */
111
- keyboardNavigation?: boolean;
112
- /** Close on overlay click (default: false) */
113
- closeOnOverlayClick?: boolean;
114
- /** Close on Escape key (default: true) */
115
- closeOnEscape?: boolean;
116
- /** Scroll target into view (default: true) */
117
- scrollToTarget?: boolean;
118
- /** Scroll behavior (default: 'smooth') */
119
- scrollBehavior?: ScrollBehavior;
120
- /** Progress indicator variant (default: 'dots') */
121
- progressVariant?: ProgressVariant;
122
- /** Show skip button (default: true) */
123
- showSkipButton?: boolean;
124
- /** Custom skip button label */
125
- skipLabel?: ReactNode;
126
- /** Custom finish button label */
127
- finishLabel?: ReactNode;
128
- /** Portal container (default: document.body) */
129
- portalContainer?: HTMLElement;
130
- /** Z-index for overlay (default: 50) */
131
- zIndex?: number;
132
- }
133
-
134
- // Hook Return
135
- export interface UseTourReturn {
136
- /** Start a tour by ID */
137
- start: (tourId: string, startIndex?: number) => void;
138
- /** Go to next step */
139
- next: () => void;
140
- /** Go to previous step */
141
- previous: () => void;
142
- /** Go to specific step */
143
- goTo: (index: number) => void;
144
- /** Close/skip tour */
145
- close: () => void;
146
- /** Is tour currently active */
147
- isActive: boolean;
148
- /** Currently active tour ID */
149
- activeTourId: string | null;
150
- /** Current step object */
151
- currentStep: TourStep | null;
152
- /** Current step index */
153
- currentStepIndex: number;
154
- /** Total number of steps */
155
- totalSteps: number;
156
- /** Is first step */
157
- isFirstStep: boolean;
158
- /** Is last step */
159
- isLastStep: boolean;
160
- /** Progress 0-1 */
161
- progress: number;
162
- }
163
-
164
- // Spotlight Target
165
- export interface SpotlightTarget {
166
- element: HTMLElement;
167
- rect: DOMRect;
168
- padding: number;
169
- radius: number;
170
- }
171
-
172
- // Component Props
173
- export interface TourSpotlightProps {
174
- targets: SpotlightTarget[];
175
- opacity?: number;
176
- blur?: number;
177
- animated?: boolean;
178
- pulseRing?: boolean;
179
- className?: string;
180
- onClick?: () => void;
181
- allowInteraction?: boolean;
182
- }
183
-
184
- export interface TourProgressProps {
185
- current: number;
186
- total: number;
187
- variant?: ProgressVariant;
188
- onDotClick?: (index: number) => void;
189
- className?: string;
190
- }
191
-
192
- export interface TourNavigationProps {
193
- onNext: () => void;
194
- onPrevious: () => void;
195
- isFirstStep: boolean;
196
- isLastStep: boolean;
197
- nextLabel?: ReactNode;
198
- previousLabel?: ReactNode;
199
- finishLabel?: ReactNode;
200
- nextRoute?: string;
201
- previousRoute?: string;
202
- className?: string;
203
- }
204
-
205
- export interface TourContentProps {
206
- step: TourStep;
207
- targetRect: DOMRect;
208
- currentIndex: number;
209
- totalSteps: number;
210
- onNext: () => void;
211
- onPrevious: () => void;
212
- onClose: () => void;
213
- progressVariant?: ProgressVariant;
214
- showSkipButton?: boolean;
215
- showArrow?: boolean;
216
- skipLabel?: ReactNode;
217
- finishLabel?: ReactNode;
218
- onGoTo?: (index: number) => void;
219
- className?: string;
220
- }
221
-
222
- export interface TourProps extends Omit<TourProviderProps, 'children'> {
223
- children?: ReactNode;
224
- }
@@ -1,98 +0,0 @@
1
- import { emitRuntimeError } from '@djangocfg/ui-core/utils';
2
-
3
- import { logger } from './logger';
4
-
5
- /**
6
- * Safely escape string for use in CSS attribute selector
7
- */
8
- function escapeCSS(str: string): string {
9
- return str.replace(/["\\]/g, '\\$&');
10
- }
11
-
12
- /**
13
- * Find target elements for a tour step.
14
- * Supports CSS selectors and data-tour-step-id attribute.
15
- */
16
- export function findTargetElements(
17
- target: string | undefined,
18
- stepId: string
19
- ): HTMLElement[] {
20
- if (!target) {
21
- // Fallback to data-tour-step-id attribute
22
- try {
23
- const escapedStepId = escapeCSS(stepId);
24
- const elements = document.querySelectorAll<HTMLElement>(
25
- `[data-tour-step-id="${escapedStepId}"], [data-tour-step-id*="${escapedStepId}"]`
26
- );
27
- return filterValidElements(Array.from(elements));
28
- } catch (error) {
29
- const err = error instanceof Error ? error : new Error(String(error));
30
- logger.error(`Tour: Invalid stepId selector "${stepId}"`, { error: err.message, stepId });
31
- emitRuntimeError('Tour', `Invalid stepId: ${stepId}`, err);
32
- return [];
33
- }
34
- }
35
-
36
- // Try as CSS selector first
37
- try {
38
- const elements = document.querySelectorAll<HTMLElement>(target);
39
- const valid = filterValidElements(Array.from(elements));
40
- if (valid.length > 0) return valid;
41
- } catch (error) {
42
- const err = error instanceof Error ? error : new Error(String(error));
43
- logger.warn(`Tour: Invalid target selector "${target}"`, { error: err.message, target, stepId });
44
- emitRuntimeError('Tour', `Invalid selector: ${target}`, err);
45
- return [];
46
- }
47
-
48
- // Fallback to data attribute
49
- try {
50
- const escapedTarget = escapeCSS(target);
51
- const elements = document.querySelectorAll<HTMLElement>(
52
- `[data-tour-step-id="${escapedTarget}"], [data-tour-step-id*="${escapedTarget}"]`
53
- );
54
- return filterValidElements(Array.from(elements));
55
- } catch (error) {
56
- const err = error instanceof Error ? error : new Error(String(error));
57
- logger.error(`Tour: Invalid fallback selector for "${target}"`, { error: err.message, target, stepId });
58
- emitRuntimeError('Tour', `Invalid fallback selector: ${target}`, err);
59
- return [];
60
- }
61
- }
62
-
63
- /**
64
- * Filter out elements that are not visible or have zero dimensions.
65
- */
66
- function filterValidElements(elements: HTMLElement[]): HTMLElement[] {
67
- return elements.filter((el) => {
68
- const rect = el.getBoundingClientRect();
69
- // Skip elements with zero dimensions
70
- if (rect.width === 0 && rect.height === 0) return false;
71
- // Skip hidden elements
72
- const style = window.getComputedStyle(el);
73
- if (style.display === 'none' || style.visibility === 'hidden') return false;
74
- return true;
75
- });
76
- }
77
-
78
- /**
79
- * Get computed border radius from element.
80
- */
81
- export function getElementBorderRadius(element: HTMLElement): number {
82
- const style = window.getComputedStyle(element);
83
- const radius = parseFloat(style.borderRadius) || 0;
84
- return Math.min(radius, 20); // Cap at 20px for reasonable spotlight
85
- }
86
-
87
- /**
88
- * Check if element is in viewport.
89
- */
90
- export function isElementInViewport(element: HTMLElement): boolean {
91
- const rect = element.getBoundingClientRect();
92
- return (
93
- rect.top >= 0 &&
94
- rect.left >= 0 &&
95
- rect.bottom <= window.innerHeight &&
96
- rect.right <= window.innerWidth
97
- );
98
- }
@@ -1,3 +0,0 @@
1
- export { logger } from './logger';
2
- export { findTargetElements, getElementBorderRadius, isElementInViewport } from './dom';
3
- export { scrollToElement, waitForScroll } from './scrollIntoView';
@@ -1,3 +0,0 @@
1
- import { createLogger } from '@djangocfg/ui-core/lib';
2
-
3
- export const logger = createLogger('Tour');
@@ -1,24 +0,0 @@
1
- import { isElementInViewport } from './dom';
2
-
3
- /**
4
- * Scroll element into view if not already visible.
5
- */
6
- export function scrollToElement(
7
- element: HTMLElement,
8
- behavior: ScrollBehavior = 'smooth'
9
- ): void {
10
- if (isElementInViewport(element)) return;
11
-
12
- element.scrollIntoView({
13
- behavior,
14
- block: 'center',
15
- inline: 'center',
16
- });
17
- }
18
-
19
- /**
20
- * Wait for scroll to complete (approximate).
21
- */
22
- export function waitForScroll(duration = 300): Promise<void> {
23
- return new Promise((resolve) => setTimeout(resolve, duration));
24
- }
@@ -1,138 +0,0 @@
1
- /**
2
- * Custom Video Controls for Vidstack Player
3
- */
4
-
5
- 'use client';
6
-
7
- import { Maximize, Minimize, Pause, Play, Volume2, VolumeX } from 'lucide-react';
8
- import React from 'react';
9
-
10
- import { cn } from '@djangocfg/ui-core/lib';
11
- import { useMediaRemote, useMediaStore } from '@vidstack/react';
12
-
13
- import type { MediaPlayerInstance } from '@vidstack/react';
14
- interface VideoControlsProps {
15
- player: React.RefObject<MediaPlayerInstance | null>;
16
- className?: string;
17
- }
18
-
19
- export function VideoControls({ player, className }: VideoControlsProps) {
20
- const store = useMediaStore(player);
21
- const remote = useMediaRemote();
22
-
23
- const isPaused = store.paused;
24
- const isMuted = store.muted;
25
- const isFullscreen = store.fullscreen;
26
- const currentTime = store.currentTime;
27
- const duration = store.duration;
28
- const volume = store.volume;
29
-
30
- const formatTime = (seconds: number): string => {
31
- if (!seconds || seconds < 0) return '0:00';
32
- const minutes = Math.floor(seconds / 60);
33
- const secs = Math.floor(seconds % 60);
34
- return `${minutes}:${secs.toString().padStart(2, '0')}`;
35
- };
36
-
37
- const handleProgressClick = (e: React.MouseEvent<HTMLDivElement>) => {
38
- if (!duration) return;
39
- const rect = e.currentTarget.getBoundingClientRect();
40
- const clickX = e.clientX - rect.left;
41
- const percentage = clickX / rect.width;
42
- const newTime = percentage * duration;
43
- remote.seek(newTime);
44
- };
45
-
46
- const handleVolumeChange = (e: React.MouseEvent<HTMLDivElement>) => {
47
- const rect = e.currentTarget.getBoundingClientRect();
48
- const clickX = e.clientX - rect.left;
49
- const percentage = Math.max(0, Math.min(1, clickX / rect.width));
50
- remote.changeVolume(percentage);
51
- if (percentage > 0 && isMuted) {
52
- remote.toggleMuted();
53
- }
54
- };
55
-
56
- const progress = duration > 0 ? (currentTime / duration) * 100 : 0;
57
-
58
- return (
59
- <div
60
- className={cn(
61
- "absolute inset-0 flex flex-col justify-end transition-opacity duration-300",
62
- "bg-gradient-to-t from-black/80 via-black/20 to-transparent",
63
- "opacity-0 group-hover:opacity-100 focus-within:opacity-100",
64
- "pointer-events-none group-hover:pointer-events-auto",
65
- className
66
- )}
67
- >
68
- {/* Progress Bar */}
69
- <div className="px-4 pb-2 pointer-events-auto">
70
- <div
71
- className="h-1.5 bg-white/20 rounded-full cursor-pointer hover:h-2 transition-all group"
72
- onClick={handleProgressClick}
73
- >
74
- <div
75
- className="h-full bg-primary rounded-full transition-all relative group-hover:bg-primary/90"
76
- style={{ width: `${progress}%` }}
77
- >
78
- <div className="absolute right-0 top-1/2 -translate-y-1/2 w-3 h-3 bg-white rounded-full opacity-0 group-hover:opacity-100 transition-opacity" />
79
- </div>
80
- </div>
81
- </div>
82
-
83
- {/* Control Bar */}
84
- <div className="flex items-center gap-4 px-4 pb-4 pointer-events-auto">
85
- {/* Play/Pause */}
86
- <button
87
- onClick={() => remote.togglePaused()}
88
- className="text-white hover:text-primary transition-colors p-1.5 hover:bg-white/10 rounded-full"
89
- >
90
- {isPaused ? <Play className="h-6 w-6" /> : <Pause className="h-6 w-6" />}
91
- </button>
92
-
93
- {/* Time */}
94
- <div className="text-white text-sm font-medium">
95
- {formatTime(currentTime)} / {formatTime(duration)}
96
- </div>
97
-
98
- <div className="flex-1" />
99
-
100
- {/* Volume Control */}
101
- <div className="flex items-center gap-2 group/volume">
102
- <button
103
- onClick={() => remote.toggleMuted()}
104
- className="text-white hover:text-primary transition-colors p-1.5 hover:bg-white/10 rounded-full"
105
- >
106
- {isMuted || volume === 0 ? (
107
- <VolumeX className="h-5 w-5" />
108
- ) : (
109
- <Volume2 className="h-5 w-5" />
110
- )}
111
- </button>
112
-
113
- <div
114
- className="w-0 group-hover/volume:w-20 transition-all overflow-hidden"
115
- >
116
- <div
117
- className="h-1.5 bg-white/20 rounded-full cursor-pointer hover:h-2 transition-all"
118
- onClick={handleVolumeChange}
119
- >
120
- <div
121
- className="h-full bg-white rounded-full transition-all"
122
- style={{ width: `${volume * 100}%` }}
123
- />
124
- </div>
125
- </div>
126
- </div>
127
-
128
- {/* Fullscreen */}
129
- <button
130
- onClick={() => isFullscreen ? remote.exitFullscreen() : remote.enterFullscreen()}
131
- className="text-white hover:text-primary transition-colors p-1.5 hover:bg-white/10 rounded-full"
132
- >
133
- {isFullscreen ? <Minimize className="h-5 w-5" /> : <Maximize className="h-5 w-5" />}
134
- </button>
135
- </div>
136
- </div>
137
- );
138
- }