nocopyrightsounds-widget 1.3.0 → 1.4.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +50 -40
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nocopyrightsounds-widget",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Un widget musical persistant pour site web utilisant l'API NoCopyrightSounds",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
package/src/index.js CHANGED
@@ -4,12 +4,13 @@ class NCSWidget {
4
4
  constructor(userOptions = {}) {
5
5
  const defaultOptions = {
6
6
  position: 'bottom-right',
7
- apiUrl: 'https://ncs-backend-api.onrender.com', // 🔗 Votre API officielle fixée !
7
+ apiUrl: 'https://ncs-backend-api.onrender.com',
8
8
  theme: 'dark',
9
9
  primaryColor: '#1DB954',
10
10
  defaultGenre: 'all',
11
11
  startVolume: 0.5,
12
- offset: '25px',
12
+ offsetX: '25px', // Séparé pour plus de précision (ex: gauche/droite)
13
+ offsetY: '25px', // Séparé (ex: haut/bas)
13
14
  zIndex: 99999,
14
15
  glassmorphism: false,
15
16
  borderRadius: '16px',
@@ -18,12 +19,13 @@ class NCSWidget {
18
19
  hideVisualizer: false,
19
20
  autoOpen: false,
20
21
 
21
- // --- 🎛️ NOUVEAUTÉS V1.3.0 : Bouton Réduit ---
22
- minimizedIcon: '🎧', // L'icône par défaut
23
- minimizedSize: '55px', // Taille du bouton
24
- minimizedRadius: '50%', // Arrondi (50% = rond, 10px = carré arrondi)
25
- minimizedBg: null, // Surcharger la couleur de fond (utilise primaryColor sinon)
26
- minimizedColor: '#ffffff' // Couleur de l'icône
22
+ // 🎛️ Bouton Réduit Ultra-Configurable
23
+ minimizedIcon: '🎧',
24
+ minWidth: '55px', // Largeur séparée
25
+ minHeight: '55px', // Hauteur séparée
26
+ minRadius: '50%',
27
+ minBg: null,
28
+ minColor: '#ffffff'
27
29
  };
28
30
 
29
31
  this.options = { ...defaultOptions, ...userOptions };
@@ -49,11 +51,7 @@ class NCSWidget {
49
51
  this.savedArtists = localStorage.getItem('ncs_currentArtists') || null;
50
52
 
51
53
  const savedState = localStorage.getItem('ncs_isOpen');
52
- if (savedState !== null) {
53
- this.isWidgetOpen = savedState === 'true';
54
- } else {
55
- this.isWidgetOpen = this.options.autoOpen;
56
- }
54
+ this.isWidgetOpen = savedState !== null ? savedState === 'true' : this.options.autoOpen;
57
55
  }
58
56
 
59
57
  this.initDOM();
@@ -73,6 +71,8 @@ class NCSWidget {
73
71
 
74
72
  this.container = document.createElement('div');
75
73
  this.container.id = 'ncs-persistent-widget';
74
+ // Ajout d'une classe globale si le widget est ouvert dès le départ
75
+ if(this.isWidgetOpen) this.container.classList.add('ncs-is-open');
76
76
 
77
77
  const isLight = this.options.theme === 'light';
78
78
  const baseBgColor = isLight ? '255, 255, 255' : '24, 24, 24';
@@ -104,25 +104,27 @@ class NCSWidget {
104
104
  --ncs-radius: ${this.options.borderRadius};
105
105
  --ncs-font: ${this.options.fontFamily};
106
106
 
107
- /* Variables Bouton Réduit */
108
- --ncs-min-size: ${this.options.minimizedSize};
109
- --ncs-min-radius: ${this.options.minimizedRadius};
110
- --ncs-min-bg: ${this.options.minimizedBg || this.options.primaryColor};
111
- --ncs-min-color: ${this.options.minimizedColor};
107
+ --ncs-min-w: ${this.options.minWidth};
108
+ --ncs-min-h: ${this.options.minHeight};
109
+ --ncs-min-radius: ${this.options.minRadius};
110
+ --ncs-min-bg: ${this.options.minBg || this.options.primaryColor};
111
+ --ncs-min-color: ${this.options.minColor};
112
+ --ncs-cover-img: url(''); /* Injecté en JS pour le design Vinyle */
112
113
 
113
114
  position: fixed;
114
115
  ${this.getPositionStyles()}
115
116
  z-index: ${this.options.zIndex};
116
117
  font-family: var(--ncs-font);
117
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
118
118
  }
119
119
 
120
- .ncs-minimized { width: var(--ncs-min-size); height: var(--ncs-min-size); border-radius: var(--ncs-min-radius); background: var(--ncs-min-bg); cursor: pointer; display: flex; justify-content: center; align-items: center; box-shadow: 0 6px 15px rgba(0,0,0, 0.2); font-size: calc(var(--ncs-min-size) * 0.45); transition: transform 0.2s; color: var(--ncs-min-color); }
120
+ .ncs-minimized { width: var(--ncs-min-w); height: var(--ncs-min-h); border-radius: var(--ncs-min-radius); background: var(--ncs-min-bg); cursor: pointer; display: flex; justify-content: center; align-items: center; box-shadow: 0 6px 15px rgba(0,0,0, 0.2); font-size: calc(min(var(--ncs-min-w), var(--ncs-min-h)) * 0.45); transition: all 0.3s ease; color: var(--ncs-min-color); overflow: hidden; background-size: cover; background-position: center; }
121
121
  .ncs-minimized:hover { transform: scale(1.05); }
122
- .ncs-minimized.hidden { display: none; }
122
+ /* Transition plus douce pour l'affichage */
123
+ .ncs-minimized.hidden { opacity: 0; pointer-events: none; position: absolute; }
123
124
 
124
- .ncs-expanded { width: 320px; background: var(--ncs-bg); color: var(--ncs-text); border-radius: var(--ncs-radius); padding: 20px; box-shadow: 0 10px 30px rgba(0,0,0,0.15); display: none; border: 1px solid var(--ncs-border); backdrop-filter: ${backdropFilter}; -webkit-backdrop-filter: ${backdropFilter}; }
125
- .ncs-expanded.active { display: block; animation: ncsFadeIn 0.3s ease; }
125
+ .ncs-expanded { width: 320px; background: var(--ncs-bg); color: var(--ncs-text); border-radius: var(--ncs-radius); padding: 20px; box-shadow: 0 10px 30px rgba(0,0,0,0.15); opacity: 0; pointer-events: none; position: absolute; bottom: 0; right: 0; border: 1px solid var(--ncs-border); backdrop-filter: ${backdropFilter}; -webkit-backdrop-filter: ${backdropFilter}; transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); transform: translateY(20px) scale(0.95); }
126
+ /* Effet Tiroir par défaut lors de l'ouverture */
127
+ .ncs-expanded.active { opacity: 1; pointer-events: auto; position: relative; transform: translateY(0) scale(1); }
126
128
 
127
129
  .ncs-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; }
128
130
  .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; }
@@ -160,19 +162,16 @@ class NCSWidget {
160
162
  .ncs-volume-container { display: flex; align-items: center; gap: 8px; color: var(--ncs-text-muted); flex: 1; margin-right: 15px; }
161
163
  #ncs-mute-btn { cursor: pointer; transition: transform 0.1s; user-select: none; }
162
164
  #ncs-mute-btn:hover { transform: scale(1.1); }
163
-
164
165
  .ncs-download-btn { display: ${this.options.hideDownload ? 'none' : 'block'}; color: var(--ncs-text-muted); text-decoration: none; font-size: 18px; transition: color 0.2s; }
165
166
  .ncs-download-btn:hover { color: var(--ncs-primary); }
166
-
167
- @keyframes ncsFadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
168
167
  `;
169
168
 
170
- const genresOptionsHTML = ncsGenres.map(genre =>
171
- `<option value="${genre.value}">${genre.label}</option>`
172
- ).join('');
169
+ const genresOptionsHTML = ncsGenres.map(genre => `<option value="${genre.value}">${genre.label}</option>`).join('');
173
170
 
174
171
  this.container.innerHTML = `
175
- <div class="ncs-minimized ${this.isWidgetOpen ? 'hidden' : ''}">${this.options.minimizedIcon}</div>
172
+ <div class="ncs-minimized ${this.isWidgetOpen ? 'hidden' : ''}">
173
+ <span class="ncs-min-content">${this.options.minimizedIcon}</span>
174
+ </div>
176
175
  <div class="ncs-expanded ${this.isWidgetOpen ? 'active' : ''}">
177
176
  <div class="ncs-header">
178
177
  <strong>NCS Player
@@ -188,9 +187,7 @@ class NCSWidget {
188
187
  <div class="ncs-details">
189
188
  <div id="ncs-track-name">Chargement...</div>
190
189
  <div id="ncs-artists">Artiste(s)</div>
191
- <select id="ncs-genre">
192
- ${genresOptionsHTML}
193
- </select>
190
+ <select id="ncs-genre">${genresOptionsHTML}</select>
194
191
  </div>
195
192
  </div>
196
193
 
@@ -238,12 +235,13 @@ class NCSWidget {
238
235
  }
239
236
 
240
237
  getPositionStyles() {
241
- const offset = this.options.offset;
238
+ const x = this.options.offsetX;
239
+ const y = this.options.offsetY;
242
240
  const positions = {
243
- 'bottom-right': `bottom: ${offset}; right: ${offset};`,
244
- 'bottom-left': `bottom: ${offset}; left: ${offset};`,
245
- 'top-right': `top: ${offset}; right: ${offset};`,
246
- 'top-left': `top: ${offset}; left: ${offset};`
241
+ 'bottom-right': `bottom: ${y}; right: ${x};`,
242
+ 'bottom-left': `bottom: ${y}; left: ${x};`,
243
+ 'top-right': `top: ${y}; right: ${x};`,
244
+ 'top-left': `top: ${y}; left: ${x};`
247
245
  };
248
246
  return positions[this.options.position] || positions['bottom-right'];
249
247
  }
@@ -263,11 +261,13 @@ class NCSWidget {
263
261
  this.playBtn.innerHTML = '⏸';
264
262
  this.playBtn.classList.add('paused');
265
263
  this.visualizer.classList.add('playing');
264
+ this.container.classList.add('ncs-is-playing'); // 🎵 CLASSE MAGIQUE POUR LES DESIGNERS
266
265
  });
267
266
  this.audio.addEventListener('pause', () => {
268
267
  this.playBtn.innerHTML = '▶';
269
268
  this.playBtn.classList.remove('paused');
270
269
  this.visualizer.classList.remove('playing');
270
+ this.container.classList.remove('ncs-is-playing');
271
271
  });
272
272
  this.audio.addEventListener('timeupdate', () => this.updateProgress());
273
273
  this.audio.addEventListener('loadedmetadata', () => {
@@ -320,9 +320,11 @@ class NCSWidget {
320
320
  if (isOpen) {
321
321
  this.minimized.classList.add('hidden');
322
322
  this.expanded.classList.add('active');
323
+ this.container.classList.add('ncs-is-open');
323
324
  } else {
324
325
  this.minimized.classList.remove('hidden');
325
326
  this.expanded.classList.remove('active');
327
+ this.container.classList.remove('ncs-is-open');
326
328
  }
327
329
  localStorage.setItem('ncs_isOpen', isOpen);
328
330
  }
@@ -397,7 +399,11 @@ class NCSWidget {
397
399
  this.audio.src = this.savedTrack;
398
400
  this.trackName.innerText = this.savedTitle;
399
401
  this.artistsName.innerText = this.savedArtists || "NCS Release";
400
- if (this.savedCover) this.coverImg.src = this.savedCover;
402
+ if (this.savedCover) {
403
+ this.coverImg.src = this.savedCover;
404
+ // Injecter l'image dans le CSS pour les hackers de design !
405
+ this.container.style.setProperty('--ncs-cover-img', `url('${this.savedCover}')`);
406
+ }
401
407
  this.downloadBtn.href = this.savedTrack;
402
408
 
403
409
  this.trackHistory = [{
@@ -417,7 +423,11 @@ class NCSWidget {
417
423
  this.artistsName.innerText = artistes;
418
424
  this.artistsName.title = artistes;
419
425
 
420
- if (track.coverUrl) this.coverImg.src = track.coverUrl;
426
+ if (track.coverUrl) {
427
+ this.coverImg.src = track.coverUrl;
428
+ // 💿 INJECTION POUR LE HACK VINYLE :
429
+ this.container.style.setProperty('--ncs-cover-img', `url('${track.coverUrl}')`);
430
+ }
421
431
  this.downloadBtn.href = track.audioUrl;
422
432
 
423
433
  if (addToHistory) {