NeoPy commited on
Commit
98d4cf1
·
verified ·
1 Parent(s): a555ac2

Update app.js

Browse files
Files changed (1) hide show
  1. app.js +182 -477
app.js CHANGED
@@ -1,540 +1,245 @@
1
  // ==UserScript==
2
- // @name Dynamic UI/UX Enhancement Suite
3
  // @namespace http://tampermonkey.net/
4
- // @version 1.2.5
5
- // @description Transforms website UI/UX with stylish animations, modern styling, and dynamic interactions
6
- // @author UXMaster
7
- // @match *://*/*
8
- // @exclude *://*.google.com/*
9
- // @exclude *://*.facebook.com/*
10
- // @exclude *://*.youtube.com/*
11
  // @grant GM_addStyle
12
- // @grant GM_getValue
13
- // @grant GM_setValue
14
- // @grant GM_registerMenuCommand
15
  // @run-at document-start
16
- // @icon https://www.example.com/icon.png
17
  // ==/UserScript==
18
 
19
  (function() {
20
  'use strict';
21
 
22
- // Configuration - customizable via ViolentMonkey UI
23
- const config = {
24
- animations: {
25
- enabled: true,
26
- duration: 0.3,
27
- easing: 'cubic-bezier(0.16, 1, 0.3, 1)',
28
- scrollSmooth: true,
29
- hoverEffects: true,
30
- fadeIns: true
31
- },
32
- styling: {
33
- enabled: true,
34
- modernShadows: true,
35
- roundedCorners: true,
36
- vibrantHoverStates: true,
37
- readableText: true,
38
- accentColor: '#6c63ff',
39
- darkMode: false
40
- },
41
- performance: {
42
- lazyLoadImages: true,
43
- intersectionObserverThreshold: 0.1
44
  }
45
- };
46
-
47
- // Initialize the enhancement suite
48
- class DynamicUIEnhancer {
49
- constructor() {
50
- this.elements = new WeakMap();
51
- this.animationFrame = null;
52
- this.observer = null;
53
- this.init();
54
- }
55
-
56
- init() {
57
- // Wait for DOM to be interactive
58
- if (document.readyState === 'loading') {
59
- document.addEventListener('DOMContentLoaded', () => this.startEnhancement());
60
- } else {
61
- this.startEnhancement();
62
- }
63
 
64
- // Setup configuration menu in ViolentMonkey UI
65
- this.setupConfigMenu();
 
 
 
66
  }
67
 
68
- setupConfigMenu() {
69
- try {
70
- GM_registerMenuCommand('Configure UI Enhancer', () => {
71
- this.showConfigDialog();
72
- });
73
- } catch (e) {
74
- console.warn('GM_registerMenuCommand not available, using console config');
75
- }
76
  }
77
 
78
- startEnhancement() {
79
- if (config.styling.enabled) this.applyModernStyling();
80
- if (config.animations.enabled) this.setupAnimations();
81
- this.setupPerformanceOptimizations();
82
- this.setupDynamicInteractions();
83
-
84
- // Handle dynamic content loading
85
- this.setupMutationObserver();
86
  }
87
 
88
- applyModernStyling() {
89
- const css = `
90
- :root {
91
- --accent-color: ${config.styling.accentColor};
92
- --shadow-sm: 0 1px 3px rgba(0,0,0,0.08), 0 1px 2px rgba(0,0,0,0.05);
93
- --shadow-md: 0 4px 6px rgba(0,0,0,0.1), 0 1px 3px rgba(0,0,0,0.08);
94
- --shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -2px rgba(0,0,0,0.05);
95
- --transition: all ${config.animations.duration}s ${config.animations.easing};
96
- --radius-sm: 4px;
97
- --radius-md: 8px;
98
- --radius-lg: 12px;
99
- --radius-full: 9999px;
100
- }
101
-
102
- * {
103
- transition: background-color 0.2s ease, color 0.2s ease !important;
104
- }
105
-
106
- body {
107
- ${config.styling.readableText ? `
108
- line-height: 1.6;
109
- color: ${config.styling.darkMode ? '#e0e0e0' : '#333'};
110
- background: ${config.styling.darkMode ? '#1a1a1a' : '#fafafa'};
111
- ` : ''}
112
- }
113
-
114
- button, .button, input[type="submit"], input[type="button"],
115
- a.button, a.btn, .btn, .button-like {
116
- ${config.styling.modernShadows ? 'box-shadow: var(--shadow-sm);' : ''}
117
- ${config.styling.roundedCorners ? 'border-radius: var(--radius-md);' : ''}
118
- background: var(--accent-color);
119
- color: white;
120
- border: none;
121
- padding: 8px 16px;
122
- cursor: pointer;
123
- font-weight: 500;
124
- transition: var(--transition) !important;
125
- position: relative;
126
- overflow: hidden;
127
- }
128
-
129
- button:hover, .button:hover, input[type="submit"]:hover,
130
- input[type="button"]:hover, a.button:hover, a.btn:hover,
131
- .btn:hover, .button-like:hover {
132
- transform: translateY(-2px);
133
- ${config.styling.modernShadows ? 'box-shadow: var(--shadow-md);' : ''}
134
- ${config.styling.vibrantHoverStates ? `
135
- background: linear-gradient(135deg, var(--accent-color), #4a44ff);
136
- ` : ''}
137
- }
138
-
139
- button:active, .button:active {
140
- transform: translateY(0);
141
- }
142
-
143
- button::after {
144
- content: '';
145
- position: absolute;
146
- top: 0;
147
- left: -100%;
148
- width: 100%;
149
- height: 100%;
150
- background: rgba(255,255,255,0.2);
151
- transition: left ${config.animations.duration}s ease;
152
- }
153
-
154
- button:hover::after {
155
- left: 100%;
156
- }
157
-
158
- input[type="text"], input[type="email"], input[type="password"],
159
- textarea, select {
160
- ${config.styling.modernShadows ? 'box-shadow: var(--shadow-sm);' : ''}
161
- ${config.styling.roundedCorners ? 'border-radius: var(--radius-sm);' : ''}
162
- border: 1px solid #ddd;
163
- padding: 8px 12px;
164
- transition: var(--transition) !important;
165
- }
166
-
167
- input[type="text"]:focus, input[type="email"]:focus,
168
- input[type="password"]:focus, textarea:focus, select:focus {
169
- outline: none;
170
- border-color: var(--accent-color);
171
- ${config.styling.modernShadows ? 'box-shadow: 0 0 0 3px rgba(108, 99, 255, 0.2);' : ''}
172
- }
173
 
174
- .card, .panel, .box, .container {
175
- ${config.styling.modernShadows ? 'box-shadow: var(--shadow-sm);' : ''}
176
- ${config.styling.roundedCorners ? 'border-radius: var(--radius-md);' : ''}
177
- background: ${config.styling.darkMode ? '#2d2d2d' : 'white'};
178
- transition: var(--transition) !important;
179
- }
180
 
181
- .card:hover, .panel:hover {
182
- ${config.styling.modernShadows ? 'box-shadow: var(--shadow-md);' : ''}
183
- }
 
184
 
185
- a {
186
- color: var(--accent-color);
187
- text-decoration: none;
188
- transition: var(--transition) !important;
189
- }
190
 
191
- a:hover {
192
- text-decoration: underline;
193
- color: #4a44ff;
194
- }
 
 
195
 
196
- .fade-in {
197
- opacity: 0;
198
- transform: translateY(20px);
199
- animation: fadeInUp ${config.animations.duration * 1.5}s ${config.animations.easing} forwards;
200
- }
201
 
202
- @keyframes fadeInUp {
203
- to {
204
- opacity: 1;
205
- transform: translateY(0);
206
- }
207
- }
208
- `;
209
 
210
- GM_addStyle(css);
 
 
211
  }
212
 
213
- setupAnimations() {
214
- if (config.animations.scrollSmooth) {
215
- document.documentElement.style.scrollBehavior = 'smooth';
216
- }
 
 
217
 
218
- if (config.animations.fadeIns) {
219
- this.setupFadeInAnimations();
220
- }
 
221
 
222
- if (config.animations.hoverEffects) {
223
- this.setupHoverEffects();
224
- }
 
 
225
  }
226
 
227
- setupFadeInAnimations() {
228
- const animateElements = () => {
229
- const elements = document.querySelectorAll(`
230
- .card, .panel, .box, article, section, header, footer,
231
- nav, .menu, .list-item, .grid-item, .product, .post,
232
- .comment, .card-container, .widget, .feature, .testimonial
233
- `);
234
-
235
- elements.forEach(element => {
236
- if (!this.elements.has(element)) {
237
- this.elements.set(element, {
238
- animated: false,
239
- observer: null
240
- });
241
- }
242
-
243
- const elementData = this.elements.get(element);
244
- if (!elementData.animated) {
245
- const rect = element.getBoundingClientRect();
246
- if (rect.top < window.innerHeight * 1.2 && rect.bottom > -rect.height * 0.2) {
247
- element.classList.add('fade-in');
248
- elementData.animated = true;
249
- }
250
- }
251
- });
252
- };
253
-
254
- // Initial animation
255
- animateElements();
256
-
257
- // Animation on scroll
258
- window.addEventListener('scroll', () => {
259
- if (this.animationFrame) return;
260
- this.animationFrame = requestAnimationFrame(() => {
261
- animateElements();
262
- this.animationFrame = null;
263
- });
264
- });
265
 
266
- // Recheck on window resize
267
- window.addEventListener('resize', animateElements);
 
268
  }
269
 
270
- setupHoverEffects() {
271
- document.addEventListener('mouseover', (e) => {
272
- const target = e.target;
273
- if (target.matches('button, .button, a.button, .btn, .card, .panel, .box, .menu-item, .nav-link')) {
274
- target.style.transform = 'translateY(-2px)';
275
- }
276
- }, true);
277
 
278
- document.addEventListener('mouseout', (e) => {
279
- const target = e.target;
280
- if (target.matches('button, .button, a.button, .btn, .card, .panel, .box, .menu-item, .nav-link')) {
281
- target.style.transform = 'translateY(0)';
282
- }
283
- }, true);
284
  }
285
 
286
- setupPerformanceOptimizations() {
287
- if (config.performance.lazyLoadImages) {
288
- this.setupLazyLoading();
 
 
 
 
 
289
  }
290
  }
291
 
292
- setupLazyLoading() {
293
- const lazyImages = document.querySelectorAll('img[data-src], img.lazy');
294
- if (lazyImages.length === 0) return;
295
-
296
- const lazyLoad = (entries, observer) => {
297
- entries.forEach(entry => {
298
- if (entry.isIntersecting) {
299
- const img = entry.target;
300
- const src = img.dataset.src || img.src;
301
- img.src = src;
302
- img.classList.remove('lazy');
303
- img.removeAttribute('data-src');
304
- observer.unobserve(img);
305
- }
306
- });
307
- };
308
-
309
- this.observer = new IntersectionObserver(lazyLoad, {
310
- rootMargin: '50px 0px',
311
- threshold: config.performance.intersectionObserverThreshold
312
- });
313
-
314
- lazyImages.forEach(img => {
315
- this.observer.observe(img);
316
- });
317
  }
318
 
319
- setupDynamicInteractions() {
320
- // Micro-interactions for buttons and inputs
321
- document.addEventListener('click', (e) => {
322
- const target = e.target;
323
- if (target.matches('button, .button, a.button, .btn')) {
324
- this.createRippleEffect(target, e);
325
- }
326
- }, true);
327
-
328
- // Form interactions
329
- document.addEventListener('focusin', (e) => {
330
- const target = e.target;
331
- if (target.matches('input, textarea, select')) {
332
- target.parentElement?.classList?.add('focused');
333
- }
334
- });
335
-
336
- document.addEventListener('focusout', (e) => {
337
- const target = e.target;
338
- if (target.matches('input, textarea, select')) {
339
- target.parentElement?.classList?.remove('focused');
340
- }
341
- });
342
  }
343
 
344
- createRippleEffect(element, event) {
345
- const rect = element.getBoundingClientRect();
346
- const size = Math.max(rect.width, rect.height);
347
- const x = event.clientX - rect.left - size / 2;
348
- const y = event.clientY - rect.top - size / 2;
349
-
350
- const ripple = document.createElement('span');
351
- ripple.style.cssText = `
352
- position: absolute;
353
- width: ${size}px;
354
- height: ${size}px;
355
- left: ${x}px;
356
- top: ${y}px;
357
- border-radius: 50%;
358
- background: rgba(255,255,255,0.3);
359
- transform: scale(0);
360
- animation: ripple ${config.animations.duration}s ease-out forwards;
361
- pointer-events: none;
362
- z-index: 1;
363
- `;
364
-
365
- element.style.overflow = 'hidden';
366
- element.style.position = 'relative';
367
- element.appendChild(ripple);
368
 
369
- setTimeout(() => {
370
- ripple.remove();
371
- }, config.animations.duration * 1000 + 100);
372
  }
 
373
 
374
- setupMutationObserver() {
375
- const observer = new MutationObserver((mutations) => {
376
- mutations.forEach(mutation => {
377
- if (mutation.type === 'childList') {
378
- mutation.addedNodes.forEach(node => {
379
- if (node.nodeType === 1) { // Element node
380
- this.enhanceNewElements(node);
381
- }
382
- });
383
- }
384
- });
385
  });
386
-
387
- observer.observe(document.body, {
388
- childList: true,
389
- subtree: true
390
  });
391
- }
392
-
393
- enhanceNewElements(element) {
394
- // Apply styling to new elements
395
- if (element.querySelectorAll) {
396
- const buttons = element.querySelectorAll('button, .button, .btn');
397
- buttons.forEach(btn => {
398
- if (!btn.dataset.enhanced) {
399
- btn.dataset.enhanced = 'true';
400
- // Add hover effects
401
- btn.addEventListener('mouseenter', () => {
402
- btn.style.transform = 'translateY(-2px)';
403
- });
404
- btn.addEventListener('mouseleave', () => {
405
- btn.style.transform = 'translateY(0)';
406
- });
407
- }
408
- });
409
-
410
- // Apply fade-in to new cards/containers
411
- const containers = element.querySelectorAll('.card, .panel, .box');
412
- containers.forEach(container => {
413
- if (!container.dataset.enhanced) {
414
- container.dataset.enhanced = 'true';
415
- container.classList.add('fade-in');
416
- }
417
- });
418
- }
419
- }
420
 
421
- showConfigDialog() {
422
- const dialog = document.createElement('div');
423
- dialog.style.cssText = `
424
- position: fixed;
425
- top: 50%;
426
- left: 50%;
427
- transform: translate(-50%, -50%);
428
- background: white;
429
- border-radius: 12px;
430
- box-shadow: 0 20px 25px -5px rgba(0,0,0,0.1), 0 10px 10px -5px rgba(0,0,0,0.04);
431
- z-index: 99999;
432
- padding: 24px;
433
- max-width: 500px;
434
- width: 90%;
435
- max-height: 80vh;
436
- overflow-y: auto;
437
- `;
438
-
439
- dialog.innerHTML = `
440
- <h2 style="margin-top: 0; color: #333;">UI/UX Enhancement Settings</h2>
441
- <div style="margin-bottom: 20px;">
442
- <label style="display: block; margin-bottom: 8px;">
443
- <input type="checkbox" id="animations-enabled" ${config.animations.enabled ? 'checked' : ''}>
444
- Enable Animations
445
- </label>
446
- <label style="display: block; margin-bottom: 8px;">
447
- <input type="checkbox" id="styling-enabled" ${config.styling.enabled ? 'checked' : ''}>
448
- Enable Modern Styling
449
- </label>
450
- <label style="display: block; margin-bottom: 8px;">
451
- <input type="color" id="accent-color" value="${config.styling.accentColor}" style="width: 50px; vertical-align: middle;">
452
- Accent Color
453
- </label>
454
- </div>
455
- <button id="save-config" style="background: #6c63ff; color: white; border: none; padding: 8px 16px; border-radius: 6px; cursor: pointer;">
456
- Save & Apply
457
- </button>
458
- <button id="reset-config" style="background: #e5e7eb; color: #333; border: none; padding: 8px 16px; border-radius: 6px; margin-left: 8px; cursor: pointer;">
459
- Reset to Defaults
460
- </button>
461
- `;
462
-
463
- document.body.appendChild(dialog);
464
-
465
- document.getElementById('save-config').addEventListener('click', () => {
466
- config.animations.enabled = document.getElementById('animations-enabled').checked;
467
- config.styling.enabled = document.getElementById('styling-enabled').checked;
468
- config.styling.accentColor = document.getElementById('accent-color').value;
469
-
470
- // Reinitialize with new config
471
- this.reinitialize();
472
- dialog.remove();
473
  });
474
-
475
- document.getElementById('reset-config').addEventListener('click', () => {
476
- // Reset to defaults
477
- Object.assign(config, {
478
- animations: { enabled: true, duration: 0.3, easing: 'cubic-bezier(0.16, 1, 0.3, 1)', scrollSmooth: true, hoverEffects: true, fadeIns: true },
479
- styling: { enabled: true, modernShadows: true, roundedCorners: true, vibrantHoverStates: true, readableText: true, accentColor: '#6c63ff', darkMode: false }
480
- });
481
- this.reinitialize();
482
- dialog.remove();
483
  });
484
-
485
- // Close dialog on outside click
486
- dialog.addEventListener('click', (e) => {
487
- if (e.target === dialog) {
488
- dialog.remove();
489
- }
 
 
 
490
  });
491
  }
492
 
493
- reinitialize() {
494
- // Clear existing styles and reapply
495
- const existingStyles = document.querySelectorAll('style[data-enhancer]');
496
- existingStyles.forEach(style => style.remove());
497
-
498
- // Reapply styling
499
- this.applyModernStyling();
500
-
501
- // Reapply animations to visible elements
502
- if (config.animations.enabled) {
503
- this.setupAnimations();
504
- }
505
-
506
- // Show notification
507
- this.showNotification('Settings applied successfully!');
508
- }
509
 
510
- showNotification(message) {
511
- const notification = document.createElement('div');
512
- notification.style.cssText = `
513
- position: fixed;
514
- bottom: 20px;
515
- right: 20px;
516
- background: #4CAF50;
517
- color: white;
518
- padding: 12px 24px;
519
- border-radius: 8px;
520
- box-shadow: 0 4px 6px rgba(0,0,0,0.1);
521
- z-index: 99999;
522
- animation: slideIn 0.3s ease, fadeOut 0.5s ease 2.5s forwards;
523
- `;
524
- notification.innerHTML = `<strong>✓</strong> ${message}`;
525
- document.body.appendChild(notification);
526
 
 
 
 
 
527
  setTimeout(() => {
528
- notification.remove();
529
- }, 3000);
530
  }
531
  }
532
 
533
- // Initialize the enhancer
534
- const uiEnhancer = new DynamicUIEnhancer();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
535
 
536
- // Expose for debugging and external access
537
- window.UIEnhancer = uiEnhancer;
538
- console.log('Dynamic UI/UX Enhancement Suite loaded successfully!');
539
 
 
540
  })();
 
1
  // ==UserScript==
2
+ // @name Spotify Dynamic UI/UX Animations
3
  // @namespace http://tampermonkey.net/
4
+ // @version 1.2
5
+ // @description Enhances Spotify web player with stylish dynamic animations for a premium UI/UX experience
6
+ // @author UI/UX Enthusiast
7
+ // @match https://open.spotify.com/*
8
+ // @icon https://www.spotify.com/favicon.ico
 
 
9
  // @grant GM_addStyle
 
 
 
10
  // @run-at document-start
 
11
  // ==/UserScript==
12
 
13
  (function() {
14
  'use strict';
15
 
16
+ // Custom CSS animations and transitions
17
+ GM_addStyle(`
18
+ /* Global smooth transitions */
19
+ * {
20
+ transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1) !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
+ /* Enhanced buttons with hover effects */
24
+ .Button-sc-1dqy6sn-0, .ButtonInner-sc-1dqy6sn-1 {
25
+ transform: scale(1) !important;
26
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2) !important;
27
+ transition: transform 0.2s ease, box-shadow 0.2s ease, background-color 0.3s ease !important;
28
  }
29
 
30
+ .Button-sc-1dqy6sn-0:hover, .ButtonInner-sc-1dqy6sn-1:hover {
31
+ transform: scale(1.05) !important;
32
+ box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3) !important;
33
+ filter: brightness(1.1) !important;
 
 
 
 
34
  }
35
 
36
+ /* Floating action buttons */
37
+ .Button-sc-1dqy6sn-0.Lsg1a0PdZMXQ3vQZlE0_M {
38
+ animation: pulse 2s infinite !important;
 
 
 
 
 
39
  }
40
 
41
+ /* Card hover effects */
42
+ .Card-sc-1uyc430-0 {
43
+ transform: translateY(0) !important;
44
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important;
45
+ transition: transform 0.3s ease, box-shadow 0.3s ease !important;
46
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
+ .Card-sc-1uyc430-0:hover {
49
+ transform: translateY(-5px) !important;
50
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.25) !important;
51
+ z-index: 100 !important;
52
+ }
 
53
 
54
+ /* Now playing bar animations */
55
+ .now-playing-bar {
56
+ transition: transform 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55) !important;
57
+ }
58
 
59
+ .now-playing-bar:hover {
60
+ transform: translateY(-3px) !important;
61
+ box-shadow: 0 -5px 20px rgba(0, 0, 0, 0.2) !important;
62
+ }
 
63
 
64
+ /* Album art hover effects */
65
+ .cover-art-image {
66
+ transition: transform 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275),
67
+ box-shadow 0.4s ease !important;
68
+ transform-origin: center !important;
69
+ }
70
 
71
+ .cover-art-image:hover {
72
+ transform: scale(1.1) rotate(2deg) !important;
73
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4) !important;
74
+ z-index: 1000 !important;
75
+ }
76
 
77
+ /* Text animations */
78
+ .Type__TypeElement-sc-goli3j-0 {
79
+ opacity: 0.9 !important;
80
+ transform: translateY(5px) !important;
81
+ transition: opacity 0.3s ease, transform 0.3s ease !important;
82
+ }
 
83
 
84
+ .Type__TypeElement-sc-goli3j-0:hover {
85
+ opacity: 1 !important;
86
+ transform: translateY(0) !important;
87
  }
88
 
89
+ /* Progress bar enhancements */
90
+ .progress-bar__slider {
91
+ width: 16px !important;
92
+ height: 16px !important;
93
+ transition: all 0.2s ease !important;
94
+ }
95
 
96
+ .progress-bar__slider:hover {
97
+ transform: scale(1.3) !important;
98
+ box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.8) !important;
99
+ }
100
 
101
+ /* Menu animations */
102
+ .menu-container {
103
+ opacity: 0 !important;
104
+ transform: translateY(10px) !important;
105
+ transition: opacity 0.2s ease, transform 0.2s ease !important;
106
  }
107
 
108
+ .menu-container.show {
109
+ opacity: 1 !important;
110
+ transform: translateY(0) !important;
111
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
+ /* Volume control slider */
114
+ .volume-bar__slider {
115
+ transition: transform 0.2s ease, box-shadow 0.2s ease !important;
116
  }
117
 
118
+ .volume-bar__slider:hover {
119
+ transform: scale(1.2) !important;
120
+ box-shadow: 0 0 8px rgba(255, 255, 255, 0.7) !important;
121
+ }
 
 
 
122
 
123
+ /* Keyframes for animations */
124
+ @keyframes pulse {
125
+ 0% { transform: scale(1); box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.4); }
126
+ 70% { transform: scale(1.05); box-shadow: 0 0 0 10px rgba(255, 255, 255, 0); }
127
+ 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(255, 255, 255, 0); }
 
128
  }
129
 
130
+ @keyframes fadeInUp {
131
+ from {
132
+ opacity: 0;
133
+ transform: translateY(20px);
134
+ }
135
+ to {
136
+ opacity: 1;
137
+ transform: translateY(0);
138
  }
139
  }
140
 
141
+ @keyframes shimmer {
142
+ 0% { background-position: -1000px 0; }
143
+ 100% { background-position: 1000px 0; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  }
145
 
146
+ /* Loading animations */
147
+ .loading-shimmer {
148
+ background: linear-gradient(90deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0.2) 50%, rgba(255,255,255,0.1) 100%);
149
+ background-size: 1000px 100%;
150
+ animation: shimmer 2s infinite linear !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  }
152
 
153
+ /* Enhanced sidebar transitions */
154
+ .sidebar {
155
+ transition: transform 0.4s cubic-bezier(0.23, 1, 0.32, 1) !important;
156
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
 
158
+ .sidebar:hover {
159
+ transform: translateX(5px) !important;
 
160
  }
161
+ `);
162
 
163
+ // JavaScript animations and interactions
164
+ function enhanceAnimations() {
165
+ // Enhanced hover effects for cards
166
+ document.querySelectorAll('.Card-sc-1uyc430-0').forEach(card => {
167
+ card.addEventListener('mouseenter', () => {
168
+ card.style.zIndex = '100';
 
 
 
 
 
169
  });
170
+ card.addEventListener('mouseleave', () => {
171
+ card.style.zIndex = '1';
 
 
172
  });
173
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
 
175
+ // Dynamic album art effects
176
+ document.querySelectorAll('.cover-art-image').forEach(cover => {
177
+ cover.addEventListener('mouseenter', () => {
178
+ cover.style.zIndex = '1000';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
  });
180
+ cover.addEventListener('mouseleave', () => {
181
+ cover.style.zIndex = '1';
 
 
 
 
 
 
 
182
  });
183
+ });
184
+
185
+ // Enhanced progress bar
186
+ const progressBar = document.querySelector('.progress-bar');
187
+ if (progressBar) {
188
+ progressBar.addEventListener('click', (e) => {
189
+ const rect = progressBar.getBoundingClientRect();
190
+ const percent = (e.clientX - rect.left) / rect.width;
191
+ animateProgressBar(percent);
192
  });
193
  }
194
 
195
+ // Animation for new elements added to DOM
196
+ const observer = new MutationObserver((mutations) => {
197
+ mutations.forEach(mutation => {
198
+ if (mutation.addedNodes.length) {
199
+ applyEnterAnimations(mutation.addedNodes);
200
+ }
201
+ });
202
+ });
 
 
 
 
 
 
 
 
203
 
204
+ observer.observe(document.body, {
205
+ childList: true,
206
+ subtree: true
207
+ });
208
+ }
 
 
 
 
 
 
 
 
 
 
 
209
 
210
+ function animateProgressBar(percent) {
211
+ const slider = document.querySelector('.progress-bar__slider');
212
+ if (slider) {
213
+ slider.style.transform = 'scale(1.5)';
214
  setTimeout(() => {
215
+ slider.style.transform = 'scale(1)';
216
+ }, 300);
217
  }
218
  }
219
 
220
+ function applyEnterAnimations(nodes) {
221
+ Array.from(nodes).forEach(node => {
222
+ if (node.nodeType === 1 && node.classList.contains('Card-sc-1uyc430-0')) {
223
+ node.style.animation = 'fadeInUp 0.4s ease forwards';
224
+ node.style.opacity = '0';
225
+ node.style.transform = 'translateY(20px)';
226
+ setTimeout(() => {
227
+ node.style.opacity = '1';
228
+ node.style.transform = 'translateY(0)';
229
+ }, 10);
230
+ }
231
+ });
232
+ }
233
+
234
+ // Initialize animations when DOM is ready
235
+ if (document.readyState === 'loading') {
236
+ document.addEventListener('DOMContentLoaded', enhanceAnimations);
237
+ } else {
238
+ enhanceAnimations();
239
+ }
240
 
241
+ // Periodic animation refresh for dynamic content
242
+ setInterval(enhanceAnimations, 2000);
 
243
 
244
+ console.log('Spotify Dynamic UI/UX Animations loaded successfully!');
245
  })();