@gentleduck/registry-ui 0.2.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 (175) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/index.css +3 -0
  3. package/package.json +59 -0
  4. package/src/_old/_table/index.ts +5 -0
  5. package/src/_old/_table/table-advanced.constants.tsx +24 -0
  6. package/src/_old/_table/table-advanced.tsx +311 -0
  7. package/src/_old/_table/table-advanced.types.ts +272 -0
  8. package/src/_old/_table/table.constants.ts +2 -0
  9. package/src/_old/_table/table.hook.tsx +115 -0
  10. package/src/_old/_table/table.lib.ts +85 -0
  11. package/src/_old/_table/table.tsx +916 -0
  12. package/src/_old/_table/table.types.ts +118 -0
  13. package/src/_old/_table/todo.md +11 -0
  14. package/src/_old/_upload/index.ts +9 -0
  15. package/src/_old/_upload/todo.md +38 -0
  16. package/src/_old/_upload/upload-advanced-chunks.tsx +1624 -0
  17. package/src/_old/_upload/upload-advanced.tsx +507 -0
  18. package/src/_old/_upload/upload-sonner.tsx +58 -0
  19. package/src/_old/_upload/upload.assets.tsx +239 -0
  20. package/src/_old/_upload/upload.constants.tsx +75 -0
  21. package/src/_old/_upload/upload.dto.ts +19 -0
  22. package/src/_old/_upload/upload.lib.tsx +630 -0
  23. package/src/_old/_upload/upload.tsx +491 -0
  24. package/src/_old/_upload/upload.types.ts +436 -0
  25. package/src/accordion/accordion.tsx +247 -0
  26. package/src/accordion/index.ts +1 -0
  27. package/src/alert/alert.constants.ts +17 -0
  28. package/src/alert/alert.tsx +52 -0
  29. package/src/alert/index.ts +2 -0
  30. package/src/alert-dialog/alert-dialog.tsx +107 -0
  31. package/src/alert-dialog/index.ts +1 -0
  32. package/src/aspect-ratio/aspect-ratio.tsx +33 -0
  33. package/src/aspect-ratio/index.ts +1 -0
  34. package/src/audio/audio-record.tsx +776 -0
  35. package/src/audio/audio-visualizer.tsx +377 -0
  36. package/src/audio/audio.libs.ts +5 -0
  37. package/src/audio/audio.types.ts +50 -0
  38. package/src/audio/index.ts +2 -0
  39. package/src/avatar/avatar.tsx +78 -0
  40. package/src/avatar/index.ts +1 -0
  41. package/src/badge/badge.constants.ts +38 -0
  42. package/src/badge/badge.tsx +19 -0
  43. package/src/badge/index.ts +2 -0
  44. package/src/breadcrumb/breadcrumb.tsx +119 -0
  45. package/src/breadcrumb/index.ts +1 -0
  46. package/src/button/button.constants.ts +44 -0
  47. package/src/button/button.tsx +79 -0
  48. package/src/button/button.types.ts +38 -0
  49. package/src/button/index.ts +3 -0
  50. package/src/button-group/button-group.constants.ts +26 -0
  51. package/src/button-group/button-group.tsx +65 -0
  52. package/src/button-group/index.ts +2 -0
  53. package/src/calendar/calendar.tsx +191 -0
  54. package/src/calendar/index.ts +1 -0
  55. package/src/card/card.tsx +81 -0
  56. package/src/card/index.ts +1 -0
  57. package/src/carousel/carousel.tsx +211 -0
  58. package/src/carousel/carousel.types.ts +23 -0
  59. package/src/carousel/index.ts +2 -0
  60. package/src/chart/chart.libs.ts +27 -0
  61. package/src/chart/chart.tsx +260 -0
  62. package/src/chart/chart.types.ts +38 -0
  63. package/src/chart/index.ts +3 -0
  64. package/src/checkbox/checkbox.tsx +144 -0
  65. package/src/checkbox/checkbox.types.ts +24 -0
  66. package/src/checkbox/index.ts +2 -0
  67. package/src/collapsible/collapsible.tsx +151 -0
  68. package/src/collapsible/index.ts +1 -0
  69. package/src/combobox/combobox.tsx +132 -0
  70. package/src/combobox/index.ts +1 -0
  71. package/src/command/command.tsx +192 -0
  72. package/src/command/command.types.ts +11 -0
  73. package/src/command/index.ts +2 -0
  74. package/src/context-menu/context-menu.tsx +178 -0
  75. package/src/context-menu/index.ts +1 -0
  76. package/src/dialog/dialog-responsive.tsx +137 -0
  77. package/src/dialog/dialog.tsx +97 -0
  78. package/src/dialog/index.ts +2 -0
  79. package/src/direction/direction.tsx +13 -0
  80. package/src/direction/index.ts +1 -0
  81. package/src/drawer/drawer.tsx +185 -0
  82. package/src/drawer/index.ts +1 -0
  83. package/src/dropdown-menu/dropdown-menu.tsx +181 -0
  84. package/src/dropdown-menu/index.ts +1 -0
  85. package/src/empty/empty.constants.ts +15 -0
  86. package/src/empty/empty.tsx +73 -0
  87. package/src/empty/index.ts +2 -0
  88. package/src/field/field.constants.ts +22 -0
  89. package/src/field/field.tsx +203 -0
  90. package/src/field/index.ts +2 -0
  91. package/src/hover-card/hover-card.tsx +79 -0
  92. package/src/hover-card/index.ts +1 -0
  93. package/src/input/index.ts +1 -0
  94. package/src/input/input.tsx +45 -0
  95. package/src/input-group/index.ts +1 -0
  96. package/src/input-group/input-group.tsx +170 -0
  97. package/src/input-otp/index.ts +1 -0
  98. package/src/input-otp/input-otp.tsx +66 -0
  99. package/src/item/index.ts +2 -0
  100. package/src/item/item.constants.ts +22 -0
  101. package/src/item/item.tsx +185 -0
  102. package/src/json-editor/index.ts +4 -0
  103. package/src/json-editor/json-editor.hooks.ts +21 -0
  104. package/src/json-editor/json-editor.libs.ts +34 -0
  105. package/src/json-editor/json-editor.tsx +425 -0
  106. package/src/json-editor/json-editor.types.ts +80 -0
  107. package/src/json-editor/json-editor.view.tsx +110 -0
  108. package/src/json-editor/json-text-area.tsx +7 -0
  109. package/src/kbd/index.ts +1 -0
  110. package/src/kbd/kbd.tsx +39 -0
  111. package/src/label/index.ts +1 -0
  112. package/src/label/label.tsx +28 -0
  113. package/src/menubar/index.ts +1 -0
  114. package/src/menubar/menubar.tsx +213 -0
  115. package/src/navigation-menu/index.ts +1 -0
  116. package/src/navigation-menu/navigation-menu.tsx +152 -0
  117. package/src/pagination/index.ts +2 -0
  118. package/src/pagination/pagination.tsx +191 -0
  119. package/src/pagination/pagination.types.ts +17 -0
  120. package/src/popover/index.ts +1 -0
  121. package/src/popover/popover.tsx +35 -0
  122. package/src/preview-panel/index.ts +3 -0
  123. package/src/preview-panel/preview-panel-dialog.tsx +99 -0
  124. package/src/preview-panel/preview-panel.tsx +389 -0
  125. package/src/preview-panel/preview-panel.types.ts +49 -0
  126. package/src/progress/index.ts +1 -0
  127. package/src/progress/progress.tsx +32 -0
  128. package/src/radio-group/index.ts +1 -0
  129. package/src/radio-group/radio-group.tsx +92 -0
  130. package/src/resizable/index.ts +1 -0
  131. package/src/resizable/resizable.tsx +52 -0
  132. package/src/scroll-area/index.ts +1 -0
  133. package/src/scroll-area/scroll-area.tsx +30 -0
  134. package/src/select/index.ts +1 -0
  135. package/src/select/select.tsx +138 -0
  136. package/src/separator/index.ts +1 -0
  137. package/src/separator/separator.tsx +28 -0
  138. package/src/sheet/index.ts +2 -0
  139. package/src/sheet/sheet.constants.tsx +20 -0
  140. package/src/sheet/sheet.tsx +92 -0
  141. package/src/sidebar/index.ts +4 -0
  142. package/src/sidebar/sidebar.constants.ts +30 -0
  143. package/src/sidebar/sidebar.hooks.ts +13 -0
  144. package/src/sidebar/sidebar.tsx +676 -0
  145. package/src/sidebar/sidebar.types.ts +28 -0
  146. package/src/skeleton/index.ts +1 -0
  147. package/src/skeleton/skeleton.tsx +22 -0
  148. package/src/slider/index.ts +1 -0
  149. package/src/slider/slider.tsx +57 -0
  150. package/src/sonner/index.ts +4 -0
  151. package/src/sonner/sonner.chunks.tsx +80 -0
  152. package/src/sonner/sonner.libs.ts +13 -0
  153. package/src/sonner/sonner.tsx +31 -0
  154. package/src/sonner/sonner.types.ts +9 -0
  155. package/src/switch/index.ts +1 -0
  156. package/src/switch/switch.tsx +63 -0
  157. package/src/table/index.ts +1 -0
  158. package/src/table/table.tsx +95 -0
  159. package/src/tabs/index.ts +1 -0
  160. package/src/tabs/tabs.tsx +151 -0
  161. package/src/textarea/index.ts +1 -0
  162. package/src/textarea/textarea.tsx +24 -0
  163. package/src/toggle/index.ts +2 -0
  164. package/src/toggle/toggle.constants.ts +22 -0
  165. package/src/toggle/toggle.tsx +24 -0
  166. package/src/toggle-group/index.ts +1 -0
  167. package/src/toggle-group/toggle-group.tsx +69 -0
  168. package/src/tooltip/index.ts +1 -0
  169. package/src/tooltip/tooltip.tsx +32 -0
  170. package/src/upload/index.ts +1 -0
  171. package/src/upload/upload.constants.tsx +19 -0
  172. package/src/upload/upload.libs.ts +97 -0
  173. package/src/upload/upload.tsx +340 -0
  174. package/src/upload/upload.types.ts +44 -0
  175. package/tsconfig.json +25 -0
@@ -0,0 +1,776 @@
1
+ // import { cn } from '@gentleduck/libs/cn'
2
+ // import {
3
+ // ArrowBigUp,
4
+ // Download,
5
+ // Ellipsis,
6
+ // Mic,
7
+ // Pause,
8
+ // Play,
9
+ // Trash2,
10
+ // Volume,
11
+ // Volume1,
12
+ // Volume2,
13
+ // VolumeX,
14
+ // } from 'lucide-react'
15
+ // import * as React from 'react'
16
+ // import { uuidv7 } from 'uuidv7'
17
+ // import { Button } from '../button'
18
+ // import { Input } from '../input'
19
+ // // import { AttachmentType } from './swapy'
20
+ // import { PopoverWrapper } from '../popover'
21
+ // import { Slider } from '../slider'
22
+ // import { format_time_handler } from './audio.libs'
23
+ // import type {
24
+ // AttachmentType,
25
+ // DeleteRecordingHandlerParams,
26
+ // RecordingtType,
27
+ // StartRecordingHandlerParams,
28
+ // StartTimerParams,
29
+ // StopRecordingHandlerParam,
30
+ // StopRecordingHandlerParams,
31
+ // VisualizerClickHandlerParams,
32
+ // } from './audio.types'
33
+ // import {
34
+ // AudioVisualizer,
35
+ // type dataPoint,
36
+ // new_audio,
37
+ // type ProcessBlobParams,
38
+ // process_blob,
39
+ // type ThemeColor,
40
+ // } from './audio-visualizer'
41
+ //
42
+ // // import { downloadAttachment } from './comment'
43
+ //
44
+ // // Handle audio visualizer click
45
+ // const visualizer_click_handler = ({ audioRef, event, setCurrentTime }: VisualizerClickHandlerParams) => {
46
+ // if (audioRef.current == null) return
47
+ // const rect = event.currentTarget.getBoundingClientRect()
48
+ // const clickX = event.clientX - rect.left
49
+ // const duration = audioRef.current.duration
50
+ //
51
+ // if (duration && duration > 0) {
52
+ // const newTime = (clickX / rect.width) * duration
53
+ // audioRef.current.currentTime = newTime
54
+ // setCurrentTime(newTime * 1000)
55
+ // }
56
+ // }
57
+ //
58
+ // // Start recording audio
59
+ // export const start_recording_handler = async ({
60
+ // setRecordings,
61
+ // setRecording,
62
+ // setRecordedDuration,
63
+ // durationRef,
64
+ // intervalRef,
65
+ // audioChunksRef,
66
+ // mediaRecorderRef,
67
+ // }: StartRecordingHandlerParams) => {
68
+ // const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
69
+ // mediaRecorderRef.current = new MediaRecorder(stream)
70
+ // audioChunksRef.current = []
71
+ //
72
+ // mediaRecorderRef.current.ondataavailable = (event: BlobEvent) => {
73
+ // audioChunksRef.current.push(event.data)
74
+ // }
75
+ //
76
+ // mediaRecorderRef.current.onstop = () => {
77
+ // setRecordedDuration((_) => 0)
78
+ // durationRef.current > 0 &&
79
+ // Stop_recording_handler({
80
+ // audioChunksRef,
81
+ // intervalRef,
82
+ // setRecordings,
83
+ // })
84
+ // }
85
+ //
86
+ // mediaRecorderRef.current.start()
87
+ // setRecording(true)
88
+ // durationRef.current = 0
89
+ // start_timer_handler({ durationRef, intervalRef, setRecordedDuration })
90
+ // }
91
+ //
92
+ // // Stop recording and process audio blob
93
+ // export const Stop_recording_handler = ({ setRecordings, intervalRef, audioChunksRef }: StopRecordingHandlerParams) => {
94
+ // const audioBlob = new Blob(audioChunksRef.current, { type: 'audio/wav' })
95
+ //
96
+ // setRecordings((prev) => [
97
+ // ...prev,
98
+ // {
99
+ // file: audioBlob as File,
100
+ // id: uuidv7(),
101
+ // name: 'recording.wav',
102
+ // size: String(audioBlob.size),
103
+ // type: 'audio/wav',
104
+ // url: URL.createObjectURL(audioBlob),
105
+ // },
106
+ // ])
107
+ // clearInterval(intervalRef.current!)
108
+ // }
109
+ //
110
+ // // Stop recording audio
111
+ // export const stop_recording_handle = ({ setRecording, intervalRef, mediaRecorderRef }: StopRecordingHandlerParam) => {
112
+ // mediaRecorderRef.current?.stop()
113
+ // setRecording(false)
114
+ // clearInterval(intervalRef.current!)
115
+ // }
116
+ //
117
+ // // Delete recording
118
+ // export const deleteRecordingHandler = ({
119
+ // setRecording,
120
+ // intervalRef,
121
+ // mediaRecorderRef,
122
+ // durationRef,
123
+ // audioChunksRef,
124
+ // }: DeleteRecordingHandlerParams) => {
125
+ // durationRef.current = 0
126
+ // audioChunksRef.current = []
127
+ // stop_recording_handle({
128
+ // durationRef,
129
+ // intervalRef,
130
+ // mediaRecorderRef,
131
+ // setRecording,
132
+ // })
133
+ // }
134
+ //
135
+ // // Start timer to track recording duration
136
+ // export const start_timer_handler = ({ durationRef, intervalRef, setRecordedDuration }: StartTimerParams) => {
137
+ // clearInterval(intervalRef.current!)
138
+ // intervalRef.current = setInterval(() => {
139
+ // durationRef.current += 1000
140
+ // setRecordedDuration(durationRef.current)
141
+ // }, 1000)
142
+ // }
143
+ //
144
+ // // Define the type for the context
145
+ // interface AudioContextType {
146
+ // recording: boolean
147
+ // recordedDuration: number
148
+ // startRecording: () => void
149
+ // stopRecording: () => void
150
+ // deleteRecording: () => void
151
+ // }
152
+ //
153
+ // // Default values for the context
154
+ // const AudioContext = React.createContext<AudioContextType | undefined>(undefined)
155
+ //
156
+ // // Use the custom hook to access the audio context
157
+ // export const useAudioProvider = (): AudioContextType => {
158
+ // const context = React.useContext(AudioContext)
159
+ // if (!context) {
160
+ // throw new Error('useAudioContext must be used within an Audio')
161
+ // }
162
+ // return context
163
+ // }
164
+ //
165
+ // // AudioProvider component that will wrap the rest of the app
166
+ // const Audio: React.FC<{ children: React.ReactNode }> = ({ children }) => {
167
+ // const [recordedDuration, setRecordedDuration] = React.useState<number>(0)
168
+ // const mediaRecorderRef = React.useRef<MediaRecorder | null>(null)
169
+ // const audioChunksRef = React.useRef<Blob[]>([])
170
+ // const intervalRef = React.useRef<NodeJS.Timeout | null>(null)
171
+ // const durationRef = React.useRef<number>(0)
172
+ // const { setRecordings, setRecording, recording } = useAudioDataProvider()
173
+ //
174
+ // // Start recording handler
175
+ // const startRecording = () => {
176
+ // start_recording_handler({
177
+ // audioChunksRef,
178
+ // durationRef,
179
+ // intervalRef,
180
+ // mediaRecorderRef,
181
+ // setRecordedDuration,
182
+ // setRecording,
183
+ // setRecordings,
184
+ // })
185
+ // }
186
+ //
187
+ // // Stop recording handler
188
+ // const stopRecording = () => {
189
+ // stop_recording_handle({
190
+ // durationRef,
191
+ // intervalRef,
192
+ // mediaRecorderRef,
193
+ // setRecording,
194
+ // })
195
+ // }
196
+ //
197
+ // // Delete recording handler
198
+ // const deleteRecording = () => {
199
+ // deleteRecordingHandler({
200
+ // audioChunksRef,
201
+ // durationRef,
202
+ // intervalRef,
203
+ // mediaRecorderRef,
204
+ // setRecording,
205
+ // })
206
+ // }
207
+ //
208
+ // // Cleanup audio element and interval on unmount
209
+ // React.useEffect(() => {
210
+ // return () => {
211
+ // if (intervalRef.current) clearInterval(intervalRef.current)
212
+ // }
213
+ // }, [])
214
+ //
215
+ // // Provide the state and functions to the children components
216
+ // return (
217
+ // <AudioContext.Provider
218
+ // value={{
219
+ // deleteRecording,
220
+ // recordedDuration,
221
+ // recording,
222
+ // startRecording,
223
+ // stopRecording,
224
+ // }}>
225
+ // <div className="flex items-center gap-2">{children}</div>
226
+ // </AudioContext.Provider>
227
+ // )
228
+ // }
229
+ //
230
+ // export interface AudioTimerProps extends React.HTMLAttributes<HTMLDivElement> {
231
+ // showInput?: boolean
232
+ // }
233
+ //
234
+ // export const AudioTimer = React.forwardRef<HTMLDivElement, AudioTimerProps>(({ showInput, className }, ref) => {
235
+ // const { recording, recordedDuration } = useAudioProvider()
236
+ // console.log(recording, recordedDuration)
237
+ // return (
238
+ // <div className={cn('relative', className)} ref={ref}>
239
+ // <div
240
+ // className={cn(
241
+ // '-translate-y-1/2 absolute top-1/2 right-4 flex items-center gap-2 transition duration-100',
242
+ // recording ? 'opacity-100' : 'pointer-events-none right-4 opacity-0',
243
+ // )}>
244
+ // <span className="font-mono">{format_time_handler(recordedDuration)}</span>
245
+ // <span className="h-2 w-2 animate-pulse rounded-full bg-primary font-mono" />
246
+ // </div>
247
+ // <div>
248
+ // {showInput && (
249
+ // <Input
250
+ // className={cn('fade_animation transition', recording ? '!opacity-100 w-[179px]' : 'w-[235px]')}
251
+ // disabled={recording}
252
+ // />
253
+ // )}
254
+ // </div>
255
+ // </div>
256
+ // )
257
+ // })
258
+ //
259
+ // export interface AudioDeleteProps extends React.ComponentPropsWithoutRef<typeof Button> {}
260
+ //
261
+ // export const AudioDelete = React.forwardRef<HTMLButtonElement, AudioDeleteProps>(
262
+ // ({ size, type, onClick, className, ...props }, ref) => {
263
+ // const { deleteRecording, recording } = useAudioProvider()
264
+ // return (
265
+ // <Button
266
+ // className={cn(
267
+ // 'fade_animation relative rounded-full transition',
268
+ // recording ? 'h-8 w-8 scale-1 opacity-1' : 'pointer-events-none h-0 w-0 scale-0 opacity-0',
269
+ // className,
270
+ // )}
271
+ // onClick={(e) => {
272
+ // deleteRecording()
273
+ // onClick && onClick(e)
274
+ // }}
275
+ // ref={ref}
276
+ // size={size ?? 'icon'}
277
+ // type={type ?? 'button'}
278
+ // {...props}>
279
+ // <Trash2 className="-translate-y-1/2 -translate-x-1/2 fade_animation absolute top-1/2 left-1/2 size-[1rem] transition" />
280
+ // </Button>
281
+ // )
282
+ // },
283
+ // )
284
+ //
285
+ // export interface AudioStartProps extends React.ComponentPropsWithoutRef<typeof Button> {}
286
+ //
287
+ // export const AudioStart = React.forwardRef<HTMLButtonElement, AudioStartProps>(
288
+ // ({ size, type, onClick, className, ...props }, ref) => {
289
+ // const { startRecording, stopRecording, recording } = useAudioProvider()
290
+ // return (
291
+ // <Button
292
+ // className={cn('relative h-8 w-8 rounded-full transition', recording ? 'ml-2' : 'ml-0', className)}
293
+ // onClick={(e) => {
294
+ // recording ? stopRecording() : startRecording()
295
+ // onClick && onClick(e)
296
+ // }}
297
+ // ref={ref}
298
+ // size={size ?? 'icon'}
299
+ // type={type ?? 'button'}
300
+ // {...props}>
301
+ // <Mic
302
+ // className={cn(
303
+ // '-translate-y-1/2 -translate-x-1/2 fade_animation absolute top-1/2 left-1/2 size-[1rem] transition',
304
+ // recording ? 'pointer-events-none scale-0 opacity-0' : 'scale-[1] opacity-100',
305
+ // )}
306
+ // />
307
+ // <ArrowBigUp
308
+ // className={cn(
309
+ // '-translate-y-1/2 -translate-x-1/2 fade_animation absolute top-1/2 left-1/2 size-[1.18rem] stroke-[1.5] transition',
310
+ // recording ? 'scale-[1.1] opacity-100' : 'pointer-events-none scale-0 opacity-0',
311
+ // )}
312
+ // />
313
+ // </Button>
314
+ // )
315
+ // },
316
+ // )
317
+ //
318
+ // const AudioVisualizerMemo = React.memo(AudioVisualizer)
319
+ //
320
+ // const AudioItemWrapper = ({
321
+ // children,
322
+ // loading,
323
+ // isPlaying,
324
+ // attachment,
325
+ // timeLeft,
326
+ // size = 'sm',
327
+ // duration,
328
+ // handlePlayPause,
329
+ // }: {
330
+ // size: 'sm' | 'md' | 'lg'
331
+ // children: React.ReactNode
332
+ // attachment: AttachmentType
333
+ // duration: number
334
+ // loading: boolean
335
+ // isPlaying: boolean
336
+ // timeLeft: number
337
+ // handlePlayPause: () => void
338
+ // }) => {
339
+ // return (
340
+ // <>
341
+ // <div
342
+ // className={cn(
343
+ // 'relative flex w-fit items-center gap-4 overflow-hidden rounded-lg bg-secondary px-4 py-2 transition hover:bg-secondary/70',
344
+ // )}>
345
+ // <div
346
+ // className={cn(
347
+ // '-left-[150%] absolute top-50% z-1 flex h-[200%] w-[150%] items-center justify-center rounded-full bg-primary/5 transition-all duration-500 ease-out',
348
+ // isPlaying && '-left-[25%]',
349
+ // )}
350
+ // />
351
+ // <Button
352
+ // className={cn(
353
+ // 'relative z-10 rounded-full',
354
+ // size === 'sm' ? 'h-8 w-8 [&_svg]:size-4' : size === 'md' ? 'h-10 w-10' : 'h-12 w-12',
355
+ // )}
356
+ // loading={loading}
357
+ // onClick={handlePlayPause}
358
+ // size="icon">
359
+ // <Play
360
+ // className={cn(
361
+ // '-translate-y-1/2 -translate-x-1/2 fade_animation absolute top-1/2 left-1/2 transition',
362
+ // !isPlaying && !loading ? 'scale-1 opacity-1' : 'pointer-events-none scale-0 opacity-0',
363
+ // )}
364
+ // />
365
+ // <Pause
366
+ // className={cn(
367
+ // '-translate-y-1/2 -translate-x-1/2 fade_animation absolute top-1/2 left-1/2 transition',
368
+ // isPlaying && !loading ? 'scale-1 opacity-1' : 'pointer-events-none scale-0 opacity-0',
369
+ // )}
370
+ // />
371
+ // </Button>
372
+ //
373
+ // {
374
+ // <div className="z-10 flex flex-col">
375
+ // <div className="w-fit cursor-pointer p-0">{children}</div>
376
+ //
377
+ // <div className="mt-1 flex items-center gap-2">
378
+ // <span className={cn('flex items-center text-accent', size === 'sm' ? 'text-xs' : 'text-sm')}>
379
+ // {isPlaying || timeLeft < duration
380
+ // ? format_time_handler(timeLeft > 0 ? timeLeft : 0)
381
+ // : format_time_handler(duration)}
382
+ // </span>
383
+ // {
384
+ // /* TODO: YOU SHOULD EDIT THE OBJ TO GIVE YOU VALUE OF RECIPIENT OPENED THE RECORD */
385
+ // <span className="h-2 w-2 rounded-full bg-green-500" />
386
+ // }
387
+ //
388
+ // <AudioSpeed />
389
+ // <AudioVolume />
390
+ // <AudioMoreOptions attachment={attachment} />
391
+ // </div>
392
+ // </div>
393
+ // }
394
+ // </div>
395
+ // </>
396
+ // )
397
+ // }
398
+ // export const AudioMoreOptions = ({ attachment }: { attachment: AttachmentType }) => {
399
+ // return (
400
+ // <PopoverWrapper
401
+ // content={{
402
+ // align: 'center',
403
+ // children: (
404
+ // <div className="flex items-center space-x-2">
405
+ // <Button
406
+ // icon={<Download />}
407
+ // onClick={() => {
408
+ // // downloadAttachment({ attachment })
409
+ // }}
410
+ // size={'sm'}
411
+ // variant={'ghost'}>
412
+ // Download
413
+ // </Button>
414
+ // </div>
415
+ // ),
416
+ // className: 'w-fit p-2',
417
+ // side: 'top',
418
+ // }}
419
+ // trigger={{
420
+ // children: (
421
+ // <Button
422
+ // className={cn('h-4 w-8 rounded-full font-semibold text-[.6rem]')}
423
+ // icon={<Ellipsis className="!size-3" />}
424
+ // size={'sm'}
425
+ // variant={'default'}
426
+ // />
427
+ // ),
428
+ // }}
429
+ // />
430
+ // )
431
+ // }
432
+ //
433
+ // const VolumeIcons = {
434
+ // 0: VolumeX, // Muted
435
+ // 1: Volume, // Low volume
436
+ // 2: Volume1, // Medium volume
437
+ // 3: Volume2, // High volume
438
+ // }
439
+ //
440
+ // export const AudioVolume = () => {
441
+ // const { volume, setVolume } = useAudioDataProvider()
442
+ //
443
+ // const handleVolumeChange = (value: number) => {
444
+ // // FIX: TYPE undefined
445
+ // const newVolume = value / 100
446
+ // setVolume(newVolume)
447
+ // }
448
+ //
449
+ // const getVolumeIcon = () => {
450
+ // if (volume === 0) return VolumeIcons[0] // Muted
451
+ // if (volume > 0 && volume <= 0.33) return VolumeIcons[1] // Low volume
452
+ // if (volume > 0.33 && volume <= 0.66) return VolumeIcons[2] // Medium volume
453
+ // return VolumeIcons[3] // High volume
454
+ // }
455
+ //
456
+ // return (
457
+ // <PopoverWrapper
458
+ // content={{
459
+ // align: 'center',
460
+ // children: (
461
+ // <div className="flex items-center space-x-2">
462
+ // <Slider
463
+ // className="[&>span]:h-[4px] [&_span[role='slider']]:mt-[-6px] [&_span[role='slider']]:h-4 [&_span[role='slider']]:w-4"
464
+ // defaultValue={volume * 100}
465
+ // max={100}
466
+ // onValueChange={handleVolumeChange}
467
+ // step={1}
468
+ // />
469
+ // </div>
470
+ // ),
471
+ // className: 'w-[100px] p-2',
472
+ // side: 'top',
473
+ // }}
474
+ // trigger={{
475
+ // children: (
476
+ // <Button
477
+ // className={cn('h-4 w-8 rounded-full font-semibold text-[.6rem]')}
478
+ // icon={getVolumeIcon()}
479
+ // size={'sm'}
480
+ // variant={'default'}
481
+ // />
482
+ // ),
483
+ // }}
484
+ // />
485
+ // )
486
+ // }
487
+ //
488
+ // export const AudioSpeed = () => {
489
+ // const { speed, setSpeed } = useAudioDataProvider()
490
+ //
491
+ // return (
492
+ // <>
493
+ // <Button
494
+ // className={cn('h-4 w-8 rounded-full font-semibold text-[.6rem]')}
495
+ // onClick={() => setSpeed(speed > 1.5 ? 0.5 : speed + 0.5)}
496
+ // size={'sm'}
497
+ // variant={'default'}>
498
+ // x{speed}
499
+ // </Button>
500
+ // </>
501
+ // )
502
+ // }
503
+ //
504
+ // export interface AudioRecordItemProps {
505
+ // loading?: boolean
506
+ // size?: 'sm' | 'md' | 'lg'
507
+ // barHeight?: number
508
+ // barWidth?: number
509
+ // gap?: number
510
+ // attachment: AttachmentType
511
+ // backgroundColor?: ThemeColor
512
+ // barColor?: ThemeColor
513
+ // barPlayedColor?: ThemeColor
514
+ // minBarHeight?: number
515
+ // style?: React.CSSProperties
516
+ // audio: Blob | null
517
+ // }
518
+ //
519
+ // const AudioRecordItem = ({
520
+ // size = 'sm',
521
+ // audio,
522
+ // loading: loadingState,
523
+ // attachment,
524
+ // style,
525
+ // minBarHeight,
526
+ // barPlayedColor,
527
+ // gap,
528
+ // barColor,
529
+ // barWidth,
530
+ // barHeight,
531
+ // backgroundColor,
532
+ // }: AudioRecordItemProps) => {
533
+ // const { duration: audioDuration, speed, volume } = useAudioDataProvider()
534
+ // const duration = audioDuration * 1000
535
+ //
536
+ // const [isPlaying, setIsPlaying] = React.useState<boolean>(false)
537
+ // const audioRef = React.useRef<HTMLAudioElement | null>(null)
538
+ // const [loading, setLoading] = React.useState<boolean>(loadingState ?? true)
539
+ // const [currentTime, setCurrentTime] = React.useState<number>(0)
540
+ // const [timeLeft, setTimeLeft] = React.useState<number>(duration)
541
+ //
542
+ // React.useEffect(() => {
543
+ // setTimeLeft(duration - currentTime)
544
+ // }, [currentTime, duration])
545
+ //
546
+ // React.useEffect(() => {
547
+ // if (audio) {
548
+ // const audioURL = URL.createObjectURL(audio)
549
+ // audioRef.current = new_audio(audioURL)
550
+ //
551
+ // // Handle end of the audio
552
+ // audioRef.current.onended = () => {
553
+ // setIsPlaying(false)
554
+ // setCurrentTime(0)
555
+ // setTimeLeft(duration)
556
+ // }
557
+ //
558
+ // // Update current time as the audio plays
559
+ // audioRef.current.ontimeupdate = () => {
560
+ // setCurrentTime(audioRef.current!.currentTime * 1000)
561
+ // }
562
+ //
563
+ // return () => {
564
+ // if (audioRef.current) {
565
+ // audioRef.current.pause()
566
+ // audioRef.current.src = ''
567
+ // }
568
+ // }
569
+ // }
570
+ // }, [audio])
571
+ //
572
+ // // Update the playback rate and keep the audio playing at the current time
573
+ // React.useEffect(() => {
574
+ // if (audioRef.current) {
575
+ // const wasPlaying = isPlaying
576
+ // const currentAudioTime = audioRef.current.currentTime
577
+ //
578
+ // // Pause the audio temporarily, change playback rate, and resume if it was playing
579
+ // audioRef.current.pause()
580
+ // audioRef.current.playbackRate = speed
581
+ // audioRef.current.currentTime = currentAudioTime
582
+ // audioRef.current.volume = volume
583
+ //
584
+ // if (wasPlaying) {
585
+ // audioRef.current.play()
586
+ // }
587
+ // }
588
+ // }, [speed, volume])
589
+ //
590
+ // // Play or pause audio
591
+ // const handlePlayPause = React.useCallback(() => {
592
+ // if (isPlaying) {
593
+ // audioRef.current?.pause()
594
+ // } else {
595
+ // audioRef.current?.play()
596
+ // }
597
+ // setIsPlaying(!isPlaying)
598
+ // }, [isPlaying])
599
+ //
600
+ // return (
601
+ // <>
602
+ // <AudioItemWrapper
603
+ // attachment={{
604
+ // ...attachment,
605
+ // file: attachment.file ?? audio,
606
+ // }}
607
+ // children={
608
+ // <div onClick={(event) => visualizer_click_handler({ audioRef, event, setCurrentTime })}>
609
+ // <AudioVisualizerMemo
610
+ // backgroundColor={backgroundColor}
611
+ // barColor={barColor}
612
+ // barPlayedColor={barPlayedColor}
613
+ // barWidth={barWidth ?? 3}
614
+ // blob={audio}
615
+ // currentTime={currentTime / 1000}
616
+ // gap={gap ?? 2}
617
+ // height={barHeight ?? 27}
618
+ // minBarHeight={minBarHeight ?? 1}
619
+ // setCurrentTime={setCurrentTime}
620
+ // setLoading={setLoading}
621
+ // style={style}
622
+ // width={barWidth ?? 180}
623
+ // />
624
+ // </div>
625
+ // }
626
+ // duration={duration}
627
+ // handlePlayPause={handlePlayPause}
628
+ // isPlaying={isPlaying}
629
+ // loading={loading}
630
+ // size={size}
631
+ // timeLeft={timeLeft}
632
+ // />
633
+ // </>
634
+ // )
635
+ // }
636
+ //
637
+ // export interface FetchAudioBlobParams {
638
+ // url: string
639
+ // setAudioBlob: React.Dispatch<React.SetStateAction<Blob | null>>
640
+ // }
641
+ //
642
+ // export const fetchAudioBlob = async ({ url, setAudioBlob }: FetchAudioBlobParams) => {
643
+ // try {
644
+ // const response = await fetch(url)
645
+ // if (!response.ok) {
646
+ // console.error('Failed to fetch audio:', response.statusText)
647
+ // return setAudioBlob(null)
648
+ // }
649
+ //
650
+ // const blob = await response.blob()
651
+ // setAudioBlob(blob)
652
+ // } catch (error) {
653
+ // setAudioBlob(null)
654
+ // console.error('Error fetching audio:', error)
655
+ // }
656
+ // }
657
+ //
658
+ // export interface AudioItemProps {
659
+ // attachment: AttachmentType
660
+ // }
661
+ //
662
+ // const AudioItem: React.FC<AudioItemProps> = ({ attachment }) => {
663
+ // const [audioBlob, setAudioBlob] = React.useState<Blob | null>(attachment.file ? attachment.file : null)
664
+ //
665
+ // React.useEffect(() => {
666
+ // // if (contentSchema.safeParse(attachment).error) return
667
+ // if (!attachment.url || !attachment.url.startsWith('https://')) return
668
+ // fetchAudioBlob({ setAudioBlob, url: attachment.url })
669
+ // }, [attachment])
670
+ //
671
+ // return (
672
+ // <AudioDataProvider>
673
+ // <AudioRecordItem attachment={attachment} audio={audioBlob} loading={audioBlob === null ? true : false} />
674
+ // </AudioDataProvider>
675
+ // )
676
+ // }
677
+ //
678
+ // // Audio Provider
679
+ // export interface AudioDataContextType {
680
+ // process_audio: (args: Omit<ProcessBlobParams, 'setAnimationProgress' | 'setDuration' | 'setData'>) => Promise<void>
681
+ // data: dataPoint[]
682
+ // speed: number
683
+ // setSpeed: React.Dispatch<React.SetStateAction<number>>
684
+ // animationProgress: number
685
+ // setAnimationProgress: React.Dispatch<React.SetStateAction<number>>
686
+ // recordings: RecordingtType[]
687
+ // setRecordings: React.Dispatch<React.SetStateAction<RecordingtType[]>>
688
+ // duration: number
689
+ // setDuration: React.Dispatch<React.SetStateAction<number>>
690
+ // recording: boolean
691
+ // setRecording: React.Dispatch<React.SetStateAction<boolean>>
692
+ // volume: number
693
+ // setVolume: React.Dispatch<React.SetStateAction<number>>
694
+ // }
695
+ //
696
+ // export const AudioDataContext = React.createContext<AudioDataContextType | undefined>(undefined)
697
+ //
698
+ // const useAudioDataProvider = (): AudioDataContextType => {
699
+ // const context = React.useContext(AudioDataContext)
700
+ // if (!context) {
701
+ // throw new Error('useAudioProvider must be used within an AudioServiceProvider')
702
+ // }
703
+ // return context
704
+ // }
705
+ //
706
+ // export interface AudioProviderProps {
707
+ // children: React.ReactNode
708
+ // }
709
+ //
710
+ // const AudioDataProvider: React.FC<AudioProviderProps> = ({ children }) => {
711
+ // const [data, setData] = React.useState<dataPoint[]>([])
712
+ // const [duration, setDuration] = React.useState<number>(0)
713
+ // const [recordings, setRecordings] = React.useState<RecordingtType[]>([])
714
+ // const [speed, setSpeed] = React.useState<number>(1)
715
+ // const [volume, setVolume] = React.useState(1)
716
+ // const [animationProgress, setAnimationProgress] = React.useState<number>(0)
717
+ // const [recording, setRecording] = React.useState<boolean>(false)
718
+ //
719
+ // const process_audio = React.useCallback(
720
+ // async ({
721
+ // canvasRef,
722
+ // blob,
723
+ // barWidth,
724
+ // gap,
725
+ // backgroundColor,
726
+ // barColor,
727
+ // barPlayedColor,
728
+ // minBarHeight,
729
+ // setLoading,
730
+ // width,
731
+ // height,
732
+ // }: Omit<ProcessBlobParams, 'setAnimationProgress' | 'setDuration' | 'setData'>) => {
733
+ // await process_blob({
734
+ // backgroundColor,
735
+ // barColor,
736
+ // barPlayedColor,
737
+ // barWidth,
738
+ // blob,
739
+ // canvasRef,
740
+ // gap,
741
+ // height,
742
+ // minBarHeight,
743
+ // setAnimationProgress,
744
+ // setData,
745
+ // setDuration,
746
+ // setLoading,
747
+ // width,
748
+ // })
749
+ // },
750
+ // [],
751
+ // )
752
+ //
753
+ // return (
754
+ // <AudioDataContext.Provider
755
+ // value={{
756
+ // animationProgress,
757
+ // data,
758
+ // duration,
759
+ // process_audio,
760
+ // recording,
761
+ // recordings,
762
+ // setAnimationProgress,
763
+ // setDuration,
764
+ // setRecording,
765
+ // setRecordings,
766
+ // setSpeed,
767
+ // setVolume,
768
+ // speed,
769
+ // volume,
770
+ // }}>
771
+ // {children}
772
+ // </AudioDataContext.Provider>
773
+ // )
774
+ // }
775
+ //
776
+ // export { Audio, AudioItem, AudioRecordItem, AudioItemWrapper, AudioDataProvider, useAudioDataProvider }