snow-flow 3.4.13 → 3.4.15

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.
@@ -0,0 +1,323 @@
1
+ // Snow-Flow Website JavaScript
2
+
3
+ document.addEventListener('DOMContentLoaded', function() {
4
+ // Mobile Navigation Toggle
5
+ const hamburger = document.querySelector('.hamburger');
6
+ const navMenu = document.querySelector('.nav-menu');
7
+
8
+ if (hamburger) {
9
+ hamburger.addEventListener('click', function() {
10
+ navMenu.classList.toggle('active');
11
+
12
+ // Animate hamburger
13
+ const spans = hamburger.querySelectorAll('span');
14
+ if (navMenu.classList.contains('active')) {
15
+ spans[0].style.transform = 'rotate(45deg) translate(5px, 5px)';
16
+ spans[1].style.opacity = '0';
17
+ spans[2].style.transform = 'rotate(-45deg) translate(7px, -6px)';
18
+ } else {
19
+ spans[0].style.transform = 'none';
20
+ spans[1].style.opacity = '1';
21
+ spans[2].style.transform = 'none';
22
+ }
23
+ });
24
+ }
25
+
26
+ // Smooth Scrolling for Navigation Links
27
+ const navLinks = document.querySelectorAll('.nav-link');
28
+ navLinks.forEach(link => {
29
+ link.addEventListener('click', function(e) {
30
+ const href = this.getAttribute('href');
31
+ if (href.startsWith('#')) {
32
+ e.preventDefault();
33
+ const target = document.querySelector(href);
34
+ if (target) {
35
+ const offset = 80; // Height of navbar
36
+ const targetPosition = target.offsetTop - offset;
37
+ window.scrollTo({
38
+ top: targetPosition,
39
+ behavior: 'smooth'
40
+ });
41
+
42
+ // Close mobile menu if open
43
+ navMenu.classList.remove('active');
44
+ }
45
+ }
46
+ });
47
+ });
48
+
49
+ // Tab Functionality for Installation Section
50
+ const tabBtns = document.querySelectorAll('.tab-btn');
51
+ const tabContents = document.querySelectorAll('.tab-content');
52
+
53
+ tabBtns.forEach(btn => {
54
+ btn.addEventListener('click', function() {
55
+ const tabName = this.getAttribute('data-tab');
56
+
57
+ // Remove active class from all tabs and contents
58
+ tabBtns.forEach(b => b.classList.remove('active'));
59
+ tabContents.forEach(c => c.classList.remove('active'));
60
+
61
+ // Add active class to clicked tab and corresponding content
62
+ this.classList.add('active');
63
+ const activeContent = document.getElementById(tabName);
64
+ if (activeContent) {
65
+ activeContent.classList.add('active');
66
+ }
67
+ });
68
+ });
69
+
70
+ // Navbar Background on Scroll
71
+ const navbar = document.querySelector('.navbar');
72
+ let lastScroll = 0;
73
+
74
+ window.addEventListener('scroll', function() {
75
+ const currentScroll = window.pageYOffset;
76
+
77
+ if (currentScroll > 100) {
78
+ navbar.style.background = 'rgba(255, 255, 255, 0.98)';
79
+ navbar.style.backdropFilter = 'blur(10px)';
80
+ navbar.style.boxShadow = '0 4px 20px rgba(0,0,0,0.1)';
81
+ } else {
82
+ navbar.style.background = 'white';
83
+ navbar.style.backdropFilter = 'none';
84
+ navbar.style.boxShadow = '0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24)';
85
+ }
86
+
87
+ // Hide/Show navbar on scroll
88
+ if (currentScroll > lastScroll && currentScroll > 500) {
89
+ navbar.style.transform = 'translateY(-100%)';
90
+ } else {
91
+ navbar.style.transform = 'translateY(0)';
92
+ }
93
+
94
+ lastScroll = currentScroll;
95
+ });
96
+
97
+ // Animate Elements on Scroll
98
+ const observerOptions = {
99
+ threshold: 0.1,
100
+ rootMargin: '0px 0px -100px 0px'
101
+ };
102
+
103
+ const observer = new IntersectionObserver(function(entries) {
104
+ entries.forEach(entry => {
105
+ if (entry.isIntersecting) {
106
+ entry.target.style.opacity = '1';
107
+ entry.target.style.transform = 'translateY(0)';
108
+
109
+ // Add stagger effect for grid items
110
+ if (entry.target.classList.contains('feature') ||
111
+ entry.target.classList.contains('mcp-card') ||
112
+ entry.target.classList.contains('what-is-card')) {
113
+ const siblings = entry.target.parentElement.children;
114
+ Array.from(siblings).forEach((sibling, index) => {
115
+ setTimeout(() => {
116
+ sibling.style.opacity = '1';
117
+ sibling.style.transform = 'translateY(0)';
118
+ }, index * 100);
119
+ });
120
+ }
121
+ }
122
+ });
123
+ }, observerOptions);
124
+
125
+ // Observe elements for animation
126
+ const animateElements = document.querySelectorAll('.feature, .mcp-card, .what-is-card, .workflow-step, .example-card, .practice');
127
+ animateElements.forEach(el => {
128
+ el.style.opacity = '0';
129
+ el.style.transform = 'translateY(20px)';
130
+ el.style.transition = 'opacity 0.6s ease, transform 0.6s ease';
131
+ observer.observe(el);
132
+ });
133
+
134
+ // Copy Code Functionality
135
+ const codeBlocks = document.querySelectorAll('pre code');
136
+ codeBlocks.forEach(block => {
137
+ const wrapper = block.parentElement;
138
+
139
+ // Create copy button
140
+ const copyBtn = document.createElement('button');
141
+ copyBtn.className = 'copy-btn';
142
+ copyBtn.textContent = 'Copy';
143
+ copyBtn.style.cssText = `
144
+ position: absolute;
145
+ top: 10px;
146
+ right: 10px;
147
+ background: rgba(255,255,255,0.1);
148
+ color: white;
149
+ border: 1px solid rgba(255,255,255,0.2);
150
+ padding: 5px 15px;
151
+ border-radius: 5px;
152
+ cursor: pointer;
153
+ font-size: 0.9rem;
154
+ transition: all 0.3s ease;
155
+ `;
156
+
157
+ wrapper.style.position = 'relative';
158
+ wrapper.appendChild(copyBtn);
159
+
160
+ copyBtn.addEventListener('click', function() {
161
+ const text = block.textContent;
162
+ navigator.clipboard.writeText(text).then(() => {
163
+ copyBtn.textContent = 'Copied!';
164
+ copyBtn.style.background = '#48bb78';
165
+ copyBtn.style.borderColor = '#48bb78';
166
+
167
+ setTimeout(() => {
168
+ copyBtn.textContent = 'Copy';
169
+ copyBtn.style.background = 'rgba(255,255,255,0.1)';
170
+ copyBtn.style.borderColor = 'rgba(255,255,255,0.2)';
171
+ }, 2000);
172
+ });
173
+ });
174
+
175
+ // Show copy button on hover
176
+ wrapper.addEventListener('mouseenter', () => {
177
+ copyBtn.style.opacity = '1';
178
+ });
179
+
180
+ wrapper.addEventListener('mouseleave', () => {
181
+ if (copyBtn.textContent === 'Copy') {
182
+ copyBtn.style.opacity = '0.7';
183
+ }
184
+ });
185
+ });
186
+
187
+ // Active Section Highlighting in Navigation
188
+ const sections = document.querySelectorAll('section[id]');
189
+
190
+ function highlightNavigation() {
191
+ const scrollPosition = window.scrollY + 100;
192
+
193
+ sections.forEach(section => {
194
+ const sectionTop = section.offsetTop;
195
+ const sectionHeight = section.offsetHeight;
196
+ const sectionId = section.getAttribute('id');
197
+
198
+ if (scrollPosition >= sectionTop && scrollPosition < sectionTop + sectionHeight) {
199
+ navLinks.forEach(link => {
200
+ link.classList.remove('active');
201
+ if (link.getAttribute('href') === `#${sectionId}`) {
202
+ link.classList.add('active');
203
+ }
204
+ });
205
+ }
206
+ });
207
+ }
208
+
209
+ window.addEventListener('scroll', highlightNavigation);
210
+
211
+ // Typing Effect for Hero Title
212
+ const heroTitle = document.querySelector('.hero-title');
213
+ if (heroTitle) {
214
+ const text = heroTitle.textContent;
215
+ heroTitle.textContent = '';
216
+ let index = 0;
217
+
218
+ function typeText() {
219
+ if (index < text.length) {
220
+ heroTitle.textContent += text.charAt(index);
221
+ index++;
222
+ setTimeout(typeText, 100);
223
+ }
224
+ }
225
+
226
+ // Start typing after a short delay
227
+ setTimeout(typeText, 500);
228
+ }
229
+
230
+ // Counter Animation for Stats
231
+ const stats = document.querySelectorAll('.stat-number');
232
+ const statsObserver = new IntersectionObserver(function(entries) {
233
+ entries.forEach(entry => {
234
+ if (entry.isIntersecting && !entry.target.classList.contains('counted')) {
235
+ entry.target.classList.add('counted');
236
+ const target = entry.target;
237
+ const value = target.textContent;
238
+
239
+ // Extract number from string (e.g., "16+" -> 16)
240
+ const number = parseInt(value.replace(/\D/g, ''));
241
+ const suffix = value.replace(/\d/g, '');
242
+ const duration = 2000; // 2 seconds
243
+ const increment = number / (duration / 16); // 60fps
244
+ let current = 0;
245
+
246
+ const counter = setInterval(() => {
247
+ current += increment;
248
+ if (current >= number) {
249
+ target.textContent = number + suffix;
250
+ clearInterval(counter);
251
+ } else {
252
+ target.textContent = Math.floor(current) + suffix;
253
+ }
254
+ }, 16);
255
+ }
256
+ });
257
+ }, { threshold: 0.5 });
258
+
259
+ stats.forEach(stat => {
260
+ statsObserver.observe(stat);
261
+ });
262
+
263
+ // Search Functionality for MCP Tools
264
+ const searchInput = document.createElement('input');
265
+ searchInput.type = 'text';
266
+ searchInput.placeholder = 'Search MCP tools...';
267
+ searchInput.className = 'mcp-search';
268
+ searchInput.style.cssText = `
269
+ width: 100%;
270
+ max-width: 400px;
271
+ margin: 0 auto 2rem;
272
+ display: block;
273
+ padding: 12px 20px;
274
+ border: 2px solid #e2e8f0;
275
+ border-radius: 25px;
276
+ font-size: 1rem;
277
+ transition: all 0.3s ease;
278
+ `;
279
+
280
+ const mcpSection = document.querySelector('#mcp-servers .container');
281
+ if (mcpSection) {
282
+ const subtitle = mcpSection.querySelector('.section-subtitle');
283
+ if (subtitle) {
284
+ subtitle.insertAdjacentElement('afterend', searchInput);
285
+ }
286
+
287
+ searchInput.addEventListener('input', function(e) {
288
+ const searchTerm = e.target.value.toLowerCase();
289
+ const mcpCards = document.querySelectorAll('.mcp-card');
290
+
291
+ mcpCards.forEach(card => {
292
+ const text = card.textContent.toLowerCase();
293
+ if (text.includes(searchTerm)) {
294
+ card.style.display = 'block';
295
+ card.style.animation = 'fadeIn 0.3s ease';
296
+ } else {
297
+ card.style.display = 'none';
298
+ }
299
+ });
300
+ });
301
+
302
+ searchInput.addEventListener('focus', function() {
303
+ this.style.borderColor = '#0066cc';
304
+ this.style.boxShadow = '0 0 0 3px rgba(0,102,204,0.1)';
305
+ });
306
+
307
+ searchInput.addEventListener('blur', function() {
308
+ this.style.borderColor = '#e2e8f0';
309
+ this.style.boxShadow = 'none';
310
+ });
311
+ }
312
+
313
+ // Add Loading Animation
314
+ window.addEventListener('load', function() {
315
+ document.body.classList.add('loaded');
316
+ });
317
+
318
+ // Console Easter Egg
319
+ console.log('%c🏔️❄️ Snow-Flow', 'font-size: 30px; font-weight: bold; background: linear-gradient(135deg, #0066cc 0%, #00d4ff 100%); color: white; padding: 10px 20px; border-radius: 10px;');
320
+ console.log('%cAdvanced ServiceNow Development Framework', 'font-size: 14px; color: #666;');
321
+ console.log('%cVersion 3.4.14 | MIT License', 'font-size: 12px; color: #999;');
322
+ console.log('%cInterested in contributing? Visit: https://github.com/groeimetai/snow-flow', 'font-size: 12px; color: #0066cc;');
323
+ });
@@ -0,0 +1,37 @@
1
+ # Netlify deployment configuration for Snow-Flow website
2
+
3
+ [build]
4
+ publish = "."
5
+
6
+ [[headers]]
7
+ for = "/*"
8
+ [headers.values]
9
+ X-Frame-Options = "DENY"
10
+ X-XSS-Protection = "1; mode=block"
11
+ X-Content-Type-Options = "nosniff"
12
+ Referrer-Policy = "strict-origin-when-cross-origin"
13
+
14
+ [[headers]]
15
+ for = "/*.js"
16
+ [headers.values]
17
+ Cache-Control = "public, max-age=604800"
18
+
19
+ [[headers]]
20
+ for = "/*.css"
21
+ [headers.values]
22
+ Cache-Control = "public, max-age=604800"
23
+
24
+ [[headers]]
25
+ for = "/images/*"
26
+ [headers.values]
27
+ Cache-Control = "public, max-age=2592000"
28
+
29
+ [[redirects]]
30
+ from = "/api"
31
+ to = "/docs/api-full.html"
32
+ status = 301
33
+
34
+ [[redirects]]
35
+ from = "/docs"
36
+ to = "/docs/api-full.html"
37
+ status = 301
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "snow-flow-website",
3
+ "version": "1.0.0",
4
+ "description": "Official documentation website for Snow-Flow - Advanced ServiceNow Development Framework",
5
+ "main": "index.html",
6
+ "scripts": {
7
+ "serve": "npx http-server -p 8080",
8
+ "serve:python": "python -m http.server 8080",
9
+ "deploy:netlify": "netlify deploy --prod",
10
+ "deploy:vercel": "vercel --prod",
11
+ "deploy:surge": "surge . snow-flow.surge.sh",
12
+ "lint:html": "npx htmlhint '**/*.html'",
13
+ "lint:css": "npx stylelint 'css/*.css'",
14
+ "optimize:images": "npx imagemin images/* --out-dir=images",
15
+ "minify:css": "npx cleancss -o css/style.min.css css/style.css && npx cleancss -o css/api-docs.min.css css/api-docs.css",
16
+ "minify:js": "npx terser js/main.js -o js/main.min.js",
17
+ "build": "npm run minify:css && npm run minify:js",
18
+ "test": "npx live-server"
19
+ },
20
+ "keywords": [
21
+ "snow-flow",
22
+ "servicenow",
23
+ "documentation",
24
+ "mcp",
25
+ "api",
26
+ "developer-tools"
27
+ ],
28
+ "author": "Snow-Flow Team",
29
+ "license": "MIT",
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "https://github.com/groeimetai/snow-flow.git"
33
+ },
34
+ "homepage": "https://snow-flow.dev",
35
+ "devDependencies": {
36
+ "http-server": "^14.1.1",
37
+ "live-server": "^1.2.2",
38
+ "htmlhint": "^1.1.4",
39
+ "stylelint": "^15.11.0",
40
+ "clean-css-cli": "^5.6.2",
41
+ "terser": "^5.24.0",
42
+ "imagemin-cli": "^7.0.0"
43
+ },
44
+ "browserslist": [
45
+ "> 1%",
46
+ "last 2 versions",
47
+ "not dead"
48
+ ]
49
+ }
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "snow-flow-docs",
3
+ "version": 2,
4
+ "public": true,
5
+ "headers": [
6
+ {
7
+ "source": "/(.*)",
8
+ "headers": [
9
+ {
10
+ "key": "X-Frame-Options",
11
+ "value": "DENY"
12
+ },
13
+ {
14
+ "key": "X-Content-Type-Options",
15
+ "value": "nosniff"
16
+ },
17
+ {
18
+ "key": "X-XSS-Protection",
19
+ "value": "1; mode=block"
20
+ }
21
+ ]
22
+ },
23
+ {
24
+ "source": "/(.*)\\.(js|css)",
25
+ "headers": [
26
+ {
27
+ "key": "Cache-Control",
28
+ "value": "public, max-age=604800"
29
+ }
30
+ ]
31
+ },
32
+ {
33
+ "source": "/images/(.*)",
34
+ "headers": [
35
+ {
36
+ "key": "Cache-Control",
37
+ "value": "public, max-age=2592000"
38
+ }
39
+ ]
40
+ }
41
+ ],
42
+ "redirects": [
43
+ {
44
+ "source": "/api",
45
+ "destination": "/docs/api-full.html",
46
+ "permanent": true
47
+ },
48
+ {
49
+ "source": "/docs",
50
+ "destination": "/docs/api-full.html",
51
+ "permanent": true
52
+ }
53
+ ]
54
+ }