snow-flow 3.4.36 → 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/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,200 @@
|
|
|
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 Code Display Component</title>
|
|
7
|
+
<link rel="stylesheet" href="CodeDisplay.css">
|
|
8
|
+
<style>
|
|
9
|
+
body {
|
|
10
|
+
background: #f5f5f5;
|
|
11
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
12
|
+
padding: 2rem;
|
|
13
|
+
margin: 0;
|
|
14
|
+
}
|
|
15
|
+
.demo-container {
|
|
16
|
+
max-width: 800px;
|
|
17
|
+
margin: 0 auto;
|
|
18
|
+
}
|
|
19
|
+
.demo-title {
|
|
20
|
+
text-align: center;
|
|
21
|
+
margin-bottom: 2rem;
|
|
22
|
+
color: #333;
|
|
23
|
+
}
|
|
24
|
+
.demo-section {
|
|
25
|
+
margin-bottom: 3rem;
|
|
26
|
+
}
|
|
27
|
+
.demo-section h3 {
|
|
28
|
+
margin-bottom: 1rem;
|
|
29
|
+
color: #666;
|
|
30
|
+
}
|
|
31
|
+
</style>
|
|
32
|
+
</head>
|
|
33
|
+
<body>
|
|
34
|
+
<div class="demo-container">
|
|
35
|
+
<h1 class="demo-title">Snow-Flow Code Display Components</h1>
|
|
36
|
+
|
|
37
|
+
<!-- Demo Section 1: JavaScript Example -->
|
|
38
|
+
<div class="demo-section">
|
|
39
|
+
<h3>JavaScript Example</h3>
|
|
40
|
+
<div class="sf-code-display" id="sf-code-display-1">
|
|
41
|
+
<div class="sf-code-display__header">
|
|
42
|
+
<div class="sf-code-display__window-controls">
|
|
43
|
+
<span class="sf-code-display__control sf-code-display__control--close"></span>
|
|
44
|
+
<span class="sf-code-display__control sf-code-display__control--minimize"></span>
|
|
45
|
+
<span class="sf-code-display__control sf-code-display__control--maximize"></span>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<div class="sf-code-display__title">
|
|
49
|
+
<span class="sf-code-display__icon">{}</span>
|
|
50
|
+
<span class="sf-code-display__filename">snow-flow-example.js</span>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<button class="sf-code-display__copy" data-target="code-1">
|
|
54
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
55
|
+
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"/>
|
|
56
|
+
<path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/>
|
|
57
|
+
</svg>
|
|
58
|
+
<span class="sf-code-display__copy-text">Copy</span>
|
|
59
|
+
</button>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<div class="sf-code-display__body">
|
|
63
|
+
<div class="sf-code-display__line-numbers" id="line-numbers-1">
|
|
64
|
+
<!-- Line numbers will be generated by JavaScript -->
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<div class="sf-code-display__content">
|
|
68
|
+
<pre class="sf-code-display__pre">
|
|
69
|
+
<code class="sf-code-display__code language-javascript" id="code-1">// Welcome to Snow-Flow
|
|
70
|
+
const snowFlow = new SnowFlowFramework({
|
|
71
|
+
mode: 'development',
|
|
72
|
+
verbose: true
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Execute background script
|
|
76
|
+
await snow_execute_script_with_output({
|
|
77
|
+
script: `
|
|
78
|
+
var gr = new GlideRecord('incident');
|
|
79
|
+
gr.addActiveQuery();
|
|
80
|
+
gr.query();
|
|
81
|
+
|
|
82
|
+
var count = 0;
|
|
83
|
+
while(gr.next()) {
|
|
84
|
+
count++;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
gs.info('Total incidents: ' + count);
|
|
88
|
+
`,
|
|
89
|
+
description: 'Count active incidents'
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
console.log('Snow-Flow initialized successfully!');</code>
|
|
93
|
+
</pre>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
|
|
97
|
+
<div class="sf-code-display__cursor"></div>
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
<!-- Demo Section 2: Shell/Bash Example -->
|
|
102
|
+
<div class="demo-section">
|
|
103
|
+
<h3>Shell Script Example</h3>
|
|
104
|
+
<div class="sf-code-display" id="sf-code-display-2">
|
|
105
|
+
<div class="sf-code-display__header">
|
|
106
|
+
<div class="sf-code-display__window-controls">
|
|
107
|
+
<span class="sf-code-display__control sf-code-display__control--close"></span>
|
|
108
|
+
<span class="sf-code-display__control sf-code-display__control--minimize"></span>
|
|
109
|
+
<span class="sf-code-display__control sf-code-display__control--maximize"></span>
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
<div class="sf-code-display__title">
|
|
113
|
+
<span class="sf-code-display__icon">$</span>
|
|
114
|
+
<span class="sf-code-display__filename">setup-snow-flow.sh</span>
|
|
115
|
+
</div>
|
|
116
|
+
|
|
117
|
+
<button class="sf-code-display__copy" data-target="code-2">
|
|
118
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
119
|
+
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"/>
|
|
120
|
+
<path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/>
|
|
121
|
+
</svg>
|
|
122
|
+
<span class="sf-code-display__copy-text">Copy</span>
|
|
123
|
+
</button>
|
|
124
|
+
</div>
|
|
125
|
+
|
|
126
|
+
<div class="sf-code-display__body">
|
|
127
|
+
<div class="sf-code-display__line-numbers" id="line-numbers-2">
|
|
128
|
+
<!-- Line numbers will be generated by JavaScript -->
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
<div class="sf-code-display__content">
|
|
132
|
+
<pre class="sf-code-display__pre">
|
|
133
|
+
<code class="sf-code-display__code language-bash" id="code-2">#!/bin/bash
|
|
134
|
+
|
|
135
|
+
# Snow-Flow Installation Script
|
|
136
|
+
echo "Installing Snow-Flow..."
|
|
137
|
+
|
|
138
|
+
# Check if Node.js is installed
|
|
139
|
+
if ! command -v node &> /dev/null; then
|
|
140
|
+
echo "Node.js is required but not installed."
|
|
141
|
+
exit 1
|
|
142
|
+
fi
|
|
143
|
+
|
|
144
|
+
# Install Snow-Flow globally
|
|
145
|
+
npm install -g snow-flow
|
|
146
|
+
|
|
147
|
+
# Initialize Snow-Flow in current directory
|
|
148
|
+
snow-flow init
|
|
149
|
+
|
|
150
|
+
# Authenticate with ServiceNow
|
|
151
|
+
echo "Please authenticate with your ServiceNow instance:"
|
|
152
|
+
snow-flow auth login
|
|
153
|
+
|
|
154
|
+
echo "Snow-Flow setup complete! 🎉"</code>
|
|
155
|
+
</pre>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
|
|
159
|
+
<div class="sf-code-display__cursor"></div>
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
162
|
+
|
|
163
|
+
<!-- Demo Section 3: Simple without header -->
|
|
164
|
+
<div class="demo-section">
|
|
165
|
+
<h3>Simple Code Block (No Header)</h3>
|
|
166
|
+
<div class="sf-code-display sf-code-display--simple" id="sf-code-display-3">
|
|
167
|
+
<div class="sf-code-display__body">
|
|
168
|
+
<div class="sf-code-display__line-numbers" id="line-numbers-3">
|
|
169
|
+
<!-- Line numbers will be generated by JavaScript -->
|
|
170
|
+
</div>
|
|
171
|
+
|
|
172
|
+
<div class="sf-code-display__content">
|
|
173
|
+
<pre class="sf-code-display__pre">
|
|
174
|
+
<code class="sf-code-display__code language-javascript" id="code-3">// Quick code snippet
|
|
175
|
+
const result = await snow_query_table({
|
|
176
|
+
table: 'incident',
|
|
177
|
+
query: 'state=1^priority=1',
|
|
178
|
+
fields: ['number', 'short_description'],
|
|
179
|
+
limit: 10
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
console.log('Found incidents:', result.length);</code>
|
|
183
|
+
</pre>
|
|
184
|
+
</div>
|
|
185
|
+
</div>
|
|
186
|
+
|
|
187
|
+
<!-- Floating copy button -->
|
|
188
|
+
<button class="sf-code-display__copy sf-code-display__copy--floating" data-target="code-3">
|
|
189
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
190
|
+
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"/>
|
|
191
|
+
<path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/>
|
|
192
|
+
</svg>
|
|
193
|
+
</button>
|
|
194
|
+
</div>
|
|
195
|
+
</div>
|
|
196
|
+
</div>
|
|
197
|
+
|
|
198
|
+
<script src="CodeDisplay.js"></script>
|
|
199
|
+
</body>
|
|
200
|
+
</html>
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
// Snow-Flow Code Display Component JavaScript
|
|
2
|
+
|
|
3
|
+
class SnowFlowCodeDisplay {
|
|
4
|
+
constructor(options = {}) {
|
|
5
|
+
// Configuration
|
|
6
|
+
this.config = {
|
|
7
|
+
selector: options.selector || '.sf-code-display',
|
|
8
|
+
theme: options.theme || 'dark',
|
|
9
|
+
showLineNumbers: options.showLineNumbers !== false,
|
|
10
|
+
enableCopy: options.enableCopy !== false,
|
|
11
|
+
enableSyntaxHighlighting: options.enableSyntaxHighlighting !== false,
|
|
12
|
+
|
|
13
|
+
// Animation settings
|
|
14
|
+
intersectionThreshold: options.intersectionThreshold || 0.1,
|
|
15
|
+
|
|
16
|
+
// State
|
|
17
|
+
instances: new Map()
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
this.init();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
init() {
|
|
24
|
+
this.findAndInitializeCodeDisplays();
|
|
25
|
+
this.setupIntersectionObserver();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
findAndInitializeCodeDisplays() {
|
|
29
|
+
const codeDisplays = document.querySelectorAll(this.config.selector);
|
|
30
|
+
|
|
31
|
+
codeDisplays.forEach((element, index) => {
|
|
32
|
+
const instance = this.initializeInstance(element, index);
|
|
33
|
+
this.config.instances.set(element, instance);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
initializeInstance(element, index) {
|
|
38
|
+
const instance = {
|
|
39
|
+
element,
|
|
40
|
+
id: `sf-code-${index}`,
|
|
41
|
+
codeElement: element.querySelector('.sf-code-display__code'),
|
|
42
|
+
lineNumbersElement: element.querySelector('.sf-code-display__line-numbers'),
|
|
43
|
+
copyButtons: element.querySelectorAll('.sf-code-display__copy'),
|
|
44
|
+
isVisible: false
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Setup line numbers
|
|
48
|
+
if (this.config.showLineNumbers && instance.codeElement && instance.lineNumbersElement) {
|
|
49
|
+
this.generateLineNumbers(instance);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Setup copy functionality
|
|
53
|
+
if (this.config.enableCopy) {
|
|
54
|
+
this.setupCopyButtons(instance);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Apply syntax highlighting
|
|
58
|
+
if (this.config.enableSyntaxHighlighting && instance.codeElement) {
|
|
59
|
+
this.applySyntaxHighlighting(instance);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return instance;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
generateLineNumbers(instance) {
|
|
66
|
+
const code = instance.codeElement.textContent || instance.codeElement.innerText;
|
|
67
|
+
const lines = code.split('\n');
|
|
68
|
+
const lineCount = lines.length;
|
|
69
|
+
|
|
70
|
+
// Clear existing line numbers
|
|
71
|
+
instance.lineNumbersElement.innerHTML = '';
|
|
72
|
+
|
|
73
|
+
// Generate line numbers
|
|
74
|
+
for (let i = 1; i <= lineCount; i++) {
|
|
75
|
+
const lineNumber = document.createElement('span');
|
|
76
|
+
lineNumber.className = 'sf-code-display__line-number';
|
|
77
|
+
lineNumber.textContent = i;
|
|
78
|
+
instance.lineNumbersElement.appendChild(lineNumber);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
setupCopyButtons(instance) {
|
|
83
|
+
instance.copyButtons.forEach(button => {
|
|
84
|
+
button.addEventListener('click', (e) => {
|
|
85
|
+
this.handleCopyClick(e, instance);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async handleCopyClick(e, instance) {
|
|
91
|
+
e.preventDefault();
|
|
92
|
+
|
|
93
|
+
const button = e.currentTarget;
|
|
94
|
+
const targetId = button.getAttribute('data-target');
|
|
95
|
+
|
|
96
|
+
let codeElement = instance.codeElement;
|
|
97
|
+
if (targetId) {
|
|
98
|
+
codeElement = document.getElementById(targetId);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (!codeElement) return;
|
|
102
|
+
|
|
103
|
+
const code = codeElement.textContent || codeElement.innerText;
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
await this.copyToClipboard(code);
|
|
107
|
+
this.showCopySuccess(button, instance);
|
|
108
|
+
} catch (err) {
|
|
109
|
+
console.error('Failed to copy code:', err);
|
|
110
|
+
this.showCopyError(button);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async copyToClipboard(text) {
|
|
115
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
116
|
+
await navigator.clipboard.writeText(text);
|
|
117
|
+
} else {
|
|
118
|
+
// Fallback for older browsers
|
|
119
|
+
const textArea = document.createElement('textarea');
|
|
120
|
+
textArea.value = text;
|
|
121
|
+
textArea.style.cssText = 'position:fixed;top:-999px;left:-999px;';
|
|
122
|
+
document.body.appendChild(textArea);
|
|
123
|
+
textArea.select();
|
|
124
|
+
document.execCommand('copy');
|
|
125
|
+
document.body.removeChild(textArea);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
showCopySuccess(button, instance) {
|
|
130
|
+
// Update button state
|
|
131
|
+
const originalContent = button.innerHTML;
|
|
132
|
+
button.classList.add('sf-code-display__copy--copied');
|
|
133
|
+
|
|
134
|
+
// Update icon and text
|
|
135
|
+
const icon = button.querySelector('svg');
|
|
136
|
+
const text = button.querySelector('.sf-code-display__copy-text');
|
|
137
|
+
|
|
138
|
+
if (icon) {
|
|
139
|
+
icon.innerHTML = '<path d="M20 6L9 17L4 12"/>';
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (text) {
|
|
143
|
+
text.textContent = 'Copied!';
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Show feedback overlay
|
|
147
|
+
this.showCopyFeedback(instance);
|
|
148
|
+
|
|
149
|
+
// Reset button after 2 seconds
|
|
150
|
+
setTimeout(() => {
|
|
151
|
+
button.classList.remove('sf-code-display__copy--copied');
|
|
152
|
+
button.innerHTML = originalContent;
|
|
153
|
+
}, 2000);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
showCopyError(button) {
|
|
157
|
+
// Simple error indication
|
|
158
|
+
button.style.background = 'rgba(255, 59, 48, 0.2)';
|
|
159
|
+
button.style.borderColor = '#ff3b30';
|
|
160
|
+
button.style.color = '#ff3b30';
|
|
161
|
+
|
|
162
|
+
setTimeout(() => {
|
|
163
|
+
button.style.background = '';
|
|
164
|
+
button.style.borderColor = '';
|
|
165
|
+
button.style.color = '';
|
|
166
|
+
}, 2000);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
showCopyFeedback(instance) {
|
|
170
|
+
// Create feedback element
|
|
171
|
+
const feedback = document.createElement('div');
|
|
172
|
+
feedback.className = 'sf-code-display__copy-feedback';
|
|
173
|
+
feedback.innerHTML = `
|
|
174
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
175
|
+
<path d="M20 6L9 17L4 12"/>
|
|
176
|
+
</svg>
|
|
177
|
+
Copied to clipboard!
|
|
178
|
+
`;
|
|
179
|
+
|
|
180
|
+
instance.element.appendChild(feedback);
|
|
181
|
+
|
|
182
|
+
// Remove after animation
|
|
183
|
+
setTimeout(() => {
|
|
184
|
+
if (feedback.parentNode) {
|
|
185
|
+
feedback.parentNode.removeChild(feedback);
|
|
186
|
+
}
|
|
187
|
+
}, 2000);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
applySyntaxHighlighting(instance) {
|
|
191
|
+
const codeElement = instance.codeElement;
|
|
192
|
+
let code = codeElement.textContent || codeElement.innerText;
|
|
193
|
+
|
|
194
|
+
// Get language from class
|
|
195
|
+
const classList = Array.from(codeElement.classList);
|
|
196
|
+
const languageClass = classList.find(cls => cls.startsWith('language-'));
|
|
197
|
+
const language = languageClass ? languageClass.replace('language-', '') : 'javascript';
|
|
198
|
+
|
|
199
|
+
// Apply highlighting based on language
|
|
200
|
+
const highlightedCode = this.highlightCode(code, language);
|
|
201
|
+
codeElement.innerHTML = highlightedCode;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
highlightCode(code, language) {
|
|
205
|
+
// Define patterns for different languages
|
|
206
|
+
const patterns = this.getLanguagePatterns(language);
|
|
207
|
+
|
|
208
|
+
let highlightedCode = code;
|
|
209
|
+
|
|
210
|
+
// Apply patterns in sequence
|
|
211
|
+
patterns.forEach(({ pattern, replacement, className }) => {
|
|
212
|
+
highlightedCode = highlightedCode.replace(pattern, replacement);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
return highlightedCode;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
getLanguagePatterns(language) {
|
|
219
|
+
const basePatterns = [
|
|
220
|
+
// Comments
|
|
221
|
+
{
|
|
222
|
+
pattern: /(\/\/.*$|\/\*[\s\S]*?\*\/|#.*$)/gm,
|
|
223
|
+
replacement: '<span class="sf-code-comment">$1</span>'
|
|
224
|
+
},
|
|
225
|
+
// Strings
|
|
226
|
+
{
|
|
227
|
+
pattern: /(['"`])((?:\\.|(?!\1)[^\\\r\n])*?)\1/g,
|
|
228
|
+
replacement: '<span class="sf-code-string">$1$2$1</span>'
|
|
229
|
+
},
|
|
230
|
+
// Numbers
|
|
231
|
+
{
|
|
232
|
+
pattern: /\b(\d+\.?\d*)\b/g,
|
|
233
|
+
replacement: '<span class="sf-code-number">$1</span>'
|
|
234
|
+
}
|
|
235
|
+
];
|
|
236
|
+
|
|
237
|
+
const languageSpecificPatterns = {
|
|
238
|
+
javascript: [
|
|
239
|
+
{
|
|
240
|
+
pattern: /\b(async|await|const|let|var|function|return|if|else|for|while|try|catch|finally|class|extends|import|export|from|default|typeof|instanceof|new|this|super|static|public|private|protected)\b/g,
|
|
241
|
+
replacement: '<span class="sf-code-keyword">$1</span>'
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
pattern: /\b([a-zA-Z_$][a-zA-Z0-9_$]*)\s*(?=\()/g,
|
|
245
|
+
replacement: '<span class="sf-code-function">$1</span>'
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
pattern: /\.([a-zA-Z_$][a-zA-Z0-9_$]*)\b/g,
|
|
249
|
+
replacement: '.<span class="sf-code-property">$1</span>'
|
|
250
|
+
}
|
|
251
|
+
],
|
|
252
|
+
bash: [
|
|
253
|
+
{
|
|
254
|
+
pattern: /\b(if|then|else|elif|fi|for|while|do|done|case|esac|function|return|local|export|alias|source|echo|cd|ls|cp|mv|rm|mkdir|chmod|chown|grep|awk|sed|sort|uniq|head|tail|cat|more|less)\b/g,
|
|
255
|
+
replacement: '<span class="sf-code-keyword">$1</span>'
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
pattern: /(\$[a-zA-Z_][a-zA-Z0-9_]*|\$\{[^}]*\})/g,
|
|
259
|
+
replacement: '<span class="sf-code-property">$1</span>'
|
|
260
|
+
}
|
|
261
|
+
],
|
|
262
|
+
python: [
|
|
263
|
+
{
|
|
264
|
+
pattern: /\b(and|as|assert|break|class|continue|def|del|elif|else|except|finally|for|from|global|if|import|in|is|lambda|nonlocal|not|or|pass|raise|return|try|while|with|yield|async|await)\b/g,
|
|
265
|
+
replacement: '<span class="sf-code-keyword">$1</span>'
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
pattern: /\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/g,
|
|
269
|
+
replacement: '<span class="sf-code-function">$1</span>'
|
|
270
|
+
}
|
|
271
|
+
]
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
// Operators (common to all languages)
|
|
275
|
+
const operatorPattern = {
|
|
276
|
+
pattern: /(\+|\-|\*|\/|%|=|==|===|!=|!==|<|>|<=|>=|&&|\|\||!|\?|:|&|\||\^|~|<<|>>)/g,
|
|
277
|
+
replacement: '<span class="sf-code-operator">$1</span>'
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
return [
|
|
281
|
+
...basePatterns,
|
|
282
|
+
...(languageSpecificPatterns[language] || languageSpecificPatterns.javascript),
|
|
283
|
+
operatorPattern
|
|
284
|
+
];
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
setupIntersectionObserver() {
|
|
288
|
+
const observer = new IntersectionObserver(
|
|
289
|
+
(entries) => {
|
|
290
|
+
entries.forEach(entry => {
|
|
291
|
+
const instance = this.config.instances.get(entry.target);
|
|
292
|
+
if (instance && entry.isIntersecting && !instance.isVisible) {
|
|
293
|
+
instance.isVisible = true;
|
|
294
|
+
entry.target.classList.add('sf-code-display--visible');
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
},
|
|
298
|
+
{ threshold: this.config.intersectionThreshold }
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
this.config.instances.forEach((instance) => {
|
|
302
|
+
observer.observe(instance.element);
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Public API methods
|
|
307
|
+
addCodeDisplay(element) {
|
|
308
|
+
const index = this.config.instances.size;
|
|
309
|
+
const instance = this.initializeInstance(element, index);
|
|
310
|
+
this.config.instances.set(element, instance);
|
|
311
|
+
|
|
312
|
+
// Setup intersection observer for the new element
|
|
313
|
+
const observer = new IntersectionObserver(
|
|
314
|
+
([entry]) => {
|
|
315
|
+
if (entry.isIntersecting && !instance.isVisible) {
|
|
316
|
+
instance.isVisible = true;
|
|
317
|
+
entry.target.classList.add('sf-code-display--visible');
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
{ threshold: this.config.intersectionThreshold }
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
observer.observe(element);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
updateCode(element, newCode) {
|
|
327
|
+
const instance = this.config.instances.get(element);
|
|
328
|
+
if (!instance || !instance.codeElement) return;
|
|
329
|
+
|
|
330
|
+
instance.codeElement.textContent = newCode;
|
|
331
|
+
|
|
332
|
+
// Re-apply highlighting and line numbers
|
|
333
|
+
if (this.config.enableSyntaxHighlighting) {
|
|
334
|
+
this.applySyntaxHighlighting(instance);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (this.config.showLineNumbers) {
|
|
338
|
+
this.generateLineNumbers(instance);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
setTheme(theme) {
|
|
343
|
+
this.config.theme = theme;
|
|
344
|
+
|
|
345
|
+
this.config.instances.forEach((instance) => {
|
|
346
|
+
if (theme === 'light') {
|
|
347
|
+
instance.element.classList.add('sf-code-display--light');
|
|
348
|
+
} else {
|
|
349
|
+
instance.element.classList.remove('sf-code-display--light');
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
destroy() {
|
|
355
|
+
// Cleanup method
|
|
356
|
+
this.config.instances.clear();
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Auto-initialize on DOM content loaded
|
|
361
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
362
|
+
// Check if code displays exist before initializing
|
|
363
|
+
const codeDisplays = document.querySelectorAll('.sf-code-display');
|
|
364
|
+
if (codeDisplays.length > 0) {
|
|
365
|
+
window.snowFlowCodeDisplay = new SnowFlowCodeDisplay();
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
// Export for module usage
|
|
370
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
371
|
+
module.exports = SnowFlowCodeDisplay;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Global access
|
|
375
|
+
window.SnowFlowCodeDisplay = SnowFlowCodeDisplay;
|