juxscript 1.1.71 → 1.1.73
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/bin/cli.js +56 -7
- package/css-classes-inventory.json +1 -556
- package/dom-structure-map.json +2 -487
- package/index.d.ts +0 -2
- package/index.d.ts.map +1 -1
- package/index.js +0 -2
- package/juxconfig.example.js +1 -0
- package/lib/styles/modal.css +402 -0
- package/machinery/build3.js +13 -3
- package/machinery/compiler3.js +83 -0
- package/package.json +1 -1
- package/lib/components/blueprint.ts +0 -421
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
/* ═══════════════════════════════════════════════════════════════════
|
|
2
|
+
* MODAL BASE STYLES
|
|
3
|
+
* ═══════════════════════════════════════════════════════════════════ */
|
|
4
|
+
|
|
5
|
+
/* Modal Overlay - Base positioning */
|
|
6
|
+
.jux-modal-overlay {
|
|
7
|
+
position: fixed;
|
|
8
|
+
inset: 0;
|
|
9
|
+
z-index: 50;
|
|
10
|
+
background-color: rgba(0, 0, 0, 0.8);
|
|
11
|
+
backdrop-filter: blur(2px);
|
|
12
|
+
display: flex;
|
|
13
|
+
align-items: center;
|
|
14
|
+
justify-content: center;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/* Modal Container */
|
|
18
|
+
.jux-modal {
|
|
19
|
+
position: relative;
|
|
20
|
+
background-color: #ffffff;
|
|
21
|
+
border: 1px solid #e4e4e7;
|
|
22
|
+
border-radius: 0.5rem;
|
|
23
|
+
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
|
24
|
+
width: 100%;
|
|
25
|
+
max-width: 32rem;
|
|
26
|
+
z-index: 51;
|
|
27
|
+
display: flex;
|
|
28
|
+
flex-direction: column;
|
|
29
|
+
gap: 1rem;
|
|
30
|
+
padding: 1.5rem;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.jux-modal-small { max-width: 24rem; }
|
|
34
|
+
.jux-modal-medium { max-width: 32rem; }
|
|
35
|
+
.jux-modal-large { max-width: 48rem; }
|
|
36
|
+
|
|
37
|
+
/* ═══════════════════════════════════════════════════════════════════
|
|
38
|
+
* POSITION VARIANTS
|
|
39
|
+
* ═══════════════════════════════════════════════════════════════════ */
|
|
40
|
+
|
|
41
|
+
/* Center (default) */
|
|
42
|
+
.jux-modal-position-center {
|
|
43
|
+
align-items: center;
|
|
44
|
+
justify-content: center;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* Top position */
|
|
48
|
+
.jux-modal-position-top {
|
|
49
|
+
align-items: flex-start;
|
|
50
|
+
justify-content: center;
|
|
51
|
+
padding-top: 2rem;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.jux-modal-position-top .jux-modal {
|
|
55
|
+
animation: modalSlideDown 0.3s ease-out;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@keyframes modalSlideDown {
|
|
59
|
+
from {
|
|
60
|
+
transform: translateY(-20px);
|
|
61
|
+
opacity: 0;
|
|
62
|
+
}
|
|
63
|
+
to {
|
|
64
|
+
transform: translateY(0);
|
|
65
|
+
opacity: 1;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* Bottom position (bottom sheet) */
|
|
70
|
+
.jux-modal-position-bottom {
|
|
71
|
+
align-items: flex-end;
|
|
72
|
+
justify-content: center;
|
|
73
|
+
padding: 0;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.jux-modal-position-bottom .jux-modal {
|
|
77
|
+
border-radius: 0.75rem 0.75rem 0 0;
|
|
78
|
+
max-height: 90vh;
|
|
79
|
+
overflow-y: auto;
|
|
80
|
+
width: 100%;
|
|
81
|
+
max-width: 100%;
|
|
82
|
+
animation: modalSlideUp 0.3s ease-out;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@keyframes modalSlideUp {
|
|
86
|
+
from {
|
|
87
|
+
transform: translateY(100%);
|
|
88
|
+
opacity: 0;
|
|
89
|
+
}
|
|
90
|
+
to {
|
|
91
|
+
transform: translateY(0);
|
|
92
|
+
opacity: 1;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/* Fullscreen position */
|
|
97
|
+
.jux-modal-position-fullscreen {
|
|
98
|
+
align-items: stretch;
|
|
99
|
+
justify-content: stretch;
|
|
100
|
+
padding: 0;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.jux-modal-position-fullscreen .jux-modal {
|
|
104
|
+
max-width: 100%;
|
|
105
|
+
width: 100%;
|
|
106
|
+
height: 100%;
|
|
107
|
+
border-radius: 0;
|
|
108
|
+
margin: 0;
|
|
109
|
+
max-height: 100vh;
|
|
110
|
+
animation: modalFadeIn 0.2s ease-out;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
@keyframes modalFadeIn {
|
|
114
|
+
from {
|
|
115
|
+
opacity: 0;
|
|
116
|
+
}
|
|
117
|
+
to {
|
|
118
|
+
opacity: 1;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* ═══════════════════════════════════════════════════════════════════
|
|
123
|
+
* POPOVER VARIANTS (Tooltip-style)
|
|
124
|
+
* ═══════════════════════════════════════════════════════════════════ */
|
|
125
|
+
|
|
126
|
+
.jux-modal-position-popover-top,
|
|
127
|
+
.jux-modal-position-popover-bottom,
|
|
128
|
+
.jux-modal-position-popover-left,
|
|
129
|
+
.jux-modal-position-popover-right {
|
|
130
|
+
background-color: rgba(0, 0, 0, 0.2);
|
|
131
|
+
backdrop-filter: none;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.jux-modal-position-popover-top .jux-modal,
|
|
135
|
+
.jux-modal-position-popover-bottom .jux-modal,
|
|
136
|
+
.jux-modal-position-popover-left .jux-modal,
|
|
137
|
+
.jux-modal-position-popover-right .jux-modal {
|
|
138
|
+
max-width: 20rem;
|
|
139
|
+
padding: 1rem;
|
|
140
|
+
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.2), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
|
141
|
+
border-radius: 0.5rem;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/* Popover Top */
|
|
145
|
+
.jux-modal-position-popover-top {
|
|
146
|
+
align-items: flex-start;
|
|
147
|
+
justify-content: center;
|
|
148
|
+
padding-top: 1rem;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.jux-modal-position-popover-top .jux-modal {
|
|
152
|
+
animation: popoverSlideDown 0.2s ease-out;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
@keyframes popoverSlideDown {
|
|
156
|
+
from {
|
|
157
|
+
transform: translateY(-10px);
|
|
158
|
+
opacity: 0;
|
|
159
|
+
}
|
|
160
|
+
to {
|
|
161
|
+
transform: translateY(0);
|
|
162
|
+
opacity: 1;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/* Popover Bottom */
|
|
167
|
+
.jux-modal-position-popover-bottom {
|
|
168
|
+
align-items: flex-end;
|
|
169
|
+
justify-content: center;
|
|
170
|
+
padding-bottom: 1rem;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.jux-modal-position-popover-bottom .jux-modal {
|
|
174
|
+
animation: popoverSlideUp 0.2s ease-out;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
@keyframes popoverSlideUp {
|
|
178
|
+
from {
|
|
179
|
+
transform: translateY(10px);
|
|
180
|
+
opacity: 0;
|
|
181
|
+
}
|
|
182
|
+
to {
|
|
183
|
+
transform: translateY(0);
|
|
184
|
+
opacity: 1;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/* Popover Left */
|
|
189
|
+
.jux-modal-position-popover-left {
|
|
190
|
+
align-items: center;
|
|
191
|
+
justify-content: flex-start;
|
|
192
|
+
padding-left: 1rem;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.jux-modal-position-popover-left .jux-modal {
|
|
196
|
+
animation: popoverSlideRight 0.2s ease-out;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
@keyframes popoverSlideRight {
|
|
200
|
+
from {
|
|
201
|
+
transform: translateX(-10px);
|
|
202
|
+
opacity: 0;
|
|
203
|
+
}
|
|
204
|
+
to {
|
|
205
|
+
transform: translateX(0);
|
|
206
|
+
opacity: 1;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/* Popover Right */
|
|
211
|
+
.jux-modal-position-popover-right {
|
|
212
|
+
align-items: center;
|
|
213
|
+
justify-content: flex-end;
|
|
214
|
+
padding-right: 1rem;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.jux-modal-position-popover-right .jux-modal {
|
|
218
|
+
animation: popoverSlideLeft 0.2s ease-out;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
@keyframes popoverSlideLeft {
|
|
222
|
+
from {
|
|
223
|
+
transform: translateX(10px);
|
|
224
|
+
opacity: 0;
|
|
225
|
+
}
|
|
226
|
+
to {
|
|
227
|
+
transform: translateX(0);
|
|
228
|
+
opacity: 1;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/* Smaller close button for popovers */
|
|
233
|
+
.jux-modal-position-popover-top .jux-modal-close,
|
|
234
|
+
.jux-modal-position-popover-bottom .jux-modal-close,
|
|
235
|
+
.jux-modal-position-popover-left .jux-modal-close,
|
|
236
|
+
.jux-modal-position-popover-right .jux-modal-close {
|
|
237
|
+
width: 1.25rem;
|
|
238
|
+
height: 1.25rem;
|
|
239
|
+
font-size: 1rem;
|
|
240
|
+
top: 0.5rem;
|
|
241
|
+
right: 0.5rem;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/* ═══════════════════════════════════════════════════════════════════
|
|
245
|
+
* MODAL CONTENT SECTIONS
|
|
246
|
+
* ═══════════════════════════════════════════════════════════════════ */
|
|
247
|
+
|
|
248
|
+
/* Header */
|
|
249
|
+
.jux-modal-header {
|
|
250
|
+
display: flex;
|
|
251
|
+
align-items: flex-start;
|
|
252
|
+
gap: 0.75rem;
|
|
253
|
+
padding: 0;
|
|
254
|
+
text-align: left;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.jux-modal-header-icon {
|
|
258
|
+
display: flex;
|
|
259
|
+
align-items: center;
|
|
260
|
+
justify-content: center;
|
|
261
|
+
flex-shrink: 0;
|
|
262
|
+
color: #09090b;
|
|
263
|
+
margin-top: 0.125rem;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.jux-modal-header-title {
|
|
267
|
+
flex: 1;
|
|
268
|
+
font-size: 1.125rem;
|
|
269
|
+
font-weight: 600;
|
|
270
|
+
line-height: 1.2;
|
|
271
|
+
color: #09090b;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/* Body / Content */
|
|
275
|
+
.jux-modal-content {
|
|
276
|
+
padding: 0;
|
|
277
|
+
font-size: 0.875rem;
|
|
278
|
+
color: #71717a;
|
|
279
|
+
line-height: 1.5;
|
|
280
|
+
display: flex;
|
|
281
|
+
flex-direction: column;
|
|
282
|
+
gap: 1rem;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/* Footer with Actions */
|
|
286
|
+
.jux-modal-footer {
|
|
287
|
+
padding: 0;
|
|
288
|
+
padding-top: 0.5rem;
|
|
289
|
+
display: flex;
|
|
290
|
+
flex-direction: row;
|
|
291
|
+
justify-content: flex-end;
|
|
292
|
+
gap: 0.5rem;
|
|
293
|
+
flex-wrap: wrap;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/* Modal Action Buttons */
|
|
297
|
+
.jux-modal-action {
|
|
298
|
+
display: inline-flex;
|
|
299
|
+
align-items: center;
|
|
300
|
+
justify-content: center;
|
|
301
|
+
white-space: nowrap;
|
|
302
|
+
border-radius: 0.375rem;
|
|
303
|
+
font-size: 0.875rem;
|
|
304
|
+
font-weight: 500;
|
|
305
|
+
height: 2.5rem;
|
|
306
|
+
padding: 0 1rem;
|
|
307
|
+
cursor: pointer;
|
|
308
|
+
transition: all 0.15s ease;
|
|
309
|
+
border: 1px solid transparent;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.jux-modal-action-ghost {
|
|
313
|
+
background-color: transparent;
|
|
314
|
+
color: #09090b;
|
|
315
|
+
border: none;
|
|
316
|
+
}
|
|
317
|
+
.jux-modal-action-ghost:hover {
|
|
318
|
+
background-color: #f4f4f5;
|
|
319
|
+
color: #18181b;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.jux-modal-action-secondary {
|
|
323
|
+
border: 1px solid #e4e4e7;
|
|
324
|
+
background-color: #ffffff;
|
|
325
|
+
color: #09090b;
|
|
326
|
+
}
|
|
327
|
+
.jux-modal-action-secondary:hover {
|
|
328
|
+
background-color: #f4f4f5;
|
|
329
|
+
color: #18181b;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
.jux-modal-action-primary {
|
|
333
|
+
background-color: #18181b;
|
|
334
|
+
color: #fafafa;
|
|
335
|
+
border: none;
|
|
336
|
+
}
|
|
337
|
+
.jux-modal-action-primary:hover {
|
|
338
|
+
background-color: #27272a;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.jux-modal-action-destructive {
|
|
342
|
+
background-color: #ef4444;
|
|
343
|
+
color: #ffffff;
|
|
344
|
+
border: none;
|
|
345
|
+
}
|
|
346
|
+
.jux-modal-action-destructive:hover {
|
|
347
|
+
background-color: #dc2626;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/* Close Button (X) */
|
|
351
|
+
.jux-modal-close {
|
|
352
|
+
position: absolute;
|
|
353
|
+
top: 1rem;
|
|
354
|
+
right: 1rem;
|
|
355
|
+
border-radius: 0.125rem;
|
|
356
|
+
opacity: 0.7;
|
|
357
|
+
transition: opacity 0.15s ease;
|
|
358
|
+
background: transparent;
|
|
359
|
+
border: none;
|
|
360
|
+
cursor: pointer;
|
|
361
|
+
color: #71717a;
|
|
362
|
+
padding: 0.25rem;
|
|
363
|
+
width: 1.5rem;
|
|
364
|
+
height: 1.5rem;
|
|
365
|
+
display: flex;
|
|
366
|
+
align-items: center;
|
|
367
|
+
justify-content: center;
|
|
368
|
+
font-size: 1.25rem;
|
|
369
|
+
line-height: 1;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
.jux-modal-close:hover {
|
|
373
|
+
opacity: 1;
|
|
374
|
+
color: #09090b;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.jux-modal-close:focus-visible {
|
|
378
|
+
outline: 2px solid #18181b;
|
|
379
|
+
outline-offset: 2px;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/* ═══════════════════════════════════════════════════════════════════
|
|
383
|
+
* RESPONSIVE ADJUSTMENTS
|
|
384
|
+
* ═══════════════════════════════════════════════════════════════════ */
|
|
385
|
+
|
|
386
|
+
@media (max-width: 640px) {
|
|
387
|
+
.jux-modal-position-top,
|
|
388
|
+
.jux-modal-position-center {
|
|
389
|
+
padding: 1rem;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
.jux-modal-position-bottom .jux-modal {
|
|
393
|
+
max-height: 95vh;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
.jux-modal-position-popover-top .jux-modal,
|
|
397
|
+
.jux-modal-position-popover-bottom .jux-modal,
|
|
398
|
+
.jux-modal-position-popover-left .jux-modal,
|
|
399
|
+
.jux-modal-position-popover-right .jux-modal {
|
|
400
|
+
max-width: calc(100vw - 2rem);
|
|
401
|
+
}
|
|
402
|
+
}
|
package/machinery/build3.js
CHANGED
|
@@ -23,7 +23,8 @@ try {
|
|
|
23
23
|
// ═══════════════════════════════════════════════════════════════
|
|
24
24
|
const directories = {
|
|
25
25
|
source: rawConfig.directories?.source || './jux',
|
|
26
|
-
distribution: rawConfig.directories?.distribution || './.jux-dist'
|
|
26
|
+
distribution: rawConfig.directories?.distribution || './.jux-dist',
|
|
27
|
+
public: rawConfig.directories?.public || './public' // ✅ Configurable public folder
|
|
27
28
|
};
|
|
28
29
|
|
|
29
30
|
const defaults = {
|
|
@@ -35,7 +36,8 @@ const defaults = {
|
|
|
35
36
|
// Resolve absolute paths
|
|
36
37
|
const paths = {
|
|
37
38
|
source: path.resolve(PROJECT_ROOT, directories.source),
|
|
38
|
-
distribution: path.resolve(PROJECT_ROOT, directories.distribution)
|
|
39
|
+
distribution: path.resolve(PROJECT_ROOT, directories.distribution),
|
|
40
|
+
public: path.resolve(PROJECT_ROOT, directories.public) // ✅ Use configured path
|
|
39
41
|
};
|
|
40
42
|
|
|
41
43
|
// ═══════════════════════════════════════════════════════════════
|
|
@@ -52,6 +54,13 @@ if (fs.existsSync(paths.source)) {
|
|
|
52
54
|
process.exit(1);
|
|
53
55
|
}
|
|
54
56
|
|
|
57
|
+
// ✅ Show public folder status
|
|
58
|
+
if (fs.existsSync(paths.public)) {
|
|
59
|
+
console.log(` ✓ public: ${paths.public}`);
|
|
60
|
+
} else {
|
|
61
|
+
console.log(` ℹ public: ${paths.public} (optional, not found)`);
|
|
62
|
+
}
|
|
63
|
+
|
|
55
64
|
// ═══════════════════════════════════════════════════════════════
|
|
56
65
|
// RUN BUILD
|
|
57
66
|
// ═══════════════════════════════════════════════════════════════
|
|
@@ -60,8 +69,9 @@ console.log(`\n`);
|
|
|
60
69
|
const compiler = new JuxCompiler({
|
|
61
70
|
srcDir: paths.source,
|
|
62
71
|
distDir: paths.distribution,
|
|
72
|
+
publicDir: directories.public, // ✅ Pass configured public directory name
|
|
63
73
|
defaults,
|
|
64
|
-
paths
|
|
74
|
+
paths // ✅ Pass resolved paths object (includes paths.public)
|
|
65
75
|
});
|
|
66
76
|
|
|
67
77
|
compiler.build()
|
package/machinery/compiler3.js
CHANGED
|
@@ -13,6 +13,7 @@ export class JuxCompiler {
|
|
|
13
13
|
this.config = config;
|
|
14
14
|
this.srcDir = config.srcDir || './jux';
|
|
15
15
|
this.distDir = config.distDir || './.jux-dist';
|
|
16
|
+
this.publicDir = config.publicDir || './public'; // ✅ Configurable public path
|
|
16
17
|
this.defaults = config.defaults || {};
|
|
17
18
|
this.paths = config.paths || {};
|
|
18
19
|
this._juxscriptExports = null;
|
|
@@ -430,6 +431,9 @@ navigate(location.pathname);
|
|
|
430
431
|
}
|
|
431
432
|
fs.mkdirSync(this.distDir, { recursive: true });
|
|
432
433
|
|
|
434
|
+
// ✅ Copy public folder if exists
|
|
435
|
+
this.copyPublicFolder();
|
|
436
|
+
|
|
433
437
|
const { views, dataModules, sharedModules } = this.scanFiles();
|
|
434
438
|
console.log(`📁 Found ${views.length} views, ${sharedModules.length} shared, ${dataModules.length} data`);
|
|
435
439
|
|
|
@@ -497,4 +501,83 @@ navigate(location.pathname);
|
|
|
497
501
|
console.log(`\n✅ Build Complete!\n`);
|
|
498
502
|
return { success: true, errors: [], warnings: validation.warnings };
|
|
499
503
|
}
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Copy public folder contents to dist
|
|
507
|
+
*/
|
|
508
|
+
copyPublicFolder() {
|
|
509
|
+
// ✅ Use configured public path or resolve from paths object
|
|
510
|
+
const publicSrc = this.paths.public
|
|
511
|
+
? this.paths.public
|
|
512
|
+
: path.resolve(process.cwd(), this.publicDir);
|
|
513
|
+
|
|
514
|
+
if (!fs.existsSync(publicSrc)) {
|
|
515
|
+
return; // No public folder, skip
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
console.log('📦 Copying public assets...');
|
|
519
|
+
|
|
520
|
+
try {
|
|
521
|
+
this._copyDirRecursive(publicSrc, this.distDir, 0);
|
|
522
|
+
console.log('✅ Public assets copied');
|
|
523
|
+
} catch (err) {
|
|
524
|
+
console.warn('⚠️ Error copying public folder:', err.message);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Recursively copy directory contents
|
|
530
|
+
*/
|
|
531
|
+
_copyDirRecursive(src, dest, depth = 0) {
|
|
532
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
533
|
+
|
|
534
|
+
entries.forEach(entry => {
|
|
535
|
+
// Skip hidden files and directories
|
|
536
|
+
if (entry.name.startsWith('.')) return;
|
|
537
|
+
|
|
538
|
+
const srcPath = path.join(src, entry.name);
|
|
539
|
+
const destPath = path.join(dest, entry.name);
|
|
540
|
+
|
|
541
|
+
if (entry.isDirectory()) {
|
|
542
|
+
// Create directory and recurse
|
|
543
|
+
if (!fs.existsSync(destPath)) {
|
|
544
|
+
fs.mkdirSync(destPath, { recursive: true });
|
|
545
|
+
}
|
|
546
|
+
this._copyDirRecursive(srcPath, destPath, depth + 1);
|
|
547
|
+
} else {
|
|
548
|
+
// Copy file
|
|
549
|
+
fs.copyFileSync(srcPath, destPath);
|
|
550
|
+
|
|
551
|
+
// Log files at root level only
|
|
552
|
+
if (depth === 0) {
|
|
553
|
+
const ext = path.extname(entry.name);
|
|
554
|
+
const icon = this._getFileIcon(ext);
|
|
555
|
+
console.log(` ${icon} ${entry.name}`);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Get icon for file type
|
|
563
|
+
*/
|
|
564
|
+
_getFileIcon(ext) {
|
|
565
|
+
const icons = {
|
|
566
|
+
'.html': '📄',
|
|
567
|
+
'.css': '🎨',
|
|
568
|
+
'.js': '📜',
|
|
569
|
+
'.json': '📋',
|
|
570
|
+
'.png': '🖼️',
|
|
571
|
+
'.jpg': '🖼️',
|
|
572
|
+
'.jpeg': '🖼️',
|
|
573
|
+
'.gif': '🖼️',
|
|
574
|
+
'.svg': '🎨',
|
|
575
|
+
'.ico': '🔖',
|
|
576
|
+
'.woff': '🔤',
|
|
577
|
+
'.woff2': '🔤',
|
|
578
|
+
'.ttf': '🔤',
|
|
579
|
+
'.eot': '🔤'
|
|
580
|
+
};
|
|
581
|
+
return icons[ext.toLowerCase()] || '📦';
|
|
582
|
+
}
|
|
500
583
|
}
|