├── README.md
├── assets
├── favicon.webp
├── stars
│ ├── star-1.webp
│ ├── star-10.webp
│ ├── star-11.webp
│ ├── star-12.webp
│ ├── star-13.webp
│ ├── star-14.webp
│ ├── star-15.webp
│ ├── star-16.webp
│ ├── star-17.webp
│ ├── star-18.webp
│ ├── star-19.webp
│ ├── star-2.webp
│ ├── star-20.webp
│ ├── star-21.webp
│ ├── star-22.webp
│ ├── star-23.webp
│ ├── star-24.webp
│ ├── star-25.webp
│ ├── star-26.webp
│ ├── star-27.webp
│ ├── star-28.webp
│ ├── star-29.webp
│ ├── star-3.webp
│ ├── star-30.webp
│ ├── star-31.webp
│ ├── star-32.webp
│ ├── star-33.webp
│ ├── star-34.webp
│ ├── star-35.webp
│ ├── star-36.webp
│ ├── star-37.webp
│ ├── star-38.webp
│ ├── star-39.webp
│ ├── star-4.webp
│ ├── star-40.webp
│ ├── star-41.webp
│ ├── star-42.webp
│ ├── star-43.webp
│ ├── star-44.webp
│ ├── star-45.webp
│ ├── star-46.webp
│ ├── star-47.webp
│ ├── star-48.webp
│ ├── star-49.webp
│ ├── star-5.webp
│ ├── star-50.webp
│ ├── star-6.webp
│ ├── star-7.webp
│ ├── star-8.webp
│ └── star-9.webp
└── svgPlayList.svg
├── preview
├── preview.avif
└── preview-og.avif
├── playlist
├── assets
│ ├── n1.avif
│ ├── favicon.webp
│ ├── preview.avif
│ ├── svgSpriteCardMusical.svg
│ └── svgSprite.svg
├── index.css
├── index.js
└── index.html
├── license.txt
└── index.html
/README.md:
--------------------------------------------------------------------------------
1 | [](https://20essentials.github.io/20TracksForEachOne/)
2 |
--------------------------------------------------------------------------------
/assets/favicon.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/favicon.webp
--------------------------------------------------------------------------------
/preview/preview.avif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/preview/preview.avif
--------------------------------------------------------------------------------
/playlist/assets/n1.avif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/playlist/assets/n1.avif
--------------------------------------------------------------------------------
/preview/preview-og.avif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/preview/preview-og.avif
--------------------------------------------------------------------------------
/assets/stars/star-1.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-1.webp
--------------------------------------------------------------------------------
/assets/stars/star-10.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-10.webp
--------------------------------------------------------------------------------
/assets/stars/star-11.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-11.webp
--------------------------------------------------------------------------------
/assets/stars/star-12.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-12.webp
--------------------------------------------------------------------------------
/assets/stars/star-13.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-13.webp
--------------------------------------------------------------------------------
/assets/stars/star-14.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-14.webp
--------------------------------------------------------------------------------
/assets/stars/star-15.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-15.webp
--------------------------------------------------------------------------------
/assets/stars/star-16.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-16.webp
--------------------------------------------------------------------------------
/assets/stars/star-17.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-17.webp
--------------------------------------------------------------------------------
/assets/stars/star-18.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-18.webp
--------------------------------------------------------------------------------
/assets/stars/star-19.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-19.webp
--------------------------------------------------------------------------------
/assets/stars/star-2.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-2.webp
--------------------------------------------------------------------------------
/assets/stars/star-20.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-20.webp
--------------------------------------------------------------------------------
/assets/stars/star-21.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-21.webp
--------------------------------------------------------------------------------
/assets/stars/star-22.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-22.webp
--------------------------------------------------------------------------------
/assets/stars/star-23.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-23.webp
--------------------------------------------------------------------------------
/assets/stars/star-24.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-24.webp
--------------------------------------------------------------------------------
/assets/stars/star-25.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-25.webp
--------------------------------------------------------------------------------
/assets/stars/star-26.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-26.webp
--------------------------------------------------------------------------------
/assets/stars/star-27.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-27.webp
--------------------------------------------------------------------------------
/assets/stars/star-28.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-28.webp
--------------------------------------------------------------------------------
/assets/stars/star-29.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-29.webp
--------------------------------------------------------------------------------
/assets/stars/star-3.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-3.webp
--------------------------------------------------------------------------------
/assets/stars/star-30.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-30.webp
--------------------------------------------------------------------------------
/assets/stars/star-31.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-31.webp
--------------------------------------------------------------------------------
/assets/stars/star-32.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-32.webp
--------------------------------------------------------------------------------
/assets/stars/star-33.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-33.webp
--------------------------------------------------------------------------------
/assets/stars/star-34.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-34.webp
--------------------------------------------------------------------------------
/assets/stars/star-35.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-35.webp
--------------------------------------------------------------------------------
/assets/stars/star-36.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-36.webp
--------------------------------------------------------------------------------
/assets/stars/star-37.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-37.webp
--------------------------------------------------------------------------------
/assets/stars/star-38.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-38.webp
--------------------------------------------------------------------------------
/assets/stars/star-39.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-39.webp
--------------------------------------------------------------------------------
/assets/stars/star-4.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-4.webp
--------------------------------------------------------------------------------
/assets/stars/star-40.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-40.webp
--------------------------------------------------------------------------------
/assets/stars/star-41.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-41.webp
--------------------------------------------------------------------------------
/assets/stars/star-42.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-42.webp
--------------------------------------------------------------------------------
/assets/stars/star-43.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-43.webp
--------------------------------------------------------------------------------
/assets/stars/star-44.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-44.webp
--------------------------------------------------------------------------------
/assets/stars/star-45.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-45.webp
--------------------------------------------------------------------------------
/assets/stars/star-46.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-46.webp
--------------------------------------------------------------------------------
/assets/stars/star-47.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-47.webp
--------------------------------------------------------------------------------
/assets/stars/star-48.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-48.webp
--------------------------------------------------------------------------------
/assets/stars/star-49.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-49.webp
--------------------------------------------------------------------------------
/assets/stars/star-5.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-5.webp
--------------------------------------------------------------------------------
/assets/stars/star-50.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-50.webp
--------------------------------------------------------------------------------
/assets/stars/star-6.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-6.webp
--------------------------------------------------------------------------------
/assets/stars/star-7.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-7.webp
--------------------------------------------------------------------------------
/assets/stars/star-8.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-8.webp
--------------------------------------------------------------------------------
/assets/stars/star-9.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/assets/stars/star-9.webp
--------------------------------------------------------------------------------
/playlist/assets/favicon.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/playlist/assets/favicon.webp
--------------------------------------------------------------------------------
/playlist/assets/preview.avif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/20essentials/20TracksForEachOne/HEAD/playlist/assets/preview.avif
--------------------------------------------------------------------------------
/assets/svgPlayList.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/license.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notzice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 |
--------------------------------------------------------------------------------
/playlist/assets/svgSpriteCardMusical.svg:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/playlist/assets/svgSprite.svg:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 20 Tracks For Each One
7 |
8 |
9 |
10 |
11 |
15 |
19 |
20 |
21 |
22 |
26 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
59 |
60 |
61 |
71 |
72 |
73 |
77 |
78 |
86 |
87 |
88 |
89 |
90 |
94 |
95 |
96 |
97 |
98 |
106 |
107 |
108 |
109 |
110 |
118 |
119 |
120 |
121 |
122 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
143 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
162 |
169 |
170 |
171 |
172 |
173 |
174 |
177 |
178 |
179 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
218 |
219 |
Things you should know about localStorage
220 |
221 | It is specific to each browser and device
222 |
223 | Average storage is 5MB per domain, which equals about 5,000,000
224 | characters
225 |
226 | Thanks to those 5MB, you can store hundreds of songs
227 |
228 | If storage is full, you won’t be able to add more playlists/songs
229 |
230 |
231 |
232 |
Actions that could lead to the deletion of the data stored in LS
233 |
234 | Clearing browsing data (cookies, history, cache)
235 | Manually deleting from the developer tools
236 | Uninstalling/Reinstalling the browser
237 | Restoring the device
238 | Switching to another browser
239 | Signing out of a synchronized browser
240 | Some browser updates
241 |
242 |
243 |
244 | I recommend making a backup of your playlists by obtaining a JSON object
245 | that will contain both the playlist name and its respective songs, with
246 | the URLs for each song.
247 |
248 |
249 |
250 | I recommend saving that JSON in
251 | Google Keep , which is free.
252 |
253 |
254 |
255 |
256 | GET THE ARRAY OF SONGS FROM A PLAYLIST
257 |
258 |
270 |
292 |
293 |
294 |
295 | GET ARRAYS OF SONGS FROM PLAYLISTS
296 |
297 |
298 |
305 |
306 | 📓
307 | ❌
308 |
309 |
331 |
332 |
333 |
334 |
337 |
338 |
339 | GET JSON OBJECT OF ALL PLAYLISTS
340 |
341 |
361 |
362 |
363 |
ADD A SINGLE PLAYLIST
364 |
365 |
381 | 📓
382 | ❌
383 |
384 |
385 |
386 |
ADD MULTIPLE PLAYLISTS
387 |
388 |
414 | 📓
415 | ❌
416 |
417 |
418 |
419 |
DELETE ALL CURRENT PLAYLISTS
420 |
421 |
422 |
423 | Number of Performers: 0
424 | Number of songs: 0
425 |
426 |
427 |
430 |
431 |
--------------------------------------------------------------------------------
/playlist/index.css:
--------------------------------------------------------------------------------
1 | *,
2 | *::after,
3 | *::before {
4 | box-sizing: border-box;
5 | margin: 0;
6 | padding: 0;
7 | font-family: sans-serif, Geneva, Tahoma;
8 | font-weight: 600;
9 | user-select: none;
10 | cursor: auto;
11 | }
12 |
13 | html {
14 | min-width: 350px;
15 | max-width: 1600px;
16 | display: block;
17 | margin-inline: auto;
18 | background-color: black;
19 | align-content: center;
20 | height: 100vh;
21 | }
22 |
23 | html,
24 | body {
25 | scroll-behavior: smooth;
26 | }
27 |
28 | body {
29 | --sb-track-color: transparent;
30 | --sb-thumb-color: linear-gradient(
31 | to bottom,
32 | var(--color1),
33 | var(--color2),
34 | var(--color3)
35 | );
36 | --sb-size: 10px;
37 | }
38 |
39 | body::-webkit-scrollbar {
40 | width: var(--sb-size);
41 | }
42 |
43 | body::-webkit-scrollbar-track {
44 | background: var(--sb-track-color);
45 | }
46 |
47 | body::-webkit-scrollbar-thumb {
48 | background: var(--sb-thumb-color);
49 | }
50 |
51 | @supports not selector(::-webkit-scrollbar) {
52 | body {
53 | scrollbar-color: var(--sb-thumb-color) var(--sb-track-color);
54 | }
55 | }
56 |
57 | .am-modal {
58 | margin: auto;
59 | border: none;
60 | width: 100%;
61 | max-width: 275px;
62 | height: max-content;
63 | padding: 1rem;
64 | padding-top: 2rem;
65 | background-color: #111;
66 | box-shadow: 0 0 1px #0008;
67 | border-radius: 20px;
68 | color: gray;
69 | overflow: hidden;
70 | scale: 0;
71 | transition: scale 0.25s ease, display 0.25s allow-discrete,
72 | overlay 0.25s allow-discrete;
73 |
74 | &[open] {
75 | scale: 1;
76 | transition: scale 0.25s;
77 |
78 | @starting-style {
79 | scale: 0;
80 | }
81 | }
82 |
83 | .tituto-modal {
84 | text-wrap: balance;
85 | width: 80%;
86 | margin-bottom: 0.7rem;
87 | }
88 |
89 | h3 {
90 | font-size: 0.85rem;
91 | }
92 |
93 | .cerrar {
94 | position: absolute;
95 | top: 0.8rem;
96 | right: 0.8rem;
97 | padding: 0.4rem;
98 | border: none;
99 | transform: scale(0.9);
100 | border-radius: 50%;
101 | background-color: #000;
102 | box-shadow: 0 0 9px 0 #fff inset;
103 | overflow: hidden;
104 | font-size: 0.8rem;
105 | transition: box-shadow 0.5s ease;
106 |
107 | &:hover {
108 | background-color: #000;
109 | box-shadow: 0 0 28px 0 #fff2 inset;
110 | }
111 | }
112 |
113 | .nav-of-options-of-the-modal {
114 | width: 100%;
115 | height: 24px;
116 | display: flex;
117 | padding: 3px;
118 | gap: 6px;
119 |
120 | .am-button-nav-modal {
121 | width: 20%;
122 | height: 100%;
123 | margin: 0;
124 | border-radius: 4px;
125 | border: 0;
126 | display: flex;
127 | flex-wrap: wrap;
128 | place-content: center;
129 | background-color: #e9e9e9;
130 |
131 | &.button-nav-selected {
132 | background-color: #333;
133 |
134 | svg {
135 | color: #fff;
136 | }
137 | }
138 |
139 | svg {
140 | width: 100%;
141 | height: 90%;
142 | pointer-events: none;
143 | }
144 | }
145 | }
146 |
147 | .container-modal {
148 | display: flex;
149 | flex-direction: column;
150 | margin-top: 0.5rem;
151 | min-height: 90px;
152 | height: 100%;
153 | max-height: 300px;
154 | padding-bottom: 0.9rem;
155 | scroll-behavior: smooth;
156 | scrollbar-gutter: both-edges;
157 | overflow-y: auto;
158 | scrollbar-width: thin;
159 | scrollbar-color: white transparent;
160 | overscroll-behavior: contain;
161 |
162 | @media (width <= 1111px) and (orientation: landscape) {
163 | max-height: 150px;
164 | }
165 |
166 | .fila {
167 | display: flex;
168 | column-gap: 0.2rem;
169 | padding: 0.5rem;
170 |
171 | input {
172 | accent-color: lime;
173 | }
174 | }
175 |
176 | label {
177 | color: white;
178 | font-size: 0.8rem;
179 | background-color: transparent;
180 | width: 100%;
181 | align-content: center;
182 | }
183 |
184 | abbr {
185 | font-size: 0.8rem;
186 | }
187 | }
188 |
189 | &::backdrop {
190 | background-image: linear-gradient(to top, #2228 20%, #4448 40%);
191 | }
192 |
193 | input[type='checkbox'] {
194 | margin-right: 0.5rem;
195 | }
196 |
197 | .container-add-playlist {
198 | --validate-color: #00ff7f;
199 | --invalid-color: #f00f;
200 | position: relative;
201 | width: 100%;
202 | height: 100%;
203 | left: 0;
204 | bottom: 0;
205 | color: #fff;
206 | display: flex;
207 | align-items: center;
208 | padding: 12px 18px;
209 | border-top: 2px solid #fff2;
210 | transition: background-color 0.3s ease, padding 0.3s linear;
211 | z-index: 1000;
212 |
213 | &::after {
214 | content: '';
215 | display: block;
216 | position: absolute;
217 | opacity: 0;
218 | left: -50%;
219 | transform-origin: left;
220 | transform: scaleX(0);
221 | transition: transform 0.5s;
222 | }
223 |
224 | &.mode-active {
225 | h3 {
226 | pointer-events: none;
227 | opacity: 0;
228 | display: none;
229 | }
230 |
231 | .container-inputs {
232 | display: flex;
233 | opacity: 1;
234 | }
235 | }
236 |
237 | h3 {
238 | z-index: 99999;
239 | font-family: Arial, Helvetica, sans-serif;
240 | pointer-events: none;
241 | transform: translateY(5px);
242 | align-content: center;
243 | text-transform: capitalize;
244 | font-size: 0.9rem;
245 | opacity: 1;
246 | visibility: visible;
247 | transition: opacity 0.7s ease;
248 |
249 | &::before {
250 | content: '+';
251 | font-size: 24px;
252 | margin-right: 8px;
253 | vertical-align: -3px;
254 | }
255 | }
256 |
257 | .container-inputs {
258 | opacity: 0;
259 | display: none;
260 | z-index: 99999;
261 | width: 100%;
262 | position: relative;
263 | padding-bottom: 10px;
264 | transition: opacity 0.5s ease, display 0.5s ease allow-discrete;
265 | }
266 |
267 | span {
268 | position: absolute;
269 | left: 80%;
270 | font-size: 0.7rem;
271 | color: #fff8;
272 | position: relative;
273 | font-style: italic;
274 | top: 26px;
275 | }
276 |
277 | input {
278 | border: none;
279 | outline: none;
280 | font-family: Arial, Helvetica, sans-serif;
281 | color: var(--validate-color);
282 |
283 | &[type='text'] {
284 | width: 88%;
285 | background-color: transparent;
286 | height: 20px;
287 | position: absolute;
288 | top: 0%;
289 | border-bottom: 2px solid #fff8;
290 |
291 | &::placeholder {
292 | color: #fff8;
293 | }
294 |
295 | &.valid {
296 | color: var(--validate-color);
297 | border-bottom: 2px solid var(--validate-color);
298 | caret-color: var(--validate-color);
299 | }
300 |
301 | &.invalid {
302 | color: var(--invalid-color);
303 | border-bottom: 2px solid var(--invalid-color);
304 | caret-color: var(--invalid-color);
305 | }
306 | }
307 |
308 | &[type='submit'] {
309 | width: 17%;
310 | background-color: transparent;
311 | aspect-ratio: 1;
312 | transform: scale(0.8);
313 | border-radius: 999px;
314 | box-shadow: inset 0 0 0 8px #0003;
315 | position: absolute;
316 | background-color: #0f08;
317 | right: -12px;
318 | top: -20%;
319 | display: flex;
320 | flex-wrap: wrap;
321 | place-content: center;
322 | line-height: 1rem;
323 | font-size: 1em;
324 | transition: box-shadow 0.4s ease;
325 |
326 | &:hover {
327 | box-shadow: inset 0 0 0 0 #0003;
328 | }
329 | }
330 | }
331 | }
332 | }
333 |
334 | .myHeader {
335 | display: block;
336 | height: 5.5rem;
337 | position: relative;
338 | z-index: 5;
339 | background-image: linear-gradient(
340 | 45deg,
341 | var(--color1, #ee82ee),
342 | var(--color2, #87ceeb),
343 | var(--color3, #00ff7f)
344 | );
345 | display: flex;
346 | flex-wrap: wrap;
347 | justify-content: center;
348 | align-items: center;
349 | flex-direction: column;
350 | row-gap: 0.5rem;
351 | padding-block: 0.6rem;
352 | --black: #0003;
353 |
354 | img {
355 | inline-size: 2.5rem;
356 | block-size: 2.5rem;
357 | filter: drop-shadow(1px 0px 0px var(--black))
358 | drop-shadow(-1px 0px 0px var(--black)) drop-shadow(0px 1px 0px var(--black))
359 | drop-shadow(0px -1px 0px var(--black));
360 | }
361 |
362 | .namePlaylist {
363 | text-transform: uppercase;
364 | color: #fff;
365 | font-size: clamp(0.6rem, 0.4794rem + 0.2072vw, 0.69rem);
366 | }
367 | }
368 |
369 | .myNav {
370 | display: flex;
371 | width: 100%;
372 | height: 2rem;
373 | background-color: #222;
374 | flex-wrap: wrap;
375 | justify-content: center;
376 | top: -1px;
377 | align-items: center;
378 | position: sticky;
379 | z-index: 99999;
380 | box-shadow: 2px 2px 3px #2228;
381 |
382 | a,
383 | button {
384 | border: none;
385 | outline: none;
386 | min-height: 100%;
387 | margin-inline: 6px;
388 | background-color: transparent;
389 | align-content: center;
390 | padding: 0.2rem;
391 |
392 | @media (width >= 1000px) {
393 | &:hover,
394 | &.nav-btn-active {
395 | svg {
396 | fill: #fff;
397 | }
398 | }
399 | }
400 |
401 | @media (width <= 999px) {
402 | &.nav-btn-active,
403 | &.home:hover,
404 | &.recarga:hover {
405 | svg {
406 | fill: #fff;
407 | }
408 | }
409 | }
410 |
411 | * {
412 | pointer-events: none;
413 | }
414 |
415 | svg {
416 | transition: 0s;
417 | display: flex;
418 | flex-wrap: wrap;
419 | place-content: center;
420 | align-content: center;
421 | }
422 | }
423 |
424 | a {
425 | -webkit-tap-highlight-color: transparent;
426 | }
427 |
428 | .nav-playbutton {
429 | svg {
430 | scale: 0.9;
431 | }
432 | }
433 |
434 | .nav-list-momentary {
435 | position: relative;
436 |
437 | .btn-tooltip {
438 | --duration: 7s;
439 | --easing: linear;
440 | --c-color-1: rgba(26, 163, 255, 0.7);
441 | /* Changed color */
442 | --c-color-2: #1aff1a;
443 | /* Changed color */
444 | --c-color-3: #ff1a75;
445 | /* Changed color */
446 | --c-color-4: rgba(26, 232, 255, 0.7);
447 | /* Changed color */
448 | --c-shadow: rgba(87, 223, 255, 0.5);
449 | /* Changed color */
450 | --c-shadow-inset-top: rgba(52, 223, 255, 0.9);
451 | /* Changed color */
452 | --c-shadow-inset-bottom: rgba(215, 250, 255, 0.8);
453 | /* Changed color */
454 | --c-radial-inner: #15d2ff;
455 | /* Changed color */
456 | --c-radial-outer: #72faff;
457 | /* Changed color */
458 | --c-color: #fff;
459 | appearance: none;
460 | outline: none;
461 | -webkit-tap-highlight-color: transparent;
462 | position: absolute;
463 | cursor: pointer;
464 | border: none;
465 | display: flex;
466 | border-radius: 24px;
467 | padding: 0;
468 | margin: 0;
469 | text-align: center;
470 | font-weight: 600;
471 | font-size: 16px;
472 | letter-spacing: 0.02em;
473 | line-height: 1.5;
474 | color: var(--c-color);
475 | background: radial-gradient(
476 | circle,
477 | var(--c-radial-inner),
478 | var(--c-radial-outer) 80%
479 | );
480 | transform: scale(0);
481 | z-index: 200;
482 | box-shadow: 0 0 14px var(--c-shadow);
483 | pointer-events: auto;
484 | top: 150%;
485 | right: -36px;
486 | min-width: 250px;
487 | transition: transform 0.3s ease-in-out;
488 |
489 | &.tooltip-active {
490 | transform: scale(0.8);
491 | }
492 |
493 | svg {
494 | width: 25px;
495 | height: 40px;
496 | zoom: 0.4;
497 | align-content: center;
498 | pointer-events: none;
499 | position: relative;
500 | transform: translateY(10px);
501 | z-index: 50;
502 | }
503 |
504 | .triangle {
505 | width: 40px;
506 | height: 20px;
507 | background-color: #6ef7ff;
508 | position: absolute;
509 | right: 10px;
510 | top: -12px;
511 | z-index: -1;
512 | clip-path: polygon(0% 100%, 50% 0, 100% 100%);
513 | }
514 | }
515 |
516 | .btn-tooltip:before {
517 | content: '';
518 | pointer-events: none;
519 | position: absolute;
520 | z-index: 3;
521 | left: 0;
522 | top: 0;
523 | right: 0;
524 | bottom: 0;
525 | border-radius: 24px;
526 | box-shadow: inset 0 3px 12px var(--c-shadow-inset-top),
527 | inset 0 -3px 4px var(--c-shadow-inset-bottom);
528 | }
529 |
530 | .btn-tooltip .wrapper {
531 | mask-image: radial-gradient(white, black);
532 | overflow: hidden;
533 | border-radius: 24px;
534 | padding: 8px 0;
535 | display: flex;
536 | text-align: center;
537 | justify-content: center;
538 | align-content: center;
539 | width: 100%;
540 | }
541 |
542 | .btn-tooltip .wrapper span {
543 | display: inline-block;
544 | position: relative;
545 | z-index: 200;
546 | }
547 |
548 | .btn-tooltip .wrapper .circle {
549 | position: absolute;
550 | left: 0;
551 | top: 0;
552 | width: 40px;
553 | height: 40px;
554 | border-radius: 50%;
555 | filter: blur(var(--blur, 8px));
556 | background: var(--background, transparent);
557 | transform: translate(var(--x, 0), var(--y, 0)) translateZ(0);
558 | animation: var(--animation, none) var(--duration) alternate var(--easing)
559 | infinite;
560 | }
561 |
562 | .btn-tooltip .wrapper .circle.circle-1,
563 | .btn-tooltip .wrapper .circle.circle-9,
564 | .btn-tooltip .wrapper .circle.circle-10 {
565 | --background: var(--c-color-4);
566 | }
567 |
568 | .btn-tooltip .wrapper .circle.circle-3,
569 | .btn-tooltip .wrapper .circle.circle-4 {
570 | --background: var(--c-color-2);
571 | --blur: 14px;
572 | }
573 |
574 | .btn-tooltip .wrapper .circle.circle-5,
575 | .btn-tooltip .wrapper .circle.circle-6 {
576 | --background: var(--c-color-3);
577 | --blur: 16px;
578 | }
579 |
580 | .btn-tooltip .wrapper .circle.circle-2,
581 | .btn-tooltip .wrapper .circle.circle-7,
582 | .btn-tooltip .wrapper .circle.circle-8,
583 | .btn-tooltip .wrapper .circle.circle-11,
584 | .btn-tooltip .wrapper .circle.circle-12 {
585 | --background: var(--c-color-1);
586 | --blur: 12px;
587 | }
588 |
589 | .btn-tooltip .wrapper .circle.circle-1 {
590 | --x: 50px;
591 | --y: -40px;
592 | --animation: circle-1;
593 | }
594 |
595 | .btn-tooltip .wrapper .circle.circle-2 {
596 | --x: 180px;
597 | --y: 8px;
598 | --animation: circle-2;
599 | }
600 |
601 | .btn-tooltip .wrapper .circle.circle-3 {
602 | --x: 200px;
603 | --y: -12px;
604 | --animation: circle-3;
605 | }
606 |
607 | .btn-tooltip .wrapper .circle.circle-4 {
608 | --x: 80px;
609 | --y: -12px;
610 | --animation: circle-4;
611 | }
612 |
613 | .btn-tooltip .wrapper .circle.circle-5 {
614 | --x: 12px;
615 | --y: -4px;
616 | --animation: circle-5;
617 | }
618 |
619 | .btn-tooltip .wrapper .circle.circle-6 {
620 | --x: 120px;
621 | --y: 16px;
622 | --animation: circle-6;
623 | }
624 |
625 | .btn-tooltip .wrapper .circle.circle-7 {
626 | --x: 180px;
627 | --y: 28px;
628 | --animation: circle-7;
629 | }
630 |
631 | .btn-tooltip .wrapper .circle.circle-8 {
632 | --x: 200px;
633 | --y: -4px;
634 | --animation: circle-8;
635 | }
636 |
637 | .btn-tooltip .wrapper .circle.circle-9 {
638 | --x: 100px;
639 | --y: -12px;
640 | --animation: circle-9;
641 | }
642 |
643 | .btn-tooltip .wrapper .circle.circle-10 {
644 | --x: 150px;
645 | --y: 16px;
646 | --animation: circle-10;
647 | }
648 |
649 | .btn-tooltip .wrapper .circle.circle-11 {
650 | --x: 200px;
651 | --y: 4px;
652 | --animation: circle-11;
653 | }
654 |
655 | .btn-tooltip .wrapper .circle.circle-12 {
656 | --blur: 190px;
657 | --x: 52px;
658 | --y: 4px;
659 | --animation: circle-12;
660 | }
661 | }
662 |
663 | svg {
664 | fill: #999;
665 | width: 18px;
666 | height: 18px;
667 | transition: 0.3s;
668 | }
669 |
670 | .nav-arrow-down {
671 | display: none;
672 | }
673 |
674 | @media (width <=1080px) {
675 | .nav-arrow-down {
676 | display: block;
677 | }
678 | }
679 | }
680 |
681 | .background-container {
682 | position: fixed;
683 | inset: 0;
684 | z-index: -1;
685 |
686 | .star-1 {
687 | width: var(--size);
688 | height: var(--size);
689 | background-color: #fff;
690 | border-radius: 50%;
691 | box-shadow: var(--shadow-layer);
692 | position: absolute;
693 | z-index: -1;
694 | animation: risingStars var(--duration) linear infinite;
695 | }
696 | }
697 |
698 | @keyframes moveLuz {
699 | 0% {
700 | left: -100%;
701 | }
702 | 100% {
703 | left: 100%;
704 | }
705 | }
706 |
707 | main {
708 | width: 100%;
709 | max-width: 1600px;
710 | min-height: max-content;
711 | padding: 1rem;
712 | display: grid;
713 | grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
714 | grid-template-rows: repeat(auto-fit, auto);
715 | align-content: start;
716 | gap: 1rem;
717 |
718 | .card {
719 | height: 150px;
720 | min-height: max-content;
721 | height: auto;
722 | display: flex;
723 | border-radius: 1rem;
724 | color: var(--color3, #00ff7f);
725 | animation: boxShadowMove 5s alternate ease infinite;
726 |
727 | .img {
728 | width: 90%;
729 | height: 90%;
730 | border-radius: 16px;
731 | background-position: center;
732 | background-size: cover;
733 | aspect-ratio: 1;
734 | background-image: var(--image-bg);
735 | position: relative;
736 | overflow: hidden;
737 | box-shadow: 0 0 10px 0 #0005, inset 0 0 20px 5px #0003;
738 |
739 | .input-range {
740 | width: 100%;
741 | position: absolute;
742 | left: 50%;
743 | transform: translateX(-50%) scale(0.7);
744 | bottom: 3px;
745 | accent-color: chartreuse;
746 | display: none;
747 | }
748 |
749 | &:hover {
750 | &::after {
751 | animation: moveLuz 0.5s linear forwards;
752 | }
753 | }
754 |
755 | &::after {
756 | content: '';
757 | position: absolute;
758 | width: 100%;
759 | height: 100%;
760 | left: -100%;
761 | top: 0;
762 | background: linear-gradient(90deg, transparent, #fff2, transparent);
763 | }
764 | }
765 |
766 | .card-left {
767 | width: 55%;
768 | display: flex;
769 | flex-wrap: wrap;
770 | place-content: center;
771 | }
772 |
773 | .card-right {
774 | width: 45%;
775 | overflow: hidden;
776 | border-radius: 1rem;
777 | border-top-left-radius: 0;
778 | border-bottom-left-radius: 0;
779 | display: flex;
780 | flex-direction: column;
781 |
782 | .card-right-top {
783 | font-size: clamp(0.5208rem, 0.4794rem + 0.2072vw, 0.64rem);
784 | height: 50%;
785 | margin-top: 0.7rem;
786 | margin-inline: auto;
787 | margin-bottom: 0.5rem;
788 | max-width: 90%;
789 | text-align: center;
790 | text-wrap: balance;
791 | display: flex;
792 | justify-content: center;
793 | align-items: center;
794 | color: #fff;
795 | overflow-wrap: anywhere;
796 |
797 | @media (width <= 1400px) {
798 | font-size: clamp(0.6508rem, 0.4794rem + 0.2072vw, 0.54rem);
799 | }
800 | }
801 |
802 | .card-right-down {
803 | height: 50%;
804 | display: flex;
805 | justify-content: center;
806 | align-items: end;
807 | margin-bottom: 0.7rem;
808 |
809 | .card-right-buttons {
810 | display: grid;
811 | margin-inline: auto;
812 | grid-template-columns: repeat(3, auto);
813 | justify-content: center;
814 | gap: 0.7rem;
815 |
816 | button {
817 | background-color: black;
818 | width: 1.4rem;
819 | height: 1.4rem;
820 | border-radius: 50%;
821 | align-content: center;
822 | outline: none;
823 | border: none;
824 | transition: background-color 0.3s linear;
825 | pointer-events: auto;
826 |
827 | * {
828 | pointer-events: none !important;
829 | }
830 |
831 | &.card-btn-active {
832 | background-color: #fff;
833 |
834 | svg {
835 | filter: invert(1);
836 | }
837 | }
838 |
839 | &.blocked {
840 | pointer-events: none;
841 | }
842 |
843 | svg {
844 | all: initial;
845 | display: block;
846 | margin-inline: auto;
847 | fill: #fff;
848 | width: 0.8rem;
849 | height: 0.8rem;
850 | transition: 0.3s ease filter;
851 | }
852 | }
853 |
854 | @media (hover: hover) {
855 | button {
856 | &:hover,
857 | &.card-btn-active {
858 | background-color: #fff;
859 |
860 | svg {
861 | filter: invert(1);
862 | }
863 | }
864 | }
865 | }
866 |
867 | .card-playbutton,
868 | .card-downloadbutton {
869 | svg {
870 | scale: 0.8;
871 | }
872 | }
873 |
874 | .card-downloadbutton {
875 | pointer-events: none;
876 | -webkit-tap-highlight-color: transparent;
877 |
878 | a {
879 | display: block;
880 | width: 100%;
881 | height: 100%;
882 | background-color: transparent;
883 | border-radius: inherit;
884 | align-content: center;
885 | }
886 |
887 | a.pointerEventsActivo {
888 | pointer-events: auto !important;
889 | }
890 | }
891 |
892 | .card-downloadbutton,
893 | .card-playlistbutton {
894 | &.card-btn-active,
895 | &:hover {
896 | background-color: #fff;
897 |
898 | svg {
899 | filter: invert(1);
900 | }
901 | }
902 | }
903 |
904 | .card-playlistbutton {
905 | &.buttonConPointerEvents {
906 | pointer-events: auto !important;
907 | }
908 | }
909 |
910 | .playlistbutton {
911 | svg {
912 | scale: 1.2;
913 | }
914 | }
915 | }
916 | }
917 | }
918 | }
919 |
920 | .card:nth-child(even) {
921 | color: var(--color1, #ee82ee);
922 | animation: boxShadowMove 5s alternate-reverse ease infinite;
923 | }
924 |
925 | .card.targeado:target {
926 | color: #fff !important;
927 | scroll-margin-top: 3rem;
928 | }
929 | }
930 |
931 | @keyframes boxShadowMove {
932 | 0% {
933 | box-shadow: 0 0 10px currentColor inset;
934 | }
935 |
936 | 100% {
937 | box-shadow: 0 0 300px currentColor inset;
938 | }
939 | }
940 |
941 | @keyframes recorrer {
942 | 0% {
943 | transform: translate(0, 0);
944 | }
945 |
946 | 50% {
947 | transform: translate(-90%, 0);
948 | }
949 |
950 | 100% {
951 | transform: translate(15%, 0);
952 | }
953 | }
954 |
955 | @keyframes risingStars {
956 | 0% {
957 | transform: translateY(0);
958 | }
959 |
960 | 100% {
961 | transform: translateY(-100vh);
962 | }
963 | }
964 |
965 | @keyframes change {
966 | from {
967 | scale: 0;
968 | translate: 50px;
969 | }
970 |
971 | to {
972 | scale: 1;
973 | translate: 0;
974 | }
975 | }
976 |
977 | @media (width <= 546px) {
978 | main {
979 | .card {
980 | transition: transform 0.3s ease, scale 0.3s ease;
981 |
982 | .card-right {
983 | .card-right-top {
984 | font-size: clamp(0.75rem, 0.6538rem + 0.44vw, 1.0938rem);
985 | }
986 |
987 | .card-right-down {
988 | .card-right-buttons {
989 | .card-infinitybutton {
990 | &:hover {
991 | background-color: black;
992 |
993 | svg {
994 | filter: invert(0);
995 | }
996 | }
997 |
998 | &.card-btn-active {
999 | background-color: #fff;
1000 |
1001 | svg {
1002 | filter: invert(1);
1003 | }
1004 | }
1005 | }
1006 | }
1007 | }
1008 | }
1009 | }
1010 |
1011 | .card:nth-child(even) {
1012 | animation: boxShadowMove 5s ease alternate infinite,
1013 | change auto linear forwards;
1014 | animation-timeline: auto, view();
1015 | animation-composition: add;
1016 | animation-range: cover -50% cover 5%;
1017 | }
1018 |
1019 | .card:nth-child(odd) {
1020 | animation: boxShadowMove 5s ease alternate-reverse infinite,
1021 | change auto linear forwards;
1022 | animation-timeline: auto, view();
1023 | animation-composition: add;
1024 | animation-range: cover -50% cover 5%;
1025 | }
1026 |
1027 | .card:nth-child(even).stopped-animation {
1028 | animation: boxShadowMove 5s ease alternate infinite;
1029 | }
1030 |
1031 | .card:nth-child(odd).stopped-animation {
1032 | animation: boxShadowMove 5s ease alternate-reverse infinite;
1033 | }
1034 |
1035 | .card:nth-child(4n + 1) {
1036 | color: var(--color1, #ee82ee);
1037 | }
1038 | .card:nth-child(4n + 2) {
1039 | color: var(--color2, #00ff7f);
1040 | }
1041 | .card:nth-child(4n + 3) {
1042 | color: var(--color3, #0099ff);
1043 | }
1044 | .card:nth-child(4n + 4) {
1045 | color: var(--color4, #ff0000);
1046 | }
1047 | }
1048 | }
1049 |
1050 | /* 2 columnas */
1051 | @media (548px <= width < 824px) {
1052 | main {
1053 | .card:nth-child(2),
1054 | .card:nth-child(3),
1055 | .card:nth-child(6),
1056 | .card:nth-child(7),
1057 | .card:nth-child(10),
1058 | .card:nth-child(11),
1059 | .card:nth-child(14),
1060 | .card:nth-child(15),
1061 | .card:nth-child(18),
1062 | .card:nth-child(19) {
1063 | color: var(--color1, #ee82ee);
1064 | animation: boxShadowMove 5s ease alternate infinite;
1065 | }
1066 |
1067 | .card:nth-child(1),
1068 | .card:nth-child(4),
1069 | .card:nth-child(5),
1070 | .card:nth-child(8),
1071 | .card:nth-child(9),
1072 | .card:nth-child(12),
1073 | .card:nth-child(13),
1074 | .card:nth-child(16),
1075 | .card:nth-child(17),
1076 | .card:nth-child(20) {
1077 | color: var(--color3, #00ff7f);
1078 | animation: boxShadowMove 5s ease alternate-reverse infinite;
1079 | }
1080 | }
1081 | }
1082 |
1083 | @media (1080px <=width < 1346px) {
1084 | main {
1085 | .card:nth-child(2),
1086 | .card:nth-child(4),
1087 | .card:nth-child(5),
1088 | .card:nth-child(7),
1089 | .card:nth-child(10),
1090 | .card:nth-child(12),
1091 | .card:nth-child(13),
1092 | .card:nth-child(15),
1093 | .card:nth-child(18),
1094 | .card:nth-child(20) {
1095 | color: var(--color1, #ee82ee);
1096 | animation: boxShadowMove 5s ease alternate infinite;
1097 | }
1098 |
1099 | .card:nth-child(1),
1100 | .card:nth-child(3),
1101 | .card:nth-child(6),
1102 | .card:nth-child(8),
1103 | .card:nth-child(9),
1104 | .card:nth-child(11),
1105 | .card:nth-child(14),
1106 | .card:nth-child(16),
1107 | .card:nth-child(17),
1108 | .card:nth-child(19) {
1109 | color: var(--color3, #00ff7f);
1110 | animation: boxShadowMove 5s ease alternate-reverse infinite;
1111 | }
1112 | }
1113 | }
1114 | /* ===========================VIEW TRANSITIONS========================= */
1115 |
1116 | html {
1117 | view-transition-name: transitionPage;
1118 | }
1119 |
1120 | @view-transition {
1121 | navigation: auto;
1122 | }
1123 |
1124 | ::view-transition-new(transitionPage) {
1125 | animation: fadeIn 1s ease forwards;
1126 | }
1127 | ::view-transition-old(transitionPage) {
1128 | animation: fadeIn 1s ease reverse forwards;
1129 | }
1130 |
1131 | @keyframes fadeIn {
1132 | 0% {
1133 | clip-path: circle(0% at 50% 50%);
1134 | }
1135 | 100% {
1136 | clip-path: circle(100% at 50% 50%);
1137 | }
1138 | }
1139 |
1140 | /* ===========================TOOLTIP========================= */
1141 | @keyframes circle-1 {
1142 | 33% {
1143 | transform: translate(0px, 16px) translateZ(0);
1144 | }
1145 |
1146 | 66% {
1147 | transform: translate(12px, 64px) translateZ(0);
1148 | }
1149 | }
1150 |
1151 | @keyframes circle-2 {
1152 | 33% {
1153 | transform: translate(80px, -10px) translateZ(0);
1154 | }
1155 |
1156 | 66% {
1157 | transform: translate(72px, -48px) translateZ(0);
1158 | }
1159 | }
1160 |
1161 | @keyframes circle-3 {
1162 | 33% {
1163 | transform: translate(20px, 12px) translateZ(0);
1164 | }
1165 |
1166 | 66% {
1167 | transform: translate(12px, 4px) translateZ(0);
1168 | }
1169 | }
1170 |
1171 | @keyframes circle-4 {
1172 | 33% {
1173 | transform: translate(76px, -12px) translateZ(0);
1174 | }
1175 |
1176 | 66% {
1177 | transform: translate(112px, -8px) translateZ(0);
1178 | }
1179 | }
1180 |
1181 | @keyframes circle-5 {
1182 | 33% {
1183 | transform: translate(84px, 28px) translateZ(0);
1184 | }
1185 |
1186 | 66% {
1187 | transform: translate(40px, -32px) translateZ(0);
1188 | }
1189 | }
1190 |
1191 | @keyframes circle-6 {
1192 | 33% {
1193 | transform: translate(28px, -16px) translateZ(0);
1194 | }
1195 |
1196 | 66% {
1197 | transform: translate(76px, -56px) translateZ(0);
1198 | }
1199 | }
1200 |
1201 | @keyframes circle-7 {
1202 | 33% {
1203 | transform: translate(8px, 28px) translateZ(0);
1204 | }
1205 |
1206 | 66% {
1207 | transform: translate(20px, -60px) translateZ(0);
1208 | }
1209 | }
1210 |
1211 | @keyframes circle-8 {
1212 | 33% {
1213 | transform: translate(32px, -4px) translateZ(0);
1214 | }
1215 |
1216 | 66% {
1217 | transform: translate(56px, -20px) translateZ(0);
1218 | }
1219 | }
1220 |
1221 | @keyframes circle-9 {
1222 | 33% {
1223 | transform: translate(20px, -12px) translateZ(0);
1224 | }
1225 |
1226 | 66% {
1227 | transform: translate(80px, -8px) translateZ(0);
1228 | }
1229 | }
1230 |
1231 | @keyframes circle-10 {
1232 | 33% {
1233 | transform: translate(68px, 20px) translateZ(0);
1234 | }
1235 |
1236 | 66% {
1237 | transform: translate(100px, 28px) translateZ(0);
1238 | }
1239 | }
1240 |
1241 | @keyframes circle-11 {
1242 | 33% {
1243 | transform: translate(4px, 4px) translateZ(0);
1244 | }
1245 |
1246 | 66% {
1247 | transform: translate(68px, 20px) translateZ(0);
1248 | }
1249 | }
1250 |
1251 | @keyframes circle-12 {
1252 | 33% {
1253 | transform: translate(56px, 0px) translateZ(0);
1254 | }
1255 |
1256 | 66% {
1257 | transform: translate(60px, -32px) translateZ(0);
1258 | }
1259 | }
1260 |
--------------------------------------------------------------------------------
/playlist/index.js:
--------------------------------------------------------------------------------
1 | /******************** DINAMICO LOCAL STORAGE ********************/
2 |
3 | let nameSongs = [];
4 | let arraySongs = [];
5 | let lastNameCard = null;
6 | let listNumbersSongs = [];
7 | let arrayPosters = [];
8 |
9 | const MAXIMUM_LENGTH_OF_PLAYLIST = 20;
10 | function updateRowsModalAndButtonActive() {
11 | setTimeout(() => {
12 | updateButtonNavActive($('.am-button-nav-modal.order'), 'button-nav-selected');
13 | scrollToBottomContainerModal();
14 | }, 50);
15 | }
16 |
17 | if (localStorage.getItem('lastNameCardClicked')) {
18 | lastNameCard = localStorage.getItem('lastNameCardClicked');
19 | let listNameCards = JSON.parse(localStorage.getItem('listname-cards'));
20 | let currentArray = listNameCards[lastNameCard];
21 | if (currentArray.length > 0) {
22 | nameSongs = currentArray.map(el => {
23 | let name = el[0].replace(/\&\;/g, '&');
24 | return name?.trim();
25 | });
26 |
27 | arraySongs = currentArray.map(el => el[1]);
28 | arrayPosters = arraySongs.map((linkPoster, i) => {
29 | const numPhoto = (i % 4) + 1;
30 | return linkPoster.replace(
31 | /\/songs\/n\d+\.mp3/,
32 | `/assets/n${numPhoto}.avif`
33 | );
34 | });
35 | }
36 | }
37 |
38 | document.addEventListener('visibilitychange', function () {
39 | if (!document.hidden) {
40 | localStorage.setItem('playbackUrl', location.href);
41 | } else {
42 | history.replaceState(null, '', location.pathname + location.search);
43 | }
44 | });
45 |
46 | localStorage.setItem('iframeUrl', location.href);
47 |
48 | /******************** MEDIA SESSION CONFIG ********************/
49 | const playlist = nameSongs.map((song, i) => ({
50 | title: song,
51 | artist: lastNameCard,
52 | url: arraySongs[i]
53 | }));
54 |
55 | function toCapitalize(text = '') {
56 | return text
57 | .split(' ')
58 | .map(el => {
59 | if (el.length === 0) return '';
60 | if (el.length < 2)
61 | return `${el[0].toUpperCase()}${el.slice(1).toLowerCase()}`;
62 | let secondLetter =
63 | el[0] === '(' ? el[1].toUpperCase() : el[1].toLowerCase();
64 | return `${el[0].toUpperCase()}${secondLetter}${el.slice(2).toLowerCase()}`;
65 | })
66 | .join(' ')
67 | .replace(/\s+/g, ' ');
68 | }
69 |
70 | function updateMetadata(currentIndex = 0) {
71 | navigator.mediaSession.metadata = new MediaMetadata({
72 | title: `${toCapitalize(playlist[currentIndex].title)}`,
73 | artist: `${toCapitalize(playlist[currentIndex].artist)}`,
74 | artwork: [
75 | {
76 | src: arrayPosters[currentIndex],
77 | sizes: '128x128',
78 | type: 'image/avif'
79 | }
80 | ]
81 | });
82 | }
83 |
84 | navigator.mediaSession.setActionHandler('play', () => {
85 | $audio.play();
86 | navigator.mediaSession.playbackState = 'playing';
87 | });
88 |
89 | navigator.mediaSession.setActionHandler('pause', () => {
90 | $audio.pause();
91 | navigator.mediaSession.playbackState = 'paused';
92 | });
93 |
94 | navigator.mediaSession.setActionHandler('seekbackward', details => {
95 | $audio.currentTime = Math.max($audio.currentTime - 10, 0);
96 | });
97 |
98 | navigator.mediaSession.setActionHandler('seekforward', details => {
99 | $audio.currentTime = Math.min($audio.currentTime + 10, $audio.duration);
100 | });
101 |
102 | function previousTrack(currentIndex) {
103 | navigator.mediaSession.setActionHandler('previoustrack', () => {
104 | currentIndex = (currentIndex - 1 + playlist.length) % playlist.length;
105 | updateMetadata(currentIndex);
106 | $audio.pause();
107 | $audio.currentTime = 0;
108 | $audio.src = arraySongs[currentIndex];
109 | $audio.loop = false;
110 | actualButtonPlayActive(currentIndex);
111 | nextTrack(currentIndex);
112 | showTitle(currentIndex);
113 | });
114 | }
115 |
116 | function nextTrack(currentIndex) {
117 | navigator.mediaSession.setActionHandler('nexttrack', () => {
118 | currentIndex = (currentIndex + 1) % playlist.length;
119 | updateMetadata(currentIndex);
120 | $audio.pause();
121 | $audio.currentTime = 0;
122 | $audio.src = arraySongs[currentIndex];
123 | $audio.loop = false;
124 | actualButtonPlayActive(currentIndex);
125 | previousTrack(currentIndex);
126 | showTitle(currentIndex);
127 | });
128 | }
129 |
130 | /******************** GLOBAL ********************/
131 | const d = document;
132 | const $ = el => d.querySelector(el);
133 | const $$ = el => d.querySelectorAll(el);
134 | let regExP = /^(?![\s0-9\-_])[\w\s\-]{1,20}(? {
210 | [...$$('.card-pausebutton')].forEach(el => el.classList.add('blocked'));
211 | [...$$('.card-stopbutton')].forEach(el => el.classList.add('blocked'));
212 | [...$$('.card-infinitybutton')].forEach(el => el.classList.add('blocked'));
213 | };
214 |
215 | const generateStars = (totalStars, selector, size, duration) => {
216 | const shadowLayers = [];
217 |
218 | for (let i = 0; i < totalStars; i++) {
219 | const x = Math.floor(Math.random() * 100);
220 | const y = Math.floor(Math.random() * 100);
221 | shadowLayers.push(`
222 | ${x}vw ${y}vh 0 #fff,
223 | ${x}vw ${y + 100}vh 0 #fff
224 | `);
225 | }
226 |
227 | const star = document.querySelector(selector);
228 | star.style.setProperty('--shadow-layer', shadowLayers.join(','));
229 | star.style.setProperty('--size', size);
230 | star.style.setProperty('--duration', duration);
231 | };
232 |
233 | const removeClassBlockedButtonNextSiblings = el => {
234 | [...el.closest('.card-right-buttons').querySelectorAll('button')].forEach(btn =>
235 | btn.classList.remove('blocked')
236 | );
237 | };
238 |
239 | const _removeClassBlockedButtonNextSiblings = index => {
240 | [
241 | ...$$('.card')
242 | [index].querySelector('.card-right-buttons')
243 | .querySelectorAll('button')
244 | ].forEach(btn => btn.classList.remove('blocked'));
245 | };
246 |
247 | const actualButtonPlayActive = (index = 0) => {
248 | let element = $$('.card')[index].querySelector(cardPlayButtonClass);
249 |
250 | [...$$('.card-btn-active')].forEach(el => {
251 | el.classList.remove('card-btn-active');
252 | });
253 | element.classList.add('card-btn-active');
254 |
255 | [...$$('.input-range')].forEach(el => {
256 | el.style.display = 'none';
257 | });
258 | const $inputRange = element.closest('.card').querySelector('.img input');
259 | $inputRange.style.display = 'block';
260 |
261 | setTimeout(() => {
262 | $audio.play();
263 | }, 30);
264 |
265 | $audio.ontimeupdate = function () {
266 | $inputRange.max = Math.floor(this.duration);
267 | $inputRange.value = this.currentTime;
268 | };
269 |
270 | d.addEventListener('input', e => {
271 | if (e.target === $inputRange) {
272 | $audio.currentTime = e.target.value;
273 | $audio.play();
274 | }
275 | });
276 | };
277 |
278 | const toKebabCase = (sentence = '') => {
279 | let words = sentence.trim().split(' ');
280 | return words.length === 1
281 | ? words.join('').toLowerCase()
282 | : words.join('-').toLowerCase();
283 | };
284 |
285 | const putTitle = title => (d.title = `${title}`);
286 |
287 | const showTitle = elIndex => {
288 | putTitle(nameSongs[elIndex]);
289 | };
290 |
291 | const playAllSongs = (songs, selector) => {
292 | if (listNumbersSongs?.length > 0) {
293 | let arrayCards = listNumbersSongs.map(i => $$('.card')[i]);
294 | let arrayColors = listNumbersSongs.map(i => $$('.card')[i].dataset.colorCard);
295 | arrayCards.forEach((card, i) => (card.style.color = arrayColors[i]));
296 | listNumbersSongs = [];
297 | }
298 |
299 | let index = 0;
300 | const $btnsPlay = $$(selector);
301 |
302 | const nextSong = () => {
303 | blockPlayPauseStopBUTTON();
304 |
305 | if (index < songs.length) {
306 | if ($audio.src) {
307 | $audio.pause();
308 | $audio.currentTime = 0;
309 | }
310 | $audio.src = songs[index];
311 | removeClassBlockedButtonNextSiblings($btnsPlay[index]);
312 | showTitle(index);
313 |
314 | actualButtonPlayActive(index);
315 | updateMetadata(index);
316 |
317 | function actualAudio(currentIndex) {
318 | updateMetadata(currentIndex);
319 | blockPlayPauseStopBUTTON();
320 | _removeClassBlockedButtonNextSiblings(currentIndex);
321 | $audio.pause();
322 | $audio.currentTime = 0;
323 | $audio.src = arraySongs[currentIndex];
324 | $audio.loop = false;
325 | actualButtonPlayActive(currentIndex);
326 | showTitle(currentIndex);
327 | }
328 |
329 | function previousTrack(currentIndex) {
330 | navigator.mediaSession.setActionHandler('previoustrack', () => {
331 | index--;
332 | currentIndex = (currentIndex - 1 + playlist.length) % playlist.length;
333 | if (index === -1) index = currentIndex + 1;
334 |
335 | nextTrack(currentIndex);
336 | actualAudio(currentIndex);
337 | });
338 | }
339 |
340 | function nextTrack(currentIndex) {
341 | navigator.mediaSession.setActionHandler('nexttrack', () => {
342 | index++;
343 | currentIndex = (currentIndex + 1) % playlist.length;
344 | previousTrack(currentIndex);
345 | actualAudio(currentIndex);
346 | });
347 | }
348 |
349 | previousTrack(index);
350 | nextTrack(index);
351 |
352 | showTitle(index);
353 | index++;
354 | $audio.onended = nextSong;
355 | } else {
356 | location.reload();
357 | }
358 | };
359 |
360 | nextSong();
361 | };
362 |
363 | const playRandomSongs = (songs, selector) => {
364 | if (listNumbersSongs?.length > 0) {
365 | let arrayCards = listNumbersSongs.map(i => $$('.card')[i]);
366 | let arrayColors = listNumbersSongs.map(i => $$('.card')[i].dataset.colorCard);
367 | arrayCards.forEach((card, i) => (card.style.color = arrayColors[i]));
368 | listNumbersSongs = [];
369 | }
370 |
371 | let unArray = [],
372 | valor;
373 |
374 | for (let i = 0; i < songs.length; i++) {
375 | do {
376 | valor = Math.floor(Math.random() * songs.length);
377 | } while (unArray.includes(valor));
378 |
379 | unArray.push(valor);
380 | }
381 |
382 | let index = 0;
383 | const $btnsPlay = $$(selector);
384 | const nextSong = () => {
385 | blockPlayPauseStopBUTTON();
386 |
387 | if (index < songs.length) {
388 | if ($audio.src) {
389 | $audio.pause();
390 | $audio.currentTime = 0;
391 | }
392 | $audio.src = songs[unArray[index]];
393 | removeClassBlockedButtonNextSiblings($btnsPlay[unArray[index]]);
394 | showTitle(unArray[index]);
395 |
396 | actualButtonPlayActive(unArray[index]);
397 | updateMetadata(unArray[index]);
398 |
399 | function actualAudio(currentIndex) {
400 | $audio.pause();
401 | blockPlayPauseStopBUTTON();
402 | _removeClassBlockedButtonNextSiblings(unArray[currentIndex]);
403 | $audio.currentTime = 0;
404 | $audio.src = arraySongs[unArray[currentIndex]];
405 | $audio.loop = false;
406 | updateMetadata(unArray[currentIndex]);
407 | actualButtonPlayActive(unArray[currentIndex]);
408 | showTitle(unArray[currentIndex]);
409 | }
410 |
411 | function previousTrackOfRandomSongs(currentIndex) {
412 | navigator.mediaSession.setActionHandler('previoustrack', () => {
413 | index--;
414 | currentIndex = (currentIndex - 1 + playlist.length) % playlist.length;
415 | if (index === -1) index = currentIndex + 1;
416 | nextTrackOfRandomSongs(currentIndex);
417 | actualAudio(currentIndex);
418 | });
419 | }
420 |
421 | function nextTrackOfRandomSongs(currentIndex) {
422 | navigator.mediaSession.setActionHandler('nexttrack', () => {
423 | index++;
424 | currentIndex = (currentIndex + 1) % playlist.length;
425 | previousTrackOfRandomSongs(currentIndex);
426 | actualAudio(currentIndex);
427 | });
428 | }
429 |
430 | previousTrackOfRandomSongs(index);
431 | nextTrackOfRandomSongs(index);
432 | index++;
433 | $audio.onended = nextSong;
434 | } else {
435 | location.reload();
436 | }
437 | };
438 |
439 | nextSong();
440 | };
441 |
442 | const removeClassNavButtonActive = () => {
443 | [...$$('.nav-btn-active')].forEach(el => el.classList.remove('nav-btn-active'));
444 | };
445 |
446 | const playSelectedSongs = (songs, selector, listNumber) => {
447 | let index = 0;
448 | const $btnsPlay = $$(selector);
449 |
450 | const nextSong = () => {
451 | blockPlayPauseStopBUTTON();
452 |
453 | if (index < songs.length) {
454 | if ($audio.src) {
455 | $audio.pause();
456 | $audio.currentTime = 0;
457 | }
458 | $audio.src = songs[index];
459 | removeClassBlockedButtonNextSiblings($btnsPlay[listNumber[index]]);
460 | showTitle(listNumber[index]);
461 |
462 | actualButtonPlayActive(listNumber[index]);
463 | updateMetadata(listNumber[index]);
464 |
465 | function actualAudio(currentIndex) {
466 | $audio.pause();
467 | blockPlayPauseStopBUTTON();
468 | _removeClassBlockedButtonNextSiblings(listNumber[currentIndex]);
469 | $audio.currentTime = 0;
470 | $audio.src = arraySongs[listNumber[currentIndex]];
471 | $audio.loop = false;
472 | updateMetadata(listNumber[currentIndex]);
473 | actualButtonPlayActive(listNumber[currentIndex]);
474 | showTitle(listNumber[currentIndex]);
475 | }
476 |
477 | function previousTrackOfSelectedSongs(currentIndex) {
478 | navigator.mediaSession.setActionHandler('previoustrack', () => {
479 | index--;
480 | currentIndex =
481 | (currentIndex - 1 + listNumber.length) % listNumber.length;
482 |
483 | if (index === -1) index = currentIndex + 1;
484 | nextTrackOfSelectedSongs(currentIndex);
485 | actualAudio(currentIndex);
486 | });
487 | }
488 |
489 | function nextTrackOfSelectedSongs(currentIndex) {
490 | navigator.mediaSession.setActionHandler('nexttrack', () => {
491 | index++;
492 | currentIndex = (currentIndex + 1) % listNumber.length;
493 | previousTrackOfSelectedSongs(currentIndex);
494 | actualAudio(currentIndex);
495 | });
496 | }
497 |
498 | previousTrackOfSelectedSongs(index);
499 | nextTrackOfSelectedSongs(index);
500 |
501 | index++;
502 | $audio.onended = nextSong;
503 | } else {
504 | window.history.replaceState(null, null, window.location.pathname);
505 | location.reload();
506 | }
507 | };
508 |
509 | nextSong();
510 | };
511 |
512 | /******************** EXECUTING FUNCTIONS ********************/
513 | generateStars(200, '.star-1', '2px', '20s');
514 |
515 | (function headerCustomProperties() {
516 | const { body } = document;
517 | let numberRandom = Math.floor(Math.random() * Object.keys(headerColors).length);
518 | const [color1, color2, color3, color4] = headerColors[numberRandom];
519 | body.style.setProperty('--color1', color1);
520 | body.style.setProperty('--color2', color2);
521 | body.style.setProperty('--color3', color3);
522 | body.style.setProperty('--color4', color4);
523 | })();
524 |
525 | (function addTitlesToCards() {
526 | [...$$('.card-right-top')].forEach((title, index) => {
527 | if (!nameSongs[index]) {
528 | $$('.card')[index].style.pointerEvents = 'none';
529 | $$('.card')[index].style.opacity = '0.3';
530 | let buttons = $$('.card')[index].querySelector(
531 | '.card-right .card-right-buttons'
532 | );
533 | [...buttons.querySelectorAll('button')].forEach(
534 | el => (el.style.pointerEvents = 'none')
535 | );
536 | [...buttons.querySelectorAll('a')].forEach(el =>
537 | el.classList.remove('pointerEventsActivo')
538 | );
539 | [...buttons.querySelectorAll('.buttonConPointerEvents')].forEach(el =>
540 | el.classList.remove('buttonConPointerEvents')
541 | );
542 | }
543 | title.innerHTML = nameSongs[index] || '';
544 | title.closest('.card').dataset.url = arraySongs[index];
545 | });
546 | })();
547 |
548 | (function addHrefAndDownloads() {
549 | [...$$('.anchor-download')].forEach((el, i) => {
550 | el.href = arraySongs[i] || '';
551 | let nameBandFirstChar = nameBand[0].toUpperCase();
552 | let nameBandComplete = nameBand.substring(1).toLowerCase();
553 | el.download = `${nameBandFirstChar}${nameBandComplete} - ${toCapitalize(
554 | nameSongs[i]
555 | )}.mp3`;
556 | });
557 | })();
558 |
559 | (function getHref() {
560 | localStorage.setItem('formUrl', location.href);
561 | })();
562 |
563 | /******************** EVENT DELEGATION ********************/
564 | d.addEventListener('click', e => {
565 | /******************** EVENT DELEGATION CARDS ********************/
566 | if (e.target.matches(cardPlayButtonClass)) {
567 | if (listNumbersSongs?.length > 0) {
568 | let arrayCards = listNumbersSongs.map(i => $$('.card')[i]);
569 | let arrayColors = listNumbersSongs.map(
570 | i => $$('.card')[i].dataset.colorCard
571 | );
572 | arrayCards.forEach((card, i) => (card.style.color = arrayColors[i]));
573 | listNumbersSongs = [];
574 | }
575 | const arrayPlayButtons = [...$$(cardPlayButtonClass)];
576 |
577 | blockPlayPauseStopBUTTON();
578 | let index = arrayPlayButtons.indexOf(e.target);
579 | _removeClassBlockedButtonNextSiblings(index);
580 |
581 | let audioActual = d.createElement('audio');
582 | audioActual.src = arraySongs[index];
583 |
584 | if (!$audio.src) {
585 | $audio.src = arraySongs[index];
586 | }
587 |
588 | if ($audio.src !== audioActual.src) {
589 | $audio.pause();
590 | $audio.currentTime = 0;
591 | $audio.src = arraySongs[index];
592 | $audio.loop = false;
593 | }
594 |
595 | actualButtonPlayActive(index);
596 | updateMetadata(index);
597 | previousTrack(index);
598 | nextTrack(index);
599 | showTitle(index);
600 |
601 | if ($audio.loop) {
602 | e.target.nextElementSibling.nextElementSibling.nextElementSibling.classList.toggle(
603 | 'card-btn-active'
604 | );
605 | return;
606 | }
607 |
608 | $audio.onended = () => {
609 | index = index = (index + 1) % playlist.length;
610 | const btnPlayNew = arrayPlayButtons[index];
611 | if (index === 0) return;
612 | btnPlayNew.click();
613 | };
614 |
615 | return;
616 | }
617 |
618 | if (e.target.matches(cardPauseButtonClass)) {
619 | $audio.pause();
620 | e.target.previousElementSibling.classList.remove('card-btn-active');
621 | e.target.classList.add('card-btn-active');
622 | return;
623 | }
624 |
625 | if (e.target.matches(cardStopButtonClass)) {
626 | $audio.pause();
627 | $audio.currentTime = 0;
628 | blockPlayPauseStopBUTTON();
629 | e.target.previousElementSibling.previousElementSibling.classList.remove(
630 | 'card-btn-active'
631 | );
632 | return;
633 | }
634 |
635 | if (e.target.matches(cardLoopButtonClass)) {
636 | if ($audio.loop) {
637 | $audio.loop = false;
638 | e.target.classList.remove('card-btn-active');
639 | return;
640 | }
641 | $audio.loop = true;
642 | e.target.classList.add('card-btn-active');
643 | }
644 |
645 | if (e.target.matches(cardPlayListButton)) {
646 | let index = [...$$('.card')].indexOf(e.target.closest('.card'));
647 | let currentNameSong = [...$$('.card')][index].querySelector(
648 | '.card-right-top'
649 | ).innerHTML;
650 | localStorage.setItem('lastCurrentNameSong', currentNameSong);
651 | localStorage.setItem('ultimoCardIndex', index);
652 | RenderPlaylistItems();
653 | $('.am-modal').showModal();
654 | let $tituloModal = $('.tituto-modal');
655 | $tituloModal.innerHTML = `Save ${currentNameSong} in..`;
656 | return;
657 | }
658 |
659 | if (e.target.matches('.cerrar')) {
660 | e.target.parentElement.close();
661 | setTimeout(() => {
662 | $('.am-modal')
663 | .querySelector('.container-add-playlist')
664 | .classList.remove('mode-active');
665 | }, 500);
666 | $('#agregarPlaylistInput').value = '';
667 | updateButtonNavActive($('.am-button-nav-modal.order'), 'button-nav-selected');
668 | return;
669 | }
670 |
671 | if (e.target.matches('.container-add-playlist')) {
672 | e.target.classList.add('mode-active');
673 | d.getElementById('agregarPlaylistInput').focus();
674 | return;
675 | }
676 |
677 | if (e.target.matches('.container-inputs input[type=submit]')) {
678 | let input = e.target.previousElementSibling.previousElementSibling;
679 | let inputValor =
680 | e.target.previousElementSibling.previousElementSibling.value.trim();
681 |
682 | if (comprobeExistThisProperty(inputValor)) {
683 | input.classList.remove('valid');
684 | input.classList.add('invalid');
685 | return;
686 | }
687 |
688 | if (!regExP.test(inputValor) || comprobeExistThisProperty(input)) {
689 | return;
690 | }
691 |
692 | if (!localStorage.getItem('listname-cards')) {
693 | localStorage.setItem(
694 | 'listname-cards',
695 | JSON.stringify({
696 | [`${inputValor}`]: ''
697 | })
698 | );
699 | RenderPlaylistItems();
700 | updateRowsModalAndButtonActive();
701 | input.value = '';
702 | return;
703 | }
704 |
705 | let objectListNameCards = JSON.parse(localStorage.getItem('listname-cards'));
706 | let newObjectListNameCards = JSON.stringify({
707 | ...objectListNameCards,
708 | [`${inputValor}`]: ''
709 | });
710 |
711 | localStorage.setItem('listname-cards', newObjectListNameCards);
712 | RenderPlaylistItems();
713 | updateRowsModalAndButtonActive();
714 | input.value = '';
715 | }
716 |
717 | /******************** EVENT DELEGATION NAV ********************/
718 | if (e.target.matches(navPlayButton)) {
719 | removeClassNavButtonActive();
720 | e.target.classList.add('nav-btn-active');
721 | playAllSongs(arraySongs, cardPlayButtonClass);
722 | return;
723 | }
724 | if (e.target.matches(navRandomButton)) {
725 | removeClassNavButtonActive();
726 | e.target.classList.add('nav-btn-active');
727 | playRandomSongs(arraySongs, cardPlayButtonClass);
728 | return;
729 | }
730 | if (e.target.matches(navMomentaryListButton)) {
731 | listNumbersSongs = [];
732 | $('.tooltip').classList.toggle('tooltip-active');
733 | e.target.classList.add('nav-btn-active');
734 |
735 | if (e.target.classList.contains('nav-btn-active')) {
736 | let allCards = [...$$('.card')];
737 |
738 | removeClassNavButtonActive();
739 | e.target.classList.add('nav-btn-active');
740 | pickCards(allCards, listNumbersSongs);
741 | return;
742 | }
743 |
744 | return;
745 | }
746 | if (e.target.matches(navArrowDownButton)) {
747 | if ($audio.src) {
748 | e.target.classList.add('nav-btn-active');
749 | let arrayButtons = [...$$('.card-playbutton')];
750 | let $btnPlayActive = $('.card-playbutton.card-btn-active');
751 | if (!$btnPlayActive?.closest('.card')) {
752 | return;
753 | }
754 | let indexActual = arrayButtons.indexOf($btnPlayActive) + 1;
755 | e.target.href = `#song-${indexActual}`;
756 |
757 | $btnPlayActive.closest('.card').classList.add('targeado');
758 | setTimeout(() => {
759 | $btnPlayActive.closest('.card').classList.remove('targeado');
760 | e.target.classList.remove('nav-btn-active');
761 | history.replaceState(null, '', location.pathname);
762 | }, 3000);
763 | }
764 | return;
765 | }
766 | });
767 |
768 | d.addEventListener('change', e => {
769 | if (e.target.matches(`input[type=checkbox]`)) {
770 | let currentNameSong = localStorage.getItem('lastCurrentNameSong');
771 | let cardCorriente = [...$$('.card')][localStorage.getItem('ultimoCardIndex')];
772 | let url = cardCorriente.dataset.url;
773 | let currentId = e.target.id;
774 | let objectListNameCards = JSON.parse(localStorage.getItem('listname-cards'));
775 | if (!objectListNameCards) return;
776 | let clase = e.target.getAttribute('data-clase');
777 | let $output = $(`.${clase}`);
778 |
779 | if (e.target.checked) {
780 | let newObject = {
781 | ...objectListNameCards,
782 | [`${currentId}`]: [
783 | ...objectListNameCards[currentId],
784 | [currentNameSong, url]
785 | ]
786 | };
787 |
788 | localStorage.setItem('listname-cards', JSON.stringify(newObject));
789 |
790 | $output.innerHTML = Number($output.innerHTML) + 1;
791 | /* RenderPlaylistItems(); */
792 | return;
793 | }
794 |
795 | let indiceReal = null;
796 | for (let i = 0; i < objectListNameCards[currentId].length; i++) {
797 | if (objectListNameCards[currentId][i][0] === currentNameSong) {
798 | indiceReal = i;
799 | break;
800 | }
801 | }
802 |
803 | let newArrray = objectListNameCards[`${currentId}`].toSpliced(indiceReal, 1);
804 |
805 | let newObject = {
806 | ...objectListNameCards,
807 | [`${currentId}`]: [...newArrray]
808 | };
809 |
810 | localStorage.setItem('listname-cards', JSON.stringify(newObject));
811 | $output.innerHTML = Number($output.innerHTML) - 1;
812 | RenderPlaylistItems();
813 | return;
814 | }
815 | });
816 |
817 | d.addEventListener('input', e => {
818 | if (e.target.matches('#agregarPlaylistInput')) {
819 | let $output = $('.container-inputs output');
820 | $output.innerHTML = e.target.value.length;
821 |
822 | if (e.target.value.length === 0) {
823 | e.target.classList.remove('valid');
824 | e.target.classList.remove('invalid');
825 | return;
826 | }
827 |
828 | if (
829 | regExP.test(e.target.value) &&
830 | !comprobeExistThisProperty(e.target.value)
831 | ) {
832 | e.target.classList.remove('invalid');
833 | e.target.classList.add('valid');
834 | } else {
835 | e.target.classList.remove('valid');
836 | e.target.classList.add('invalid');
837 | }
838 | }
839 | });
840 |
841 | d.addEventListener('keydown', e => {
842 | if (e.target.matches('#agregarPlaylistInput')) {
843 | if (e.key !== 'Enter') return;
844 | let input = e.target;
845 | let inputValor = e.target.value.trim();
846 |
847 | if (comprobeExistThisProperty(inputValor)) {
848 | input.classList.remove('valid');
849 | input.classList.add('invalid');
850 | return;
851 | }
852 |
853 | if (!regExP.test(inputValor) || comprobeExistThisProperty(input)) {
854 | return;
855 | }
856 |
857 | if (!localStorage.getItem('listname-cards')) {
858 | localStorage.setItem(
859 | 'listname-cards',
860 | JSON.stringify({
861 | [`${inputValor}`]: ''
862 | })
863 | );
864 | RenderPlaylistItems();
865 | updateRowsModalAndButtonActive();
866 | input.value = '';
867 | return;
868 | }
869 |
870 | let objectListNameCards = JSON.parse(localStorage.getItem('listname-cards'));
871 | let newObjectListNameCards = JSON.stringify({
872 | ...objectListNameCards,
873 | [`${inputValor}`]: ''
874 | });
875 |
876 | localStorage.setItem('listname-cards', newObjectListNameCards);
877 | RenderPlaylistItems();
878 | updateRowsModalAndButtonActive();
879 | input.value = '';
880 | }
881 | });
882 |
883 | /******************** MODAL FUNCTIONS ********************/
884 |
885 | function existThisSongInSomePlaylist(currentName) {
886 | let nameCurrent = currentName ?? '';
887 | if (localStorage.getItem('listname-cards')) {
888 | let objetoNamePlaylists = JSON.parse(localStorage.getItem('listname-cards'));
889 | let playlistsWhereExistsCurrenName = [];
890 | let namesPlaylists = [];
891 |
892 | for (let property in objetoNamePlaylists) {
893 | namesPlaylists = [...namesPlaylists, property];
894 | }
895 |
896 | for (let i = 0; i < namesPlaylists.length; i++) {
897 | let currentPlaylist = namesPlaylists[i];
898 | let multiArrayCurrent = objetoNamePlaylists[currentPlaylist];
899 |
900 | for (let j = 0; j < multiArrayCurrent.length; j++) {
901 | if (multiArrayCurrent[j].includes(nameCurrent.toString())) {
902 | playlistsWhereExistsCurrenName.push(currentPlaylist);
903 | break;
904 | }
905 | }
906 | }
907 |
908 | return playlistsWhereExistsCurrenName;
909 | }
910 | }
911 |
912 | function RenderPlaylistItems() {
913 | if (localStorage.getItem('listname-cards')) {
914 | let currentName = localStorage.getItem('lastCurrentNameSong');
915 | let objectNames = JSON.parse(localStorage.getItem('listname-cards'));
916 | let $template = $('.template-modal-fila').content;
917 | let $tituloModal = $('.tituto-modal');
918 | $tituloModal.innerHTML = `Save ${currentName} in..`;
919 | let myFragment = d.createDocumentFragment();
920 | let $containerModal = $('.container-modal');
921 | $containerModal.innerHTML = '';
922 | let arrayCorriente = existThisSongInSomePlaylist(currentName);
923 | let guardarKey = null;
924 |
925 | for (let key in objectNames) {
926 | let clon = $template.cloneNode(true);
927 | clon.querySelector('input').id = key;
928 | clon.querySelector('input').dataset.clase = toKebabCase(key);
929 | clon.querySelector('label').setAttribute('for', key);
930 | clon.querySelector('label').innerHTML = key;
931 | clon.querySelector('output').setAttribute('class', toKebabCase(key));
932 | clon.querySelector('output').innerHTML = objectNames[key].length;
933 | if (objectNames[key].length === MAXIMUM_LENGTH_OF_PLAYLIST) {
934 | clon.querySelector('input[type=checkbox]').disabled = 'true';
935 | guardarKey = key;
936 | }
937 | myFragment.appendChild(clon);
938 | }
939 |
940 | $containerModal.appendChild(myFragment);
941 |
942 | if (currentName === objectNames?.[guardarKey]?.[19][0]) {
943 | setTimeout(() => {
944 | let dataclase = toKebabCase(guardarKey);
945 | $containerModal.querySelector(
946 | `input[data-clase=${dataclase}`
947 | ).disabled = false;
948 | }, 100);
949 | }
950 |
951 | for (let i = 0; i < arrayCorriente.length; i++) {
952 | let checkboxCurrent = toKebabCase(arrayCorriente[i]);
953 | let checkboxActual = $containerModal.querySelector(
954 | `[data-clase='${checkboxCurrent}']`
955 | );
956 | checkboxActual.checked = true;
957 | checkboxActual.disabled = false;
958 | }
959 | }
960 | }
961 |
962 | function comprobeExistThisProperty(nameProperty) {
963 | if (localStorage.getItem('listname-cards')) {
964 | let object = JSON.parse(localStorage.getItem('listname-cards'));
965 | return object.hasOwnProperty(nameProperty) ? true : false;
966 | }
967 | }
968 |
969 | d.addEventListener('DOMContentLoaded', () => {
970 | blockPlayPauseStopBUTTON();
971 | putTitle(nameBand);
972 | updateMetadata();
973 | });
974 |
975 | function findDuplicates(array, element) {
976 | let filterArray = array.filter(el => el === element);
977 | return filterArray.length;
978 | }
979 |
980 | (function addDataAttributeColor() {
981 | [...$$('.card')].forEach(el => {
982 | el.dataset.colorCard = getComputedStyle(el).getPropertyValue('color');
983 | });
984 | })();
985 |
986 | function pickCards(allCards, listNumbersSongs) {
987 | d.addEventListener('click', e => {
988 | if (e.target.matches('.card *')) {
989 | let actualCard = e.target.closest('.card');
990 | let index = allCards.indexOf(actualCard);
991 |
992 | if ($('.tooltip').classList.contains('tooltip-active')) {
993 | listNumbersSongs.push(index);
994 |
995 | if (findDuplicates(listNumbersSongs, index) > 1) {
996 | actualCard.style.color = actualCard.dataset.colorCard;
997 | let newArray = listNumbersSongs.filter(el => el !== index);
998 | listNumbersSongs = newArray;
999 | return;
1000 | }
1001 |
1002 | actualCard.style.color = '#fff';
1003 | }
1004 | }
1005 |
1006 | if (e.target.matches('.tooltip')) {
1007 | e.target.classList.remove('tooltip-active');
1008 | $('.nav-list-momentary').classList.remove('nav-btn-active');
1009 | let canciones = listNumbersSongs.map(el => arraySongs[el]);
1010 | playSelectedSongs(canciones, cardPlayButtonClass, listNumbersSongs);
1011 |
1012 | [...$$('.card')].forEach(el => (el.style.color = el.dataset.colorCard));
1013 | listNumbersSongs.forEach(el => {
1014 | [...$$('.card')][el].style.color = '#fff';
1015 | });
1016 | }
1017 | });
1018 | }
1019 |
1020 | /******************** REMOVE ANIMATION VIEW() OF CARDS ********************/
1021 | const cards = document.querySelectorAll('.card');
1022 |
1023 | const observer = new IntersectionObserver(
1024 | (entries, observer) => {
1025 | entries.forEach(entry => {
1026 | if (entry.isIntersecting) {
1027 | entry.target.classList.add('stopped-animation');
1028 | observer.unobserve(entry.target);
1029 | }
1030 | });
1031 | },
1032 | { threshold: 0.5 }
1033 | );
1034 |
1035 | cards.forEach(card => observer.observe(card));
1036 |
1037 | /******************** BUTTON NAV MODAL ********************/
1038 |
1039 | let containerModal = document.querySelector('.container-modal');
1040 |
1041 | function RenderPlaylistItemsOfTheContainerBottom(objectOfCards) {
1042 | const currentName = localStorage.getItem('lastCurrentNameSong');
1043 |
1044 | if (!currentName) return;
1045 |
1046 | const objectNames =
1047 | objectOfCards ?? JSON.parse(localStorage.getItem('listname-cards'));
1048 | const template = $('.template-modal-fila').content;
1049 | const tituloModal = $('.tituto-modal');
1050 | const containerModal = $('.container-modal');
1051 |
1052 | tituloModal.textContent = `Save ${currentName} in..`;
1053 | containerModal.innerHTML = '';
1054 |
1055 | const fragment = d.createDocumentFragment();
1056 | const currentPlaylists = existThisSongInSomePlaylist(currentName);
1057 |
1058 | for (const name in objectNames) {
1059 | const kebabName = toKebabCase(name);
1060 | const playlist = objectNames[name];
1061 | const clone = template.cloneNode(true);
1062 |
1063 | const input = clone.querySelector('input');
1064 | const label = clone.querySelector('label');
1065 | const output = clone.querySelector('output');
1066 |
1067 | input.id = name;
1068 | input.dataset.clase = kebabName;
1069 | input.disabled = playlist.length === MAXIMUM_LENGTH_OF_PLAYLIST;
1070 |
1071 | label.htmlFor = name;
1072 | label.textContent = name;
1073 |
1074 | output.className = kebabName;
1075 | output.textContent = playlist.length;
1076 |
1077 | fragment.appendChild(clone);
1078 | }
1079 |
1080 | containerModal.appendChild(fragment);
1081 |
1082 | currentPlaylists.forEach(name => {
1083 | const checkbox = containerModal.querySelector(
1084 | `[data-clase="${toKebabCase(name)}"]`
1085 | );
1086 | if (checkbox) {
1087 | checkbox.checked = true;
1088 | checkbox.disabled = false;
1089 | }
1090 | });
1091 | }
1092 |
1093 | function updateButtonNavActive(target, classNameToAdd) {
1094 | if (!target.classList.contains(classNameToAdd)) {
1095 | $(`.${classNameToAdd}`).classList.remove(classNameToAdd);
1096 | let timer = setTimeout(() => {
1097 | target.classList.add(classNameToAdd);
1098 | clearTimeout(timer);
1099 | }, 20);
1100 | }
1101 | }
1102 |
1103 | function scrollToTopContainerModal() {
1104 | $('.container-modal').scrollTop = 0;
1105 | }
1106 |
1107 | function scrollToBottomContainerModal() {
1108 | $('.container-modal').scrollTop = $('.container-modal').scrollHeight;
1109 | }
1110 |
1111 | document.addEventListener('click', e => {
1112 | const target = e.target;
1113 | if (target.matches('.am-button-nav-modal')) {
1114 | if (target.matches('.order')) {
1115 | containerModal.innerHTML = '';
1116 |
1117 | updateButtonNavActive(target, 'button-nav-selected');
1118 | scrollToTopContainerModal();
1119 | RenderPlaylistItemsOfTheContainerBottom();
1120 | return;
1121 | }
1122 |
1123 | if (target.matches('.unorder')) {
1124 | containerModal.innerHTML = '';
1125 | updateButtonNavActive(target, 'button-nav-selected');
1126 | scrollToTopContainerModal();
1127 |
1128 | const objectNames = JSON.parse(localStorage.getItem('listname-cards'));
1129 | if (!objectNames) return;
1130 | const reversedObj = Object.entries(objectNames)
1131 | .reverse()
1132 | .reduce((acc, [key, value]) => {
1133 | acc[key] = value;
1134 | return acc;
1135 | }, {});
1136 |
1137 | RenderPlaylistItemsOfTheContainerBottom(reversedObj);
1138 | return;
1139 | }
1140 |
1141 | if (target.matches('.random')) {
1142 | containerModal.innerHTML = '';
1143 | updateButtonNavActive(target, 'button-nav-selected');
1144 | scrollToTopContainerModal();
1145 |
1146 | const objectNames = JSON.parse(localStorage.getItem('listname-cards'));
1147 | if (!objectNames) return;
1148 | const shuffledEntries = Object.entries(objectNames).sort(
1149 | () => Math.random() - 0.5
1150 | );
1151 |
1152 | const shuffledObj = Object.fromEntries(shuffledEntries);
1153 | RenderPlaylistItemsOfTheContainerBottom(shuffledObj);
1154 | return;
1155 | }
1156 |
1157 | if (target.matches('.a-to-z')) {
1158 | containerModal.innerHTML = '';
1159 | updateButtonNavActive(target, 'button-nav-selected');
1160 | scrollToTopContainerModal();
1161 |
1162 | const objectNames = JSON.parse(localStorage.getItem('listname-cards'));
1163 | if (!objectNames) return;
1164 | const sortedEntries = Object.entries(objectNames).sort((a, b) =>
1165 | a[0].localeCompare(b[0])
1166 | );
1167 |
1168 | const sortedObj = Object.fromEntries(sortedEntries);
1169 | RenderPlaylistItemsOfTheContainerBottom(sortedObj);
1170 | return;
1171 | }
1172 |
1173 | if (target.matches('.z-to-a')) {
1174 | containerModal.innerHTML = '';
1175 | updateButtonNavActive(target, 'button-nav-selected');
1176 | scrollToTopContainerModal();
1177 |
1178 | const objectNames = JSON.parse(localStorage.getItem('listname-cards'));
1179 | if (!objectNames) return;
1180 | const sortedEntries = Object.entries(objectNames).sort((a, b) =>
1181 | b[0].localeCompare(a[0])
1182 | );
1183 |
1184 | const sortedObj = Object.fromEntries(sortedEntries);
1185 | RenderPlaylistItemsOfTheContainerBottom(sortedObj);
1186 | return;
1187 | }
1188 | }
1189 | });
1190 |
--------------------------------------------------------------------------------
/playlist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
15 |
19 |
20 |
21 |
22 |
26 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
41 |
42 |
43 | Save the audio in...
44 | ❌
45 |
46 |
50 |
51 |
59 |
60 |
61 |
62 |
63 |
67 |
68 |
69 |
70 |
71 |
79 |
80 |
81 |
82 |
83 |
91 |
92 |
93 |
94 |
95 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 | 0 /20
112 |
113 |
114 |
115 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
Choose and press here
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
203 |
252 |
253 |
254 |
259 |
308 |
309 |
310 |
315 |
364 |
365 |
366 |
371 |
420 |
421 |
422 |
427 |
476 |
477 |
478 |
483 |
532 |
533 |
534 |
539 |
588 |
589 |
590 |
595 |
644 |
645 |
646 |
651 |
700 |
701 |
702 |
707 |
756 |
757 |
758 |
763 |
812 |
813 |
814 |
819 |
868 |
869 |
870 |
875 |
924 |
925 |
926 |
931 |
980 |
981 |
982 |
987 |
1036 |
1037 |
1038 |
1043 |
1088 |
1089 |
1090 |
1095 |
1144 |
1145 |
1146 |
1151 |
1200 |
1201 |
1202 |
1207 |
1256 |
1257 |
1258 |
1263 |
1312 |
1313 |
1314 |
1315 |
1318 |
1319 |
--------------------------------------------------------------------------------