danielNisnevich commited on
Commit
8bc8450
·
verified ·
1 Parent(s): 36fd854

PoC of the idea

Files changed (1) hide show
  1. index.html +339 -19
index.html CHANGED
@@ -1,19 +1,339 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>Modern Regex Generator</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
9
+ <style>
10
+ body {
11
+ font-family: 'Inter', sans-serif;
12
+ background: linear-gradient(135deg, #e0c3fc 0%, #8ec5fc 100%);
13
+ min-height: 100vh;
14
+ }
15
+
16
+ .card {
17
+ background: rgba(255, 255, 255, 0.9);
18
+ backdrop-filter: blur(10px);
19
+ border-radius: 16px;
20
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
21
+ transition: all 0.3s ease;
22
+ }
23
+
24
+ .card:hover {
25
+ transform: translateY(-2px);
26
+ box-shadow: 0 15px 35px rgba(0, 0, 0, 0.15);
27
+ }
28
+
29
+ .input-box {
30
+ background: linear-gradient(90deg, rgba(245, 245, 245, 0.8) 0%, rgba(255, 255, 255, 0.9) 100%);
31
+ border-radius: 12px;
32
+ }
33
+
34
+ .btn-primary {
35
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
36
+ color: white;
37
+ border: none;
38
+ transition: all 0.3s ease;
39
+ }
40
+
41
+ .btn-primary:hover {
42
+ transform: translateY(-2px);
43
+ box-shadow: 0 5px 15px rgba(118, 75, 162, 0.4);
44
+ }
45
+
46
+ .regex-output {
47
+ font-family: 'Courier New', monospace;
48
+ background: rgba(0, 0, 0, 0.05);
49
+ padding: 0.5rem;
50
+ border-radius: 6px;
51
+ word-break: break-all;
52
+ }
53
+
54
+ .match-highlight {
55
+ background-color: rgba(102, 126, 234, 0.2);
56
+ padding: 0.2rem;
57
+ border-radius: 4px;
58
+ border-left: 3px solid #667eea;
59
+ display: inline-block; /* For better spacing of multiple matches */
60
+ margin-right: 4px; /* Spacing between matches */
61
+ margin-bottom: 4px; /* Spacing if matches wrap */
62
+ }
63
+ </style>
64
+ </head>
65
+ <body class="flex items-center justify-center p-4 md:p-8">
66
+ <div class="w-full max-w-4xl space-y-6">
67
+ <div class="text-center mb-8">
68
+ <h1 class="text-3xl md:text-4xl font-bold text-white drop-shadow-lg">Regex Generator</h1>
69
+ <p class="text-white/90 mt-2">Transform your natural language requests into regular expressions</p>
70
+ </div>
71
+
72
+ <div class="card p-6">
73
+ <div class="flex items-center justify-between mb-4">
74
+ <h2 class="text-xl font-semibold text-gray-800">Chatbox</h2>
75
+ <button id="generateBtn" class="btn-primary px-4 py-2 rounded-lg font-medium flex items-center">
76
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-1" viewBox="0 0 20 20" fill="currentColor">
77
+ <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-11a1 1 0 10-2 0v3.586L7.707 9.293a1 1 0 00-1.414 1.414l3 3a1 1 0 001.414 0l3-3a1 1 0 00-1.414-1.414L11 10.586V7z" clip-rule="evenodd" />
78
+ </svg>
79
+ Generate
80
+ </button>
81
+ </div>
82
+ <textarea id="chatbox" placeholder="e.g. extract emails, find phone numbers, match dates" class="input-box w-full p-4 border border-gray-200 focus:border-purple-300 focus:ring-2 focus:ring-purple-200 outline-none transition duration-200 h-24"></textarea>
83
+ </div>
84
+
85
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
86
+ <div class="card p-6">
87
+ <h2 class="text-xl font-semibold text-gray-800 mb-4">Regex Output</h2>
88
+ <div id="regexOutput" class="regex-output p-4 bg-gray-50 rounded-lg">/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/</div>
89
+ <div class="mt-4 flex space-x-3">
90
+ <button id="copyRegexBtn" class="btn-primary px-4 py-2 rounded-lg font-medium flex items-center">
91
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-1" viewBox="0 0 20 20" fill="currentColor">
92
+ <path d="M8 3a1 1 0 011-1h2a1 1 0 110 2H9a1 1 0 01-1-1z" />
93
+ <path d="M6 3a2 2 0 00-2 2v11a2 2 0 002 2h8a2 2 0 002-2V5a2 2 0 00-2-2 3 3 0 01-3 3H9a3 3 0 01-3-3z" />
94
+ </svg>
95
+ Copy
96
+ </button>
97
+ <button id="testRegexBtn" class="bg-white border border-gray-200 px-4 py-2 rounded-lg font-medium flex items-center hover:bg-gray-50 transition">
98
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-1" viewBox="0 0 20 20" fill="currentColor">
99
+ <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z" clip-rule="evenodd" />
100
+ </svg>
101
+ Test
102
+ </button>
103
+ </div>
104
+ </div>
105
+
106
+ <div class="card p-6">
107
+ <h2 class="text-xl font-semibold text-gray-800 mb-4">Test Input</h2>
108
+ <textarea id="testInput" placeholder="Text to test your regex against..." class="input-box w-full p-4 border border-gray-200 focus:border-purple-300 focus:ring-2 focus:ring-purple-200 outline-none transition duration-200 h-28"></textarea>
109
+ <div class="mt-4">
110
+ <h3 class="font-medium text-gray-700 mb-2">Applied Regex Output:</h3>
111
+ <div id="appliedRegexOutput" class="p-3 bg-gray-50 rounded-lg min-h-[3rem]">
112
+ </div>
113
+ </div>
114
+ </div>
115
+ </div>
116
+
117
+ <div class="card p-6">
118
+ <div class="flex items-center justify-between mb-4">
119
+ <h2 class="text-xl font-semibold text-gray-800">Saved Regex Patterns</h2>
120
+ <button id="addPatternBtn" class="btn-primary px-3 py-1 rounded-lg font-medium flex items-center">
121
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
122
+ <path fill-rule="evenodd" d="M10 5a1 1 0 011 1v3h3a1 1 0 110 2h-3v3a1 1 0 11-2 0v-3H6a1 1 0 110-2h3V6a1 1 0 011-1z" clip-rule="evenodd" />
123
+ </svg>
124
+ </button>
125
+ </div>
126
+ <div id="savedPatterns" class="space-y-2">
127
+ </div>
128
+ </div>
129
+ </div>
130
+
131
+ <script>
132
+ document.addEventListener('DOMContentLoaded', function() {
133
+ const generateBtn = document.getElementById('generateBtn');
134
+ const chatboxEl = document.getElementById('chatbox');
135
+ const regexOutputEl = document.getElementById('regexOutput');
136
+ const copyRegexBtn = document.getElementById('copyRegexBtn');
137
+ const testRegexBtn = document.getElementById('testRegexBtn');
138
+ const testInputEl = document.getElementById('testInput');
139
+ const appliedRegexOutputEl = document.getElementById('appliedRegexOutput');
140
+ const addPatternBtn = document.getElementById('addPatternBtn');
141
+ const savedPatternsEl = document.getElementById('savedPatterns');
142
+
143
+ // Generate button click handler
144
+ generateBtn.addEventListener('click', function() {
145
+ const chatboxValue = chatboxEl.value.trim();
146
+ if (chatboxValue) {
147
+ regexOutputEl.textContent = generateRegexFromPrompt(chatboxValue);
148
+ testRegexBtn.click(); // Automatically test after generating
149
+ } else {
150
+ chatboxEl.focus();
151
+ }
152
+ });
153
+
154
+ // Copy regex button
155
+ copyRegexBtn.addEventListener('click', function() {
156
+ const regex = regexOutputEl.textContent;
157
+ if (!regex) return;
158
+ navigator.clipboard.writeText(regex).then(() => {
159
+ const originalHTML = this.innerHTML; // Save current content
160
+ const btn = this;
161
+ btn.innerHTML = `
162
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-1" viewBox="0 0 20 20" fill="currentColor">
163
+ <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
164
+ </svg>
165
+ Copied!
166
+ `;
167
+ setTimeout(() => {
168
+ btn.innerHTML = originalHTML; // Restore original content
169
+ }, 2000);
170
+ }).catch(err => {
171
+ console.error('Failed to copy regex: ', err);
172
+ alert('Failed to copy. Please copy manually.');
173
+ });
174
+ });
175
+
176
+ // Test regex button
177
+ testRegexBtn.addEventListener('click', function() {
178
+ const regexStringSource = regexOutputEl.textContent.trim();
179
+ const testInputValue = testInputEl.value;
180
+ appliedRegexOutputEl.innerHTML = ''; // Clear previous results
181
+
182
+ if (!regexStringSource) {
183
+ appliedRegexOutputEl.textContent = 'No regex to test.';
184
+ return;
185
+ }
186
+
187
+ try {
188
+ let pattern;
189
+ let flagsAttribute = ''; // Flags found in the /pattern/flags string
190
+
191
+ // Try to parse /pattern/flags format first
192
+ // This regex captures the pattern between slashes and any flags after the second slash.
193
+ // It expects at least one character for the pattern: /.+/
194
+ const regexParts = regexStringSource.match(/^\/(.+)\/([gimyus]*)$/);
195
+
196
+ if (regexParts) {
197
+ // Successfully parsed /pattern/flags (e.g., "/abc/gi" or "/xyz/")
198
+ pattern = regexParts[1]; // Content between slashes
199
+ flagsAttribute = regexParts[2]; // Flags after the last slash (can be empty)
200
+ } else if (regexStringSource.startsWith('/') && regexStringSource.endsWith('/') && regexStringSource.length >= 2) {
201
+ // Handles "/pattern/" case more explicitly if regexParts didn't match (e.g. empty pattern like "//")
202
+ // This extracts content between the first and last slash.
203
+ pattern = regexStringSource.substring(1, regexStringSource.length - 1);
204
+ // flagsAttribute remains ""
205
+ } else {
206
+ // Not in /.../... format (e.g. "abc" or "/abc" (no trailing slash))
207
+ // Treat the whole string as the pattern, no flags from string
208
+ pattern = regexStringSource;
209
+ }
210
+
211
+ if (pattern === "" && !regexStringSource.match(/^\/\/([gimyus]*)$/)) { // Allow empty pattern only if it was explicitly `//` or `///flags`
212
+ appliedRegexOutputEl.textContent = 'Pattern is effectively empty or malformed.';
213
+ return;
214
+ }
215
+
216
+ // Combine flags from string with a default 'g' for global matching
217
+ let finalFlags = flagsAttribute;
218
+ if (!finalFlags.includes('g')) {
219
+ finalFlags += 'g';
220
+ }
221
+ // Ensure unique flags and valid order (though order doesn't strictly matter for RegExp constructor)
222
+ finalFlags = Array.from(new Set(finalFlags.split(''))).join('');
223
+
224
+ const regex = new RegExp(pattern, finalFlags);
225
+ const matches = testInputValue.match(regex); // .match with 'g' flag returns array of matched strings or null
226
+
227
+ if (matches && matches.length > 0) {
228
+ matches.forEach(matchText => {
229
+ const span = document.createElement('span');
230
+ span.className = 'match-highlight';
231
+ span.textContent = matchText;
232
+ appliedRegexOutputEl.appendChild(span);
233
+ });
234
+ } else {
235
+ appliedRegexOutputEl.textContent = 'No matches found';
236
+ }
237
+ } catch (e) {
238
+ console.error("Regex error:", e);
239
+ appliedRegexOutputEl.textContent = 'Error: ' + e.message;
240
+ }
241
+ });
242
+
243
+ // Add pattern button
244
+ addPatternBtn.addEventListener('click', function() {
245
+ const regex = regexOutputEl.textContent.trim();
246
+ if (regex) {
247
+ const newPatternDiv = document.createElement('div');
248
+ // Add a specific class to identify these dynamically added items
249
+ newPatternDiv.className = 'p-3 bg-gray-50 rounded-lg flex justify-between items-center saved-pattern-item';
250
+
251
+ const regexSpan = document.createElement('span');
252
+ regexSpan.className = 'regex-output';
253
+ regexSpan.textContent = regex;
254
+
255
+ const controlsDiv = document.createElement('div');
256
+ controlsDiv.className = 'flex space-x-2';
257
+
258
+ const useBtn = document.createElement('button');
259
+ useBtn.className = 'p-1 text-gray-500 hover:text-purple-600 use-pattern-btn';
260
+ useBtn.title = "Use Pattern";
261
+ useBtn.innerHTML = `
262
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
263
+ <path d="M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM11.379 5.793L3 14.172V17h2.828l8.38-8.379-2.83-2.828z" />
264
+ </svg>`;
265
+
266
+ const deleteBtn = document.createElement('button');
267
+ deleteBtn.className = 'p-1 text-gray-500 hover:text-red-500 delete-pattern-btn';
268
+ deleteBtn.title = "Delete Pattern";
269
+ deleteBtn.innerHTML = `
270
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
271
+ <path fill-rule="evenodd" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd" />
272
+ </svg>`;
273
+
274
+ controlsDiv.appendChild(useBtn);
275
+ controlsDiv.appendChild(deleteBtn);
276
+ newPatternDiv.appendChild(regexSpan);
277
+ newPatternDiv.appendChild(controlsDiv);
278
+ savedPatternsEl.appendChild(newPatternDiv);
279
+ }
280
+ });
281
+
282
+ // Event delegation for dynamically added "Use" and "Delete" buttons in saved patterns
283
+ savedPatternsEl.addEventListener('click', function(event) {
284
+ const button = event.target.closest('button'); // Get the button element
285
+ if (!button) return; // Exit if the click was not on a button or its child
286
+
287
+ const patternItem = button.closest('.saved-pattern-item');
288
+ if (!patternItem) return; // Exit if not part of a saved pattern item
289
+
290
+ const regexText = patternItem.querySelector('.regex-output').textContent;
291
+
292
+ if (button.classList.contains('use-pattern-btn')) {
293
+ regexOutputEl.textContent = regexText;
294
+ testInputEl.focus(); // Focus input for convenience
295
+ testRegexBtn.click(); // Automatically test when a saved pattern is used
296
+ } else if (button.classList.contains('delete-pattern-btn')) {
297
+ patternItem.remove();
298
+ }
299
+ });
300
+
301
+ // Simple regex generator for demo purposes
302
+ function generateRegexFromPrompt(prompt) {
303
+ prompt = prompt.toLowerCase();
304
+
305
+ if (prompt.includes('email') || prompt.includes('e-mail')) {
306
+ return '/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}/';
307
+ } else if (prompt.includes('phone') || prompt.includes('number')) {
308
+ return '/(?:\\+?\\d{1,3}[-.\\s]?)?(?:\\(?\\d{3}\\)?[-.\\s]?)?\\d{3}[-.\\s]?\\d{4}/';
309
+ } else if (prompt.includes('url') || prompt.includes('website') || prompt.includes('web address')) {
310
+ return '/https?:\/\/(?:www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b(?:[-a-zA-Z0-9()@:%._\\+.~#?&//=]*)/';
311
+ } else if (prompt.includes('date')) {
312
+ return '/(?:\\d{1,2}[\\/\\-.](?:0?[1-9]|1[0-2])[\\/\\-.]\\d{2,4})|(?:\\d{4}[\\/\\-.](?:0?[1-9]|1[0-2])[\\/\\-.]\\d{1,2})|(?:(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\\s\\d{1,2}(?:st|nd|rd|th)?,?\\s\\d{4})/i';
313
+ } else if (prompt.includes('ip address') || prompt.includes('ipv4')) {
314
+ return '/\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b/';
315
+ } else if (prompt.includes('hex color') || prompt.includes('hexcode')) {
316
+ return '/#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})\\b/';
317
+ } else if (prompt.includes('html tag')) {
318
+ return '/<([a-z][a-z0-9]*)\\b[^>]*>(.*?)<\\/\\1>/is';
319
+ }
320
+ else {
321
+ // Default regex for extraction - any sequence of word characters
322
+ return '/\\b\\w+\\b/g';
323
+ }
324
+ }
325
+
326
+ // Set an example in testInput for initial demo if it's empty
327
+ if (!testInputEl.value) {
328
+ testInputEl.value = "My email is user@example.com, test.user@sub.example.org.\nMy site is http://example.com and https://www.another-site.co.uk/path?query=value.\nCall +1 (555) 123-4567 or 555-123-1234.\nDates: 12/31/2025, 2024-01-15, Feb 14th, 2023.\nIP: 192.168.1.1. Color: #F00 or #A2B3C4.\nTags: <p>Hello</p> <div>World</div>";
329
+ }
330
+ // Clear any hardcoded initial placeholder content in appliedRegexOutput
331
+ appliedRegexOutputEl.innerHTML = '';
332
+ // Perform an initial test if there's default regex and test input
333
+ if (regexOutputEl.textContent && testInputEl.value) {
334
+ testRegexBtn.click();
335
+ }
336
+ });
337
+ </script>
338
+ </body>
339
+ </html>