@djangocfg/ui-nextjs 2.1.89 → 2.1.91

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 (161) hide show
  1. package/README.md +6 -15
  2. package/package.json +6 -25
  3. package/src/blocks/SplitHero/SplitHeroMedia.tsx +1 -1
  4. package/src/components/index.ts +0 -40
  5. package/src/hooks/index.ts +0 -6
  6. package/src/index.ts +2 -11
  7. package/src/components/button-download.tsx +0 -277
  8. package/src/components/markdown/MarkdownMessage.tsx +0 -340
  9. package/src/components/markdown/index.ts +0 -5
  10. package/src/components/menubar.tsx +0 -275
  11. package/src/components/multi-select-pro/async.tsx +0 -598
  12. package/src/components/multi-select-pro/helpers.tsx +0 -84
  13. package/src/components/multi-select-pro/index.tsx +0 -612
  14. package/src/components/navigation-menu.tsx +0 -154
  15. package/src/components/otp/index.tsx +0 -197
  16. package/src/components/otp/types.ts +0 -133
  17. package/src/components/otp/use-otp-input.ts +0 -225
  18. package/src/components/phone-input.tsx +0 -277
  19. package/src/components/sonner.tsx +0 -32
  20. package/src/hooks/useLocalStorage.ts +0 -300
  21. package/src/hooks/useSessionStorage.ts +0 -290
  22. package/src/lib/index.ts +0 -5
  23. package/src/lib/logger/index.ts +0 -10
  24. package/src/lib/logger/logStore.ts +0 -122
  25. package/src/lib/logger/logger.ts +0 -175
  26. package/src/lib/logger/types.ts +0 -82
  27. package/src/stores/index.ts +0 -8
  28. package/src/stores/mediaCache.ts +0 -534
  29. package/src/tools/AudioPlayer/README.md +0 -206
  30. package/src/tools/AudioPlayer/components/HybridAudioPlayer.tsx +0 -216
  31. package/src/tools/AudioPlayer/components/HybridSimplePlayer.tsx +0 -280
  32. package/src/tools/AudioPlayer/components/HybridWaveform.tsx +0 -279
  33. package/src/tools/AudioPlayer/components/ReactiveCover/AudioReactiveCover.tsx +0 -149
  34. package/src/tools/AudioPlayer/components/ReactiveCover/effects/GlowEffect.tsx +0 -110
  35. package/src/tools/AudioPlayer/components/ReactiveCover/effects/MeshEffect.tsx +0 -58
  36. package/src/tools/AudioPlayer/components/ReactiveCover/effects/OrbsEffect.tsx +0 -45
  37. package/src/tools/AudioPlayer/components/ReactiveCover/effects/SpotlightEffect.tsx +0 -82
  38. package/src/tools/AudioPlayer/components/ReactiveCover/effects/index.ts +0 -8
  39. package/src/tools/AudioPlayer/components/ReactiveCover/index.ts +0 -6
  40. package/src/tools/AudioPlayer/components/index.ts +0 -22
  41. package/src/tools/AudioPlayer/context/HybridAudioProvider.tsx +0 -158
  42. package/src/tools/AudioPlayer/context/index.ts +0 -16
  43. package/src/tools/AudioPlayer/effects/index.ts +0 -412
  44. package/src/tools/AudioPlayer/hooks/index.ts +0 -35
  45. package/src/tools/AudioPlayer/hooks/useHybridAudio.ts +0 -387
  46. package/src/tools/AudioPlayer/hooks/useHybridAudioAnalysis.ts +0 -95
  47. package/src/tools/AudioPlayer/hooks/useVisualization.tsx +0 -207
  48. package/src/tools/AudioPlayer/index.ts +0 -133
  49. package/src/tools/AudioPlayer/types/effects.ts +0 -73
  50. package/src/tools/AudioPlayer/types/index.ts +0 -27
  51. package/src/tools/AudioPlayer/utils/debug.ts +0 -14
  52. package/src/tools/AudioPlayer/utils/formatTime.ts +0 -10
  53. package/src/tools/AudioPlayer/utils/index.ts +0 -6
  54. package/src/tools/ImageViewer/@refactoring/00-PLAN.md +0 -71
  55. package/src/tools/ImageViewer/@refactoring/01-TYPES.md +0 -121
  56. package/src/tools/ImageViewer/@refactoring/02-UTILS.md +0 -143
  57. package/src/tools/ImageViewer/@refactoring/03-HOOKS.md +0 -261
  58. package/src/tools/ImageViewer/@refactoring/04-COMPONENTS.md +0 -427
  59. package/src/tools/ImageViewer/@refactoring/05-EXECUTION-CHECKLIST.md +0 -126
  60. package/src/tools/ImageViewer/README.md +0 -200
  61. package/src/tools/ImageViewer/components/ImageInfo.tsx +0 -44
  62. package/src/tools/ImageViewer/components/ImageToolbar.tsx +0 -150
  63. package/src/tools/ImageViewer/components/ImageViewer.tsx +0 -241
  64. package/src/tools/ImageViewer/components/index.ts +0 -7
  65. package/src/tools/ImageViewer/hooks/index.ts +0 -9
  66. package/src/tools/ImageViewer/hooks/useImageLoading.ts +0 -204
  67. package/src/tools/ImageViewer/hooks/useImageTransform.ts +0 -101
  68. package/src/tools/ImageViewer/index.ts +0 -60
  69. package/src/tools/ImageViewer/types.ts +0 -81
  70. package/src/tools/ImageViewer/utils/constants.ts +0 -59
  71. package/src/tools/ImageViewer/utils/debug.ts +0 -14
  72. package/src/tools/ImageViewer/utils/index.ts +0 -17
  73. package/src/tools/ImageViewer/utils/lqip.ts +0 -47
  74. package/src/tools/JsonForm/JsonSchemaForm.tsx +0 -197
  75. package/src/tools/JsonForm/examples/BotConfigExample.tsx +0 -249
  76. package/src/tools/JsonForm/examples/RealBotConfigExample.tsx +0 -161
  77. package/src/tools/JsonForm/index.ts +0 -46
  78. package/src/tools/JsonForm/templates/ArrayFieldItemTemplate.tsx +0 -47
  79. package/src/tools/JsonForm/templates/ArrayFieldTemplate.tsx +0 -74
  80. package/src/tools/JsonForm/templates/BaseInputTemplate.tsx +0 -107
  81. package/src/tools/JsonForm/templates/ErrorListTemplate.tsx +0 -35
  82. package/src/tools/JsonForm/templates/FieldTemplate.tsx +0 -62
  83. package/src/tools/JsonForm/templates/ObjectFieldTemplate.tsx +0 -116
  84. package/src/tools/JsonForm/templates/index.ts +0 -12
  85. package/src/tools/JsonForm/types.ts +0 -83
  86. package/src/tools/JsonForm/utils.ts +0 -213
  87. package/src/tools/JsonForm/widgets/CheckboxWidget.tsx +0 -37
  88. package/src/tools/JsonForm/widgets/ColorWidget.tsx +0 -219
  89. package/src/tools/JsonForm/widgets/NumberWidget.tsx +0 -89
  90. package/src/tools/JsonForm/widgets/SelectWidget.tsx +0 -97
  91. package/src/tools/JsonForm/widgets/SliderWidget.tsx +0 -148
  92. package/src/tools/JsonForm/widgets/SwitchWidget.tsx +0 -35
  93. package/src/tools/JsonForm/widgets/TextWidget.tsx +0 -96
  94. package/src/tools/JsonForm/widgets/index.ts +0 -14
  95. package/src/tools/JsonTree/index.tsx +0 -243
  96. package/src/tools/LottiePlayer/LottiePlayer.client.tsx +0 -213
  97. package/src/tools/LottiePlayer/index.tsx +0 -55
  98. package/src/tools/LottiePlayer/types.ts +0 -108
  99. package/src/tools/LottiePlayer/useLottie.ts +0 -164
  100. package/src/tools/Mermaid/Mermaid.client.tsx +0 -82
  101. package/src/tools/Mermaid/components/MermaidCodeViewer.tsx +0 -95
  102. package/src/tools/Mermaid/components/MermaidFullscreenModal.tsx +0 -103
  103. package/src/tools/Mermaid/hooks/index.ts +0 -4
  104. package/src/tools/Mermaid/hooks/useMermaidCleanup.ts +0 -73
  105. package/src/tools/Mermaid/hooks/useMermaidFullscreen.ts +0 -46
  106. package/src/tools/Mermaid/hooks/useMermaidRenderer.ts +0 -226
  107. package/src/tools/Mermaid/hooks/useMermaidValidation.ts +0 -29
  108. package/src/tools/Mermaid/index.tsx +0 -41
  109. package/src/tools/Mermaid/utils/mermaid-helpers.ts +0 -33
  110. package/src/tools/OpenapiViewer/components/EndpointInfo.tsx +0 -149
  111. package/src/tools/OpenapiViewer/components/EndpointsLibrary.tsx +0 -263
  112. package/src/tools/OpenapiViewer/components/PlaygroundLayout.tsx +0 -125
  113. package/src/tools/OpenapiViewer/components/PlaygroundStepper.tsx +0 -100
  114. package/src/tools/OpenapiViewer/components/RequestBuilder.tsx +0 -157
  115. package/src/tools/OpenapiViewer/components/RequestParametersForm.tsx +0 -253
  116. package/src/tools/OpenapiViewer/components/ResponseViewer.tsx +0 -173
  117. package/src/tools/OpenapiViewer/components/VersionSelector.tsx +0 -68
  118. package/src/tools/OpenapiViewer/components/index.ts +0 -14
  119. package/src/tools/OpenapiViewer/constants.ts +0 -39
  120. package/src/tools/OpenapiViewer/context/PlaygroundContext.tsx +0 -337
  121. package/src/tools/OpenapiViewer/hooks/index.ts +0 -8
  122. package/src/tools/OpenapiViewer/hooks/useMobile.ts +0 -10
  123. package/src/tools/OpenapiViewer/hooks/useOpenApiSchema.ts +0 -199
  124. package/src/tools/OpenapiViewer/index.tsx +0 -38
  125. package/src/tools/OpenapiViewer/types.ts +0 -151
  126. package/src/tools/OpenapiViewer/utils/apiKeyManager.ts +0 -149
  127. package/src/tools/OpenapiViewer/utils/formatters.ts +0 -71
  128. package/src/tools/OpenapiViewer/utils/index.ts +0 -9
  129. package/src/tools/OpenapiViewer/utils/versionManager.ts +0 -161
  130. package/src/tools/PrettyCode/PrettyCode.client.tsx +0 -208
  131. package/src/tools/PrettyCode/index.tsx +0 -45
  132. package/src/tools/VideoPlayer/@refactoring/00-PLAN.md +0 -91
  133. package/src/tools/VideoPlayer/@refactoring/01-TYPES.md +0 -284
  134. package/src/tools/VideoPlayer/@refactoring/02-UTILS.md +0 -141
  135. package/src/tools/VideoPlayer/@refactoring/03-HOOKS.md +0 -178
  136. package/src/tools/VideoPlayer/@refactoring/04-COMPONENTS.md +0 -95
  137. package/src/tools/VideoPlayer/@refactoring/05-EXECUTION-CHECKLIST.md +0 -139
  138. package/src/tools/VideoPlayer/README.md +0 -264
  139. package/src/tools/VideoPlayer/components/VideoControls.tsx +0 -138
  140. package/src/tools/VideoPlayer/components/VideoErrorFallback.tsx +0 -174
  141. package/src/tools/VideoPlayer/components/VideoPlayer.tsx +0 -201
  142. package/src/tools/VideoPlayer/components/index.ts +0 -14
  143. package/src/tools/VideoPlayer/context/VideoPlayerContext.tsx +0 -52
  144. package/src/tools/VideoPlayer/context/index.ts +0 -8
  145. package/src/tools/VideoPlayer/hooks/index.ts +0 -12
  146. package/src/tools/VideoPlayer/hooks/useVideoPlayerSettings.ts +0 -70
  147. package/src/tools/VideoPlayer/hooks/useVideoPositionCache.ts +0 -116
  148. package/src/tools/VideoPlayer/index.ts +0 -77
  149. package/src/tools/VideoPlayer/providers/NativeProvider.tsx +0 -284
  150. package/src/tools/VideoPlayer/providers/StreamProvider.tsx +0 -505
  151. package/src/tools/VideoPlayer/providers/VidstackProvider.tsx +0 -400
  152. package/src/tools/VideoPlayer/providers/index.ts +0 -8
  153. package/src/tools/VideoPlayer/types/index.ts +0 -38
  154. package/src/tools/VideoPlayer/types/player.ts +0 -116
  155. package/src/tools/VideoPlayer/types/provider.ts +0 -93
  156. package/src/tools/VideoPlayer/types/sources.ts +0 -97
  157. package/src/tools/VideoPlayer/utils/debug.ts +0 -14
  158. package/src/tools/VideoPlayer/utils/fileSource.ts +0 -78
  159. package/src/tools/VideoPlayer/utils/index.ts +0 -12
  160. package/src/tools/VideoPlayer/utils/resolvers.ts +0 -75
  161. package/src/tools/index.ts +0 -170
@@ -1,264 +0,0 @@
1
- # VideoPlayer
2
-
3
- Unified video player component supporting multiple modes and source types.
4
-
5
- ## Modes
6
-
7
- | Mode | Source Types | Use Case |
8
- |------|-------------|----------|
9
- | `vidstack` | YouTube, Vimeo, HLS, DASH | Full-featured player with themes and controls |
10
- | `native` | URL, data-url | Lightweight HTML5 player |
11
- | `streaming` | stream, blob | HTTP Range streaming with auth, binary data |
12
-
13
- Mode is auto-detected from source type, or can be forced via `mode` prop.
14
-
15
- ## Installation
16
-
17
- ```tsx
18
- import {
19
- VideoPlayer,
20
- VideoPlayerProvider,
21
- VideoErrorFallback,
22
- resolveFileSource
23
- } from '@djangocfg/ui-nextjs';
24
- ```
25
-
26
- ## Basic Usage
27
-
28
- ### YouTube / Vimeo
29
-
30
- ```tsx
31
- <VideoPlayer source={{ type: 'youtube', id: 'dQw4w9WgXcQ' }} />
32
- <VideoPlayer source={{ type: 'vimeo', id: '123456789' }} />
33
- ```
34
-
35
- ### HLS / DASH Streaming
36
-
37
- ```tsx
38
- <VideoPlayer source={{ type: 'hls', url: 'https://example.com/video.m3u8' }} />
39
- <VideoPlayer source={{ type: 'dash', url: 'https://example.com/video.mpd' }} />
40
- ```
41
-
42
- ### Direct URL
43
-
44
- ```tsx
45
- <VideoPlayer source={{ type: 'url', url: 'https://example.com/video.mp4' }} />
46
- ```
47
-
48
- ### HTTP Range Streaming (with auth)
49
-
50
- ```tsx
51
- // Full source (standalone)
52
- <VideoPlayer
53
- source={{
54
- type: 'stream',
55
- sessionId: 'abc123',
56
- path: '/videos/movie.mp4',
57
- getStreamUrl: (id, path) => `/api/stream/${id}?path=${path}&token=${token}`
58
- }}
59
- />
60
-
61
- // Simplified source (with context)
62
- <VideoPlayerProvider sessionId={sessionId} getStreamUrl={getStreamUrl}>
63
- <VideoPlayer source={{ type: 'stream', path: '/videos/movie.mp4' }} />
64
- </VideoPlayerProvider>
65
- ```
66
-
67
- ### Blob / ArrayBuffer
68
-
69
- ```tsx
70
- <VideoPlayer
71
- source={{
72
- type: 'blob',
73
- data: arrayBuffer,
74
- mimeType: 'video/mp4'
75
- }}
76
- />
77
- ```
78
-
79
- ## Props
80
-
81
- | Prop | Type | Default | Description |
82
- |------|------|---------|-------------|
83
- | `source` | `VideoSourceUnion` | required | Video source configuration |
84
- | `mode` | `'auto' \| 'vidstack' \| 'native' \| 'streaming'` | `'auto'` | Force specific player mode |
85
- | `aspectRatio` | `number \| 'auto' \| 'fill'` | `16/9` | Aspect ratio or fill parent |
86
- | `autoPlay` | `boolean` | `false` | Auto-play on load |
87
- | `muted` | `boolean` | `false` | Muted by default |
88
- | `loop` | `boolean` | `false` | Loop playback |
89
- | `controls` | `boolean` | `true` | Show player controls |
90
- | `playsInline` | `boolean` | `true` | Inline playback on mobile |
91
- | `preload` | `'none' \| 'metadata' \| 'auto'` | `'metadata'` | Preload strategy |
92
- | `theme` | `'default' \| 'minimal' \| 'modern'` | `'default'` | Vidstack theme |
93
- | `errorFallback` | `ReactNode \| (props) => ReactNode` | - | Custom error UI |
94
- | `className` | `string` | - | Container className |
95
- | `videoClassName` | `string` | - | Video element className |
96
-
97
- ## Events
98
-
99
- | Event | Type | Description |
100
- |-------|------|-------------|
101
- | `onPlay` | `() => void` | Playback started |
102
- | `onPause` | `() => void` | Playback paused |
103
- | `onEnded` | `() => void` | Playback ended |
104
- | `onError` | `(error: string) => void` | Error occurred |
105
- | `onLoadStart` | `() => void` | Loading started |
106
- | `onCanPlay` | `() => void` | Ready to play |
107
- | `onTimeUpdate` | `(time: number, duration: number) => void` | Time updated |
108
-
109
- ## Ref API
110
-
111
- ```tsx
112
- const playerRef = useRef<VideoPlayerRef>(null);
113
-
114
- <VideoPlayer ref={playerRef} source={source} />
115
-
116
- // Control methods
117
- playerRef.current?.play();
118
- playerRef.current?.pause();
119
- playerRef.current?.seek(30); // Seek to 30 seconds
120
- playerRef.current?.setVolume(0.5); // 0-1
121
- playerRef.current?.setMuted(true);
122
- playerRef.current?.reload();
123
- ```
124
-
125
- ## Error Handling
126
-
127
- ### Custom Error Fallback
128
-
129
- ```tsx
130
- <VideoPlayer
131
- source={source}
132
- errorFallback={(props) => (
133
- <div>
134
- <p>Error: {props.error}</p>
135
- <button onClick={props.retry}>Retry</button>
136
- </div>
137
- )}
138
- />
139
- ```
140
-
141
- ### Pre-built Error Fallback with Download
142
-
143
- ```tsx
144
- import { VideoErrorFallback } from '@djangocfg/ui-nextjs';
145
-
146
- <VideoPlayer
147
- source={source}
148
- errorFallback={(props) => (
149
- <VideoErrorFallback
150
- {...props}
151
- downloadUrl={getDownloadUrl()}
152
- downloadFilename="video.mp4"
153
- fileSize="125 MB"
154
- />
155
- )}
156
- />
157
- ```
158
-
159
- ## Fill Mode
160
-
161
- Use `aspectRatio="fill"` to fill the parent container:
162
-
163
- ```tsx
164
- <div className="absolute inset-0">
165
- <VideoPlayer source={source} aspectRatio="fill" />
166
- </div>
167
- ```
168
-
169
- ## Context Provider
170
-
171
- For apps with multiple streaming videos, use the context to avoid repetition:
172
-
173
- ```tsx
174
- // In layout or parent component
175
- <VideoPlayerProvider
176
- sessionId={sessionId}
177
- getStreamUrl={(id, path) => `/api/stream/${id}?path=${path}`}
178
- >
179
- {/* All nested VideoPlayers use this config */}
180
- <VideoPlayer source={{ type: 'stream', path: '/video1.mp4' }} />
181
- <VideoPlayer source={{ type: 'stream', path: '/video2.mp4' }} />
182
- </VideoPlayerProvider>
183
- ```
184
-
185
- ## File Source Helper
186
-
187
- For file browser integration:
188
-
189
- ```tsx
190
- import { resolveFileSource } from '@djangocfg/ui-nextjs';
191
-
192
- const source = resolveFileSource({
193
- file: { name: 'movie.mp4', path: '/videos/movie.mp4' },
194
- sessionId: 'abc123',
195
- getStreamUrl: (id, path) => `/api/stream/${id}?path=${path}`,
196
- });
197
-
198
- if (source) {
199
- return <VideoPlayer source={source} />;
200
- }
201
- ```
202
-
203
- ## Source Types Reference
204
-
205
- ```typescript
206
- type VideoSourceUnion =
207
- | { type: 'url'; url: string; title?: string; poster?: string }
208
- | { type: 'youtube'; id: string; title?: string; poster?: string }
209
- | { type: 'vimeo'; id: string; title?: string; poster?: string }
210
- | { type: 'hls'; url: string; title?: string; poster?: string }
211
- | { type: 'dash'; url: string; title?: string; poster?: string }
212
- | { type: 'stream'; sessionId: string; path: string; getStreamUrl: fn; mimeType?: string }
213
- | { type: 'blob'; data: ArrayBuffer | Blob; mimeType?: string }
214
- | { type: 'data-url'; data: string; mimeType?: string }
215
- ```
216
-
217
- ## Architecture
218
-
219
- ```
220
- VideoPlayer/
221
- ├── index.ts # Public API exports
222
- ├── types/
223
- │ ├── index.ts # Type re-exports
224
- │ ├── sources.ts # Source types (Url, YouTube, HLS, etc.)
225
- │ ├── player.ts # Player props, ref, events
226
- │ └── provider.ts # Provider & context types
227
- ├── hooks/
228
- │ ├── index.ts
229
- │ └── useVideoPositionCache.ts # Playback position caching
230
- ├── utils/
231
- │ ├── index.ts
232
- │ ├── resolvers.ts # resolvePlayerMode, isSimpleStreamSource
233
- │ └── fileSource.ts # resolveFileSource helper
234
- ├── components/
235
- │ ├── index.ts
236
- │ ├── VideoPlayer.tsx # Main orchestrator
237
- │ ├── VideoControls.tsx # Standalone Vidstack controls
238
- │ └── VideoErrorFallback.tsx # Pre-built error UI
239
- ├── context/
240
- │ ├── index.ts
241
- │ └── VideoPlayerContext.tsx # Streaming config provider
242
- └── providers/
243
- ├── index.ts
244
- ├── VidstackProvider.tsx # YouTube, Vimeo, HLS, DASH
245
- ├── NativeProvider.tsx # HTML5 <video>
246
- └── StreamProvider.tsx # HTTP Range, Blob
247
- ```
248
-
249
- ## Accessibility
250
-
251
- Full accessibility support:
252
- - Keyboard navigation (Space, Arrow keys, F for fullscreen)
253
- - Screen reader announcements
254
- - Focus indicators
255
- - ARIA labels and roles
256
-
257
- ## Browser Support
258
-
259
- - Chrome 63+
260
- - Firefox 67+
261
- - Safari 12+
262
- - Edge 79+
263
- - iOS Safari 12+
264
- - Chrome Android 63+
@@ -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
- }
@@ -1,174 +0,0 @@
1
- /**
2
- * VideoErrorFallback - Pre-built error fallback with download button
3
- * For use with VideoPlayer errorFallback prop
4
- */
5
-
6
- 'use client';
7
-
8
- import React from 'react';
9
- import { FileVideo, RefreshCw } from 'lucide-react';
10
-
11
- import { cn } from '@djangocfg/ui-core/lib';
12
- import { Button } from '@djangocfg/ui-core/components';
13
- import { DownloadButton } from '../../../components/button-download';
14
-
15
- import type { ErrorFallbackProps } from '../types';
16
-
17
- // ============================================================================
18
- // Types
19
- // ============================================================================
20
-
21
- export interface VideoErrorFallbackProps extends ErrorFallbackProps {
22
- /** URL for download button (if provided, shows download button) */
23
- downloadUrl?: string;
24
- /** Filename for download */
25
- downloadFilename?: string;
26
- /** File size to display */
27
- fileSize?: string;
28
- /** Show retry button */
29
- showRetry?: boolean;
30
- /** Custom className */
31
- className?: string;
32
- /** Custom icon */
33
- icon?: React.ReactNode;
34
- /** Custom title (defaults to error message) */
35
- title?: string;
36
- /** Custom description */
37
- description?: string;
38
- }
39
-
40
- // ============================================================================
41
- // Component
42
- // ============================================================================
43
-
44
- /**
45
- * Pre-built error fallback component for VideoPlayer
46
- *
47
- * @example
48
- * // Basic usage
49
- * <VideoPlayer
50
- * source={source}
51
- * errorFallback={(props) => (
52
- * <VideoErrorFallback
53
- * {...props}
54
- * downloadUrl={getDownloadUrl()}
55
- * downloadFilename="video.mp4"
56
- * />
57
- * )}
58
- * />
59
- *
60
- * @example
61
- * // With file size
62
- * <VideoErrorFallback
63
- * error="Failed to load video"
64
- * downloadUrl="/api/download/video.mp4"
65
- * fileSize="125 MB"
66
- * showRetry
67
- * retry={() => reloadVideo()}
68
- * />
69
- */
70
- export function VideoErrorFallback({
71
- error,
72
- retry,
73
- downloadUrl,
74
- downloadFilename,
75
- fileSize,
76
- showRetry = true,
77
- className,
78
- icon,
79
- title,
80
- description,
81
- }: VideoErrorFallbackProps) {
82
- const displayTitle = title || error || 'Video cannot be previewed';
83
-
84
- return (
85
- <div
86
- className={cn(
87
- 'absolute inset-0 flex flex-col items-center justify-center gap-4 bg-black/90 text-white p-6',
88
- className
89
- )}
90
- >
91
- {/* Icon */}
92
- {icon || <FileVideo className="w-16 h-16 text-muted-foreground" />}
93
-
94
- {/* Title */}
95
- <p className="text-lg font-medium text-center">{displayTitle}</p>
96
-
97
- {/* Description / File size */}
98
- {(description || fileSize) && (
99
- <p className="text-sm text-muted-foreground text-center">
100
- {description || fileSize}
101
- </p>
102
- )}
103
-
104
- {/* Actions */}
105
- <div className="flex items-center gap-3 mt-2">
106
- {/* Retry button */}
107
- {showRetry && retry && (
108
- <Button
109
- variant="outline"
110
- size="sm"
111
- onClick={retry}
112
- className="gap-2"
113
- >
114
- <RefreshCw className="w-4 h-4" />
115
- Retry
116
- </Button>
117
- )}
118
-
119
- {/* Download button */}
120
- {downloadUrl && (
121
- <DownloadButton
122
- url={downloadUrl}
123
- filename={downloadFilename}
124
- variant="default"
125
- size="sm"
126
- >
127
- Download to view
128
- </DownloadButton>
129
- )}
130
- </div>
131
- </div>
132
- );
133
- }
134
-
135
- // ============================================================================
136
- // Factory for common use cases
137
- // ============================================================================
138
-
139
- export interface CreateVideoErrorFallbackOptions {
140
- /** Function to get download URL from source */
141
- getDownloadUrl?: (source: unknown) => string | undefined;
142
- /** Function to get filename from source */
143
- getFilename?: (source: unknown) => string | undefined;
144
- /** Function to get file size from source */
145
- getFileSize?: (source: unknown) => string | undefined;
146
- /** Show retry button */
147
- showRetry?: boolean;
148
- }
149
-
150
- /**
151
- * Factory to create error fallback function for VideoPlayer
152
- *
153
- * @example
154
- * const errorFallback = createVideoErrorFallback({
155
- * getDownloadUrl: (source) => source.downloadUrl,
156
- * getFilename: (source) => source.filename,
157
- * showRetry: true,
158
- * });
159
- *
160
- * <VideoPlayer source={source} errorFallback={errorFallback} />
161
- */
162
- export function createVideoErrorFallback(
163
- options: CreateVideoErrorFallbackOptions
164
- ): (props: ErrorFallbackProps, source?: unknown) => React.ReactNode {
165
- return (props: ErrorFallbackProps, source?: unknown) => (
166
- <VideoErrorFallback
167
- {...props}
168
- downloadUrl={options.getDownloadUrl?.(source)}
169
- downloadFilename={options.getFilename?.(source)}
170
- fileSize={options.getFileSize?.(source)}
171
- showRetry={options.showRetry}
172
- />
173
- );
174
- }