snow-flow 3.4.35 → 3.4.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +412 -287
- package/dist/cli/deploy-artifact.js +2 -2
- package/dist/mcp/servicenow-deployment-mcp.js +1 -1
- package/dist/mcp/servicenow-mcp-server.js +2 -2
- package/dist/mcp/shared/mcp-logger.js +6 -12
- package/dist/queen/agent-factory.js +134 -52
- package/dist/queen/servicenow-queen.d.ts +127 -2
- package/dist/queen/servicenow-queen.js +978 -618
- package/dist/services/widget-deployment-service.d.ts +1 -1
- package/dist/services/widget-deployment-service.js +1 -1
- package/dist/templates/claude-md-template.d.ts +1 -1
- package/dist/templates/claude-md-template.js +2 -2
- package/dist/types/servicenow.types.d.ts +1 -1
- package/dist/utils/dependency-detector.d.ts +1 -1
- package/dist/utils/dependency-detector.js +1 -1
- package/dist/utils/servicenow-client.d.ts +1 -1
- package/dist/utils/servicenow-client.js +4 -8
- package/package.json +1 -1
- package/website/components/README.md +419 -0
- package/website/components/code-display/CodeDisplay.css +583 -0
- package/website/components/code-display/CodeDisplay.html +200 -0
- package/website/components/code-display/CodeDisplay.js +375 -0
- package/website/components/code-display/CodeDisplay.jsx +268 -0
- package/website/components/demo/ComponentLibraryDemo.html +845 -0
- package/website/components/feature-cards/FeatureCards.css +573 -0
- package/website/components/feature-cards/FeatureCards.html +247 -0
- package/website/components/feature-cards/FeatureCards.js +382 -0
- package/website/components/feature-cards/FeatureCards.jsx +235 -0
- package/website/components/hero/Hero.css +558 -0
- package/website/components/hero/Hero.html +98 -0
- package/website/components/hero/Hero.js +415 -0
- package/website/components/hero/Hero.jsx +214 -0
- package/website/components/interactive/InteractiveElements.css +776 -0
- package/website/components/interactive/InteractiveElements.html +283 -0
- package/website/components/interactive/InteractiveElements.js +489 -0
- package/website/components/interactive/InteractiveElements.jsx +444 -0
- package/website/components/layout/LayoutComponents.css +697 -0
- package/website/components/layout/LayoutComponents.html +374 -0
- package/website/components/layout/LayoutComponents.js +447 -0
- package/website/components/layout/LayoutComponents.jsx +379 -0
- package/website/components/navigation/Navigation.css +383 -0
- package/website/components/navigation/Navigation.html +89 -0
- package/website/components/navigation/Navigation.js +248 -0
- package/website/components/navigation/Navigation.jsx +124 -0
- package/website/css/animations.css +854 -0
- package/website/css/style.css +916 -948
- package/website/index.html +394 -424
- package/website/js/animations.js +707 -0
- package/website/js/main.js +310 -383
- package/website/mcp-servers.html +310 -0
|
@@ -0,0 +1,707 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SNOW-FLOW ADVANCED ANIMATION SYSTEM
|
|
3
|
+
* Sophisticated animations and interactions using modern APIs
|
|
4
|
+
* Optimized for performance with IntersectionObserver
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
class SnowFlowAnimations {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.init();
|
|
10
|
+
this.observers = [];
|
|
11
|
+
this.animationQueue = [];
|
|
12
|
+
this.isAnimating = false;
|
|
13
|
+
this.scrollProgress = 0;
|
|
14
|
+
this.lastScrollPosition = 0;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
init() {
|
|
18
|
+
// Wait for DOM to be ready
|
|
19
|
+
if (document.readyState === 'loading') {
|
|
20
|
+
document.addEventListener('DOMContentLoaded', () => this.setupAnimations());
|
|
21
|
+
} else {
|
|
22
|
+
this.setupAnimations();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
setupAnimations() {
|
|
27
|
+
this.createScrollProgress();
|
|
28
|
+
this.setupScrollAnimations();
|
|
29
|
+
this.setupParallaxEffects();
|
|
30
|
+
this.setupHoverAnimations();
|
|
31
|
+
this.setupLoadingAnimations();
|
|
32
|
+
this.setupMicroInteractions();
|
|
33
|
+
this.setupBackgroundAnimations();
|
|
34
|
+
this.setupPerformanceOptimizations();
|
|
35
|
+
this.handleReducedMotion();
|
|
36
|
+
|
|
37
|
+
// Initialize on load
|
|
38
|
+
window.addEventListener('load', () => {
|
|
39
|
+
this.triggerEntranceAnimations();
|
|
40
|
+
this.optimizeAnimations();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
console.log('🎭 Snow-Flow Animation System Initialized');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* SCROLL PROGRESS INDICATOR
|
|
48
|
+
*/
|
|
49
|
+
createScrollProgress() {
|
|
50
|
+
// Create progress bar element
|
|
51
|
+
const progressBar = document.createElement('div');
|
|
52
|
+
progressBar.className = 'scroll-progress';
|
|
53
|
+
progressBar.innerHTML = '<div class="scroll-progress-fill"></div>';
|
|
54
|
+
document.body.appendChild(progressBar);
|
|
55
|
+
|
|
56
|
+
const progressFill = progressBar.querySelector('.scroll-progress-fill');
|
|
57
|
+
|
|
58
|
+
// Update progress on scroll
|
|
59
|
+
const updateProgress = () => {
|
|
60
|
+
const winScroll = document.body.scrollTop || document.documentElement.scrollTop;
|
|
61
|
+
const height = document.documentElement.scrollHeight - document.documentElement.clientHeight;
|
|
62
|
+
const scrolled = (winScroll / height) * 100;
|
|
63
|
+
|
|
64
|
+
progressFill.style.width = `${scrolled}%`;
|
|
65
|
+
this.scrollProgress = scrolled;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// Throttled scroll listener
|
|
69
|
+
let ticking = false;
|
|
70
|
+
window.addEventListener('scroll', () => {
|
|
71
|
+
if (!ticking) {
|
|
72
|
+
requestAnimationFrame(() => {
|
|
73
|
+
updateProgress();
|
|
74
|
+
ticking = false;
|
|
75
|
+
});
|
|
76
|
+
ticking = true;
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* SCROLL ANIMATIONS WITH INTERSECTION OBSERVER
|
|
83
|
+
*/
|
|
84
|
+
setupScrollAnimations() {
|
|
85
|
+
// Enhanced intersection observer options
|
|
86
|
+
const observerOptions = {
|
|
87
|
+
root: null,
|
|
88
|
+
rootMargin: '-50px 0px -100px 0px',
|
|
89
|
+
threshold: [0.1, 0.3, 0.5, 0.7, 1.0]
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// Main scroll animation observer
|
|
93
|
+
const scrollObserver = new IntersectionObserver((entries) => {
|
|
94
|
+
entries.forEach(entry => {
|
|
95
|
+
const element = entry.target;
|
|
96
|
+
const intersectionRatio = entry.intersectionRatio;
|
|
97
|
+
|
|
98
|
+
if (entry.isIntersecting) {
|
|
99
|
+
// Add reveal class with stagger timing
|
|
100
|
+
const delay = this.calculateStaggerDelay(element);
|
|
101
|
+
setTimeout(() => {
|
|
102
|
+
element.classList.add('revealed');
|
|
103
|
+
this.triggerCustomAnimation(element);
|
|
104
|
+
}, delay);
|
|
105
|
+
|
|
106
|
+
// Progressive reveal based on intersection ratio
|
|
107
|
+
element.style.opacity = Math.min(intersectionRatio * 2, 1);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}, observerOptions);
|
|
111
|
+
|
|
112
|
+
// Observe scroll reveal elements
|
|
113
|
+
const scrollElements = document.querySelectorAll([
|
|
114
|
+
'.scroll-reveal',
|
|
115
|
+
'.scroll-reveal-left',
|
|
116
|
+
'.scroll-reveal-right',
|
|
117
|
+
'.feature',
|
|
118
|
+
'.mcp-card',
|
|
119
|
+
'.what-is-card',
|
|
120
|
+
'.workflow-step',
|
|
121
|
+
'.example-card',
|
|
122
|
+
'.practice'
|
|
123
|
+
].join(','));
|
|
124
|
+
|
|
125
|
+
scrollElements.forEach(el => {
|
|
126
|
+
el.classList.add('gpu-accelerated');
|
|
127
|
+
scrollObserver.observe(el);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
this.observers.push(scrollObserver);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* PARALLAX EFFECTS
|
|
135
|
+
*/
|
|
136
|
+
setupParallaxEffects() {
|
|
137
|
+
const parallaxElements = document.querySelectorAll('.hero-parallax, .gradient-mesh, .particles');
|
|
138
|
+
|
|
139
|
+
const updateParallax = () => {
|
|
140
|
+
const scrolled = window.pageYOffset;
|
|
141
|
+
const rate = scrolled * -0.5;
|
|
142
|
+
|
|
143
|
+
parallaxElements.forEach(element => {
|
|
144
|
+
if (this.isInViewport(element)) {
|
|
145
|
+
const speed = element.dataset.speed || 0.5;
|
|
146
|
+
const yPos = -(scrolled * speed);
|
|
147
|
+
element.style.transform = `translate3d(0, ${yPos}px, 0)`;
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
// Optimized scroll handler for parallax
|
|
153
|
+
let parallaxTicking = false;
|
|
154
|
+
window.addEventListener('scroll', () => {
|
|
155
|
+
if (!parallaxTicking) {
|
|
156
|
+
requestAnimationFrame(() => {
|
|
157
|
+
updateParallax();
|
|
158
|
+
parallaxTicking = false;
|
|
159
|
+
});
|
|
160
|
+
parallaxTicking = true;
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* ENTRANCE ANIMATIONS
|
|
167
|
+
*/
|
|
168
|
+
triggerEntranceAnimations() {
|
|
169
|
+
// Hero section animation
|
|
170
|
+
const heroContent = document.querySelector('.hero-content');
|
|
171
|
+
if (heroContent) {
|
|
172
|
+
heroContent.classList.add('animate-fade-in-up');
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Stagger navigation items
|
|
176
|
+
const navItems = document.querySelectorAll('.nav-link');
|
|
177
|
+
navItems.forEach((item, index) => {
|
|
178
|
+
setTimeout(() => {
|
|
179
|
+
item.classList.add('animate-fade-in-down');
|
|
180
|
+
}, index * 100);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// Stats counter animation
|
|
184
|
+
this.animateCounters();
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* HOVER ANIMATIONS AND EFFECTS
|
|
189
|
+
*/
|
|
190
|
+
setupHoverAnimations() {
|
|
191
|
+
// Enhanced button animations
|
|
192
|
+
const buttons = document.querySelectorAll('.btn, button, .nav-link');
|
|
193
|
+
buttons.forEach(btn => {
|
|
194
|
+
btn.classList.add('btn-animated', 'ripple-effect');
|
|
195
|
+
|
|
196
|
+
// Add magnetic effect for larger screens
|
|
197
|
+
if (window.innerWidth > 768) {
|
|
198
|
+
this.addMagneticEffect(btn);
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Card hover effects
|
|
203
|
+
const cards = document.querySelectorAll('.feature, .mcp-card, .what-is-card, .example-card, .practice');
|
|
204
|
+
cards.forEach(card => {
|
|
205
|
+
card.classList.add('card-hover', 'gpu-accelerated');
|
|
206
|
+
|
|
207
|
+
// Add tilt effect
|
|
208
|
+
this.addTiltEffect(card);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// Text gradient animations
|
|
212
|
+
const gradientTexts = document.querySelectorAll('.hero-title, .section-title, .brand-name');
|
|
213
|
+
gradientTexts.forEach(text => {
|
|
214
|
+
text.classList.add('text-gradient-animated');
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
// Icon animations
|
|
218
|
+
const icons = document.querySelectorAll('.feature-icon, .card-icon');
|
|
219
|
+
icons.forEach(icon => {
|
|
220
|
+
icon.classList.add('icon-scale');
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* LOADING STATES AND SKELETON SCREENS
|
|
226
|
+
*/
|
|
227
|
+
setupLoadingAnimations() {
|
|
228
|
+
// Create skeleton loading for dynamic content
|
|
229
|
+
this.createSkeletonLoaders();
|
|
230
|
+
|
|
231
|
+
// Progress bar animations
|
|
232
|
+
const progressBars = document.querySelectorAll('.progress-bar');
|
|
233
|
+
progressBars.forEach(bar => {
|
|
234
|
+
const fill = bar.querySelector('.progress-fill');
|
|
235
|
+
if (fill) {
|
|
236
|
+
const observer = new IntersectionObserver((entries) => {
|
|
237
|
+
entries.forEach(entry => {
|
|
238
|
+
if (entry.isIntersecting) {
|
|
239
|
+
fill.style.width = fill.dataset.width || '100%';
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
observer.observe(bar);
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
// Spinner variations for async operations
|
|
248
|
+
this.createSpinners();
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* MICRO-INTERACTIONS
|
|
253
|
+
*/
|
|
254
|
+
setupMicroInteractions() {
|
|
255
|
+
// Form field animations
|
|
256
|
+
const inputs = document.querySelectorAll('input, textarea, select');
|
|
257
|
+
inputs.forEach(input => {
|
|
258
|
+
input.classList.add('input-animated');
|
|
259
|
+
|
|
260
|
+
// Focus animations
|
|
261
|
+
input.addEventListener('focus', () => {
|
|
262
|
+
input.parentElement?.classList.add('focused');
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
input.addEventListener('blur', () => {
|
|
266
|
+
input.parentElement?.classList.remove('focused');
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// Toggle switches
|
|
271
|
+
this.setupToggleSwitches();
|
|
272
|
+
|
|
273
|
+
// Tooltip interactions
|
|
274
|
+
this.setupTooltips();
|
|
275
|
+
|
|
276
|
+
// Copy code interactions
|
|
277
|
+
this.enhanceCopyButtons();
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* BACKGROUND ANIMATIONS
|
|
282
|
+
*/
|
|
283
|
+
setupBackgroundAnimations() {
|
|
284
|
+
// Add gradient mesh to hero
|
|
285
|
+
const hero = document.querySelector('.hero');
|
|
286
|
+
if (hero && !hero.querySelector('.gradient-mesh')) {
|
|
287
|
+
const mesh = document.createElement('div');
|
|
288
|
+
mesh.className = 'gradient-mesh';
|
|
289
|
+
hero.appendChild(mesh);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Add particles to sections
|
|
293
|
+
this.addParticleEffects();
|
|
294
|
+
|
|
295
|
+
// Wave patterns for section breaks
|
|
296
|
+
this.addWavePatterns();
|
|
297
|
+
|
|
298
|
+
// Noise overlay for texture
|
|
299
|
+
this.addNoiseOverlay();
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* PERFORMANCE OPTIMIZATIONS
|
|
304
|
+
*/
|
|
305
|
+
setupPerformanceOptimizations() {
|
|
306
|
+
// Use Intersection Observer for expensive animations
|
|
307
|
+
const expensiveAnimations = document.querySelectorAll('.morphing, .text-glow, .particles');
|
|
308
|
+
|
|
309
|
+
const performanceObserver = new IntersectionObserver((entries) => {
|
|
310
|
+
entries.forEach(entry => {
|
|
311
|
+
if (entry.isIntersecting) {
|
|
312
|
+
entry.target.classList.add('animate');
|
|
313
|
+
} else {
|
|
314
|
+
entry.target.classList.remove('animate');
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
}, { rootMargin: '50px' });
|
|
318
|
+
|
|
319
|
+
expensiveAnimations.forEach(el => {
|
|
320
|
+
performanceObserver.observe(el);
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
// Throttle resize events
|
|
324
|
+
this.setupResponsiveAnimations();
|
|
325
|
+
|
|
326
|
+
// Preload critical animations
|
|
327
|
+
this.preloadAnimations();
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* UTILITY METHODS
|
|
332
|
+
*/
|
|
333
|
+
|
|
334
|
+
calculateStaggerDelay(element) {
|
|
335
|
+
const parent = element.parentElement;
|
|
336
|
+
if (!parent) return 0;
|
|
337
|
+
|
|
338
|
+
const siblings = Array.from(parent.children);
|
|
339
|
+
const index = siblings.indexOf(element);
|
|
340
|
+
return Math.min(index * 100, 800); // Max 800ms delay
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
triggerCustomAnimation(element) {
|
|
344
|
+
const animationType = element.dataset.animation;
|
|
345
|
+
if (!animationType) return;
|
|
346
|
+
|
|
347
|
+
const animations = {
|
|
348
|
+
'bounce': () => element.classList.add('animate-bounce'),
|
|
349
|
+
'scale': () => element.classList.add('animate-scale-in'),
|
|
350
|
+
'slide-up': () => element.classList.add('animate-slide-in-bottom'),
|
|
351
|
+
'slide-down': () => element.classList.add('animate-slide-in-top'),
|
|
352
|
+
'fade-left': () => element.classList.add('animate-fade-in-left'),
|
|
353
|
+
'fade-right': () => element.classList.add('animate-fade-in-right')
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
if (animations[animationType]) {
|
|
357
|
+
animations[animationType]();
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
isInViewport(element) {
|
|
362
|
+
const rect = element.getBoundingClientRect();
|
|
363
|
+
return (
|
|
364
|
+
rect.top < window.innerHeight &&
|
|
365
|
+
rect.bottom > 0
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
addMagneticEffect(element) {
|
|
370
|
+
element.addEventListener('mousemove', (e) => {
|
|
371
|
+
const rect = element.getBoundingClientRect();
|
|
372
|
+
const x = e.clientX - rect.left - rect.width / 2;
|
|
373
|
+
const y = e.clientY - rect.top - rect.height / 2;
|
|
374
|
+
|
|
375
|
+
element.style.transform = `translate(${x * 0.1}px, ${y * 0.1}px)`;
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
element.addEventListener('mouseleave', () => {
|
|
379
|
+
element.style.transform = '';
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
addTiltEffect(card) {
|
|
384
|
+
card.addEventListener('mousemove', (e) => {
|
|
385
|
+
const rect = card.getBoundingClientRect();
|
|
386
|
+
const x = e.clientX - rect.left;
|
|
387
|
+
const y = e.clientY - rect.top;
|
|
388
|
+
|
|
389
|
+
const centerX = rect.width / 2;
|
|
390
|
+
const centerY = rect.height / 2;
|
|
391
|
+
|
|
392
|
+
const rotateX = (y - centerY) / 10;
|
|
393
|
+
const rotateY = (centerX - x) / 10;
|
|
394
|
+
|
|
395
|
+
card.style.transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`;
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
card.addEventListener('mouseleave', () => {
|
|
399
|
+
card.style.transform = '';
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
animateCounters() {
|
|
404
|
+
const counters = document.querySelectorAll('.stat-number');
|
|
405
|
+
|
|
406
|
+
const counterObserver = new IntersectionObserver((entries) => {
|
|
407
|
+
entries.forEach(entry => {
|
|
408
|
+
if (entry.isIntersecting && !entry.target.classList.contains('counted')) {
|
|
409
|
+
this.animateCounter(entry.target);
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
}, { threshold: 0.5 });
|
|
413
|
+
|
|
414
|
+
counters.forEach(counter => {
|
|
415
|
+
counterObserver.observe(counter);
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
animateCounter(counter) {
|
|
420
|
+
counter.classList.add('counted');
|
|
421
|
+
const target = parseInt(counter.textContent.replace(/\D/g, ''));
|
|
422
|
+
const suffix = counter.textContent.replace(/\d/g, '');
|
|
423
|
+
const duration = 2000;
|
|
424
|
+
const increment = target / (duration / 16);
|
|
425
|
+
let current = 0;
|
|
426
|
+
|
|
427
|
+
const updateCounter = () => {
|
|
428
|
+
current += increment;
|
|
429
|
+
if (current >= target) {
|
|
430
|
+
counter.textContent = target + suffix;
|
|
431
|
+
} else {
|
|
432
|
+
counter.textContent = Math.floor(current) + suffix;
|
|
433
|
+
requestAnimationFrame(updateCounter);
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
updateCounter();
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
createSkeletonLoaders() {
|
|
441
|
+
const skeletonContainer = document.createElement('div');
|
|
442
|
+
skeletonContainer.className = 'skeleton-container';
|
|
443
|
+
skeletonContainer.innerHTML = `
|
|
444
|
+
<div class="skeleton skeleton-card"></div>
|
|
445
|
+
<div class="skeleton skeleton-text"></div>
|
|
446
|
+
<div class="skeleton skeleton-text"></div>
|
|
447
|
+
<div class="skeleton skeleton-text" style="width: 60%;"></div>
|
|
448
|
+
`;
|
|
449
|
+
|
|
450
|
+
// Add to body but keep hidden initially
|
|
451
|
+
skeletonContainer.style.display = 'none';
|
|
452
|
+
document.body.appendChild(skeletonContainer);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
createSpinners() {
|
|
456
|
+
// Dots spinner
|
|
457
|
+
const dotsSpinner = document.createElement('div');
|
|
458
|
+
dotsSpinner.className = 'spinner-dots';
|
|
459
|
+
dotsSpinner.innerHTML = '<div></div><div></div><div></div>';
|
|
460
|
+
|
|
461
|
+
// Rotate spinner
|
|
462
|
+
const rotateSpinner = document.createElement('div');
|
|
463
|
+
rotateSpinner.className = 'spinner-rotate';
|
|
464
|
+
|
|
465
|
+
// Store references for later use
|
|
466
|
+
this.spinners = { dots: dotsSpinner, rotate: rotateSpinner };
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
setupToggleSwitches() {
|
|
470
|
+
const toggles = document.querySelectorAll('.toggle-switch, [data-toggle]');
|
|
471
|
+
toggles.forEach(toggle => {
|
|
472
|
+
toggle.addEventListener('click', () => {
|
|
473
|
+
toggle.classList.toggle('active');
|
|
474
|
+
|
|
475
|
+
// Trigger custom event
|
|
476
|
+
toggle.dispatchEvent(new CustomEvent('toggle', {
|
|
477
|
+
detail: { active: toggle.classList.contains('active') }
|
|
478
|
+
}));
|
|
479
|
+
});
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
setupTooltips() {
|
|
484
|
+
const tooltipElements = document.querySelectorAll('[data-tooltip]');
|
|
485
|
+
tooltipElements.forEach(element => {
|
|
486
|
+
element.classList.add('tooltip');
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
enhanceCopyButtons() {
|
|
491
|
+
const copyButtons = document.querySelectorAll('.copy-btn');
|
|
492
|
+
copyButtons.forEach(btn => {
|
|
493
|
+
btn.addEventListener('click', () => {
|
|
494
|
+
// Add success animation
|
|
495
|
+
btn.classList.add('success-animation');
|
|
496
|
+
setTimeout(() => {
|
|
497
|
+
btn.classList.remove('success-animation');
|
|
498
|
+
}, 2000);
|
|
499
|
+
});
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
addParticleEffects() {
|
|
504
|
+
const sections = document.querySelectorAll('.hero, .features');
|
|
505
|
+
sections.forEach(section => {
|
|
506
|
+
if (!section.querySelector('.particles')) {
|
|
507
|
+
const particles = document.createElement('div');
|
|
508
|
+
particles.className = 'particles';
|
|
509
|
+
particles.innerHTML = `
|
|
510
|
+
<div class="particle particle-1"></div>
|
|
511
|
+
<div class="particle particle-2"></div>
|
|
512
|
+
<div class="particle particle-3"></div>
|
|
513
|
+
`;
|
|
514
|
+
section.appendChild(particles);
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
addWavePatterns() {
|
|
520
|
+
const sections = document.querySelectorAll('section');
|
|
521
|
+
sections.forEach((section, index) => {
|
|
522
|
+
if (index % 2 === 1 && !section.querySelector('.wave-bg')) {
|
|
523
|
+
const wave = document.createElement('div');
|
|
524
|
+
wave.className = 'wave-bg';
|
|
525
|
+
section.appendChild(wave);
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
addNoiseOverlay() {
|
|
531
|
+
const hero = document.querySelector('.hero');
|
|
532
|
+
if (hero && !hero.querySelector('.noise-overlay')) {
|
|
533
|
+
const noise = document.createElement('div');
|
|
534
|
+
noise.className = 'noise-overlay';
|
|
535
|
+
hero.appendChild(noise);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
setupResponsiveAnimations() {
|
|
540
|
+
let resizeTimer;
|
|
541
|
+
window.addEventListener('resize', () => {
|
|
542
|
+
clearTimeout(resizeTimer);
|
|
543
|
+
resizeTimer = setTimeout(() => {
|
|
544
|
+
this.handleResponsiveAnimations();
|
|
545
|
+
}, 250);
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
handleResponsiveAnimations() {
|
|
550
|
+
const isMobile = window.innerWidth < 768;
|
|
551
|
+
const animations = document.querySelectorAll('[class*="animate"]');
|
|
552
|
+
|
|
553
|
+
animations.forEach(element => {
|
|
554
|
+
if (isMobile) {
|
|
555
|
+
element.style.animationDuration = '0.4s';
|
|
556
|
+
} else {
|
|
557
|
+
element.style.animationDuration = '';
|
|
558
|
+
}
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
preloadAnimations() {
|
|
563
|
+
// Preload critical CSS animations
|
|
564
|
+
const link = document.createElement('link');
|
|
565
|
+
link.rel = 'preload';
|
|
566
|
+
link.href = 'css/animations.css';
|
|
567
|
+
link.as = 'style';
|
|
568
|
+
document.head.appendChild(link);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
optimizeAnimations() {
|
|
572
|
+
// Enable GPU acceleration for animated elements
|
|
573
|
+
const animatedElements = document.querySelectorAll([
|
|
574
|
+
'[class*="animate"]',
|
|
575
|
+
'.card-hover',
|
|
576
|
+
'.btn-animated',
|
|
577
|
+
'.scroll-reveal'
|
|
578
|
+
].join(','));
|
|
579
|
+
|
|
580
|
+
animatedElements.forEach(element => {
|
|
581
|
+
element.classList.add('gpu-accelerated');
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
handleReducedMotion() {
|
|
586
|
+
// Respect user's motion preferences
|
|
587
|
+
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
|
|
588
|
+
|
|
589
|
+
if (prefersReducedMotion.matches) {
|
|
590
|
+
document.documentElement.style.setProperty('--animation-duration', '0.01ms');
|
|
591
|
+
document.documentElement.style.setProperty('--transition-duration', '0.01ms');
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// Listen for changes
|
|
595
|
+
prefersReducedMotion.addEventListener('change', () => {
|
|
596
|
+
if (prefersReducedMotion.matches) {
|
|
597
|
+
document.documentElement.style.setProperty('--animation-duration', '0.01ms');
|
|
598
|
+
} else {
|
|
599
|
+
document.documentElement.style.removeProperty('--animation-duration');
|
|
600
|
+
}
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* PUBLIC API METHODS
|
|
606
|
+
*/
|
|
607
|
+
|
|
608
|
+
// Show loading spinner
|
|
609
|
+
showSpinner(type = 'rotate', container = document.body) {
|
|
610
|
+
const spinner = this.spinners[type].cloneNode(true);
|
|
611
|
+
spinner.classList.add('active-spinner');
|
|
612
|
+
container.appendChild(spinner);
|
|
613
|
+
return spinner;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
// Hide spinner
|
|
617
|
+
hideSpinner(spinner) {
|
|
618
|
+
if (spinner && spinner.parentNode) {
|
|
619
|
+
spinner.remove();
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// Trigger custom animation on element
|
|
624
|
+
animate(element, animation, options = {}) {
|
|
625
|
+
const { delay = 0, duration = 600, easing = 'ease' } = options;
|
|
626
|
+
|
|
627
|
+
element.style.animationDelay = `${delay}ms`;
|
|
628
|
+
element.style.animationDuration = `${duration}ms`;
|
|
629
|
+
element.style.animationTimingFunction = easing;
|
|
630
|
+
|
|
631
|
+
element.classList.add(`animate-${animation}`);
|
|
632
|
+
|
|
633
|
+
// Return promise that resolves when animation ends
|
|
634
|
+
return new Promise(resolve => {
|
|
635
|
+
element.addEventListener('animationend', resolve, { once: true });
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// Batch animate multiple elements
|
|
640
|
+
animateBatch(elements, animation, stagger = 100) {
|
|
641
|
+
const promises = [];
|
|
642
|
+
elements.forEach((element, index) => {
|
|
643
|
+
const promise = this.animate(element, animation, { delay: index * stagger });
|
|
644
|
+
promises.push(promise);
|
|
645
|
+
});
|
|
646
|
+
return Promise.all(promises);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// Destroy animations and observers
|
|
650
|
+
destroy() {
|
|
651
|
+
this.observers.forEach(observer => observer.disconnect());
|
|
652
|
+
this.observers = [];
|
|
653
|
+
|
|
654
|
+
// Remove event listeners
|
|
655
|
+
window.removeEventListener('scroll', this.updateProgress);
|
|
656
|
+
window.removeEventListener('resize', this.handleResponsiveAnimations);
|
|
657
|
+
|
|
658
|
+
console.log('🎭 Snow-Flow Animation System Destroyed');
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
// Initialize the animation system
|
|
663
|
+
const snowFlowAnimations = new SnowFlowAnimations();
|
|
664
|
+
|
|
665
|
+
// Export for global access
|
|
666
|
+
window.SnowFlowAnimations = snowFlowAnimations;
|
|
667
|
+
|
|
668
|
+
// Add some additional CSS styles dynamically for the scroll progress
|
|
669
|
+
const additionalStyles = `
|
|
670
|
+
.scroll-progress {
|
|
671
|
+
position: fixed;
|
|
672
|
+
top: 0;
|
|
673
|
+
left: 0;
|
|
674
|
+
width: 100%;
|
|
675
|
+
height: 4px;
|
|
676
|
+
background: rgba(0, 102, 204, 0.1);
|
|
677
|
+
z-index: 9999;
|
|
678
|
+
pointer-events: none;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
.scroll-progress-fill {
|
|
682
|
+
height: 100%;
|
|
683
|
+
background: linear-gradient(90deg, #0066cc, #00d4ff);
|
|
684
|
+
width: 0%;
|
|
685
|
+
transition: width 0.1s ease;
|
|
686
|
+
box-shadow: 0 0 10px rgba(0, 102, 204, 0.3);
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
.success-animation {
|
|
690
|
+
animation: pulse 0.3s ease-in-out;
|
|
691
|
+
background: #48bb78 !important;
|
|
692
|
+
border-color: #48bb78 !important;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
.active-spinner {
|
|
696
|
+
position: fixed;
|
|
697
|
+
top: 50%;
|
|
698
|
+
left: 50%;
|
|
699
|
+
transform: translate(-50%, -50%);
|
|
700
|
+
z-index: 10000;
|
|
701
|
+
}
|
|
702
|
+
`;
|
|
703
|
+
|
|
704
|
+
// Inject additional styles
|
|
705
|
+
const styleSheet = document.createElement('style');
|
|
706
|
+
styleSheet.textContent = additionalStyles;
|
|
707
|
+
document.head.appendChild(styleSheet);
|