@neuctra/ui 0.2.2 → 0.2.4

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 (105) hide show
  1. package/dist/components/basic/Accordation.d.ts +27 -18
  2. package/dist/components/basic/Alert.d.ts +14 -2
  3. package/dist/components/basic/Avatar.d.ts +5 -3
  4. package/dist/components/basic/Badge.d.ts +3 -3
  5. package/dist/components/basic/Button.d.ts +15 -17
  6. package/dist/components/basic/Card.d.ts +7 -49
  7. package/dist/components/basic/{CheckRadioInput.d.ts → CheckboxGroup.d.ts} +4 -5
  8. package/dist/components/basic/Container.d.ts +28 -26
  9. package/dist/components/basic/Drawer.d.ts +20 -11
  10. package/dist/components/basic/DropDown.d.ts +24 -34
  11. package/dist/components/basic/Flexbox.d.ts +18 -10
  12. package/dist/components/basic/GridView.d.ts +7 -5
  13. package/dist/components/basic/Image.d.ts +31 -6
  14. package/dist/components/basic/Input.d.ts +18 -10
  15. package/dist/components/basic/List.d.ts +11 -3
  16. package/dist/components/basic/Modal.d.ts +8 -2
  17. package/dist/components/basic/RadioGroup.d.ts +25 -0
  18. package/dist/components/basic/Section.d.ts +36 -0
  19. package/dist/components/basic/Stack.d.ts +27 -0
  20. package/dist/components/basic/SwitchGroup.d.ts +25 -0
  21. package/dist/components/basic/Table.d.ts +18 -54
  22. package/dist/components/basic/Tabs.d.ts +28 -28
  23. package/dist/components/basic/Text.d.ts +19 -32
  24. package/dist/index.cjs.js +55 -176
  25. package/dist/index.cjs.js.map +1 -0
  26. package/dist/index.d.ts +19 -18
  27. package/dist/index.es.js +3501 -4738
  28. package/dist/index.es.js.map +1 -0
  29. package/dist/src/components/avatar/AvatarGroup.js +9 -0
  30. package/dist/src/components/avatar/AvatarWithStatus.js +18 -0
  31. package/dist/src/components/basic/Accordation.js +74 -0
  32. package/dist/src/components/basic/Alert.js +141 -0
  33. package/dist/src/components/basic/AudioGallery.js +425 -0
  34. package/dist/src/components/basic/AudioPlayer.js +116 -0
  35. package/dist/src/components/basic/Avatar.js +181 -0
  36. package/dist/src/components/basic/Badge.js +66 -0
  37. package/dist/src/components/basic/Button.js +101 -0
  38. package/dist/src/components/basic/Card.js +47 -0
  39. package/dist/src/components/basic/CheckboxGroup.js +40 -0
  40. package/dist/src/components/basic/Container.js +45 -0
  41. package/dist/src/components/basic/Drawer.js +94 -0
  42. package/dist/src/components/basic/DropDown.js +162 -0
  43. package/dist/src/components/basic/Flexbox.js +67 -0
  44. package/dist/src/components/basic/GridView.js +51 -0
  45. package/dist/src/components/basic/Image.js +95 -0
  46. package/dist/src/components/basic/Input.js +123 -0
  47. package/dist/src/components/basic/List.js +71 -0
  48. package/dist/src/components/basic/Modal.js +86 -0
  49. package/dist/src/components/basic/RadioGroup.js +37 -0
  50. package/dist/src/components/basic/Section.js +100 -0
  51. package/dist/src/components/basic/Stack.js +75 -0
  52. package/dist/src/components/basic/SwitchGroup.js +50 -0
  53. package/dist/src/components/basic/Table.js +32 -0
  54. package/dist/src/components/basic/Tabs.js +149 -0
  55. package/dist/src/components/basic/Text.js +117 -0
  56. package/dist/src/index.js +46 -0
  57. package/dist/types/src/components/basic/Accordation.d.ts +44 -0
  58. package/dist/types/{components → src/components}/basic/Alert.d.ts +14 -2
  59. package/dist/types/{components → src/components}/basic/Avatar.d.ts +5 -3
  60. package/dist/types/{components → src/components}/basic/Badge.d.ts +3 -3
  61. package/dist/types/src/components/basic/Button.d.ts +26 -0
  62. package/dist/types/src/components/basic/Card.d.ts +28 -0
  63. package/dist/types/{components/basic/CheckRadioInput.d.ts → src/components/basic/CheckboxGroup.d.ts} +4 -5
  64. package/dist/types/src/components/basic/Container.d.ts +32 -0
  65. package/dist/types/src/components/basic/Drawer.d.ts +33 -0
  66. package/dist/types/src/components/basic/DropDown.d.ts +53 -0
  67. package/dist/types/src/components/basic/Flexbox.d.ts +25 -0
  68. package/dist/types/{components → src/components}/basic/GridView.d.ts +7 -5
  69. package/dist/types/src/components/basic/Image.d.ts +58 -0
  70. package/dist/types/{components → src/components}/basic/Input.d.ts +18 -10
  71. package/dist/types/{components → src/components}/basic/List.d.ts +11 -3
  72. package/dist/types/{components → src/components}/basic/Modal.d.ts +8 -2
  73. package/dist/types/src/components/basic/RadioGroup.d.ts +25 -0
  74. package/dist/types/src/components/basic/Section.d.ts +36 -0
  75. package/dist/types/src/components/basic/Stack.d.ts +27 -0
  76. package/dist/types/src/components/basic/SwitchGroup.d.ts +25 -0
  77. package/dist/types/src/components/basic/Table.d.ts +23 -0
  78. package/dist/types/src/components/basic/Tabs.d.ts +47 -0
  79. package/dist/types/src/components/basic/Text.d.ts +26 -0
  80. package/dist/types/{index.d.ts → src/index.d.ts} +19 -18
  81. package/dist/types/vite.config.d.ts +2 -0
  82. package/dist/ui.css +1 -1
  83. package/dist/vite.config.js +34 -0
  84. package/package.json +2 -1
  85. package/dist/components/basic/ImageGallery.d.ts +0 -21
  86. package/dist/components/basic/VideoGallery.d.ts +0 -136
  87. package/dist/components/basic/VideoPlayer.d.ts +0 -36
  88. package/dist/types/components/basic/Accordation.d.ts +0 -35
  89. package/dist/types/components/basic/Button.d.ts +0 -28
  90. package/dist/types/components/basic/Card.d.ts +0 -70
  91. package/dist/types/components/basic/Container.d.ts +0 -30
  92. package/dist/types/components/basic/Drawer.d.ts +0 -24
  93. package/dist/types/components/basic/DropDown.d.ts +0 -63
  94. package/dist/types/components/basic/Flexbox.d.ts +0 -17
  95. package/dist/types/components/basic/Image.d.ts +0 -33
  96. package/dist/types/components/basic/ImageGallery.d.ts +0 -21
  97. package/dist/types/components/basic/Table.d.ts +0 -59
  98. package/dist/types/components/basic/Tabs.d.ts +0 -47
  99. package/dist/types/components/basic/Text.d.ts +0 -39
  100. package/dist/types/components/basic/VideoGallery.d.ts +0 -136
  101. package/dist/types/components/basic/VideoPlayer.d.ts +0 -36
  102. /package/dist/types/{components → src/components}/avatar/AvatarGroup.d.ts +0 -0
  103. /package/dist/types/{components → src/components}/avatar/AvatarWithStatus.d.ts +0 -0
  104. /package/dist/types/{components → src/components}/basic/AudioGallery.d.ts +0 -0
  105. /package/dist/types/{components → src/components}/basic/AudioPlayer.d.ts +0 -0
@@ -0,0 +1,425 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useRef, useState, useEffect } from "react";
3
+ import { Play, Pause, Volume2, VolumeX, RotateCcw, SkipBack, SkipForward, Heart, Music, Shuffle, } from "lucide-react";
4
+ const defaultTracks = [
5
+ {
6
+ src: "https://www.soundjay.com/misc/sounds/bell-ringing-05.wav",
7
+ title: "Morning Bell",
8
+ artist: "Nature Sounds",
9
+ duration: "0:15",
10
+ thumbnail: "https://images.unsplash.com/photo-1493225457124-a3eb161ffa5f?w=300&h=300&fit=crop",
11
+ },
12
+ {
13
+ src: "https://www.soundjay.com/buttons/sounds/button-4.wav",
14
+ title: "Digital Click",
15
+ artist: "Tech Audio",
16
+ duration: "0:05",
17
+ thumbnail: "https://images.unsplash.com/photo-1514525253161-7a46d19cd819?w=300&h=300&fit=crop",
18
+ },
19
+ {
20
+ src: "https://www.soundjay.com/buttons/sounds/button-10.wav",
21
+ title: "Soft Chime",
22
+ artist: "Ambient Studio",
23
+ duration: "0:08",
24
+ thumbnail: "https://images.unsplash.com/photo-1493225457124-a3eb161ffa5f?w=300&h=300&fit=crop",
25
+ },
26
+ ];
27
+ export function AudioGallery({ tracks = defaultTracks, className = "", galleryTitle = "Audio Gallery", primaryColor = "#8b5cf6", backgroundColor = "#0f0f23", textColor = "#e4e4e7", secondaryColor = "#1a1a2e", border = 0, borderColor, maxWidth = 420, autoplay = false, loop = false, }) {
28
+ const [currentTrackIndex, setCurrentTrackIndex] = useState(null);
29
+ const [isPlaying, setIsPlaying] = useState(false);
30
+ const [currentTime, setCurrentTime] = useState(0);
31
+ const [duration, setDuration] = useState(0);
32
+ const [volume, setVolume] = useState(0.7);
33
+ const [isFullscreen, setIsFullscreen] = useState(false);
34
+ const [isLooping, setIsLooping] = useState(loop);
35
+ const [isShuffle, setIsShuffle] = useState(false);
36
+ const [isLiked, setIsLiked] = useState(false);
37
+ const [showVolumeSlider, setShowVolumeSlider] = useState(false);
38
+ const audioRef = useRef(null);
39
+ const playerRef = useRef(null);
40
+ const volumeTimeoutRef = useRef(null);
41
+ useEffect(() => {
42
+ if (audioRef.current) {
43
+ audioRef.current.volume = volume;
44
+ }
45
+ }, [volume]);
46
+ useEffect(() => {
47
+ if (audioRef.current) {
48
+ audioRef.current.loop = isLooping;
49
+ }
50
+ }, [isLooping]);
51
+ useEffect(() => {
52
+ if (currentTrackIndex === null && audioRef.current) {
53
+ audioRef.current.pause();
54
+ setIsPlaying(false);
55
+ setCurrentTime(0);
56
+ setDuration(0);
57
+ }
58
+ }, [currentTrackIndex]);
59
+ const playPauseTrack = (index) => {
60
+ if (currentTrackIndex === index) {
61
+ if (!audioRef.current)
62
+ return;
63
+ if (audioRef.current.paused) {
64
+ audioRef.current.play().catch(() => { });
65
+ setIsPlaying(true);
66
+ }
67
+ else {
68
+ audioRef.current.pause();
69
+ setIsPlaying(false);
70
+ }
71
+ }
72
+ else {
73
+ setCurrentTrackIndex(index);
74
+ setTimeout(() => {
75
+ if (audioRef.current) {
76
+ audioRef.current.play().catch(() => { });
77
+ setIsPlaying(true);
78
+ }
79
+ }, 100);
80
+ }
81
+ };
82
+ const handleTimeUpdate = () => {
83
+ if (!audioRef.current)
84
+ return;
85
+ setCurrentTime(audioRef.current.currentTime);
86
+ if (audioRef.current.duration) {
87
+ setDuration(audioRef.current.duration);
88
+ }
89
+ };
90
+ const handleSeek = (e) => {
91
+ if (!audioRef.current || !duration)
92
+ return;
93
+ const rect = e.currentTarget.getBoundingClientRect();
94
+ const clickPos = e.clientX - rect.left;
95
+ const percent = clickPos / rect.width;
96
+ const seekTime = percent * duration;
97
+ audioRef.current.currentTime = seekTime;
98
+ setCurrentTime(seekTime);
99
+ };
100
+ const handleVolumeChange = (e) => {
101
+ const rect = e.currentTarget.getBoundingClientRect();
102
+ const clickPos = e.clientX - rect.left;
103
+ const percent = clickPos / rect.width;
104
+ const newVolume = Math.max(0, Math.min(1, percent));
105
+ setVolume(newVolume);
106
+ };
107
+ const skip = (seconds) => {
108
+ if (audioRef.current && duration) {
109
+ let newTime = audioRef.current.currentTime + seconds;
110
+ newTime = Math.min(Math.max(newTime, 0), duration);
111
+ audioRef.current.currentTime = newTime;
112
+ setCurrentTime(newTime);
113
+ }
114
+ };
115
+ const nextTrack = () => {
116
+ if (currentTrackIndex === null)
117
+ return;
118
+ let nextIndex;
119
+ if (isShuffle) {
120
+ nextIndex = Math.floor(Math.random() * tracks.length);
121
+ }
122
+ else {
123
+ nextIndex = (currentTrackIndex + 1) % tracks.length;
124
+ }
125
+ playPauseTrack(nextIndex);
126
+ };
127
+ const prevTrack = () => {
128
+ if (currentTrackIndex === null)
129
+ return;
130
+ let prevIndex;
131
+ if (isShuffle) {
132
+ prevIndex = Math.floor(Math.random() * tracks.length);
133
+ }
134
+ else {
135
+ prevIndex = (currentTrackIndex - 1 + tracks.length) % tracks.length;
136
+ }
137
+ playPauseTrack(prevIndex);
138
+ };
139
+ const toggleMute = () => {
140
+ setVolume((prev) => (prev > 0 ? 0 : 0.7));
141
+ };
142
+ const showVolume = () => {
143
+ setShowVolumeSlider(true);
144
+ if (volumeTimeoutRef.current) {
145
+ clearTimeout(volumeTimeoutRef.current);
146
+ }
147
+ volumeTimeoutRef.current = setTimeout(() => {
148
+ setShowVolumeSlider(false);
149
+ }, 3000);
150
+ };
151
+ const formatTime = (time) => {
152
+ if (isNaN(time))
153
+ return "0:00";
154
+ const minutes = Math.floor(time / 60);
155
+ const seconds = Math.floor(time % 60);
156
+ return `${minutes}:${seconds < 10 ? "0" : ""}${seconds}`;
157
+ };
158
+ const currentTrack = currentTrackIndex !== null ? tracks[currentTrackIndex] : null;
159
+ return (_jsxs("div", { className: className, style: {
160
+ maxWidth: `${maxWidth}px`,
161
+ margin: "20px auto",
162
+ background: `linear-gradient(145deg, ${backgroundColor}, ${secondaryColor})`,
163
+ color: textColor,
164
+ borderRadius: "24px",
165
+ padding: "24px 16px",
166
+ fontFamily: "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
167
+ userSelect: "none",
168
+ backdropFilter: "blur(20px)",
169
+ border: `${border}px solid ${borderColor}40`,
170
+ }, children: [_jsxs("div", { style: {
171
+ display: "flex",
172
+ alignItems: "center",
173
+ justifyContent: "space-between",
174
+ marginBottom: "24px",
175
+ }, children: [_jsxs("div", { style: { display: "flex", alignItems: "center", gap: "12px" }, children: [_jsx("div", { style: {
176
+ width: "40px",
177
+ height: "40px",
178
+ borderRadius: "12px",
179
+ background: `linear-gradient(135deg, ${primaryColor}, ${secondaryColor})`,
180
+ display: "flex",
181
+ alignItems: "center",
182
+ justifyContent: "center",
183
+ }, children: _jsx(Music, { size: 20, color: "white" }) }), _jsxs("div", { children: [_jsx("h2", { style: {
184
+ margin: 0,
185
+ fontSize: "1.25rem",
186
+ fontWeight: "700",
187
+ color: primaryColor, // fallback for browsers without WebkitTextFillColor
188
+ }, children: galleryTitle }), _jsxs("p", { style: { margin: 0, fontSize: "0.875rem", opacity: 0.7 }, children: [tracks.length, " tracks"] })] })] }), _jsx("button", { onClick: () => setIsShuffle(!isShuffle), style: {
189
+ background: isShuffle ? primaryColor : "transparent",
190
+ border: "none",
191
+ borderRadius: "12px",
192
+ padding: "8px",
193
+ cursor: "pointer",
194
+ transition: "all 0.3s ease",
195
+ opacity: isShuffle ? 1 : 0.6,
196
+ }, "aria-label": "Toggle Shuffle", children: _jsx(Shuffle, { size: 18, color: isShuffle ? "white" : textColor }) })] }), _jsx("div", { style: {
197
+ display: "flex",
198
+ flexDirection: "column",
199
+ gap: "8px",
200
+ marginBottom: "20px",
201
+ maxHeight: "240px",
202
+ overflowY: "auto",
203
+ paddingRight: "4px",
204
+ }, children: tracks.map((track, index) => {
205
+ const isActive = currentTrackIndex === index;
206
+ const isCurrentlyPlaying = isActive && isPlaying;
207
+ return (_jsxs("div", { onClick: () => playPauseTrack(index), style: {
208
+ display: "flex",
209
+ alignItems: "center",
210
+ padding: "12px 16px",
211
+ borderRadius: "16px",
212
+ background: isActive
213
+ ? `linear-gradient(135deg, ${primaryColor}20, ${primaryColor}10)`
214
+ : "rgba(255,255,255,0.05)",
215
+ border: isActive
216
+ ? `1px solid ${primaryColor}40`
217
+ : "1px solid transparent",
218
+ cursor: "pointer",
219
+ transition: "all 0.3s ease",
220
+ backdropFilter: isActive ? `blur(20px)` : "none",
221
+ }, children: [_jsxs("div", { style: {
222
+ width: "48px",
223
+ height: "48px",
224
+ borderRadius: "12px",
225
+ background: track.thumbnail
226
+ ? `url(${track.thumbnail}) center/cover`
227
+ : primaryColor,
228
+ display: "flex",
229
+ alignItems: "center",
230
+ justifyContent: "center",
231
+ marginRight: "12px",
232
+ position: "relative",
233
+ overflow: "hidden",
234
+ }, children: [!track.thumbnail && _jsx(Music, { size: 20, color: "white" }), isCurrentlyPlaying && (_jsx("div", { style: {
235
+ position: "absolute",
236
+ top: 0,
237
+ left: 0,
238
+ right: 0,
239
+ bottom: 0,
240
+ background: "rgba(0,0,0,0.6)",
241
+ display: "flex",
242
+ alignItems: "center",
243
+ justifyContent: "center",
244
+ }, children: _jsx("div", { style: {
245
+ width: "16px",
246
+ height: "16px",
247
+ display: "flex",
248
+ gap: "2px",
249
+ alignItems: "end",
250
+ justifyContent: "center",
251
+ }, children: [0, 1, 2].map((i) => (_jsx("div", { style: {
252
+ width: "3px",
253
+ background: "white",
254
+ borderRadius: "2px",
255
+ animation: `equalizer 1s ease-in-out infinite ${i * 0.2}s`,
256
+ height: "12px",
257
+ } }, i))) }) }))] }), _jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [_jsx("div", { style: {
258
+ fontWeight: "600",
259
+ fontSize: "0.95rem",
260
+ color: isActive ? primaryColor : textColor,
261
+ whiteSpace: "nowrap",
262
+ overflow: "hidden",
263
+ textOverflow: "ellipsis",
264
+ }, children: track.title }), track.artist && (_jsx("div", { style: {
265
+ fontSize: "0.8rem",
266
+ opacity: 0.7,
267
+ whiteSpace: "nowrap",
268
+ overflow: "hidden",
269
+ textOverflow: "ellipsis",
270
+ }, children: track.artist }))] }), _jsxs("div", { style: { display: "flex", alignItems: "center", gap: "12px" }, children: [track.duration && (_jsx("span", { style: { fontSize: "0.8rem", opacity: 0.6 }, children: track.duration })), _jsx("div", { style: {
271
+ width: "32px",
272
+ height: "32px",
273
+ borderRadius: "8px",
274
+ background: isActive
275
+ ? primaryColor
276
+ : "rgba(255,255,255,0.1)",
277
+ display: "flex",
278
+ alignItems: "center",
279
+ justifyContent: "center",
280
+ transition: "all 0.3s ease",
281
+ }, children: isCurrentlyPlaying ? (_jsx(Pause, { size: 16, color: "white" })) : (_jsx(Play, { size: 16, color: "white" })) })] })] }, index));
282
+ }) }), currentTrack && (_jsxs("div", { ref: playerRef, style: {
283
+ background: `linear-gradient(135deg, ${secondaryColor}, ${backgroundColor})`,
284
+ borderRadius: "20px",
285
+ padding: "20px",
286
+ border: `1px solid ${primaryColor}40`,
287
+ backdropFilter: "blur(20px)",
288
+ position: "relative",
289
+ overflow: "hidden",
290
+ }, children: [currentTrack.thumbnail && (_jsx("div", { style: {
291
+ position: "absolute",
292
+ top: 0,
293
+ left: 0,
294
+ right: 0,
295
+ bottom: 0,
296
+ backgroundImage: `url(${currentTrack.thumbnail})`,
297
+ backgroundSize: "cover",
298
+ backgroundPosition: "center",
299
+ filter: "blur(60px) opacity(0.1)",
300
+ transform: "scale(1.1)",
301
+ } })), _jsxs("div", { style: { position: "relative", zIndex: 1 }, children: [_jsxs("div", { style: { textAlign: "center", marginBottom: "20px" }, children: [_jsx("h3", { style: {
302
+ margin: "0 0 4px 0",
303
+ fontSize: "1.1rem",
304
+ fontWeight: "700",
305
+ color: primaryColor,
306
+ }, children: currentTrack.title }), currentTrack.artist && (_jsx("p", { style: { margin: 0, opacity: 0.7, fontSize: "0.9rem" }, children: currentTrack.artist }))] }), _jsxs("div", { style: {
307
+ display: "flex",
308
+ alignItems: "center",
309
+ justifyContent: "center",
310
+ gap: "20px",
311
+ marginBottom: "20px",
312
+ }, children: [_jsx("button", { onClick: prevTrack, style: controlButtonStyle(textColor, "rgba(255,255,255,0.1)"), "aria-label": "Previous Track", children: _jsx(SkipBack, { size: 20 }) }), _jsxs("button", { onClick: () => skip(-10), style: controlButtonStyle(textColor, "rgba(255,255,255,0.1)"), "aria-label": "Skip back 10 seconds", children: [_jsx(SkipBack, { size: 16 }), _jsx("span", { style: { fontSize: "0.7rem", marginLeft: "2px" }, children: "10" })] }), _jsx("button", { onClick: () => {
313
+ if (!audioRef.current)
314
+ return;
315
+ if (isPlaying) {
316
+ audioRef.current.pause();
317
+ setIsPlaying(false);
318
+ }
319
+ else {
320
+ audioRef.current.play().catch(() => { });
321
+ setIsPlaying(true);
322
+ }
323
+ }, style: {
324
+ ...controlButtonStyle("#fff", primaryColor),
325
+ width: "60px",
326
+ height: "60px",
327
+ borderRadius: "50%",
328
+ boxShadow: `0 8px 25px ${primaryColor}40`,
329
+ }, "aria-label": isPlaying ? "Pause" : "Play", children: isPlaying ? _jsx(Pause, { size: 24 }) : _jsx(Play, { size: 24 }) }), _jsxs("button", { onClick: () => skip(10), style: controlButtonStyle(textColor, "rgba(255,255,255,0.1)"), "aria-label": "Skip forward 10 seconds", children: [_jsx("span", { style: { fontSize: "0.7rem", marginRight: "2px" }, children: "10" }), _jsx(SkipForward, { size: 16 })] }), _jsx("button", { onClick: nextTrack, style: controlButtonStyle(textColor, "rgba(255,255,255,0.1)"), "aria-label": "Next Track", children: _jsx(SkipForward, { size: 20 }) })] }), _jsxs("div", { style: { marginBottom: "16px" }, children: [_jsxs("div", { style: {
330
+ display: "flex",
331
+ alignItems: "center",
332
+ justifyContent: "space-between",
333
+ marginBottom: "8px",
334
+ fontSize: "0.8rem",
335
+ opacity: 0.7,
336
+ }, children: [_jsx("span", { children: formatTime(currentTime) }), _jsx("span", { children: formatTime(duration) })] }), _jsx("div", { onClick: handleSeek, style: {
337
+ height: "6px",
338
+ background: "rgba(255,255,255,0.2)",
339
+ borderRadius: "3px",
340
+ cursor: "pointer",
341
+ position: "relative",
342
+ overflow: "hidden",
343
+ }, children: _jsx("div", { style: {
344
+ width: `${(currentTime / duration) * 100 || 0}%`,
345
+ height: "100%",
346
+ background: `linear-gradient(90deg, ${primaryColor}, #ec4899)`,
347
+ borderRadius: "3px",
348
+ position: "relative",
349
+ }, children: _jsx("div", { style: {
350
+ position: "absolute",
351
+ right: "-6px",
352
+ top: "50%",
353
+ transform: "translateY(-50%)",
354
+ width: "12px",
355
+ height: "12px",
356
+ background: primaryColor,
357
+ borderRadius: "50%",
358
+ boxShadow: `0 2px 8px ${primaryColor}60`,
359
+ } }) }) })] }), _jsxs("div", { style: {
360
+ display: "flex",
361
+ alignItems: "center",
362
+ justifyContent: "space-between",
363
+ }, children: [_jsxs("div", { style: { display: "flex", gap: "8px" }, children: [_jsx("button", { onClick: () => setIsLiked(!isLiked), style: controlButtonStyle(isLiked ? "#ec4899" : textColor, "rgba(255,255,255,0.1)"), "aria-label": "Like", children: _jsx(Heart, { size: 16, fill: isLiked ? "#ec4899" : "none" }) }), _jsx("button", { onClick: () => setIsLooping(!isLooping), style: controlButtonStyle(isLooping ? primaryColor : textColor, "rgba(255,255,255,0.1)"), "aria-label": "Toggle Loop", children: _jsx(RotateCcw, { size: 16 }) })] }), _jsxs("div", { style: {
364
+ display: "flex",
365
+ alignItems: "center",
366
+ gap: "8px",
367
+ position: "relative",
368
+ }, children: [showVolumeSlider && (_jsx("div", { onClick: handleVolumeChange, style: {
369
+ width: "80px",
370
+ height: "4px",
371
+ background: "rgba(255,255,255,0.2)",
372
+ borderRadius: "2px",
373
+ cursor: "pointer",
374
+ position: "relative",
375
+ }, children: _jsx("div", { style: {
376
+ width: `${volume * 100}%`,
377
+ height: "100%",
378
+ background: primaryColor,
379
+ borderRadius: "2px",
380
+ } }) })), _jsx("button", { onClick: toggleMute, onMouseEnter: showVolume, style: controlButtonStyle(textColor, "rgba(255,255,255,0.1)"), "aria-label": volume > 0 ? "Mute" : "Unmute", children: volume > 0 ? _jsx(Volume2, { size: 16 }) : _jsx(VolumeX, { size: 16 }) })] })] })] }), _jsx("audio", { ref: audioRef, src: currentTrack.src, autoPlay: autoplay, loop: isLooping, onTimeUpdate: handleTimeUpdate, onEnded: () => {
381
+ setIsPlaying(false);
382
+ if (!isLooping) {
383
+ nextTrack();
384
+ }
385
+ }, onLoadedMetadata: handleTimeUpdate, preload: "metadata", style: { display: "none" } })] })), _jsx("style", { children: `
386
+ @keyframes equalizer {
387
+ 0%, 100% { height: 4px; }
388
+ 50% { height: 12px; }
389
+ }
390
+
391
+ /* Custom Scrollbar */
392
+ div::-webkit-scrollbar {
393
+ width: 4px;
394
+ }
395
+
396
+ div::-webkit-scrollbar-track {
397
+ background: rgba(255,255,255,0.1);
398
+ border-radius: 2px;
399
+ }
400
+
401
+ div::-webkit-scrollbar-thumb {
402
+ background: ${primaryColor};
403
+ border-radius: 2px;
404
+ }
405
+
406
+ div::-webkit-scrollbar-thumb:hover {
407
+ background: ${primaryColor}dd;
408
+ }
409
+ ` })] }));
410
+ }
411
+ function controlButtonStyle(color, backgroundColor) {
412
+ return {
413
+ border: "none",
414
+ backgroundColor,
415
+ color,
416
+ cursor: "pointer",
417
+ padding: "10px",
418
+ borderRadius: "12px",
419
+ display: "flex",
420
+ alignItems: "center",
421
+ justifyContent: "center",
422
+ transition: "all 0.3s ease",
423
+ backdropFilter: "blur(10px)",
424
+ };
425
+ }
@@ -0,0 +1,116 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useRef, useState, useEffect } from "react";
3
+ import { Play, Pause, Volume2, VolumeX, Maximize, Minimize, RotateCcw, SkipBack, SkipForward, } from "lucide-react";
4
+ export const AudioPlayer = ({ src, thumbnail, autoPlay = false, loop = false, backgroundColor = "#000000", primaryColor = "#10b981", secondaryColor = "#ffffff", borderRadius = "12px", padding = "16px", width = "100%", className, }) => {
5
+ const audioRef = useRef(null);
6
+ const playerRef = useRef(null);
7
+ const [isPlaying, setIsPlaying] = useState(autoPlay);
8
+ const [currentTime, setCurrentTime] = useState(0);
9
+ const [duration, setDuration] = useState(0);
10
+ const [volume, setVolume] = useState(0.5);
11
+ const [isFullscreen, setIsFullscreen] = useState(false);
12
+ const [isLooping, setIsLooping] = useState(loop);
13
+ useEffect(() => {
14
+ if (audioRef.current)
15
+ audioRef.current.volume = volume;
16
+ }, [volume]);
17
+ useEffect(() => {
18
+ if (audioRef.current)
19
+ audioRef.current.loop = isLooping;
20
+ }, [isLooping]);
21
+ const togglePlayPause = () => {
22
+ if (!audioRef.current)
23
+ return;
24
+ isPlaying ? audioRef.current.pause() : audioRef.current.play();
25
+ setIsPlaying(!isPlaying);
26
+ };
27
+ const handleTimeUpdate = () => {
28
+ if (!audioRef.current)
29
+ return;
30
+ setCurrentTime(audioRef.current.currentTime);
31
+ setDuration(audioRef.current.duration);
32
+ };
33
+ const handleSeek = (e) => {
34
+ if (!audioRef.current || !e.currentTarget)
35
+ return;
36
+ const rect = e.currentTarget.getBoundingClientRect();
37
+ const percent = (e.clientX - rect.left) / rect.width;
38
+ const time = percent * duration;
39
+ audioRef.current.currentTime = time;
40
+ setCurrentTime(time);
41
+ };
42
+ const skip = (seconds) => {
43
+ if (audioRef.current)
44
+ audioRef.current.currentTime += seconds;
45
+ };
46
+ const toggleFullscreen = () => {
47
+ if (!playerRef.current)
48
+ return;
49
+ isFullscreen
50
+ ? document.exitFullscreen?.()
51
+ : playerRef.current.requestFullscreen?.();
52
+ setIsFullscreen(!isFullscreen);
53
+ };
54
+ const formatTime = (time) => {
55
+ const minutes = Math.floor(time / 60);
56
+ const seconds = Math.floor(time % 60);
57
+ return `${minutes}:${seconds < 10 ? "0" : ""}${seconds}`;
58
+ };
59
+ return (_jsxs("div", { ref: playerRef, className: className, style: {
60
+ position: "relative",
61
+ width,
62
+ backgroundColor,
63
+ borderRadius,
64
+ color: secondaryColor,
65
+ boxShadow: "0 4px 12px rgba(0,0,0,0.3)",
66
+ overflow: "hidden",
67
+ padding,
68
+ boxSizing: "border-box",
69
+ maxWidth: "100%",
70
+ }, children: [_jsx("audio", { ref: audioRef, src: src, autoPlay: autoPlay, loop: loop, onTimeUpdate: handleTimeUpdate, onLoadedMetadata: handleTimeUpdate }), thumbnail && (_jsx("img", { src: thumbnail, alt: "Audio Thumbnail", style: {
71
+ width: "100%",
72
+ objectFit: "cover",
73
+ borderRadius,
74
+ marginBottom: "16px",
75
+ maxHeight: "150px",
76
+ } })), _jsxs("div", { style: {
77
+ display: "flex",
78
+ alignItems: "center",
79
+ justifyContent: "center",
80
+ gap: "10px",
81
+ flexShrink: 0,
82
+ marginTop: "10px",
83
+ }, children: [_jsx("button", { onClick: () => skip(-10), "aria-label": "Skip Back 10s", children: _jsx(SkipBack, { size: 20 }) }), _jsx("button", { onClick: togglePlayPause, style: {
84
+ background: primaryColor,
85
+ borderRadius: "9999px",
86
+ padding: "10px",
87
+ color: "#fff",
88
+ border: "none",
89
+ cursor: "pointer",
90
+ }, "aria-label": isPlaying ? "Pause" : "Play", children: isPlaying ? _jsx(Pause, { size: 20 }) : _jsx(Play, { size: 20 }) }), _jsx("button", { onClick: () => skip(10), "aria-label": "Skip Forward 10s", children: _jsx(SkipForward, { size: 20 }) })] }), _jsxs("div", { style: {
91
+ display: "flex",
92
+ flexWrap: "wrap",
93
+ alignItems: "center",
94
+ justifyContent: "space-between",
95
+ gap: "12px",
96
+ width: "100%",
97
+ }, children: [_jsxs("div", { style: { flexShrink: 0, minWidth: "60px", textAlign: "center" }, children: [_jsx("span", { style: { fontSize: "14px", marginRight: "4px" }, children: formatTime(currentTime) }), _jsxs("span", { style: { fontSize: "14px", color: "#aaa" }, children: ["/ ", formatTime(duration)] })] }), _jsx("div", { onClick: handleSeek, style: {
98
+ flex: 1,
99
+ height: "8px",
100
+ background: "#444",
101
+ borderRadius: "4px",
102
+ cursor: "pointer",
103
+ position: "relative",
104
+ minWidth: "100px",
105
+ }, children: _jsx("div", { style: {
106
+ width: `${(currentTime / duration) * 100 || 0}%`,
107
+ height: "100%",
108
+ background: primaryColor,
109
+ borderRadius: "4px",
110
+ } }) }), _jsxs("div", { style: {
111
+ display: "flex",
112
+ alignItems: "center",
113
+ gap: "10px",
114
+ flexShrink: 0,
115
+ }, children: [_jsx("button", { onClick: () => setIsLooping(!isLooping), "aria-label": "Toggle Loop", children: _jsx(RotateCcw, { size: 18, color: isLooping ? primaryColor : undefined }) }), _jsx("button", { onClick: () => setVolume(volume > 0 ? 0 : 0.5), "aria-label": "Toggle Mute", children: volume > 0 ? _jsx(Volume2, { size: 18 }) : _jsx(VolumeX, { size: 18 }) }), _jsx("button", { onClick: toggleFullscreen, "aria-label": "Toggle Fullscreen", children: isFullscreen ? _jsx(Minimize, { size: 18 }) : _jsx(Maximize, { size: 18 }) })] })] })] }));
116
+ };