acecalisto3 commited on
Commit
4d67e4e
·
verified ·
1 Parent(s): e46fd23

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +783 -1
index.html CHANGED
@@ -1 +1,783 @@
1
- <html><head><link href="https://cdn.jsdelivr.net/npm/daisyui@3.1.6/dist/full.css" rel="stylesheet" type="text/css" /><script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script><script src="https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio"></script><script defer src="https://cdnjs.cloudflare.com/ajax/libs/three.js/0.156.1/three.min.js"></script><script type="module" src="main.js"></script><title>UIKitV3 Automator</title></head><body><main class="prose"><div x-data="{ open: false }"><button @click="open =! open">Transform</button><div x-show="open"><textarea id="input" placeholder="Paste or type your code here" rows="10" cols="50"></textarea><button id="transform">Transform</button><div id="output" placeholder="Your transformed code will appear here"></div></div></div></main></body></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>UIKitV3 Automator</title>
7
+
8
+ <!-- Load Tailwind CSS -->
9
+ <script src="https://cdn.tailwindcss.com"></script>
10
+
11
+ <!-- Load highlight.js for syntax highlighting -->
12
+ <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/default.min.css">
13
+
14
+ <!-- Load Google Font -->
15
+ <link rel="preconnect" href="https://fonts.googleapis.com">
16
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
17
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
18
+
19
+ <!-- Custom Styles (from style.css) -->
20
+ <style>
21
+ /* Base styles */
22
+ body {
23
+ font-family: 'Inter', sans-serif;
24
+ background-color: #111827; /* bg-gray-900 */
25
+ }
26
+
27
+ .container {
28
+ max-width: 800px;
29
+ margin: 0 auto;
30
+ }
31
+
32
+ /* Dropdown styles */
33
+ .dropdown {
34
+ position: relative;
35
+ display: inline-block;
36
+ }
37
+
38
+ .dropdown-content {
39
+ display: none;
40
+ position: absolute;
41
+ background-color: #1F2937; /* bg-gray-800 */
42
+ min-width: 160px;
43
+ box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
44
+ z-index: 1;
45
+ border-radius: 0.375rem; /* rounded-md */
46
+ }
47
+
48
+ .dropdown-content a {
49
+ color: white;
50
+ padding: 12px 16px;
51
+ text-decoration: none;
52
+ display: block;
53
+ }
54
+
55
+ .dropdown-content a:hover {
56
+ background-color: #374151; /* bg-gray-700 */
57
+ }
58
+
59
+ .dropdown:hover .dropdown-content {
60
+ display: block;
61
+ }
62
+
63
+ /* Loading spinner styles */
64
+ .loader {
65
+ border: 4px solid #f3f3f3; /* Light grey */
66
+ border-top: 4px solid #3498db; /* Blue */
67
+ border-radius: 50%;
68
+ width: 40px;
69
+ height: 40px;
70
+ animation: spin 1s linear infinite;
71
+ margin: 20px auto;
72
+ }
73
+
74
+ @keyframes spin {
75
+ 0% { transform: rotate(0deg); }
76
+ 100% { transform: rotate(360deg); }
77
+ }
78
+
79
+ /* Custom scrollbar for generated code */
80
+ pre {
81
+ max-height: 400px;
82
+ overflow-y: auto;
83
+ background-color: #1F2937; /* bg-gray-800 */
84
+ padding: 1rem;
85
+ border-radius: 0.375rem; /* rounded-md */
86
+ }
87
+
88
+ /* Simple scrollbar styling */
89
+ pre::-webkit-scrollbar {
90
+ width: 8px;
91
+ }
92
+
93
+ pre::-webkit-scrollbar-track {
94
+ background: #1F2937; /* bg-gray-800 */
95
+ border-radius: 4px;
96
+ }
97
+
98
+ pre::-webkit-scrollbar-thumb {
99
+ background: #4B5563; /* bg-gray-600 */
100
+ border-radius: 4px;
101
+ }
102
+
103
+ pre::-webkit-scrollbar-thumb:hover {
104
+ background: #6B7280; /* bg-gray-500 */
105
+ }
106
+ </style>
107
+ </head>
108
+ <body class="bg-gray-900 text-white">
109
+
110
+ <!-- App container -->
111
+ <div id="app">
112
+ <!-- The JavaScript will render the app content here -->
113
+ </div>
114
+
115
+ <!-- Load highlight.js script -->
116
+ <script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
117
+
118
+ <!-- App Logic (from main.js) -->
119
+ <script>
120
+ // --- Start of main.js content ---
121
+
122
+ // Function to render the main application UI
123
+ function renderApp() {
124
+ // Injects the entire UI into the 'app' div
125
+ document.getElementById('app').innerHTML = `
126
+ <div class="container p-8">
127
+ <h1 class="text-3xl font-bold text-center mb-8 text-blue-400">UIKitV3 Automator</h1>
128
+
129
+ <!-- Component Selection -->
130
+ <div class="bg-gray-800 p-6 rounded-lg shadow-lg mb-6">
131
+ <h2 class="text-xl font-semibold mb-4">1. Select Component</h2>
132
+ <div class="dropdown">
133
+ <button id="uitkit-v3-automator-dropdown-button" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded inline-flex items-center">
134
+ <span id="selected-option">Select Component</span>
135
+ <svg class="fill-current h-4 w-4 ml-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z"/></svg>
136
+ </button>
137
+ <div id="uitkit-v3-automator-dropdown-content" class="dropdown-content">
138
+ <a href="#" data-value="Button">Button</a>
139
+ <a href="#" data-value="Input">Input</a>
140
+ <a href="#" data-value="Card">Card</a>
141
+ <a href="#" data-value="Navbar">Navbar</a>
142
+ <a href="#" data-value="Modal">Modal</a>
143
+ <a href="#" data-value="Alert">Alert</a>
144
+ <a href="#" data-value="Badge">Badge</a>
145
+ <a href="#" data-value="Breadcrumb">Breadcrumb</a>
146
+ <a href="#" data-value="Tabs">Tabs</a>
147
+ <a href="#" data-value="Pagination">Pagination</a>
148
+ </div>
149
+ </div>
150
+ </div>
151
+
152
+ <!-- Property Inputs -->
153
+ <div class="bg-gray-800 p-6 rounded-lg shadow-lg mb-6">
154
+ <h2 class="text-xl font-semibold mb-4">2. Component Properties</h2>
155
+ <div id="inputs-container">
156
+ <!-- Dynamic inputs will be added here -->
157
+ </div>
158
+ <button id="add-input-button" class="mt-4 bg-green-600 hover:bg-green-700 text-white font-bold py-2 px-4 rounded">
159
+ + Add Property
160
+ </button>
161
+ </div>
162
+
163
+ <!-- Generate Button -->
164
+ <div class="text-center mb-6">
165
+ <button id="generate-code-button" class="bg-purple-600 hover:bg-purple-700 text-white font-bold py-3 px-6 rounded-lg text-lg transition duration-200 shadow-md">
166
+ Generate Code
167
+ </button>
168
+ </div>
169
+
170
+ <!-- Code Output -->
171
+ <div class="bg-gray-800 p-6 rounded-lg shadow-lg">
172
+ <h2 class="text-xl font-semibold mb-4">3. Generated Code</h2>
173
+ <div id="loading-spinner" class="loader" style="display: none;"></div>
174
+ <div class="relative">
175
+ <pre><code id="generated-code" class="language-html rounded-md"><!-- Generated code will appear here --></code></pre>
176
+ <button id="copy-button" class="absolute top-2 right-2 bg-gray-700 hover:bg-gray-600 text-white font-bold py-1 px-3 rounded text-sm transition duration-200">
177
+ Copy
178
+ </button>
179
+ </div>
180
+ </div>
181
+ </div>
182
+ `;
183
+ }
184
+
185
+ // Function to toggle dropdown visibility (for mobile or non-hover)
186
+ function toggleDropdown() {
187
+ const dropdownContent = document.getElementById('uitkit-v3-automator-dropdown-content');
188
+ dropdownContent.style.display = dropdownContent.style.display === 'block' ? 'none' : 'block';
189
+ }
190
+
191
+ // Function to handle option selection from the dropdown
192
+ function selectOption(event) {
193
+ event.preventDefault(); // Prevent default link behavior
194
+ const value = event.target.dataset.value;
195
+ if (value) {
196
+ document.getElementById('selected-option').textContent = value;
197
+ // Automatically close dropdown after selection
198
+ document.getElementById('uitkit-v3-automator-dropdown-content').style.display = 'none';
199
+
200
+ // Clear existing inputs
201
+ document.getElementById('inputs-container').innerHTML = '';
202
+
203
+ // Add default properties for the selected component
204
+ addDefaultInputs(value);
205
+ }
206
+ }
207
+
208
+ // Function to add default inputs based on the selected component
209
+ function addDefaultInputs(component) {
210
+ const container = document.getElementById('inputs-container');
211
+
212
+ let defaultProps = [];
213
+
214
+ switch(component) {
215
+ case 'Button':
216
+ defaultProps = [{key: 'text', value: 'Click Me'}, {key: 'color', value: 'blue'}, {key: 'size', value: 'medium'}];
217
+ break;
218
+ case 'Input':
219
+ defaultProps = [{key: 'placeholder', value: 'Enter text...'}, {key: 'type', value: 'text'}, {key: 'label', value: 'Username'}];
220
+ break;
221
+ case 'Card':
222
+ defaultProps = [{key: 'title', value: 'Card Title'}, {key: 'content', value: 'Some quick example text.'}, {key: 'imageUrl', value: 'https://placehold.co/600x400'}];
223
+ break;
224
+ case 'Navbar':
225
+ defaultProps = [{key: 'brand', value: 'MyApp'}, {key: 'links', value: 'Home,About,Contact'}];
226
+ break;
227
+ case 'Modal':
228
+ defaultProps = [{key: 'title', value: 'Modal Title'}, {key: 'body', value: 'This is the modal body.'}, {key: 'footer', value: 'Close,Save Changes'}];
229
+ break;
230
+ case 'Alert':
231
+ defaultProps = [{key: 'text', value: 'This is an alert.'}, {key: 'type', value: 'info'}];
232
+ break;
233
+ case 'Badge':
234
+ defaultProps = [{key: 'text', value: 'New'}, {key: 'color', value: 'blue'}];
235
+ break;
236
+ case 'Breadcrumb':
237
+ defaultProps = [{key: 'links', value: 'Home,Library,Data'}];
238
+ break;
239
+ case 'Tabs':
240
+ defaultProps = [{key: 'tabs', value: 'Profile,Settings,Danger Zone'}, {key: 'active', value: 'Profile'}];
241
+ break;
242
+ case 'Pagination':
243
+ defaultProps = [{key: 'items', value: 'Prev,1,2,3,Next'}];
244
+ break;
245
+ }
246
+
247
+ // Add an input field for each default property
248
+ defaultProps.forEach(prop => {
249
+ addInput(prop.key, prop.value);
250
+ });
251
+ }
252
+
253
+ // Function to add a new key-value input pair
254
+ function addInput(key = '', value = '') {
255
+ const container = document.getElementById('inputs-container');
256
+ const inputGroup = document.createElement('div');
257
+ inputGroup.className = 'flex items-center space-x-2 mb-2';
258
+
259
+ inputGroup.innerHTML = `
260
+ <input type="text" class="property-key bg-gray-700 text-white p-2 rounded w-1/3 border border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Property" value="${key}">
261
+ <input type="text" class="property-value bg-gray-700 text-white p-2 rounded w-2/3 border border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Value" value="${value}">
262
+ <button class="remove-input-button bg-red-600 hover:bg-red-700 text-white font-bold py-2 px-3 rounded transition duration-200">
263
+ -
264
+ </button>
265
+ `;
266
+
267
+ container.appendChild(inputGroup);
268
+
269
+ // Add event listener to the new remove button
270
+ inputGroup.querySelector('.remove-input-button').addEventListener('click', removeInput);
271
+ }
272
+
273
+ // Function to remove a key-value input pair
274
+ function removeInput(event) {
275
+ // Removes the parent 'div' of the clicked remove button
276
+ event.target.parentElement.remove();
277
+ }
278
+
279
+ // Function to generate code
280
+ function generateCode() {
281
+ const component = document.getElementById('selected-option').textContent;
282
+ if (component === 'Select Component') {
283
+ console.warn('Please select a component first.');
284
+ return;
285
+ }
286
+
287
+ // Collect all properties from the input fields
288
+ const inputs = document.getElementById('inputs-container').children;
289
+ let properties = {};
290
+ for (let input of inputs) {
291
+ const key = input.querySelector('.property-key').value;
292
+ const value = input.querySelector('.property-value').value;
293
+ if (key) {
294
+ properties[key] = value;
295
+ }
296
+ }
297
+
298
+ // --- DEBUGGING ---
299
+ console.log('Collected properties:', properties);
300
+ // --- END DEBUGGING ---
301
+
302
+ const codeOutput = document.getElementById('generated-code');
303
+ const loadingSpinner = document.getElementById('loading-spinner');
304
+ const copyButton = document.getElementById('copy-button');
305
+
306
+ codeOutput.textContent = ''; // Clear previous code
307
+ copyButton.textContent = 'Copy'; // Reset copy button text
308
+ copyButton.classList.remove('bg-green-500', 'bg-red-500'); // Reset copy button color
309
+ loadingSpinner.style.display = 'block'; // Show spinner
310
+
311
+ // Simulate API call delay
312
+ setTimeout(() => {
313
+ let generatedHtml = '';
314
+
315
+ try {
316
+ // Route to the correct generator function based on component
317
+ switch(component) {
318
+ case 'Button':
319
+ generatedHtml = generateButtonCode(properties);
320
+ break;
321
+ case 'Input':
322
+ generatedHtml = generateInputCode(properties);
323
+ break;
324
+ case 'Card':
325
+ generatedHtml = generateCardCode(properties);
326
+ break;
327
+ case 'Navbar':
328
+ generatedHtml = generateNavbarCode(properties);
329
+ break;
330
+ case 'Modal':
331
+ generatedHtml = generateModalCode(properties);
332
+ break;
333
+ case 'Alert':
334
+ generatedHtml = generateAlertCode(properties);
335
+ break;
336
+ case 'Badge':
337
+ generatedHtml = generateBadgeCode(properties);
338
+ break;
339
+ case 'Breadcrumb':
340
+ generatedHtml = generateBreadcrumbCode(properties);
341
+ break;
342
+ case 'Tabs':
343
+ generatedHtml = generateTabsCode(properties);
344
+ break;
345
+ case 'Pagination':
346
+ generatedHtml = generatePaginationCode(properties);
347
+ break;
348
+ default:
349
+ generatedHtml = `<div class="text-red-400">Error: Component generator not found.</div>`;
350
+ }
351
+ } catch (error) {
352
+ generatedHtml = `<div class="text-red-400">Error generating code: ${error.message}</div>`;
353
+ }
354
+
355
+ // Set text content for syntax highlighting
356
+ codeOutput.textContent = generatedHtml;
357
+
358
+ // Highlight the generated code using highlight.js
359
+ if (window.hljs) {
360
+ // Check if hljs is loaded
361
+ try {
362
+ hljs.highlightElement(codeOutput);
363
+ } catch (e) {
364
+ console.error("highlight.js failed:", e);
365
+ codeOutput.innerHTML = generatedHtml.replace(/</g, "&lt;").replace(/>/g, "&gt;");
366
+ }
367
+ } else {
368
+ codeOutput.innerHTML = generatedHtml.replace(/</g, "&lt;").replace(/>/g, "&gt;");
369
+ }
370
+
371
+ loadingSpinner.style.display = 'none'; // Hide spinner
372
+ }, 1000); // Simulate network delay
373
+ }
374
+
375
+ // --- Component Code Generators ---
376
+
377
+ function generateButtonCode(props) {
378
+ const text = props.text || 'Button';
379
+ const color = props.color || 'blue';
380
+ const size = props.size || 'medium';
381
+
382
+ let colorClasses = 'bg-blue-600 hover:bg-blue-700';
383
+ switch(color) {
384
+ case 'red': colorClasses = 'bg-red-600 hover:bg-red-700'; break;
385
+ case 'green': colorClasses = 'bg-green-600 hover:bg-green-700'; break;
386
+ case 'gray': colorClasses = 'bg-gray-600 hover:bg-gray-700'; break;
387
+ }
388
+
389
+ let sizeClasses = 'py-2 px-4 text-base';
390
+ switch(size) {
391
+ case 'small': sizeClasses = 'py-1 px-3 text-sm'; break;
392
+ case 'large': sizeClasses = 'py-3 px-6 text-lg'; break;
393
+ }
394
+
395
+ return `
396
+ <button class="${colorClasses} ${sizeClasses} text-white font-bold rounded-lg shadow-md transition duration-200 ease-in-out">
397
+ ${text}
398
+ </button>
399
+ `.trim();
400
+ }
401
+
402
+ function generateInputCode(props) {
403
+ const placeholder = props.placeholder || '';
404
+ const type = props.type || 'text';
405
+ const label = props.label || '';
406
+
407
+ let labelHtml = '';
408
+ if (label) {
409
+ labelHtml = `
410
+ <label for="generated-input" class="block text-sm font-medium text-gray-300 mb-1">
411
+ ${label}
412
+ </label>
413
+ `.trim();
414
+ }
415
+
416
+ return `
417
+ <div>
418
+ ${labelHtml}
419
+ <input
420
+ type="${type}"
421
+ id="generated-input"
422
+ class="bg-gray-700 text-white p-2 rounded-md w-full border border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500"
423
+ placeholder="${placeholder}"
424
+ >
425
+ </div>
426
+ `.trim();
427
+ }
428
+
429
+ function generateCardCode(props) {
430
+ const title = props.title || 'Card Title';
431
+ const content = props.content || 'Card content goes here.';
432
+ const imageUrl = props.imageUrl || '';
433
+
434
+ let imageHtml = '';
435
+ if (imageUrl) {
436
+ imageHtml = `
437
+ <img
438
+ class="w-full h-48 object-cover rounded-t-lg"
439
+ src="${imageUrl}"
440
+ alt="${title}"
441
+ onerror="this.src='https://placehold.co/600x400/374151/FFFFFF?text=Image+Not+Found'"
442
+ >
443
+ `.trim();
444
+ }
445
+
446
+ return `
447
+ <div class="max-w-sm bg-gray-800 rounded-lg shadow-lg overflow-hidden">
448
+ ${imageHtml}
449
+ <div class="p-6">
450
+ <h3 class="text-xl font-semibold text-white mb-2">${title}</h3>
451
+ <p class="text-gray-400">${content}</p>
452
+ </div>
453
+ </div>
454
+ `.trim();
455
+ }
456
+
457
+ function generateNavbarCode(props) {
458
+ const brand = props.brand || 'Brand';
459
+ const links = (props.links || 'Home,About').split(',').map(link => link.trim());
460
+
461
+ let linksHtml = links.map(link => `
462
+ <a href="#" class="text-gray-300 hover:text-white px-3 py-2 rounded-md text-sm font-medium">${link}</a>
463
+ `).join('');
464
+
465
+ return `
466
+ <nav class="bg-gray-800 shadow-lg">
467
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
468
+ <div class="flex items-center justify-between h-16">
469
+ <div class="flex-shrink-0">
470
+ <span class="text-white font-bold text-xl">${brand}</span>
471
+ </div>
472
+ <div class="hidden md:block">
473
+ <div class="ml-10 flex items-baseline space-x-4">
474
+ ${linksHtml}
475
+ </div>
476
+ </div>
477
+ <!-- Mobile menu button -->
478
+ <div class="-mr-2 flex md:hidden">
479
+ <button type"button" class="bg-gray-700 inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-white hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-800 focus:ring-white" aria-controls="mobile-menu" aria-expanded="false">
480
+ <span class="sr-only">Open main menu</span>
481
+ <!-- Icon for menu (e.g., hamburger icon) -->
482
+ <svg class="block h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
483
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
484
+ </svg>
485
+ </button>
486
+ </div>
487
+ </div>
488
+ </div>
489
+ </nav>
490
+ `.trim();
491
+ }
492
+
493
+ function generateModalCode(props) {
494
+ const title = props.title || 'Modal Title';
495
+ const body = props.body || 'Modal body text goes here.';
496
+ const footerButtons = (props.footer || 'Close').split(',').map(btn => btn.trim());
497
+
498
+ let buttonsHtml = footerButtons.map((btnText, index) => {
499
+ const isPrimary = (index === footerButtons.length - 1) && footerButtons.length > 1;
500
+ const colorClasses = isPrimary
501
+ ? 'bg-blue-600 hover:bg-blue-700'
502
+ : 'bg-gray-600 hover:bg-gray-700';
503
+ return `
504
+ <button class="${colorClasses} text-white font-bold py-2 px-4 rounded transition duration-200">${btnText}</button>
505
+ `;
506
+ }).join('');
507
+
508
+ return `
509
+ <!-- Modal Backdrop (background overlay) -->
510
+ <div class="fixed inset-0 bg-black bg-opacity-50 z-40 flex items-center justify-center p-4">
511
+
512
+ <!-- Modal Dialog -->
513
+ <div class="bg-gray-800 rounded-lg shadow-xl max-w-lg w-full z-50 overflow-hidden">
514
+
515
+ <!-- Modal Header -->
516
+ <div class="flex justify-between items-center p-4 border-b border-gray-700">
517
+ <h3 class="text-xl font-semibold text-white">${title}</h3>
518
+ <button class="text-gray-400 hover:text-white transition duration-200">
519
+ <!-- Close Icon -->
520
+ <svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
521
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
522
+ </svg>
523
+ </button>
524
+ </div>
525
+
526
+ <!-- Modal Body -->
527
+ <div class="p-6">
528
+ <p class="text-gray-300">${body}</p>
529
+ </div>
530
+
531
+ <!-- Modal Footer -->
532
+ <div class="flex justify-end items-center p-4 space-x-2 border-t border-gray-700 bg-gray-700">
533
+ ${buttonsHtml}
534
+ </div>
535
+
536
+ </div>
537
+ </div>
538
+ `.trim();
539
+ }
540
+
541
+ // --- NEW COMPONENT GENERATORS ---
542
+
543
+ function generateAlertCode(props) {
544
+ const text = props.text || 'Alert text.';
545
+ const type = props.type || 'info';
546
+
547
+ let bgClass = 'bg-blue-900 border-blue-700';
548
+ let textClass = 'text-blue-300';
549
+ let iconSvg = `
550
+ <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
551
+ <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"></path>
552
+ </svg>
553
+ `;
554
+
555
+ switch(type) {
556
+ case 'success':
557
+ bgClass = 'bg-green-900 border-green-700';
558
+ textClass = 'text-green-300';
559
+ iconSvg = `
560
+ <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
561
+ <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"></path>
562
+ </svg>
563
+ `;
564
+ break;
565
+ case 'warning':
566
+ bgClass = 'bg-yellow-900 border-yellow-700';
567
+ textClass = 'text-yellow-300';
568
+ iconSvg = `
569
+ <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
570
+ <path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd"></path>
571
+ </svg>
572
+ `;
573
+ break;
574
+ case 'danger':
575
+ bgClass = 'bg-red-900 border-red-700';
576
+ textClass = 'text-red-300';
577
+ iconSvg = `
578
+ <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
579
+ <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"></path>
580
+ </svg>
581
+ `;
582
+ break;
583
+ }
584
+
585
+ return `
586
+ <div class="flex p-4 rounded-lg ${bgClass} ${textClass} border" role="alert">
587
+ <span class="flex-shrink-0">
588
+ ${iconSvg}
589
+ </span>
590
+ <span class="sr-only">${type}</span>
591
+ <div class="ml-3 text-sm font-medium">
592
+ ${text}
593
+ </div>
594
+ <button type="button" class="ml-auto -mx-1.5 -my-1.5 ${bgClass} ${textClass} rounded-lg focus:ring-2 focus:ring-gray-400 p-1.5 hover:bg-gray-700 inline-flex h-8 w-8" aria-label="Dismiss">
595
+ <span class="sr-only">Dismiss</span>
596
+ <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
597
+ </button>
598
+ </div>
599
+ `.trim();
600
+ }
601
+
602
+ function generateBadgeCode(props) {
603
+ const text = props.text || 'Badge';
604
+ const color = props.color || 'blue';
605
+
606
+ let colorClasses = 'bg-blue-800 text-blue-300';
607
+ switch(color) {
608
+ case 'red': colorClasses = 'bg-red-800 text-red-300'; break;
609
+ case 'green': colorClasses = 'bg-green-800 text-green-300'; break;
610
+ case 'yellow': colorClasses = 'bg-yellow-800 text-yellow-300'; break;
611
+ case 'gray': colorClasses = 'bg-gray-700 text-gray-300'; break;
612
+ }
613
+
614
+ return `
615
+ <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${colorClasses}">
616
+ ${text}
617
+ </span>
618
+ `.trim();
619
+ }
620
+
621
+ function generateBreadcrumbCode(props) {
622
+ const links = (props.links || 'Home,Page').split(',').map(link => link.trim());
623
+ const separatorSvg = `
624
+ <svg class="w-6 h-6 text-gray-400" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
625
+ <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path>
626
+ </svg>
627
+ `;
628
+
629
+ let linksHtml = links.map((link, index) => {
630
+ const isLast = index === links.length - 1;
631
+ if (isLast) {
632
+ return `
633
+ <li aria-current="page">
634
+ <div class="flex items-center">
635
+ ${index > 0 ? separatorSvg : ''}
636
+ <span class="ml-1 text-sm font-medium text-gray-400 md:ml-2">${link}</span>
637
+ </div>
638
+ </li>
639
+ `.trim();
640
+ } else {
641
+ return `
642
+ <li>
643
+ <div class="flex items-center">
644
+ ${index > 0 ? separatorSvg : ''}
645
+ <a href="#" class="ml-1 text-sm font-medium text-gray-300 hover:text-white md:ml-2">${link}</a>
646
+ </div>
647
+ </li>
648
+ `.trim();
649
+ }
650
+ }).join('\n');
651
+
652
+ return `
653
+ <nav class="flex" aria-label="Breadcrumb">
654
+ <ol class="inline-flex items-center space-x-1 md:space-x-3">
655
+ ${linksHtml}
656
+ </ol>
657
+ </nav>
658
+ `.trim();
659
+ }
660
+
661
+ function generateTabsCode(props) {
662
+ const tabs = (props.tabs || 'Tab 1,Tab 2').split(',').map(tab => tab.trim());
663
+ const activeTab = props.active || tabs[0];
664
+
665
+ let tabsHtml = tabs.map(tab => {
666
+ const isActive = tab === activeTab;
667
+ const activeClasses = 'text-blue-500 border-blue-500';
668
+ const inactiveClasses = 'text-gray-400 border-transparent hover:text-gray-300 hover:border-gray-500';
669
+
670
+ return `
671
+ <li class="mr-2">
672
+ <a href="#" class="inline-block p-4 border-b-2 rounded-t-lg ${isActive ? activeClasses : inactiveClasses}">
673
+ ${tab}
674
+ </a>
675
+ </li>
676
+ `.trim();
677
+ }).join('\n');
678
+
679
+ return `
680
+ <div class="text-sm font-medium text-center text-gray-400 border-b border-gray-700">
681
+ <ul class="flex flex-wrap -mb-px">
682
+ ${tabsHtml}
683
+ </ul>
684
+ </div>
685
+ `.trim();
686
+ }
687
+
688
+ function generatePaginationCode(props) {
689
+ const items = (props.items || '1,2,3').split(',').map(item => item.trim());
690
+
691
+ let itemsHtml = items.map(item => {
692
+ // Simple check if it's 'Prev' or 'Next' for different styling
693
+ const isText = isNaN(parseInt(item));
694
+ const textClasses = 'px-4 py-2';
695
+ const numClasses = 'w-10 h-10 flex items-center justify-center';
696
+
697
+ return `
698
+ <li>
699
+ <a href="#" class="flex items-center justify-center ${isText ? textClasses : numClasses} leading-tight text-gray-400 bg-gray-800 border border-gray-700 rounded-lg hover:bg-gray-700 hover:text-white">
700
+ ${item}
701
+ </a>
702
+ </li>
703
+ `.trim();
704
+ }).join('\n');
705
+
706
+ return `
707
+ <nav aria-label="Page navigation">
708
+ <ul class="inline-flex items-center -space-x-px space-x-2">
709
+ ${itemsHtml}
710
+ </ul>
711
+ </nav>
712
+ `.trim();
713
+ }
714
+
715
+
716
+ // Function to copy code to clipboard
717
+ function copyToClipboard() {
718
+ const code = document.getElementById('generated-code').textContent;
719
+ const copyButton = document.getElementById('copy-button');
720
+
721
+ try {
722
+ const textArea = document.createElement('textarea');
723
+ textArea.value = code;
724
+ textArea.style.top = "0";
725
+ textArea.style.left = "0";
726
+ textArea.style.position = "fixed";
727
+
728
+ document.body.appendChild(textArea);
729
+ textArea.focus();
730
+ textArea.select();
731
+
732
+ const successful = document.execCommand('copy');
733
+ if (successful) {
734
+ copyButton.textContent = 'Copied!';
735
+ copyButton.classList.add('bg-green-500'); // Give visual feedback
736
+ } else {
737
+ throw new Error('Copy command failed');
738
+ }
739
+ } catch (err) {
740
+ console.error('Fallback: Oops, unable to copy', err);
741
+ copyButton.textContent = 'Failed!';
742
+ copyButton.classList.add('bg-red-500');
743
+ } finally {
744
+ const textArea = document.body.querySelector('textarea');
745
+ if (textArea) {
746
+ document.body.removeChild(textArea);
747
+ }
748
+ }
749
+ }
750
+
751
+ // Function to attach all event listeners
752
+ function attachEventListeners() {
753
+ // Dropdown button
754
+ document.getElementById('uitkit-v3-automator-dropdown-button').addEventListener('click', toggleDropdown);
755
+
756
+ // Dropdown options (using event delegation on the container)
757
+ document.getElementById('uitkit-v3-automator-dropdown-content').addEventListener('click', selectOption);
758
+
759
+ // Add property button
760
+ document.getElementById('add-input-button').addEventListener('click', () => addInput());
761
+
762
+ // Generate code button
763
+ document.getElementById('generate-code-button').addEventListener('click', generateCode);
764
+
765
+ // Copy button
766
+ document.getElementById('copy-button').addEventListener('click', copyToClipboard);
767
+
768
+ // Event listeners for remove buttons are added dynamically in the addInput() function
769
+ }
770
+
771
+ // --- Main Execution ---
772
+
773
+ // Render the app on load
774
+ renderApp();
775
+
776
+ // Attach event listeners after rendering
777
+ attachEventListeners();
778
+
779
+ // --- End of main.js content ---
780
+ </script>
781
+
782
+ </body>
783
+ </html>