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,247 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Snow-Flow Feature Cards Component</title>
|
|
7
|
+
<link rel="stylesheet" href="FeatureCards.css">
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<!-- Feature Cards Section Component -->
|
|
11
|
+
<section class="sf-feature-cards" id="sf-feature-cards">
|
|
12
|
+
<div class="sf-feature-cards__container">
|
|
13
|
+
<!-- Header -->
|
|
14
|
+
<div class="sf-feature-cards__header">
|
|
15
|
+
<h2 class="sf-feature-cards__title">Features</h2>
|
|
16
|
+
<p class="sf-feature-cards__subtitle">Discover what makes our platform unique and powerful</p>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<!-- Feature Grid -->
|
|
20
|
+
<div class="sf-feature-cards__grid" id="sf-feature-grid">
|
|
21
|
+
<!-- Feature Card 1 -->
|
|
22
|
+
<div class="sf-feature-card sf-feature-card--clickable" data-link="#performance" data-index="0">
|
|
23
|
+
<!-- 3D Border Effect -->
|
|
24
|
+
<div class="sf-feature-card__border">
|
|
25
|
+
<div class="sf-feature-card__border-top"></div>
|
|
26
|
+
<div class="sf-feature-card__border-right"></div>
|
|
27
|
+
<div class="sf-feature-card__border-bottom"></div>
|
|
28
|
+
<div class="sf-feature-card__border-left"></div>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<!-- Background Glow -->
|
|
32
|
+
<div class="sf-feature-card__glow"></div>
|
|
33
|
+
|
|
34
|
+
<!-- Content -->
|
|
35
|
+
<div class="sf-feature-card__content">
|
|
36
|
+
<!-- Icon -->
|
|
37
|
+
<div class="sf-feature-card__icon-wrapper">
|
|
38
|
+
<div class="sf-feature-card__icon">
|
|
39
|
+
<span role="img" aria-hidden="true">⚡</span>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<!-- Text Content -->
|
|
44
|
+
<div class="sf-feature-card__text">
|
|
45
|
+
<h3 class="sf-feature-card__title">Lightning Fast</h3>
|
|
46
|
+
<p class="sf-feature-card__description">Optimized performance with cutting-edge technology for instant results and seamless user experience.</p>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<!-- Hover Arrow -->
|
|
50
|
+
<div class="sf-feature-card__arrow">
|
|
51
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
52
|
+
<path d="M7 17L17 7M17 7H7M17 7V17"/>
|
|
53
|
+
</svg>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<!-- Ripple Effect -->
|
|
58
|
+
<div class="sf-feature-card__ripple"></div>
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
<!-- Feature Card 2 -->
|
|
62
|
+
<div class="sf-feature-card sf-feature-card--clickable" data-link="#security" data-index="1">
|
|
63
|
+
<div class="sf-feature-card__border">
|
|
64
|
+
<div class="sf-feature-card__border-top"></div>
|
|
65
|
+
<div class="sf-feature-card__border-right"></div>
|
|
66
|
+
<div class="sf-feature-card__border-bottom"></div>
|
|
67
|
+
<div class="sf-feature-card__border-left"></div>
|
|
68
|
+
</div>
|
|
69
|
+
<div class="sf-feature-card__glow"></div>
|
|
70
|
+
<div class="sf-feature-card__content">
|
|
71
|
+
<div class="sf-feature-card__icon-wrapper">
|
|
72
|
+
<div class="sf-feature-card__icon">
|
|
73
|
+
<span role="img" aria-hidden="true">🔒</span>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
<div class="sf-feature-card__text">
|
|
77
|
+
<h3 class="sf-feature-card__title">Secure by Design</h3>
|
|
78
|
+
<p class="sf-feature-card__description">Enterprise-grade security with end-to-end encryption and compliance standards built-in.</p>
|
|
79
|
+
</div>
|
|
80
|
+
<div class="sf-feature-card__arrow">
|
|
81
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
82
|
+
<path d="M7 17L17 7M17 7H7M17 7V17"/>
|
|
83
|
+
</svg>
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
<div class="sf-feature-card__ripple"></div>
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
<!-- Feature Card 3 -->
|
|
90
|
+
<div class="sf-feature-card sf-feature-card--clickable" data-link="#integration" data-index="2">
|
|
91
|
+
<div class="sf-feature-card__border">
|
|
92
|
+
<div class="sf-feature-card__border-top"></div>
|
|
93
|
+
<div class="sf-feature-card__border-right"></div>
|
|
94
|
+
<div class="sf-feature-card__border-bottom"></div>
|
|
95
|
+
<div class="sf-feature-card__border-left"></div>
|
|
96
|
+
</div>
|
|
97
|
+
<div class="sf-feature-card__glow"></div>
|
|
98
|
+
<div class="sf-feature-card__content">
|
|
99
|
+
<div class="sf-feature-card__icon-wrapper">
|
|
100
|
+
<div class="sf-feature-card__icon">
|
|
101
|
+
<span role="img" aria-hidden="true">🚀</span>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
<div class="sf-feature-card__text">
|
|
105
|
+
<h3 class="sf-feature-card__title">Easy Integration</h3>
|
|
106
|
+
<p class="sf-feature-card__description">Seamless integration with your existing tools and workflows, no complex setup required.</p>
|
|
107
|
+
</div>
|
|
108
|
+
<div class="sf-feature-card__arrow">
|
|
109
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
110
|
+
<path d="M7 17L17 7M17 7H7M17 7V17"/>
|
|
111
|
+
</svg>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
<div class="sf-feature-card__ripple"></div>
|
|
115
|
+
</div>
|
|
116
|
+
|
|
117
|
+
<!-- Feature Card 4 -->
|
|
118
|
+
<div class="sf-feature-card sf-feature-card--clickable" data-link="#analytics" data-index="3">
|
|
119
|
+
<div class="sf-feature-card__border">
|
|
120
|
+
<div class="sf-feature-card__border-top"></div>
|
|
121
|
+
<div class="sf-feature-card__border-right"></div>
|
|
122
|
+
<div class="sf-feature-card__border-bottom"></div>
|
|
123
|
+
<div class="sf-feature-card__border-left"></div>
|
|
124
|
+
</div>
|
|
125
|
+
<div class="sf-feature-card__glow"></div>
|
|
126
|
+
<div class="sf-feature-card__content">
|
|
127
|
+
<div class="sf-feature-card__icon-wrapper">
|
|
128
|
+
<div class="sf-feature-card__icon">
|
|
129
|
+
<span role="img" aria-hidden="true">📊</span>
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
<div class="sf-feature-card__text">
|
|
133
|
+
<h3 class="sf-feature-card__title">Real-time Analytics</h3>
|
|
134
|
+
<p class="sf-feature-card__description">Comprehensive insights and analytics to drive informed decisions with real-time data.</p>
|
|
135
|
+
</div>
|
|
136
|
+
<div class="sf-feature-card__arrow">
|
|
137
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
138
|
+
<path d="M7 17L17 7M17 7H7M17 7V17"/>
|
|
139
|
+
</svg>
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
<div class="sf-feature-card__ripple"></div>
|
|
143
|
+
</div>
|
|
144
|
+
|
|
145
|
+
<!-- Feature Card 5 -->
|
|
146
|
+
<div class="sf-feature-card sf-feature-card--clickable" data-link="#control" data-index="4">
|
|
147
|
+
<div class="sf-feature-card__border">
|
|
148
|
+
<div class="sf-feature-card__border-top"></div>
|
|
149
|
+
<div class="sf-feature-card__border-right"></div>
|
|
150
|
+
<div class="sf-feature-card__border-bottom"></div>
|
|
151
|
+
<div class="sf-feature-card__border-left"></div>
|
|
152
|
+
</div>
|
|
153
|
+
<div class="sf-feature-card__glow"></div>
|
|
154
|
+
<div class="sf-feature-card__content">
|
|
155
|
+
<div class="sf-feature-card__icon-wrapper">
|
|
156
|
+
<div class="sf-feature-card__icon">
|
|
157
|
+
<span role="img" aria-hidden="true">🎯</span>
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
<div class="sf-feature-card__text">
|
|
161
|
+
<h3 class="sf-feature-card__title">Precision Control</h3>
|
|
162
|
+
<p class="sf-feature-card__description">Granular control over every aspect of your system operations with advanced configuration options.</p>
|
|
163
|
+
</div>
|
|
164
|
+
<div class="sf-feature-card__arrow">
|
|
165
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
166
|
+
<path d="M7 17L17 7M17 7H7M17 7V17"/>
|
|
167
|
+
</svg>
|
|
168
|
+
</div>
|
|
169
|
+
</div>
|
|
170
|
+
<div class="sf-feature-card__ripple"></div>
|
|
171
|
+
</div>
|
|
172
|
+
|
|
173
|
+
<!-- Feature Card 6 -->
|
|
174
|
+
<div class="sf-feature-card sf-feature-card--clickable" data-link="#updates" data-index="5">
|
|
175
|
+
<div class="sf-feature-card__border">
|
|
176
|
+
<div class="sf-feature-card__border-top"></div>
|
|
177
|
+
<div class="sf-feature-card__border-right"></div>
|
|
178
|
+
<div class="sf-feature-card__border-bottom"></div>
|
|
179
|
+
<div class="sf-feature-card__border-left"></div>
|
|
180
|
+
</div>
|
|
181
|
+
<div class="sf-feature-card__glow"></div>
|
|
182
|
+
<div class="sf-feature-card__content">
|
|
183
|
+
<div class="sf-feature-card__icon-wrapper">
|
|
184
|
+
<div class="sf-feature-card__icon">
|
|
185
|
+
<span role="img" aria-hidden="true">🔄</span>
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
<div class="sf-feature-card__text">
|
|
189
|
+
<h3 class="sf-feature-card__title">Auto Updates</h3>
|
|
190
|
+
<p class="sf-feature-card__description">Stay current with automatic updates and feature enhancements, zero maintenance required.</p>
|
|
191
|
+
</div>
|
|
192
|
+
<div class="sf-feature-card__arrow">
|
|
193
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
194
|
+
<path d="M7 17L17 7M17 7H7M17 7V17"/>
|
|
195
|
+
</svg>
|
|
196
|
+
</div>
|
|
197
|
+
</div>
|
|
198
|
+
<div class="sf-feature-card__ripple"></div>
|
|
199
|
+
</div>
|
|
200
|
+
</div>
|
|
201
|
+
|
|
202
|
+
<!-- Optional CTA -->
|
|
203
|
+
<div class="sf-feature-cards__cta" id="sf-feature-cta">
|
|
204
|
+
<button class="sf-feature-cards__cta-button">
|
|
205
|
+
View All Features
|
|
206
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
207
|
+
<path d="M5 12H19M12 5L19 12L12 19"/>
|
|
208
|
+
</svg>
|
|
209
|
+
</button>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
|
|
213
|
+
<!-- Background Elements -->
|
|
214
|
+
<div class="sf-feature-cards__background">
|
|
215
|
+
<div class="sf-feature-cards__bg-grid"></div>
|
|
216
|
+
<div class="sf-feature-cards__bg-gradient"></div>
|
|
217
|
+
</div>
|
|
218
|
+
</section>
|
|
219
|
+
|
|
220
|
+
<!-- Demo Sections for Link Testing -->
|
|
221
|
+
<section id="performance" style="height: 100vh; background: linear-gradient(135deg, #f0f0f0, #e0e0e0); display: flex; align-items: center; justify-content: center;">
|
|
222
|
+
<h2>Performance Section</h2>
|
|
223
|
+
</section>
|
|
224
|
+
|
|
225
|
+
<section id="security" style="height: 100vh; background: linear-gradient(135deg, #e0e0e0, #d0d0d0); display: flex; align-items: center; justify-content: center;">
|
|
226
|
+
<h2>Security Section</h2>
|
|
227
|
+
</section>
|
|
228
|
+
|
|
229
|
+
<section id="integration" style="height: 100vh; background: linear-gradient(135deg, #d0d0d0, #c0c0c0); display: flex; align-items: center; justify-content: center;">
|
|
230
|
+
<h2>Integration Section</h2>
|
|
231
|
+
</section>
|
|
232
|
+
|
|
233
|
+
<section id="analytics" style="height: 100vh; background: linear-gradient(135deg, #c0c0c0, #b0b0b0); display: flex; align-items: center; justify-content: center;">
|
|
234
|
+
<h2>Analytics Section</h2>
|
|
235
|
+
</section>
|
|
236
|
+
|
|
237
|
+
<section id="control" style="height: 100vh; background: linear-gradient(135deg, #b0b0b0, #a0a0a0); display: flex; align-items: center; justify-content: center;">
|
|
238
|
+
<h2>Control Section</h2>
|
|
239
|
+
</section>
|
|
240
|
+
|
|
241
|
+
<section id="updates" style="height: 100vh; background: linear-gradient(135deg, #a0a0a0, #909090); display: flex; align-items: center; justify-content: center;">
|
|
242
|
+
<h2>Updates Section</h2>
|
|
243
|
+
</section>
|
|
244
|
+
|
|
245
|
+
<script src="FeatureCards.js"></script>
|
|
246
|
+
</body>
|
|
247
|
+
</html>
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
// Snow-Flow Feature Cards Component JavaScript
|
|
2
|
+
|
|
3
|
+
class SnowFlowFeatureCards {
|
|
4
|
+
constructor(options = {}) {
|
|
5
|
+
// Configuration
|
|
6
|
+
this.config = {
|
|
7
|
+
containerId: options.containerId || 'sf-feature-cards',
|
|
8
|
+
gridId: options.gridId || 'sf-feature-grid',
|
|
9
|
+
ctaId: options.ctaId || 'sf-feature-cta',
|
|
10
|
+
|
|
11
|
+
// Animation settings
|
|
12
|
+
staggerDelay: options.staggerDelay || 150,
|
|
13
|
+
intersectionThreshold: options.intersectionThreshold || 0.1,
|
|
14
|
+
|
|
15
|
+
// State
|
|
16
|
+
isVisible: false,
|
|
17
|
+
visibleCards: new Set(),
|
|
18
|
+
cardElements: []
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// DOM elements
|
|
22
|
+
this.elements = {
|
|
23
|
+
container: document.getElementById(this.config.containerId),
|
|
24
|
+
grid: document.getElementById(this.config.gridId),
|
|
25
|
+
cta: document.getElementById(this.config.ctaId)
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
this.init();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
init() {
|
|
32
|
+
if (!this.elements.container) {
|
|
33
|
+
console.warn('SnowFlowFeatureCards: Container element not found');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
this.setupCards();
|
|
38
|
+
this.setupIntersectionObserver();
|
|
39
|
+
this.setupEventListeners();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
setupCards() {
|
|
43
|
+
// Get all card elements
|
|
44
|
+
this.config.cardElements = Array.from(
|
|
45
|
+
this.elements.container.querySelectorAll('.sf-feature-card')
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
// Setup each card
|
|
49
|
+
this.config.cardElements.forEach((card, index) => {
|
|
50
|
+
card.style.animationDelay = `${index * this.config.staggerDelay}ms`;
|
|
51
|
+
card.setAttribute('data-index', index.toString());
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
setupIntersectionObserver() {
|
|
56
|
+
const observer = new IntersectionObserver(
|
|
57
|
+
(entries) => {
|
|
58
|
+
entries.forEach(entry => {
|
|
59
|
+
if (entry.isIntersecting && !this.config.isVisible) {
|
|
60
|
+
this.config.isVisible = true;
|
|
61
|
+
this.startAnimations();
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
{ threshold: this.config.intersectionThreshold }
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
observer.observe(this.elements.container);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
setupEventListeners() {
|
|
72
|
+
// Card click handlers
|
|
73
|
+
this.config.cardElements.forEach((card, index) => {
|
|
74
|
+
// Mouse events
|
|
75
|
+
card.addEventListener('mouseenter', () => this.handleCardHover(card, true));
|
|
76
|
+
card.addEventListener('mouseleave', () => this.handleCardHover(card, false));
|
|
77
|
+
card.addEventListener('click', (e) => this.handleCardClick(e, card, index));
|
|
78
|
+
|
|
79
|
+
// Touch events for mobile
|
|
80
|
+
card.addEventListener('touchstart', () => this.handleCardHover(card, true), { passive: true });
|
|
81
|
+
card.addEventListener('touchend', () => {
|
|
82
|
+
setTimeout(() => this.handleCardHover(card, false), 300);
|
|
83
|
+
}, { passive: true });
|
|
84
|
+
|
|
85
|
+
// Keyboard events
|
|
86
|
+
card.addEventListener('keydown', (e) => {
|
|
87
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
88
|
+
e.preventDefault();
|
|
89
|
+
this.handleCardClick(e, card, index);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Focus events
|
|
94
|
+
card.addEventListener('focus', () => this.handleCardFocus(card, true));
|
|
95
|
+
card.addEventListener('blur', () => this.handleCardFocus(card, false));
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// CTA button
|
|
99
|
+
if (this.elements.cta) {
|
|
100
|
+
const ctaButton = this.elements.cta.querySelector('.sf-feature-cards__cta-button');
|
|
101
|
+
if (ctaButton) {
|
|
102
|
+
ctaButton.addEventListener('click', () => this.handleCTAClick());
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Resize handler
|
|
107
|
+
window.addEventListener('resize', () => this.handleResize());
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
startAnimations() {
|
|
111
|
+
// Add visible class to container
|
|
112
|
+
this.elements.container.classList.add('sf-feature-cards--visible');
|
|
113
|
+
|
|
114
|
+
// Stagger card animations
|
|
115
|
+
this.config.cardElements.forEach((card, index) => {
|
|
116
|
+
setTimeout(() => {
|
|
117
|
+
this.config.visibleCards.add(index);
|
|
118
|
+
card.classList.add('sf-feature-card--visible');
|
|
119
|
+
this.animateCardAppearance(card, index);
|
|
120
|
+
}, index * this.config.staggerDelay);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Show CTA after all cards are visible
|
|
124
|
+
if (this.elements.cta) {
|
|
125
|
+
const totalDelay = this.config.cardElements.length * this.config.staggerDelay + 500;
|
|
126
|
+
setTimeout(() => {
|
|
127
|
+
this.elements.cta.classList.add('sf-feature-cards__cta--visible');
|
|
128
|
+
}, totalDelay);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
animateCardAppearance(card, index) {
|
|
133
|
+
// Optional: Add additional entrance effects
|
|
134
|
+
const icon = card.querySelector('.sf-feature-card__icon');
|
|
135
|
+
if (icon) {
|
|
136
|
+
setTimeout(() => {
|
|
137
|
+
icon.style.transform = 'scale(1.1)';
|
|
138
|
+
setTimeout(() => {
|
|
139
|
+
icon.style.transform = '';
|
|
140
|
+
}, 200);
|
|
141
|
+
}, 100);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
handleCardHover(card, isEntering) {
|
|
146
|
+
const icon = card.querySelector('.sf-feature-card__icon');
|
|
147
|
+
const arrow = card.querySelector('.sf-feature-card__arrow');
|
|
148
|
+
|
|
149
|
+
if (isEntering) {
|
|
150
|
+
if (icon) {
|
|
151
|
+
icon.classList.add('sf-feature-card__icon--animated');
|
|
152
|
+
}
|
|
153
|
+
if (arrow) {
|
|
154
|
+
arrow.classList.add('sf-feature-card__arrow--visible');
|
|
155
|
+
}
|
|
156
|
+
} else {
|
|
157
|
+
if (icon) {
|
|
158
|
+
icon.classList.remove('sf-feature-card__icon--animated');
|
|
159
|
+
}
|
|
160
|
+
if (arrow) {
|
|
161
|
+
arrow.classList.remove('sf-feature-card__arrow--visible');
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
handleCardFocus(card, isFocused) {
|
|
167
|
+
// Handle focus state for accessibility
|
|
168
|
+
if (isFocused) {
|
|
169
|
+
card.style.outline = '2px solid #000000';
|
|
170
|
+
card.style.outlineOffset = '2px';
|
|
171
|
+
this.handleCardHover(card, true);
|
|
172
|
+
} else {
|
|
173
|
+
card.style.outline = '';
|
|
174
|
+
card.style.outlineOffset = '';
|
|
175
|
+
this.handleCardHover(card, false);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
handleCardClick(e, card, index) {
|
|
180
|
+
const link = card.getAttribute('data-link');
|
|
181
|
+
|
|
182
|
+
if (link) {
|
|
183
|
+
// Add ripple effect
|
|
184
|
+
this.createRippleEffect(card, e);
|
|
185
|
+
|
|
186
|
+
// Navigate after short delay for ripple effect
|
|
187
|
+
setTimeout(() => {
|
|
188
|
+
if (link.startsWith('#')) {
|
|
189
|
+
this.scrollToSection(link);
|
|
190
|
+
} else {
|
|
191
|
+
window.open(link, '_blank', 'noopener,noreferrer');
|
|
192
|
+
}
|
|
193
|
+
}, 150);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Optional: Trigger custom event
|
|
197
|
+
const event = new CustomEvent('cardClick', {
|
|
198
|
+
detail: {
|
|
199
|
+
index,
|
|
200
|
+
card,
|
|
201
|
+
link,
|
|
202
|
+
title: card.querySelector('.sf-feature-card__title')?.textContent
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
this.elements.container.dispatchEvent(event);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
createRippleEffect(card, clickEvent) {
|
|
209
|
+
const ripple = card.querySelector('.sf-feature-card__ripple');
|
|
210
|
+
if (!ripple) return;
|
|
211
|
+
|
|
212
|
+
// Reset ripple
|
|
213
|
+
ripple.style.width = '0';
|
|
214
|
+
ripple.style.height = '0';
|
|
215
|
+
|
|
216
|
+
// Calculate ripple position for click events
|
|
217
|
+
if (clickEvent && clickEvent.type === 'click') {
|
|
218
|
+
const rect = card.getBoundingClientRect();
|
|
219
|
+
const x = clickEvent.clientX - rect.left;
|
|
220
|
+
const y = clickEvent.clientY - rect.top;
|
|
221
|
+
|
|
222
|
+
ripple.style.left = `${x}px`;
|
|
223
|
+
ripple.style.top = `${y}px`;
|
|
224
|
+
ripple.style.transform = 'translate(-50%, -50%)';
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Trigger ripple animation
|
|
228
|
+
setTimeout(() => {
|
|
229
|
+
ripple.style.width = '300px';
|
|
230
|
+
ripple.style.height = '300px';
|
|
231
|
+
}, 10);
|
|
232
|
+
|
|
233
|
+
// Reset after animation
|
|
234
|
+
setTimeout(() => {
|
|
235
|
+
ripple.style.width = '0';
|
|
236
|
+
ripple.style.height = '0';
|
|
237
|
+
ripple.style.left = '50%';
|
|
238
|
+
ripple.style.top = '50%';
|
|
239
|
+
}, 600);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
scrollToSection(target) {
|
|
243
|
+
const element = document.querySelector(target);
|
|
244
|
+
if (element) {
|
|
245
|
+
const offset = 80; // Account for fixed navbar
|
|
246
|
+
const targetPosition = element.offsetTop - offset;
|
|
247
|
+
|
|
248
|
+
window.scrollTo({
|
|
249
|
+
top: targetPosition,
|
|
250
|
+
behavior: 'smooth'
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
handleCTAClick() {
|
|
256
|
+
// Optional: Implement show all features logic
|
|
257
|
+
console.log('View All Features clicked');
|
|
258
|
+
|
|
259
|
+
// Example: Could expand to show more cards or navigate to features page
|
|
260
|
+
const event = new CustomEvent('ctaClick', {
|
|
261
|
+
detail: {
|
|
262
|
+
action: 'viewAllFeatures'
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
this.elements.container.dispatchEvent(event);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
handleResize() {
|
|
269
|
+
// Handle responsive behavior if needed
|
|
270
|
+
// Could recalculate positions or update layout
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Public API methods
|
|
274
|
+
addFeature(featureData) {
|
|
275
|
+
const { icon, title, description, link } = featureData;
|
|
276
|
+
|
|
277
|
+
const cardHTML = `
|
|
278
|
+
<div class="sf-feature-card sf-feature-card--clickable" data-link="${link || ''}" data-index="${this.config.cardElements.length}">
|
|
279
|
+
<div class="sf-feature-card__border">
|
|
280
|
+
<div class="sf-feature-card__border-top"></div>
|
|
281
|
+
<div class="sf-feature-card__border-right"></div>
|
|
282
|
+
<div class="sf-feature-card__border-bottom"></div>
|
|
283
|
+
<div class="sf-feature-card__border-left"></div>
|
|
284
|
+
</div>
|
|
285
|
+
<div class="sf-feature-card__glow"></div>
|
|
286
|
+
<div class="sf-feature-card__content">
|
|
287
|
+
<div class="sf-feature-card__icon-wrapper">
|
|
288
|
+
<div class="sf-feature-card__icon">
|
|
289
|
+
<span role="img" aria-hidden="true">${icon}</span>
|
|
290
|
+
</div>
|
|
291
|
+
</div>
|
|
292
|
+
<div class="sf-feature-card__text">
|
|
293
|
+
<h3 class="sf-feature-card__title">${title}</h3>
|
|
294
|
+
<p class="sf-feature-card__description">${description}</p>
|
|
295
|
+
</div>
|
|
296
|
+
${link ? `
|
|
297
|
+
<div class="sf-feature-card__arrow">
|
|
298
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
299
|
+
<path d="M7 17L17 7M17 7H7M17 7V17"/>
|
|
300
|
+
</svg>
|
|
301
|
+
</div>
|
|
302
|
+
` : ''}
|
|
303
|
+
</div>
|
|
304
|
+
<div class="sf-feature-card__ripple"></div>
|
|
305
|
+
</div>
|
|
306
|
+
`;
|
|
307
|
+
|
|
308
|
+
this.elements.grid.insertAdjacentHTML('beforeend', cardHTML);
|
|
309
|
+
this.setupCards(); // Re-setup cards with new element
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
updateFeature(index, featureData) {
|
|
313
|
+
const card = this.config.cardElements[index];
|
|
314
|
+
if (!card) return;
|
|
315
|
+
|
|
316
|
+
const { icon, title, description, link } = featureData;
|
|
317
|
+
|
|
318
|
+
if (icon) {
|
|
319
|
+
const iconElement = card.querySelector('.sf-feature-card__icon span');
|
|
320
|
+
if (iconElement) iconElement.textContent = icon;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (title) {
|
|
324
|
+
const titleElement = card.querySelector('.sf-feature-card__title');
|
|
325
|
+
if (titleElement) titleElement.textContent = title;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (description) {
|
|
329
|
+
const descElement = card.querySelector('.sf-feature-card__description');
|
|
330
|
+
if (descElement) descElement.textContent = description;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (link !== undefined) {
|
|
334
|
+
card.setAttribute('data-link', link);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
removeFeature(index) {
|
|
339
|
+
const card = this.config.cardElements[index];
|
|
340
|
+
if (card) {
|
|
341
|
+
card.remove();
|
|
342
|
+
this.setupCards(); // Re-setup after removal
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
resetAnimations() {
|
|
347
|
+
this.config.isVisible = false;
|
|
348
|
+
this.config.visibleCards.clear();
|
|
349
|
+
|
|
350
|
+
this.elements.container.classList.remove('sf-feature-cards--visible');
|
|
351
|
+
this.config.cardElements.forEach(card => {
|
|
352
|
+
card.classList.remove('sf-feature-card--visible');
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
if (this.elements.cta) {
|
|
356
|
+
this.elements.cta.classList.remove('sf-feature-cards__cta--visible');
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
destroy() {
|
|
361
|
+
// Cleanup method
|
|
362
|
+
this.resetAnimations();
|
|
363
|
+
// Remove event listeners if needed
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Auto-initialize on DOM content loaded
|
|
368
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
369
|
+
// Check if feature cards exist before initializing
|
|
370
|
+
const featureCardsElement = document.getElementById('sf-feature-cards');
|
|
371
|
+
if (featureCardsElement) {
|
|
372
|
+
window.snowFlowFeatureCards = new SnowFlowFeatureCards();
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
// Export for module usage
|
|
377
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
378
|
+
module.exports = SnowFlowFeatureCards;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Global access
|
|
382
|
+
window.SnowFlowFeatureCards = SnowFlowFeatureCards;
|