nocopyrightsounds-widget 1.3.0 → 1.4.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.
- package/README.md +110 -78
- package/package.json +1 -1
- package/src/index.js +50 -40
package/README.md
CHANGED
|
@@ -3,122 +3,154 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/nocopyrightsounds-widget)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
A sleek, floating, and **100% CSS-hackable** music player to easily integrate royalty-free music from **NoCopyrightSounds** into any website.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Built for modern developers: lightweight, persistent across page reloads, and infinitely customizable.
|
|
9
9
|
|
|
10
|
-

|
|
10
|
+

|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
-
## ✨
|
|
14
|
+
## ✨ Features
|
|
15
15
|
|
|
16
|
-
* ⚡ **
|
|
17
|
-
* 💾 **
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* 🔘 **Bouton Réduit Sur Mesure :** Transformez l'icône flottante en cercle, en carré, changez l'émoji ou mettez-y du texte !
|
|
22
|
-
* 🔌 **Prêt à l'emploi (Plug & Play) :** API backend officielle intégrée par défaut. Zéro configuration requise !
|
|
16
|
+
* ⚡ **Zero Latency:** Smart background preloading (buffering) for instant track transitions.
|
|
17
|
+
* 💾 **State Persistence:** Remembers the current track, volume, and playback progress across page navigation via `localStorage`.
|
|
18
|
+
* 🎵 **Full Catalog:** Intelligent random navigation through 60+ historical NCS genres.
|
|
19
|
+
* 🛠️ **Limitless Customization (v1.4.0):** The widget is a blank canvas! It exposes the album cover via the `--ncs-cover-img` CSS variable and dynamically injects state classes (`.ncs-is-playing`, `.ncs-is-open`). You can literally reshape the entire player using just CSS.
|
|
20
|
+
* 🔌 **Plug & Play:** Official backend API integrated by default. Zero server configuration required.
|
|
23
21
|
|
|
24
22
|
---
|
|
25
23
|
|
|
26
24
|
## 📦 Installation
|
|
27
25
|
|
|
28
|
-
### Via NPM (
|
|
26
|
+
### Via NPM (React, Vue, Angular, Next.js...)
|
|
29
27
|
\`\`\`bash
|
|
30
28
|
npm install nocopyrightsounds-widget
|
|
31
29
|
\`\`\`
|
|
32
30
|
|
|
33
|
-
### Via CDN (
|
|
31
|
+
### Via CDN (HTML / Vanilla JS)
|
|
34
32
|
\`\`\`html
|
|
35
33
|
<script type="module">
|
|
36
34
|
import NCSWidget from 'https://cdn.jsdelivr.net/npm/nocopyrightsounds-widget@latest/src/index.js';
|
|
35
|
+
const player = new NCSWidget();
|
|
37
36
|
</script>
|
|
38
37
|
\`\`\`
|
|
39
38
|
|
|
40
39
|
---
|
|
41
40
|
|
|
42
|
-
##
|
|
41
|
+
## ⚙️ Configuration (JS Options)
|
|
43
42
|
|
|
44
|
-
|
|
45
|
-
\`\`\`html
|
|
46
|
-
<script type="module">
|
|
47
|
-
import NCSWidget from 'https://cdn.jsdelivr.net/npm/nocopyrightsounds-widget@latest/src/index.js';
|
|
48
|
-
|
|
49
|
-
// Le widget s'occupe de tout avec les paramètres par défaut !
|
|
50
|
-
const player = new NCSWidget();
|
|
51
|
-
</script>
|
|
52
|
-
\`\`\`
|
|
43
|
+
You can pass an options object to the constructor to tweak the widget's behavior and default look:
|
|
53
44
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
minimizedSize: '80px', // Bouton plus large
|
|
67
|
-
minimizedRadius: '12px', // Bords arrondis (au lieu d'un cercle parfait)
|
|
68
|
-
minimizedBg: '#222222', // Fond sombre
|
|
69
|
-
minimizedColor: '#ff0055' // Texte coloré
|
|
70
|
-
});
|
|
71
|
-
\`\`\`
|
|
45
|
+
| Option | Type | Default | Description |
|
|
46
|
+
| :--- | :--- | :--- | :--- |
|
|
47
|
+
| \`position\` | String | \`'bottom-right'\` | Screen position (\`bottom-right\`, \`bottom-left\`, \`top-right\`, \`top-left\`). |
|
|
48
|
+
| \`offsetX\` / \`offsetY\` | String | \`'25px'\` | Margin from the screen edges (e.g., \`'0px'\`). |
|
|
49
|
+
| \`theme\` | String | \`'dark'\` | Base UI theme (\`'dark'\` or \`'light'\`). |
|
|
50
|
+
| \`primaryColor\` | String | \`'#1DB954'\` | Main accent color (sliders, active states). |
|
|
51
|
+
| \`glassmorphism\`| Boolean| \`false\` | Enables a semi-transparent blurred background. |
|
|
52
|
+
| \`hideDownload\` | Boolean| \`false\` | Hides the direct MP3 download icon. |
|
|
53
|
+
| \`autoOpen\` | Boolean| \`false\` | Automatically opens the widget on the user's first visit. |
|
|
54
|
+
| \`defaultGenre\` | String | \`'all'\` | Starting genre ID (e.g., \`'10'\` for House). |
|
|
55
|
+
| \`minWidth\` / \`minHeight\` | String | \`'55px'\` | Dimensions of the minimized button. |
|
|
56
|
+
| \`minimizedIcon\`| String | \`'🎧'\` | Text or emoji inside the minimized button. |
|
|
72
57
|
|
|
73
58
|
---
|
|
74
59
|
|
|
75
|
-
##
|
|
60
|
+
## 🎨 CSS Cookbook: The "Spinning Vinyl" Example
|
|
76
61
|
|
|
77
|
-
|
|
78
|
-
| :--- | :--- | :--- | :--- |
|
|
79
|
-
| \`position\` | String | \`'bottom-right'\` | Position (\`bottom-right\`, \`bottom-left\`, \`top-right\`, \`top-left\`). |
|
|
80
|
-
| \`offset\` | String | \`'25px'\` | Marge par rapport au bord de l'écran. |
|
|
81
|
-
| \`theme\` | String | \`'dark'\` | Thème de base de l'interface (\`'dark'\` ou \`'light'\`). |
|
|
82
|
-
| \`primaryColor\` | String | \`'#1DB954'\` | Couleur principale (Sliders, visualizer). |
|
|
83
|
-
| \`glassmorphism\`| Boolean | \`false\` | Active un fond semi-transparent avec flou d'arrière-plan. |
|
|
84
|
-
| \`borderRadius\` | String | \`'16px'\` | Rayon des bordures du lecteur étendu. |
|
|
85
|
-
| \`fontFamily\` | String | \`'system-ui...'\`| Typographie utilisée dans tout le widget. |
|
|
86
|
-
| \`minimizedIcon\`| String | \`'🎧'\` | Icône ou texte du bouton réduit. |
|
|
87
|
-
| \`minimizedSize\`| String | \`'55px'\` | Largeur/Hauteur du bouton réduit. |
|
|
88
|
-
| \`minimizedRadius\`| String| \`'50%'\` | Arrondi du bouton réduit (\`50%\` = rond, \`8px\` = carré arrondi). |
|
|
89
|
-
| \`minimizedBg\` | String | *primaryColor*| Couleur de fond spécifique au bouton réduit. |
|
|
90
|
-
| \`minimizedColor\`| String| \`'#ffffff'\` | Couleur de l'icône/texte du bouton réduit. |
|
|
91
|
-
| \`hideDownload\` | Boolean | \`false\` | Masque l'icône de téléchargement direct. |
|
|
92
|
-
| \`hideVisualizer\`| Boolean | \`false\` | Masque les barres animées à côté du titre. |
|
|
93
|
-
| \`autoOpen\` | Boolean | \`false\` | Déploie le widget automatiquement à la 1ère visite. |
|
|
94
|
-
| \`defaultGenre\` | String | \`'all'\` | L'ID du genre au démarrage (ex: \`'10'\` pour House). |
|
|
95
|
-
| \`startVolume\` | Number | \`0.5\` | Volume initial entre 0.0 et 1.0. |
|
|
96
|
-
|
|
97
|
-
---
|
|
62
|
+
To show you just how far you can push the customization, here is an example of the creative freedom this widget offers. By combining our JS options and a bit of custom CSS, you can completely transform the standard rectangular player into a **spinning interactive vinyl record**!
|
|
98
63
|
|
|
99
|
-
|
|
64
|
+
### 1. The JavaScript Setup
|
|
65
|
+
First, stick the widget to the corner and make it a square:
|
|
66
|
+
\`\`\`html
|
|
67
|
+
<script type="module">
|
|
68
|
+
import NCSWidget from 'https://cdn.jsdelivr.net/npm/nocopyrightsounds-widget@1.4.0/src/index.js';
|
|
69
|
+
|
|
70
|
+
new NCSWidget({
|
|
71
|
+
position: 'bottom-right',
|
|
72
|
+
offsetX: '0px',
|
|
73
|
+
offsetY: '0px',
|
|
74
|
+
minWidth: '120px',
|
|
75
|
+
minHeight: '120px',
|
|
76
|
+
minimizedIcon: '' // Remove the text to leave room for the cover art
|
|
77
|
+
});
|
|
78
|
+
</script>
|
|
79
|
+
\`\`\`
|
|
100
80
|
|
|
101
|
-
|
|
81
|
+
### 2. The CSS Magic
|
|
82
|
+
Copy this code into your website's stylesheet. It uses the `--ncs-cover-img` variable and the `.ncs-is-playing` state class to create a spinning vinyl record that pops out into a full-screen player when clicked!
|
|
102
83
|
|
|
103
84
|
\`\`\`css
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
85
|
+
/* --- THE QUARTER VINYL (Minimized State) --- */
|
|
86
|
+
.ncs-minimized {
|
|
87
|
+
border-radius: 0 !important;
|
|
88
|
+
background: transparent !important;
|
|
89
|
+
overflow: hidden !important;
|
|
90
|
+
position: relative;
|
|
91
|
+
box-shadow: none !important;
|
|
108
92
|
}
|
|
109
|
-
\`\`\`
|
|
110
93
|
|
|
111
|
-
|
|
94
|
+
.ncs-minimized::before {
|
|
95
|
+
content: '';
|
|
96
|
+
position: absolute;
|
|
97
|
+
width: 200%; height: 200%; top: 0; left: 0;
|
|
98
|
+
border-radius: 50%;
|
|
99
|
+
background-image: radial-gradient(circle at center, #1e1e2f 0%, #1e1e2f 8%, rgba(0,0,0,0.8) 8.5%, #181818 9%, #181818 25%, transparent 25.5%, transparent 90%, #333 90.5%, #181818 91%, #181818 100%), var(--ncs-cover-img);
|
|
100
|
+
background-size: cover; background-position: center;
|
|
101
|
+
transform-origin: center center;
|
|
102
|
+
}
|
|
112
103
|
|
|
113
|
-
|
|
104
|
+
/* Spin animation when music plays */
|
|
105
|
+
@keyframes spin { 100% { transform: rotate(360deg); } }
|
|
106
|
+
#ncs-persistent-widget.ncs-is-playing:not(.ncs-is-open) .ncs-minimized::before {
|
|
107
|
+
animation: spin 4s linear infinite;
|
|
108
|
+
}
|
|
109
|
+
#ncs-persistent-widget:not(.ncs-is-open) .ncs-minimized:hover::before { cursor: pointer; filter: brightness(1.15); }
|
|
110
|
+
|
|
111
|
+
/* --- THE FULL VINYL (Expanded State) --- */
|
|
112
|
+
.ncs-expanded {
|
|
113
|
+
width: 360px !important; height: 360px !important;
|
|
114
|
+
border-radius: 50% !important; padding: 30px !important;
|
|
115
|
+
background: transparent !important; border: none !important;
|
|
116
|
+
transform-origin: bottom right;
|
|
117
|
+
display: flex !important; flex-direction: column; justify-content: center; align-items: center;
|
|
118
|
+
box-shadow: 0 20px 50px rgba(0,0,0,0.8) !important;
|
|
119
|
+
}
|
|
114
120
|
|
|
115
|
-
|
|
116
|
-
|
|
121
|
+
/* The animated vinyl background */
|
|
122
|
+
.ncs-expanded::before {
|
|
123
|
+
content: ''; position: absolute; inset: 0; border-radius: 50%; z-index: -2;
|
|
124
|
+
background-image: radial-gradient(circle at center, #1e1e2f 0%, #1e1e2f 3%, rgba(0,0,0,0.8) 3.5%, rgba(24,24,24, 0.95) 4%, rgba(24,24,24, 0.9) 35%, transparent 35.5%, transparent 85%, #333 85.5%, #181818 86%, #181818 100%), var(--ncs-cover-img);
|
|
125
|
+
background-size: cover; background-position: center;
|
|
126
|
+
}
|
|
127
|
+
#ncs-persistent-widget.ncs-is-playing .ncs-expanded::before { animation: spin 10s linear infinite; }
|
|
128
|
+
|
|
129
|
+
/* Dark overlay for text readability */
|
|
130
|
+
.ncs-expanded::after { content: ''; position: absolute; inset: 0; border-radius: 50%; z-index: -1; background: radial-gradient(circle at center, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0.5) 45%, rgba(0,0,0,0.2) 100%); pointer-events: none; }
|
|
131
|
+
|
|
132
|
+
/* Open/Close Animation */
|
|
133
|
+
.ncs-expanded:not(.active) { transform: scale(0) rotate(-90deg) !important; opacity: 0; pointer-events: none; }
|
|
134
|
+
.ncs-expanded.active { transform: scale(1) rotate(0deg) !important; opacity: 1; }
|
|
135
|
+
|
|
136
|
+
/* Reorganize internal elements for the circular layout */
|
|
137
|
+
.ncs-header, .ncs-track-info, .ncs-progress-container, .ncs-controls, .ncs-bottom-bar { position: relative; z-index: 1; width: 100%; }
|
|
138
|
+
.ncs-header strong, .ncs-cover, .ncs-download-btn { display: none !important; }
|
|
139
|
+
.ncs-header { position: absolute; top: 35px; right: 50px; justify-content: flex-end !important; }
|
|
140
|
+
.ncs-close-btn { background: rgba(255,255,255,0.1) !important; color: white !important; width: 32px; height: 32px; border-radius: 50%; display: flex; justify-content: center; align-items: center; backdrop-filter: blur(4px); }
|
|
141
|
+
.ncs-details { text-align: center; display: flex; flex-direction: column; align-items: center; margin-bottom: 10px; }
|
|
142
|
+
#ncs-track-name { font-size: 18px !important; color: white !important; text-shadow: 0 2px 4px rgba(0,0,0,0.8); margin-bottom: 0 !important; }
|
|
143
|
+
#ncs-artists { font-size: 13px !important; color: #ccc !important; }
|
|
144
|
+
#ncs-genre { max-width: 160px; margin-top: 10px; background: rgba(0,0,0,0.6) !important; color: white !important; border: 1px solid rgba(255,255,255,0.2) !important; border-radius: 20px !important; padding: 6px 15px !important; font-size: 12px !important; text-align: center; }
|
|
145
|
+
.ncs-controls { margin: 15px 0 !important; gap: 20px !important; }
|
|
146
|
+
.ncs-btn-circle { width: 60px !important; height: 60px !important; background: white !important; color: black !important; }
|
|
147
|
+
.ncs-progress-container { width: 80% !important; margin: 0 auto 15px auto !important; }
|
|
148
|
+
.ncs-bottom-bar { width: 60% !important; margin: 0 auto !important; justify-content: center !important; }
|
|
149
|
+
\`\`\`
|
|
117
150
|
|
|
118
151
|
---
|
|
119
152
|
|
|
120
|
-
## 📄
|
|
121
|
-
|
|
122
|
-
Distribué sous la licence MIT. Voir `LICENSE` pour plus d'informations.
|
|
153
|
+
## 📄 License
|
|
123
154
|
|
|
124
|
-
|
|
155
|
+
Distributed under the MIT License.
|
|
156
|
+
**Disclaimer:** This project is not affiliated with NoCopyrightSounds. All streamed music belongs to their respective creators and NCS.
|
package/package.json
CHANGED
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',
|
|
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
|
-
|
|
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
|
-
//
|
|
22
|
-
minimizedIcon: '🎧',
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
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
|
-
|
|
108
|
-
--ncs-min-
|
|
109
|
-
--ncs-min-radius: ${this.options.
|
|
110
|
-
--ncs-min-bg: ${this.options.
|
|
111
|
-
--ncs-min-color: ${this.options.
|
|
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-
|
|
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
|
-
|
|
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);
|
|
125
|
-
|
|
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' : ''}"
|
|
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
|
|
238
|
+
const x = this.options.offsetX;
|
|
239
|
+
const y = this.options.offsetY;
|
|
242
240
|
const positions = {
|
|
243
|
-
'bottom-right': `bottom: ${
|
|
244
|
-
'bottom-left': `bottom: ${
|
|
245
|
-
'top-right': `top: ${
|
|
246
|
-
'top-left': `top: ${
|
|
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)
|
|
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)
|
|
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) {
|