juxscript 1.0.56 → 1.0.57
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/lib/components/alert.ts +0 -87
- package/lib/components/badge.ts +0 -53
- package/lib/components/base/FormInput.ts +0 -95
- package/lib/components/charts/lib/BaseChart.ts +0 -13
- package/lib/components/checkbox.ts +0 -94
- package/lib/components/datepicker.ts +0 -40
- package/lib/components/dialog.ts +0 -116
- package/lib/components/divider.ts +0 -27
- package/lib/components/docs-data.json +19 -1
- package/lib/components/dropdown.ts +0 -100
- package/lib/components/element.ts +0 -60
- package/lib/components/fileupload.ts +0 -67
- package/lib/components/hero.ts +25 -9
- package/lib/components/input.ts +1 -1
- package/lib/components/list.ts +0 -130
- package/lib/components/loading.ts +0 -94
- package/lib/components/progress.ts +0 -55
- package/lib/components/radio.ts +0 -106
- package/lib/components/select.ts +2 -28
- package/lib/components/sidebar.ts +0 -71
- package/lib/components/switch.ts +0 -85
- package/lib/components/tooltip.ts +0 -29
- package/package.json +7 -2
- package/presets/default/all.jux +190 -0
- package/presets/default/layout.css +1017 -0
package/lib/components/radio.ts
CHANGED
|
@@ -269,114 +269,8 @@ export class Radio extends FormInput<RadioState> {
|
|
|
269
269
|
}
|
|
270
270
|
|
|
271
271
|
container.appendChild(wrapper);
|
|
272
|
-
this._injectRadioStyles();
|
|
273
|
-
|
|
274
272
|
return this;
|
|
275
273
|
}
|
|
276
|
-
|
|
277
|
-
private _injectRadioStyles(): void {
|
|
278
|
-
const styleId = 'jux-radio-styles';
|
|
279
|
-
if (document.getElementById(styleId)) return;
|
|
280
|
-
|
|
281
|
-
const style = document.createElement('style');
|
|
282
|
-
style.id = styleId;
|
|
283
|
-
style.textContent = `
|
|
284
|
-
.jux-radio {
|
|
285
|
-
margin-bottom: 12px;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
.jux-radio-options {
|
|
289
|
-
display: flex;
|
|
290
|
-
gap: 8px;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
/* ✅ Vertical orientation (default) */
|
|
294
|
-
.jux-radio-vertical {
|
|
295
|
-
flex-direction: column;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
/* ✅ Horizontal orientation */
|
|
299
|
-
.jux-radio-horizontal {
|
|
300
|
-
flex-direction: row;
|
|
301
|
-
flex-wrap: wrap;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
.jux-radio-option {
|
|
305
|
-
display: inline-flex;
|
|
306
|
-
align-items: center;
|
|
307
|
-
cursor: pointer;
|
|
308
|
-
user-select: none;
|
|
309
|
-
position: relative;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
.jux-radio-input {
|
|
313
|
-
position: absolute;
|
|
314
|
-
opacity: 0;
|
|
315
|
-
cursor: pointer;
|
|
316
|
-
height: 0;
|
|
317
|
-
width: 0;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
.jux-radio-mark {
|
|
321
|
-
position: relative;
|
|
322
|
-
height: 20px;
|
|
323
|
-
width: 20px;
|
|
324
|
-
border: 2px solid #d1d5db;
|
|
325
|
-
border-radius: 50%;
|
|
326
|
-
background-color: white;
|
|
327
|
-
transition: all 0.2s;
|
|
328
|
-
display: flex;
|
|
329
|
-
align-items: center;
|
|
330
|
-
justify-content: center;
|
|
331
|
-
margin-right: 8px;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
.jux-radio-mark::after {
|
|
335
|
-
content: '';
|
|
336
|
-
position: absolute;
|
|
337
|
-
width: 10px;
|
|
338
|
-
height: 10px;
|
|
339
|
-
border-radius: 50%;
|
|
340
|
-
background-color: white;
|
|
341
|
-
opacity: 0;
|
|
342
|
-
transition: opacity 0.2s;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
.jux-radio-input:checked ~ .jux-radio-mark {
|
|
346
|
-
background-color: #3b82f6;
|
|
347
|
-
border-color: #3b82f6;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
.jux-radio-input:checked ~ .jux-radio-mark::after {
|
|
351
|
-
opacity: 1;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
.jux-radio-input:disabled ~ .jux-radio-mark {
|
|
355
|
-
background-color: #f3f4f6;
|
|
356
|
-
border-color: #d1d5db;
|
|
357
|
-
cursor: not-allowed;
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
.jux-radio-input:disabled ~ .jux-radio-label-text {
|
|
361
|
-
color: #9ca3af;
|
|
362
|
-
cursor: not-allowed;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
.jux-radio-input:focus ~ .jux-radio-mark {
|
|
366
|
-
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
.jux-radio-input.jux-input-invalid ~ .jux-radio-mark {
|
|
370
|
-
border-color: #ef4444;
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
.jux-radio-label-text {
|
|
374
|
-
font-size: 14px;
|
|
375
|
-
color: #374151;
|
|
376
|
-
}
|
|
377
|
-
`;
|
|
378
|
-
document.head.appendChild(style);
|
|
379
|
-
}
|
|
380
274
|
}
|
|
381
275
|
|
|
382
276
|
export function radio(id: string, options: RadioOptions = {}): Radio {
|
package/lib/components/select.ts
CHANGED
|
@@ -239,38 +239,12 @@ export class Select extends FormInput<SelectState> {
|
|
|
239
239
|
}
|
|
240
240
|
|
|
241
241
|
container.appendChild(wrapper);
|
|
242
|
-
|
|
243
|
-
this._injectFormStyles();
|
|
242
|
+
|
|
244
243
|
|
|
245
244
|
return this;
|
|
246
245
|
}
|
|
247
246
|
|
|
248
|
-
|
|
249
|
-
const styleId = 'jux-select-styles';
|
|
250
|
-
if (document.getElementById(styleId)) return;
|
|
251
|
-
|
|
252
|
-
const style = document.createElement('style');
|
|
253
|
-
style.id = styleId;
|
|
254
|
-
style.textContent = `
|
|
255
|
-
.jux-select-container {
|
|
256
|
-
position: relative;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
.jux-select-element {
|
|
260
|
-
appearance: none;
|
|
261
|
-
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%236b7280' d='M6 9L1 4h10z'/%3E%3C/svg%3E");
|
|
262
|
-
background-repeat: no-repeat;
|
|
263
|
-
background-position: right 12px center;
|
|
264
|
-
padding-right: 36px;
|
|
265
|
-
cursor: pointer;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
.jux-select-element:disabled {
|
|
269
|
-
cursor: not-allowed;
|
|
270
|
-
}
|
|
271
|
-
`;
|
|
272
|
-
document.head.appendChild(style);
|
|
273
|
-
}
|
|
247
|
+
|
|
274
248
|
}
|
|
275
249
|
|
|
276
250
|
export function select(id: string, options: SelectOptions = {}): Select {
|
|
@@ -157,80 +157,9 @@ export class Sidebar extends BaseComponent<SidebarState> {
|
|
|
157
157
|
|
|
158
158
|
container.appendChild(sidebar);
|
|
159
159
|
this._sidebar = sidebar;
|
|
160
|
-
this._injectDefaultStyles();
|
|
161
160
|
|
|
162
161
|
return this;
|
|
163
162
|
}
|
|
164
|
-
|
|
165
|
-
private _injectDefaultStyles(): void {
|
|
166
|
-
const styleId = 'jux-sidebar-styles';
|
|
167
|
-
if (document.getElementById(styleId)) return;
|
|
168
|
-
|
|
169
|
-
const style = document.createElement('style');
|
|
170
|
-
style.id = styleId;
|
|
171
|
-
style.textContent = `
|
|
172
|
-
.jux-sidebar {
|
|
173
|
-
position: relative;
|
|
174
|
-
height: 100vh;
|
|
175
|
-
background: #f9fafb;
|
|
176
|
-
border-right: 1px solid #e5e7eb;
|
|
177
|
-
transition: width 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
178
|
-
overflow: hidden;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
.jux-sidebar-right {
|
|
182
|
-
border-right: none;
|
|
183
|
-
border-left: 1px solid #e5e7eb;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
.jux-sidebar-toggle {
|
|
187
|
-
position: absolute;
|
|
188
|
-
bottom: 20px;
|
|
189
|
-
right: 20px;
|
|
190
|
-
width: 32px;
|
|
191
|
-
height: 32px;
|
|
192
|
-
border: none;
|
|
193
|
-
background: #3b82f6;
|
|
194
|
-
color: white;
|
|
195
|
-
border-radius: 6px;
|
|
196
|
-
cursor: pointer;
|
|
197
|
-
font-size: 14px;
|
|
198
|
-
display: flex;
|
|
199
|
-
align-items: center;
|
|
200
|
-
justify-content: center;
|
|
201
|
-
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
202
|
-
z-index: 100;
|
|
203
|
-
box-shadow: 0 2px 8px rgba(59, 130, 246, 0.3);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
.jux-sidebar-toggle:hover {
|
|
207
|
-
background: #2563eb;
|
|
208
|
-
transform: scale(1.05);
|
|
209
|
-
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
.jux-sidebar-toggle:active {
|
|
213
|
-
transform: scale(0.95);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
.jux-sidebar-collapsed {
|
|
217
|
-
width: 60px !important;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
.jux-sidebar-collapsed > *:not(.jux-sidebar-toggle) {
|
|
221
|
-
opacity: 0;
|
|
222
|
-
pointer-events: none;
|
|
223
|
-
transition: opacity 0.2s ease-out;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
.jux-sidebar > *:not(.jux-sidebar-toggle) {
|
|
227
|
-
opacity: 1;
|
|
228
|
-
pointer-events: auto;
|
|
229
|
-
transition: opacity 0.3s ease-in 0.1s;
|
|
230
|
-
}
|
|
231
|
-
`;
|
|
232
|
-
document.head.appendChild(style);
|
|
233
|
-
}
|
|
234
163
|
}
|
|
235
164
|
|
|
236
165
|
export function sidebar(id: string, options: SidebarOptions = {}): Sidebar {
|
package/lib/components/switch.ts
CHANGED
|
@@ -235,94 +235,9 @@ export class Switch extends FormInput<SwitchState> {
|
|
|
235
235
|
}
|
|
236
236
|
|
|
237
237
|
container.appendChild(wrapper);
|
|
238
|
-
this._injectSwitchStyles();
|
|
239
238
|
|
|
240
239
|
return this;
|
|
241
240
|
}
|
|
242
|
-
|
|
243
|
-
private _injectSwitchStyles(): void {
|
|
244
|
-
const styleId = 'jux-switch-styles';
|
|
245
|
-
if (document.getElementById(styleId)) return;
|
|
246
|
-
|
|
247
|
-
const style = document.createElement('style');
|
|
248
|
-
style.id = styleId;
|
|
249
|
-
style.textContent = `
|
|
250
|
-
.jux-switch {
|
|
251
|
-
margin-bottom: 12px;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
.jux-switch-container {
|
|
255
|
-
display: inline-flex;
|
|
256
|
-
align-items: center;
|
|
257
|
-
cursor: pointer;
|
|
258
|
-
user-select: none;
|
|
259
|
-
position: relative;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
.jux-switch-input {
|
|
263
|
-
position: absolute;
|
|
264
|
-
opacity: 0;
|
|
265
|
-
cursor: pointer;
|
|
266
|
-
height: 0;
|
|
267
|
-
width: 0;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
.jux-switch-slider {
|
|
271
|
-
position: relative;
|
|
272
|
-
width: 48px;
|
|
273
|
-
height: 24px;
|
|
274
|
-
background-color: #d1d5db;
|
|
275
|
-
border-radius: 24px;
|
|
276
|
-
transition: background-color 0.3s;
|
|
277
|
-
margin-right: 8px;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
.jux-switch-slider::before {
|
|
281
|
-
content: '';
|
|
282
|
-
position: absolute;
|
|
283
|
-
height: 18px;
|
|
284
|
-
width: 18px;
|
|
285
|
-
left: 3px;
|
|
286
|
-
top: 3px;
|
|
287
|
-
background-color: white;
|
|
288
|
-
border-radius: 50%;
|
|
289
|
-
transition: transform 0.3s;
|
|
290
|
-
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
.jux-switch-input:checked ~ .jux-switch-slider {
|
|
294
|
-
background-color: #3b82f6;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
.jux-switch-input:checked ~ .jux-switch-slider::before {
|
|
298
|
-
transform: translateX(24px);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
.jux-switch-input:disabled ~ .jux-switch-slider {
|
|
302
|
-
background-color: #f3f4f6;
|
|
303
|
-
cursor: not-allowed;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
.jux-switch-input:disabled ~ .jux-switch-label-text {
|
|
307
|
-
color: #9ca3af;
|
|
308
|
-
cursor: not-allowed;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
.jux-switch-input:focus ~ .jux-switch-slider {
|
|
312
|
-
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
.jux-switch-input.jux-input-invalid ~ .jux-switch-slider {
|
|
316
|
-
box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
.jux-switch-label-text {
|
|
320
|
-
font-size: 14px;
|
|
321
|
-
color: #374151;
|
|
322
|
-
}
|
|
323
|
-
`;
|
|
324
|
-
document.head.appendChild(style);
|
|
325
|
-
}
|
|
326
241
|
}
|
|
327
242
|
|
|
328
243
|
export function switchComponent(id: string, options: SwitchOptions = {}): Switch {
|
|
@@ -91,7 +91,6 @@ export class Tooltip extends BaseComponent<TooltipState> {
|
|
|
91
91
|
this._hide();
|
|
92
92
|
});
|
|
93
93
|
|
|
94
|
-
this._injectTooltipStyles();
|
|
95
94
|
}
|
|
96
95
|
|
|
97
96
|
private _show(): void {
|
|
@@ -138,34 +137,6 @@ export class Tooltip extends BaseComponent<TooltipState> {
|
|
|
138
137
|
console.warn('Tooltip: Use .attachTo(element) instead of .render()');
|
|
139
138
|
return this;
|
|
140
139
|
}
|
|
141
|
-
|
|
142
|
-
private _injectTooltipStyles(): void {
|
|
143
|
-
const styleId = 'jux-tooltip-styles';
|
|
144
|
-
if (document.getElementById(styleId)) return;
|
|
145
|
-
|
|
146
|
-
const style = document.createElement('style');
|
|
147
|
-
style.id = styleId;
|
|
148
|
-
style.textContent = `
|
|
149
|
-
.jux-tooltip {
|
|
150
|
-
position: fixed;
|
|
151
|
-
background: #1f2937;
|
|
152
|
-
color: white;
|
|
153
|
-
padding: 6px 12px;
|
|
154
|
-
border-radius: 6px;
|
|
155
|
-
font-size: 12px;
|
|
156
|
-
white-space: nowrap;
|
|
157
|
-
z-index: 10000;
|
|
158
|
-
pointer-events: none;
|
|
159
|
-
animation: jux-tooltip-fade 0.2s;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
@keyframes jux-tooltip-fade {
|
|
163
|
-
from { opacity: 0; }
|
|
164
|
-
to { opacity: 1; }
|
|
165
|
-
}
|
|
166
|
-
`;
|
|
167
|
-
document.head.appendChild(style);
|
|
168
|
-
}
|
|
169
140
|
}
|
|
170
141
|
|
|
171
142
|
export function tooltip(id: string, options: TooltipOptions = {}): Tooltip {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "juxscript",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.57",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A JavaScript UX authorship platform",
|
|
6
6
|
"main": "lib/jux.js",
|
|
@@ -50,7 +50,11 @@
|
|
|
50
50
|
"scripts": {
|
|
51
51
|
"build": "tsc",
|
|
52
52
|
"dev": "tsc --watch",
|
|
53
|
-
"prepublishOnly": "npm run build"
|
|
53
|
+
"prepublishOnly": "npm run build",
|
|
54
|
+
"analyze": "node scripts/analyze-components.js",
|
|
55
|
+
"check-styles": "node scripts/check-inline-styles.js",
|
|
56
|
+
"find-inject-styles": "node scripts/find-inject-styles.js",
|
|
57
|
+
"find-jux-classes": "node scripts/find-jux-classes.js"
|
|
54
58
|
},
|
|
55
59
|
"dependencies": {
|
|
56
60
|
"chokidar": "^3.5.3",
|
|
@@ -63,6 +67,7 @@
|
|
|
63
67
|
"@types/express": "^4.17.17",
|
|
64
68
|
"@types/node": "^20.0.0",
|
|
65
69
|
"@types/ws": "^8.5.5",
|
|
70
|
+
"jsdom": "^27.4.0",
|
|
66
71
|
"typescript": "^5.0.0"
|
|
67
72
|
}
|
|
68
73
|
}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { jux, state } from 'juxscript';
|
|
2
|
+
jux.include('layout.css');
|
|
3
|
+
|
|
4
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
5
|
+
// ALL COMPONENTS SHOWCASE - Maximum DOM nodes per component
|
|
6
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
7
|
+
|
|
8
|
+
// Hero - All DOM-generating options
|
|
9
|
+
jux.hero('all-hero', {
|
|
10
|
+
title: 'Hero Title',
|
|
11
|
+
subtitle: 'Hero Subtitle',
|
|
12
|
+
content: 'Hero body content goes here',
|
|
13
|
+
cta: 'Call to Action',
|
|
14
|
+
ctaLink: '#',
|
|
15
|
+
backgroundImage: 'https://via.placeholder.com/1200x400',
|
|
16
|
+
backgroundOverlay: true,
|
|
17
|
+
centered: true
|
|
18
|
+
}).render();
|
|
19
|
+
|
|
20
|
+
jux.alert('all-alert').render();
|
|
21
|
+
jux.badge('all-badge').render();
|
|
22
|
+
jux.button('all-button').render();
|
|
23
|
+
jux.card('all-card').render();
|
|
24
|
+
jux.checkbox('all-checkbox').render();
|
|
25
|
+
jux.code('all-code').render();
|
|
26
|
+
jux.container('all-container').render();
|
|
27
|
+
jux.datepicker('all-datepicker').render();
|
|
28
|
+
jux.dropdown('all-dropdown', {
|
|
29
|
+
items: [{ label: 'Item 1', value: '1' }, { label: 'Item 2', value: '2' }]
|
|
30
|
+
}).render();
|
|
31
|
+
jux.fileupload('all-fileupload').render();
|
|
32
|
+
jux.heading('all-h1').render();
|
|
33
|
+
// jux.icon('all-icon').render();
|
|
34
|
+
jux.input('all-input').render();
|
|
35
|
+
jux.kpicard('all-kpicard').render();
|
|
36
|
+
jux.list('all-list', {
|
|
37
|
+
items: ['Item 1', 'Item 2', 'Item 3']
|
|
38
|
+
}).render();
|
|
39
|
+
jux.loading('all-loading').render();
|
|
40
|
+
jux.menu('all-menu', {
|
|
41
|
+
items: [{ label: 'Home', path: '/' }, { label: 'About', path: '/about' }]
|
|
42
|
+
}).render();
|
|
43
|
+
jux.nav('all-nav', {
|
|
44
|
+
items: [{ label: 'Home', path: '/' }, { label: 'About', path: '/about' }]
|
|
45
|
+
}).render();
|
|
46
|
+
jux.paragraph('all-paragraph').render();
|
|
47
|
+
jux.progress('all-progress').render();
|
|
48
|
+
jux.radio('all-radio', {
|
|
49
|
+
options: [{ label: 'Option 1', value: '1' }, { label: 'Option 2', value: '2' }]
|
|
50
|
+
}).render();
|
|
51
|
+
jux.select('all-select', {
|
|
52
|
+
options: [{ label: 'Option 1', value: '1' }, { label: 'Option 2', value: '2' }]
|
|
53
|
+
}).render();
|
|
54
|
+
jux.sidebar('all-sidebar').render();
|
|
55
|
+
jux.switch('all-switch').render();
|
|
56
|
+
jux.table('all-table', {
|
|
57
|
+
columns: ['Name', 'Age'],
|
|
58
|
+
rows: [
|
|
59
|
+
{ Name: 'John', Age: '25' },
|
|
60
|
+
{ Name: 'Jane', Age: '30' }
|
|
61
|
+
]
|
|
62
|
+
}).render();
|
|
63
|
+
jux.tabs('all-tabs', {
|
|
64
|
+
tabs: [{ label: 'Tab 1', content: 'Content 1' }, { label: 'Tab 2', content: 'Content 2' }]
|
|
65
|
+
}).render();
|
|
66
|
+
|
|
67
|
+
jux.button('tooltip-trigger').label('Hover for tooltip').render();
|
|
68
|
+
jux.tooltip('all-tooltip', {
|
|
69
|
+
text: 'Tooltip content',
|
|
70
|
+
position: 'top'
|
|
71
|
+
}).render('#tooltip-trigger');
|
|
72
|
+
|
|
73
|
+
jux.view('all-view').render();
|
|
74
|
+
|
|
75
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
76
|
+
// SELF-ANALYSIS: Build component tree from #app
|
|
77
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
78
|
+
|
|
79
|
+
function buildComponentTree(element, depth = 0) {
|
|
80
|
+
const indent = ' '.repeat(depth);
|
|
81
|
+
const tagName = element.tagName.toLowerCase();
|
|
82
|
+
// ✅ Fix: Check if className exists and is a string
|
|
83
|
+
const classes = (element.className && typeof element.className === 'string')
|
|
84
|
+
? `.${element.className.split(' ').join('.')}`
|
|
85
|
+
: '';
|
|
86
|
+
|
|
87
|
+
let tree = `${indent}${tagName}${classes}\n`;
|
|
88
|
+
|
|
89
|
+
// Recurse through children
|
|
90
|
+
Array.from(element.children).forEach(child => {
|
|
91
|
+
tree += buildComponentTree(child, depth + 1);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
return tree;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function analyzeComponents() {
|
|
98
|
+
const app = document.getElementById('app');
|
|
99
|
+
if (!app) return 'No #app container found';
|
|
100
|
+
|
|
101
|
+
const components = Array.from(app.children);
|
|
102
|
+
const componentTypes = new Map();
|
|
103
|
+
|
|
104
|
+
let analysis = `═══════════════════════════════════════════════════════════════
|
|
105
|
+
COMPONENT TREE ANALYSIS
|
|
106
|
+
═══════════════════════════════════════════════════════════════
|
|
107
|
+
|
|
108
|
+
Found ${components.length} components in #app
|
|
109
|
+
|
|
110
|
+
`;
|
|
111
|
+
|
|
112
|
+
components.forEach((component, index) => {
|
|
113
|
+
const componentId = component.id || `component-${index}`;
|
|
114
|
+
// ✅ Fix: Safely handle className
|
|
115
|
+
const className = (component.className && typeof component.className === 'string')
|
|
116
|
+
? component.className
|
|
117
|
+
: '';
|
|
118
|
+
const rootClasses = className.split(' ').filter(c => c);
|
|
119
|
+
const primaryClass = rootClasses.find(c => c.startsWith('jux-')) || rootClasses[0] || 'unknown';
|
|
120
|
+
|
|
121
|
+
const componentName = primaryClass
|
|
122
|
+
.replace(/^jux-/, '')
|
|
123
|
+
.split('-')
|
|
124
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
125
|
+
.join('');
|
|
126
|
+
|
|
127
|
+
// Track component types
|
|
128
|
+
const typeName = primaryClass.replace(/^jux-/, '');
|
|
129
|
+
componentTypes.set(typeName, (componentTypes.get(typeName) || 0) + 1);
|
|
130
|
+
|
|
131
|
+
analysis += `┌─ ${componentName} (${componentId})\n`;
|
|
132
|
+
analysis += '│\n';
|
|
133
|
+
|
|
134
|
+
const tree = buildComponentTree(component);
|
|
135
|
+
tree.split('\n').forEach(line => {
|
|
136
|
+
if (line.trim()) {
|
|
137
|
+
analysis += `│ ${line}\n`;
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
analysis += `└${'─'.repeat(66)}\n\n`;
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// Add summary
|
|
145
|
+
analysis += `═══════════════════════════════════════════════════════════════
|
|
146
|
+
SUMMARY
|
|
147
|
+
═══════════════════════════════════════════════════════════════
|
|
148
|
+
|
|
149
|
+
Component Types:
|
|
150
|
+
`;
|
|
151
|
+
|
|
152
|
+
Array.from(componentTypes.entries())
|
|
153
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
154
|
+
.forEach(([type, count]) => {
|
|
155
|
+
analysis += ` - ${type}: ${count}\n`;
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
analysis += `\nTotal: ${components.length} components rendered\n`;
|
|
159
|
+
|
|
160
|
+
return analysis;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Wait for DOM to be fully rendered
|
|
164
|
+
setTimeout(() => {
|
|
165
|
+
const analysis = analyzeComponents();
|
|
166
|
+
|
|
167
|
+
// Create analysis display
|
|
168
|
+
jux.container('analysis-container')
|
|
169
|
+
.style('margin-top: 3rem; padding: 2rem; background: #1e1e1e; border-radius: 8px;')
|
|
170
|
+
.render();
|
|
171
|
+
|
|
172
|
+
jux.heading('analysis-title')
|
|
173
|
+
.level(2)
|
|
174
|
+
.text('🔍 Self-Analysis')
|
|
175
|
+
.style('color: #10b981; margin-bottom: 1rem;')
|
|
176
|
+
.render('#analysis-container');
|
|
177
|
+
|
|
178
|
+
jux.code('component-tree')
|
|
179
|
+
.language('text')
|
|
180
|
+
.code(analysis)
|
|
181
|
+
.style('background: #0d1117; color: #c9d1d9; font-size: 0.875rem; max-height: 600px; overflow-y: auto;')
|
|
182
|
+
.render('#analysis-container');
|
|
183
|
+
|
|
184
|
+
jux.paragraph('analysis-note')
|
|
185
|
+
.text('This tree was generated by JavaScript analyzing the DOM structure of this page.')
|
|
186
|
+
.style('margin-top: 1rem; color: #8b949e; font-size: 0.875rem;')
|
|
187
|
+
.render('#analysis-container');
|
|
188
|
+
}, 100);
|
|
189
|
+
|
|
190
|
+
|