nocopyrightsounds-widget 1.0.6 → 1.1.0
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.
- package/package.json +1 -1
- package/src/index.js +84 -102
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
class NCSWidget {
|
|
2
|
-
constructor(
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
constructor(userOptions = {}) {
|
|
3
|
+
// 🛠️ 1. Configurations par défaut (Fusionnées avec les choix de l'utilisateur)
|
|
4
|
+
const defaultOptions = {
|
|
5
|
+
position: 'bottom-right',
|
|
6
|
+
apiUrl: 'https://VOTRE-URL-RENDER.onrender.com', // ⚠️ METTEZ VOTRE URL RENDER ICI
|
|
7
|
+
theme: 'dark', // 'dark' ou 'light'
|
|
8
|
+
primaryColor: '#1DB954', // Vert NCS par défaut
|
|
9
|
+
defaultGenre: 'all',
|
|
10
|
+
startVolume: 0.5,
|
|
11
|
+
offset: '25px', // Distance par rapport au bord de l'écran
|
|
12
|
+
zIndex: 99999
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
this.options = { ...defaultOptions, ...userOptions };
|
|
5
16
|
|
|
6
17
|
this.audio = new Audio();
|
|
7
18
|
this.isPlaying = false;
|
|
@@ -13,10 +24,9 @@ class NCSWidget {
|
|
|
13
24
|
|
|
14
25
|
this.isBrowser = typeof window !== 'undefined';
|
|
15
26
|
if (this.isBrowser) {
|
|
16
|
-
// Le volume est à 1 (100%) par défaut s'il n'y a rien en cache
|
|
17
27
|
const savedVol = localStorage.getItem('ncs_volume');
|
|
18
|
-
this.audio.volume = savedVol !== null ? parseFloat(savedVol) :
|
|
19
|
-
this.lastVolume = this.audio.volume > 0 ? this.audio.volume :
|
|
28
|
+
this.audio.volume = savedVol !== null ? parseFloat(savedVol) : this.options.startVolume;
|
|
29
|
+
this.lastVolume = this.audio.volume > 0 ? this.audio.volume : this.options.startVolume;
|
|
20
30
|
|
|
21
31
|
this.savedTime = localStorage.getItem('ncs_currentTime') || 0;
|
|
22
32
|
this.savedTrack = localStorage.getItem('ncs_currentTrack') || null;
|
|
@@ -33,7 +43,9 @@ class NCSWidget {
|
|
|
33
43
|
this.restoreTrack();
|
|
34
44
|
this.fillQueue(this.genreSelect.value);
|
|
35
45
|
} else {
|
|
36
|
-
|
|
46
|
+
// Utiliser le genre par défaut défini dans les options
|
|
47
|
+
this.genreSelect.value = this.options.defaultGenre;
|
|
48
|
+
this.changeGenre(this.options.defaultGenre);
|
|
37
49
|
}
|
|
38
50
|
}
|
|
39
51
|
|
|
@@ -43,54 +55,85 @@ class NCSWidget {
|
|
|
43
55
|
this.container = document.createElement('div');
|
|
44
56
|
this.container.id = 'ncs-persistent-widget';
|
|
45
57
|
|
|
58
|
+
// 🎨 2. Application du thème (Variables CSS dynamiques)
|
|
59
|
+
const isLight = this.options.theme === 'light';
|
|
60
|
+
const colors = {
|
|
61
|
+
bg: isLight ? '#ffffff' : '#181818',
|
|
62
|
+
text: isLight ? '#222222' : '#ffffff',
|
|
63
|
+
textMuted: isLight ? '#666666' : '#b3b3b3',
|
|
64
|
+
border: isLight ? '#e0e0e0' : '#282828',
|
|
65
|
+
panelBg: isLight ? '#f5f5f5' : '#282828',
|
|
66
|
+
sliderBg: isLight ? '#d3d3d3' : '#535353',
|
|
67
|
+
btnBg: isLight ? '#222222' : '#ffffff',
|
|
68
|
+
btnColor: isLight ? '#ffffff' : '#000000'
|
|
69
|
+
};
|
|
70
|
+
|
|
46
71
|
const style = document.createElement('style');
|
|
47
72
|
style.textContent = `
|
|
48
|
-
#ncs-persistent-widget {
|
|
49
|
-
|
|
73
|
+
#ncs-persistent-widget {
|
|
74
|
+
/* Variables CSS exposées pour les développeurs */
|
|
75
|
+
--ncs-primary: ${this.options.primaryColor};
|
|
76
|
+
--ncs-bg: ${colors.bg};
|
|
77
|
+
--ncs-text: ${colors.text};
|
|
78
|
+
--ncs-text-muted: ${colors.textMuted};
|
|
79
|
+
--ncs-border: ${colors.border};
|
|
80
|
+
--ncs-panel-bg: ${colors.panelBg};
|
|
81
|
+
--ncs-slider-bg: ${colors.sliderBg};
|
|
82
|
+
--ncs-btn-bg: ${colors.btnBg};
|
|
83
|
+
--ncs-btn-color: ${colors.btnColor};
|
|
84
|
+
|
|
85
|
+
position: fixed;
|
|
86
|
+
${this.getPositionStyles()}
|
|
87
|
+
z-index: ${this.options.zIndex};
|
|
88
|
+
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
89
|
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.ncs-minimized { width: 55px; height: 55px; border-radius: 50%; background: var(--ncs-primary); cursor: pointer; display: flex; justify-content: center; align-items: center; box-shadow: 0 6px 15px rgba(0,0,0, 0.2); font-size: 24px; transition: transform 0.2s; color: white; }
|
|
50
93
|
.ncs-minimized:hover { transform: scale(1.1); }
|
|
51
94
|
.ncs-minimized.hidden { display: none; }
|
|
52
95
|
|
|
53
|
-
.ncs-expanded { width: 320px; background:
|
|
96
|
+
.ncs-expanded { width: 320px; background: var(--ncs-bg); color: var(--ncs-text); border-radius: 16px; padding: 20px; box-shadow: 0 10px 30px rgba(0,0,0,0.15); display: none; border: 1px solid var(--ncs-border); }
|
|
54
97
|
.ncs-expanded.active { display: block; animation: ncsFadeIn 0.3s ease; }
|
|
55
98
|
|
|
56
99
|
.ncs-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; }
|
|
57
|
-
.ncs-header strong { font-size: 14px; font-weight: 600; color:
|
|
58
|
-
.ncs-close-btn { background: transparent; border: none; color:
|
|
59
|
-
.ncs-close-btn:hover { color:
|
|
100
|
+
.ncs-header strong { font-size: 14px; font-weight: 600; color: var(--ncs-text-muted); letter-spacing: 1px; text-transform: uppercase; display: flex; align-items: center; gap: 8px; }
|
|
101
|
+
.ncs-close-btn { background: transparent; border: none; color: var(--ncs-text-muted); font-size: 18px; cursor: pointer; padding: 0; transition: color 0.2s; }
|
|
102
|
+
.ncs-close-btn:hover { color: var(--ncs-text); }
|
|
60
103
|
|
|
61
104
|
.ncs-visualizer { display: flex; gap: 2px; height: 12px; align-items: flex-end; opacity: 0; transition: opacity 0.3s; }
|
|
62
105
|
.ncs-visualizer.playing { opacity: 1; }
|
|
63
|
-
.ncs-bar { width: 3px; background:
|
|
106
|
+
.ncs-bar { width: 3px; background: var(--ncs-primary); border-radius: 2px; animation: bounce 0.5s infinite alternate; }
|
|
64
107
|
.ncs-bar:nth-child(2) { animation-delay: 0.15s; }
|
|
65
108
|
.ncs-bar:nth-child(3) { animation-delay: 0.3s; }
|
|
66
109
|
@keyframes bounce { from { height: 3px; } to { height: 12px; } }
|
|
67
110
|
|
|
68
111
|
.ncs-track-info { display: flex; align-items: center; margin-bottom: 15px; }
|
|
69
|
-
.ncs-cover { width: 65px; height: 65px; border-radius: 8px; background:
|
|
112
|
+
.ncs-cover { width: 65px; height: 65px; border-radius: 8px; background: var(--ncs-panel-bg); margin-right: 15px; object-fit: cover; box-shadow: 0 4px 10px rgba(0,0,0,0.1); }
|
|
70
113
|
.ncs-details { flex: 1; overflow: hidden; display: flex; flex-direction: column; justify-content: center; }
|
|
71
|
-
#ncs-track-name { font-size: 14px; font-weight:
|
|
72
|
-
#ncs-artists { font-size: 11px; color:
|
|
73
|
-
#ncs-genre { width: 100%; padding: 4px 8px; background:
|
|
114
|
+
#ncs-track-name { font-size: 14px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-bottom: 2px; }
|
|
115
|
+
#ncs-artists { font-size: 11px; color: var(--ncs-text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-bottom: 8px; }
|
|
116
|
+
#ncs-genre { width: 100%; padding: 4px 8px; background: var(--ncs-panel-bg); color: var(--ncs-text); border: 1px solid var(--ncs-border); border-radius: 6px; font-size: 12px; cursor: pointer; outline: none; }
|
|
74
117
|
|
|
75
|
-
.ncs-progress-container { margin-bottom: 15px; display:flex; align-items:center; gap: 10px; font-size: 11px; color:
|
|
76
|
-
.ncs-slider { -webkit-appearance: none; width: 100%; height: 4px; background:
|
|
77
|
-
.ncs-slider::-webkit-slider-thumb { -webkit-appearance: none; width: 12px; height: 12px; border-radius: 50%; background:
|
|
118
|
+
.ncs-progress-container { margin-bottom: 15px; display:flex; align-items:center; gap: 10px; font-size: 11px; color: var(--ncs-text-muted); font-variant-numeric: tabular-nums; }
|
|
119
|
+
.ncs-slider { -webkit-appearance: none; width: 100%; height: 4px; background: var(--ncs-slider-bg); border-radius: 2px; outline: none; cursor: pointer; }
|
|
120
|
+
.ncs-slider::-webkit-slider-thumb { -webkit-appearance: none; width: 12px; height: 12px; border-radius: 50%; background: var(--ncs-primary); cursor: pointer; transition: transform 0.1s; }
|
|
78
121
|
.ncs-slider::-webkit-slider-thumb:hover { transform: scale(1.2); }
|
|
79
122
|
|
|
80
123
|
.ncs-controls { display: flex; justify-content: center; align-items: center; gap: 15px; margin-bottom: 15px; }
|
|
81
|
-
.ncs-btn-circle { width: 50px; height: 50px; border-radius: 50%; background:
|
|
124
|
+
.ncs-btn-circle { width: 50px; height: 50px; border-radius: 50%; background: var(--ncs-btn-bg); color: var(--ncs-btn-color); border: none; font-size: 20px; cursor: pointer; display:flex; justify-content:center; align-items:center; transition: transform 0.2s; padding-left: 4px; box-shadow: 0 2px 5px rgba(0,0,0,0.1); }
|
|
82
125
|
.ncs-btn-circle.paused { padding-left: 0; }
|
|
83
126
|
.ncs-btn-circle:hover { transform: scale(1.05); }
|
|
84
|
-
.ncs-btn-icon { background: transparent; border: none; color:
|
|
85
|
-
.ncs-btn-icon:hover { color:
|
|
86
|
-
.ncs-btn-icon:disabled { color:
|
|
127
|
+
.ncs-btn-icon { background: transparent; border: none; color: var(--ncs-text-muted); font-size: 20px; cursor: pointer; transition: color 0.2s; padding: 5px; }
|
|
128
|
+
.ncs-btn-icon:hover { color: var(--ncs-text); }
|
|
129
|
+
.ncs-btn-icon:disabled { color: var(--ncs-border); cursor: not-allowed; }
|
|
87
130
|
|
|
88
131
|
.ncs-bottom-bar { display: flex; justify-content: space-between; align-items: center; }
|
|
89
|
-
.ncs-volume-container { display: flex; align-items: center; gap: 8px; color:
|
|
132
|
+
.ncs-volume-container { display: flex; align-items: center; gap: 8px; color: var(--ncs-text-muted); flex: 1; margin-right: 15px; }
|
|
90
133
|
#ncs-mute-btn { cursor: pointer; transition: transform 0.1s; user-select: none; }
|
|
91
134
|
#ncs-mute-btn:hover { transform: scale(1.1); }
|
|
92
|
-
.ncs-download-btn { color:
|
|
93
|
-
.ncs-download-btn:hover { color:
|
|
135
|
+
.ncs-download-btn { color: var(--ncs-text-muted); text-decoration: none; font-size: 18px; transition: color 0.2s; }
|
|
136
|
+
.ncs-download-btn:hover { color: var(--ncs-primary); }
|
|
94
137
|
|
|
95
138
|
@keyframes ncsFadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
|
|
96
139
|
`;
|
|
@@ -115,72 +158,14 @@ class NCSWidget {
|
|
|
115
158
|
<select id="ncs-genre">
|
|
116
159
|
<option value="all">🌍 Tous les genres</option>
|
|
117
160
|
<option value="31">Alternative Dance</option>
|
|
118
|
-
<option value="
|
|
119
|
-
<option value="33">Alternative Pop</option>
|
|
120
|
-
<option value="23">Ambient</option>
|
|
121
|
-
<option value="34">Anti-Pop</option>
|
|
122
|
-
<option value="1">Bass</option>
|
|
123
|
-
<option value="18">Bass House</option>
|
|
124
|
-
<option value="78">Bass Music</option>
|
|
125
|
-
<option value="26">Brazilian Phonk</option>
|
|
126
|
-
<option value="27">Breakbeat</option>
|
|
161
|
+
<option value="10">House</option>
|
|
127
162
|
<option value="2">Chill</option>
|
|
128
|
-
<option value="24">Chill Bass</option>
|
|
129
|
-
<option value="35">Chill Pop</option>
|
|
130
|
-
<option value="85">Colour Bass</option>
|
|
131
|
-
<option value="65">Complextro</option>
|
|
132
|
-
<option value="36">Dance-Pop</option>
|
|
133
|
-
<option value="66">Deep House</option>
|
|
134
|
-
<option value="45">Disco</option>
|
|
135
|
-
<option value="46">Disco House</option>
|
|
136
|
-
<option value="3">Drum & Bass</option>
|
|
137
|
-
<option value="4">Drumstep</option>
|
|
138
163
|
<option value="5">Dubstep</option>
|
|
139
|
-
<option value="6">EDM</option>
|
|
140
|
-
<option value="47">Electro</option>
|
|
141
|
-
<option value="48">Electro House</option>
|
|
142
164
|
<option value="7">Electronic</option>
|
|
143
|
-
<option value="
|
|
144
|
-
<option value="83">Electronic Rock</option>
|
|
145
|
-
<option value="17">Future Bass</option>
|
|
146
|
-
<option value="68">Future Bounce</option>
|
|
147
|
-
<option value="50">Future Funk</option>
|
|
148
|
-
<option value="8">Future House</option>
|
|
149
|
-
<option value="69">Future Rave</option>
|
|
150
|
-
<option value="57">Future Trap</option>
|
|
151
|
-
<option value="40">Futurepop</option>
|
|
152
|
-
<option value="51">Garage</option>
|
|
153
|
-
<option value="15">Glitch Hop</option>
|
|
154
|
-
<option value="82">Hardcore</option>
|
|
165
|
+
<option value="3">Drum & Bass</option>
|
|
155
166
|
<option value="9">Hardstyle</option>
|
|
156
|
-
<option value="10">House</option>
|
|
157
|
-
<option value="41">Hyperpop</option>
|
|
158
|
-
<option value="11">Indie Dance</option>
|
|
159
|
-
<option value="91">J-Pop</option>
|
|
160
|
-
<option value="84">Jersey Club</option>
|
|
161
|
-
<option value="28">Jump-Up</option>
|
|
162
|
-
<option value="29">Liquid DnB</option>
|
|
163
|
-
<option value="60">Lofi Hip-Hop</option>
|
|
164
|
-
<option value="12">Melodic Dubstep</option>
|
|
165
|
-
<option value="54">Melodic House</option>
|
|
166
|
-
<option value="22">Midtempo Bass</option>
|
|
167
|
-
<option value="30">Neurofunk</option>
|
|
168
|
-
<option value="87">Nu-Jazz</option>
|
|
169
|
-
<option value="16">Phonk</option>
|
|
170
|
-
<option value="86">Pluggnb</option>
|
|
171
|
-
<option value="19">Pop</option>
|
|
172
|
-
<option value="55">Progressive House</option>
|
|
173
|
-
<option value="88">RnB</option>
|
|
174
|
-
<option value="89">Speed Garage</option>
|
|
175
|
-
<option value="73">Tech House</option>
|
|
176
|
-
<option value="80">Techno</option>
|
|
177
|
-
<option value="81">Trance</option>
|
|
178
167
|
<option value="14">Trap</option>
|
|
179
|
-
|
|
180
|
-
<option value="21">UKG</option>
|
|
181
|
-
<option value="92">Wave</option>
|
|
182
|
-
<option value="90">Witch House</option>
|
|
183
|
-
</select>
|
|
168
|
+
</select>
|
|
184
169
|
</div>
|
|
185
170
|
</div>
|
|
186
171
|
|
|
@@ -209,6 +194,7 @@ class NCSWidget {
|
|
|
209
194
|
document.head.appendChild(style);
|
|
210
195
|
document.body.appendChild(this.container);
|
|
211
196
|
|
|
197
|
+
// Références
|
|
212
198
|
this.minimized = this.container.querySelector('.ncs-minimized');
|
|
213
199
|
this.expanded = this.container.querySelector('.ncs-expanded');
|
|
214
200
|
this.playBtn = this.container.querySelector('#ncs-play-pause');
|
|
@@ -228,13 +214,14 @@ class NCSWidget {
|
|
|
228
214
|
}
|
|
229
215
|
|
|
230
216
|
getPositionStyles() {
|
|
217
|
+
const offset = this.options.offset;
|
|
231
218
|
const positions = {
|
|
232
|
-
'bottom-right':
|
|
233
|
-
'bottom-left':
|
|
234
|
-
'top-right':
|
|
235
|
-
'top-left':
|
|
219
|
+
'bottom-right': `bottom: ${offset}; right: ${offset};`,
|
|
220
|
+
'bottom-left': `bottom: ${offset}; left: ${offset};`,
|
|
221
|
+
'top-right': `top: ${offset}; right: ${offset};`,
|
|
222
|
+
'top-left': `top: ${offset}; left: ${offset};`
|
|
236
223
|
};
|
|
237
|
-
return positions[this.position] || positions['bottom-right'];
|
|
224
|
+
return positions[this.options.position] || positions['bottom-right'];
|
|
238
225
|
}
|
|
239
226
|
|
|
240
227
|
attachEvents() {
|
|
@@ -267,30 +254,26 @@ class NCSWidget {
|
|
|
267
254
|
|
|
268
255
|
this.progressBar.addEventListener('input', (e) => { this.audio.currentTime = e.target.value; });
|
|
269
256
|
|
|
270
|
-
// --- NOUVEAU : GESTION DU MUTE ET DU VOLUME ---
|
|
271
257
|
this.volumeBar.addEventListener('input', (e) => {
|
|
272
258
|
const vol = parseFloat(e.target.value);
|
|
273
259
|
this.audio.volume = vol;
|
|
274
|
-
if (vol > 0) this.lastVolume = vol;
|
|
260
|
+
if (vol > 0) this.lastVolume = vol;
|
|
275
261
|
this.updateMuteIcon(vol);
|
|
276
262
|
localStorage.setItem('ncs_volume', vol);
|
|
277
263
|
});
|
|
278
264
|
|
|
279
265
|
this.muteBtn.addEventListener('click', () => {
|
|
280
266
|
if (this.audio.volume > 0) {
|
|
281
|
-
// On Mute
|
|
282
267
|
this.lastVolume = this.audio.volume;
|
|
283
268
|
this.audio.volume = 0;
|
|
284
269
|
this.volumeBar.value = 0;
|
|
285
270
|
} else {
|
|
286
|
-
// On Unmute
|
|
287
271
|
this.audio.volume = this.lastVolume || 1.0;
|
|
288
272
|
this.volumeBar.value = this.audio.volume;
|
|
289
273
|
}
|
|
290
274
|
this.updateMuteIcon(this.audio.volume);
|
|
291
275
|
localStorage.setItem('ncs_volume', this.audio.volume);
|
|
292
276
|
});
|
|
293
|
-
// ----------------------------------------------
|
|
294
277
|
|
|
295
278
|
setInterval(() => {
|
|
296
279
|
if (this.isPlaying && this.audio.currentTime > 0) {
|
|
@@ -346,7 +329,7 @@ class NCSWidget {
|
|
|
346
329
|
|
|
347
330
|
async fetchSingleTrack(genre) {
|
|
348
331
|
try {
|
|
349
|
-
const response = await fetch(`${this.apiUrl}/search?genre=${genre}`);
|
|
332
|
+
const response = await fetch(`${this.options.apiUrl}/search?genre=${genre}`);
|
|
350
333
|
const data = await response.json();
|
|
351
334
|
return (data && data.length > 0) ? data[0] : null;
|
|
352
335
|
} catch (error) {
|
|
@@ -406,10 +389,9 @@ class NCSWidget {
|
|
|
406
389
|
this.audio.src = track.audioUrl;
|
|
407
390
|
this.trackName.innerText = track.title;
|
|
408
391
|
|
|
409
|
-
// Mettre à jour l'affichage des artistes
|
|
410
392
|
const artistes = track.artists || "NCS Release";
|
|
411
393
|
this.artistsName.innerText = artistes;
|
|
412
|
-
this.artistsName.title = artistes;
|
|
394
|
+
this.artistsName.title = artistes;
|
|
413
395
|
|
|
414
396
|
if (track.coverUrl) this.coverImg.src = track.coverUrl;
|
|
415
397
|
this.downloadBtn.href = track.audioUrl;
|