@cmssy/cli 0.1.0

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.
Files changed (113) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +649 -0
  3. package/config.d.ts +2 -0
  4. package/config.js +2 -0
  5. package/dist/cli.d.ts +3 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +236 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/commands/add-source.d.ts +7 -0
  10. package/dist/commands/add-source.d.ts.map +1 -0
  11. package/dist/commands/add-source.js +238 -0
  12. package/dist/commands/add-source.js.map +1 -0
  13. package/dist/commands/build.d.ts +7 -0
  14. package/dist/commands/build.d.ts.map +1 -0
  15. package/dist/commands/build.js +105 -0
  16. package/dist/commands/build.js.map +1 -0
  17. package/dist/commands/configure.d.ts +6 -0
  18. package/dist/commands/configure.d.ts.map +1 -0
  19. package/dist/commands/configure.js +42 -0
  20. package/dist/commands/configure.js.map +1 -0
  21. package/dist/commands/create.d.ts +18 -0
  22. package/dist/commands/create.d.ts.map +1 -0
  23. package/dist/commands/create.js +444 -0
  24. package/dist/commands/create.js.map +1 -0
  25. package/dist/commands/dev.d.ts +6 -0
  26. package/dist/commands/dev.d.ts.map +1 -0
  27. package/dist/commands/dev.js +962 -0
  28. package/dist/commands/dev.js.map +1 -0
  29. package/dist/commands/init.d.ts +2 -0
  30. package/dist/commands/init.d.ts.map +1 -0
  31. package/dist/commands/init.js +362 -0
  32. package/dist/commands/init.js.map +1 -0
  33. package/dist/commands/migrate.d.ts +2 -0
  34. package/dist/commands/migrate.d.ts.map +1 -0
  35. package/dist/commands/migrate.js +227 -0
  36. package/dist/commands/migrate.js.map +1 -0
  37. package/dist/commands/package.d.ts +7 -0
  38. package/dist/commands/package.d.ts.map +1 -0
  39. package/dist/commands/package.js +136 -0
  40. package/dist/commands/package.js.map +1 -0
  41. package/dist/commands/publish.d.ts +13 -0
  42. package/dist/commands/publish.d.ts.map +1 -0
  43. package/dist/commands/publish.js +910 -0
  44. package/dist/commands/publish.js.map +1 -0
  45. package/dist/commands/sync.d.ts +6 -0
  46. package/dist/commands/sync.d.ts.map +1 -0
  47. package/dist/commands/sync.js +208 -0
  48. package/dist/commands/sync.js.map +1 -0
  49. package/dist/commands/upload.d.ts +7 -0
  50. package/dist/commands/upload.d.ts.map +1 -0
  51. package/dist/commands/upload.js +126 -0
  52. package/dist/commands/upload.js.map +1 -0
  53. package/dist/commands/workspaces.d.ts +2 -0
  54. package/dist/commands/workspaces.d.ts.map +1 -0
  55. package/dist/commands/workspaces.js +67 -0
  56. package/dist/commands/workspaces.js.map +1 -0
  57. package/dist/dev-ui/app.js +1284 -0
  58. package/dist/dev-ui/index.html +1511 -0
  59. package/dist/dev-ui-react/App.tsx +164 -0
  60. package/dist/dev-ui-react/__tests__/previewData.test.ts +193 -0
  61. package/dist/dev-ui-react/components/BlocksList.tsx +232 -0
  62. package/dist/dev-ui-react/components/Editor.tsx +469 -0
  63. package/dist/dev-ui-react/components/Preview.tsx +146 -0
  64. package/dist/dev-ui-react/hooks/useBlocks.ts +80 -0
  65. package/dist/dev-ui-react/index.html +13 -0
  66. package/dist/dev-ui-react/main.tsx +8 -0
  67. package/dist/dev-ui-react/styles.css +856 -0
  68. package/dist/dev-ui-react/types.ts +45 -0
  69. package/dist/types/block-config.d.ts +315 -0
  70. package/dist/types/block-config.d.ts.map +1 -0
  71. package/dist/types/block-config.js +8 -0
  72. package/dist/types/block-config.js.map +1 -0
  73. package/dist/utils/block-config.d.ts +10 -0
  74. package/dist/utils/block-config.d.ts.map +1 -0
  75. package/dist/utils/block-config.js +199 -0
  76. package/dist/utils/block-config.js.map +1 -0
  77. package/dist/utils/blocks-meta-cache.d.ts +28 -0
  78. package/dist/utils/blocks-meta-cache.d.ts.map +1 -0
  79. package/dist/utils/blocks-meta-cache.js +72 -0
  80. package/dist/utils/blocks-meta-cache.js.map +1 -0
  81. package/dist/utils/builder.d.ts +34 -0
  82. package/dist/utils/builder.d.ts.map +1 -0
  83. package/dist/utils/builder.js +140 -0
  84. package/dist/utils/builder.js.map +1 -0
  85. package/dist/utils/cmssy-config.d.ts +16 -0
  86. package/dist/utils/cmssy-config.d.ts.map +1 -0
  87. package/dist/utils/cmssy-config.js +19 -0
  88. package/dist/utils/cmssy-config.js.map +1 -0
  89. package/dist/utils/config.d.ts +9 -0
  90. package/dist/utils/config.d.ts.map +1 -0
  91. package/dist/utils/config.js +46 -0
  92. package/dist/utils/config.js.map +1 -0
  93. package/dist/utils/field-schema.d.ts +12 -0
  94. package/dist/utils/field-schema.d.ts.map +1 -0
  95. package/dist/utils/field-schema.js +202 -0
  96. package/dist/utils/field-schema.js.map +1 -0
  97. package/dist/utils/graphql.d.ts +8 -0
  98. package/dist/utils/graphql.d.ts.map +1 -0
  99. package/dist/utils/graphql.js +118 -0
  100. package/dist/utils/graphql.js.map +1 -0
  101. package/dist/utils/publish-helpers.d.ts +35 -0
  102. package/dist/utils/publish-helpers.d.ts.map +1 -0
  103. package/dist/utils/publish-helpers.js +141 -0
  104. package/dist/utils/publish-helpers.js.map +1 -0
  105. package/dist/utils/scanner.d.ts +36 -0
  106. package/dist/utils/scanner.d.ts.map +1 -0
  107. package/dist/utils/scanner.js +140 -0
  108. package/dist/utils/scanner.js.map +1 -0
  109. package/dist/utils/type-generator.d.ts +9 -0
  110. package/dist/utils/type-generator.d.ts.map +1 -0
  111. package/dist/utils/type-generator.js +85 -0
  112. package/dist/utils/type-generator.js.map +1 -0
  113. package/package.json +88 -0
@@ -0,0 +1,1511 @@
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>Cmssy Dev Server</title>
7
+ <link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Crect width='100' height='100' rx='20' fill='%23667eea'/%3E%3Ctext x='50' y='70' font-size='60' font-weight='bold' text-anchor='middle' fill='white' font-family='system-ui'%3EC%3C/text%3E%3C/svg%3E">
8
+ <style>
9
+ /* CSS Reset - scoped to dev UI only, not blocks in iframe */
10
+ *,
11
+ *::before,
12
+ *::after {
13
+ box-sizing: border-box;
14
+ }
15
+
16
+ html,
17
+ body {
18
+ height: 100%;
19
+ margin: 0;
20
+ padding: 0;
21
+ }
22
+
23
+ body {
24
+ line-height: 1.5;
25
+ -webkit-font-smoothing: antialiased;
26
+ }
27
+
28
+ img,
29
+ picture,
30
+ video,
31
+ canvas,
32
+ svg {
33
+ display: block;
34
+ max-width: 100%;
35
+ }
36
+
37
+ input,
38
+ button,
39
+ textarea,
40
+ select {
41
+ font: inherit;
42
+ }
43
+
44
+ p,
45
+ h1,
46
+ h2,
47
+ h3,
48
+ h4,
49
+ h5,
50
+ h6 {
51
+ overflow-wrap: break-word;
52
+ }
53
+
54
+ /* App Styles */
55
+ body {
56
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
57
+ sans-serif;
58
+ background: #f5f5f5;
59
+ overflow: hidden;
60
+ height: 100vh;
61
+ }
62
+
63
+ .container {
64
+ display: grid;
65
+ grid-template-columns: 280px 1fr 400px;
66
+ height: 100vh;
67
+ gap: 0;
68
+ transition: grid-template-columns 0.3s cubic-bezier(0.4, 0, 0.2, 1);
69
+ }
70
+
71
+ /* Collapsed sidebar states - narrow bar instead of hidden */
72
+ .container.left-collapsed {
73
+ grid-template-columns: 48px 1fr 400px;
74
+ }
75
+
76
+ .container.right-collapsed {
77
+ grid-template-columns: 280px 1fr 48px;
78
+ }
79
+
80
+ .container.left-collapsed.right-collapsed {
81
+ grid-template-columns: 48px 1fr 48px;
82
+ }
83
+
84
+ /* Left Panel - Blocks List */
85
+ .blocks-panel {
86
+ background: #ffffff;
87
+ border-right: 1px solid #e0e0e0;
88
+ overflow-y: auto;
89
+ display: flex;
90
+ flex-direction: column;
91
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
92
+ }
93
+
94
+ /* When collapsed, hide overflow */
95
+ .container.left-collapsed .blocks-panel {
96
+ overflow: hidden;
97
+ }
98
+
99
+ .blocks-header {
100
+ padding: 16px;
101
+ border-bottom: 1px solid #e0e0e0;
102
+ background: #fafafa;
103
+ display: flex;
104
+ align-items: center;
105
+ justify-content: space-between;
106
+ min-height: 60px;
107
+ flex-shrink: 0;
108
+ }
109
+
110
+ .blocks-header-content {
111
+ flex: 1;
112
+ min-width: 0;
113
+ transition: opacity 0.2s ease;
114
+ }
115
+
116
+ .blocks-header h1 {
117
+ font-size: 18px;
118
+ font-weight: 600;
119
+ color: #1a1a1a;
120
+ margin-bottom: 4px;
121
+ white-space: nowrap;
122
+ overflow: hidden;
123
+ text-overflow: ellipsis;
124
+ }
125
+
126
+ .blocks-header p {
127
+ font-size: 13px;
128
+ color: #666;
129
+ white-space: nowrap;
130
+ overflow: hidden;
131
+ text-overflow: ellipsis;
132
+ }
133
+
134
+ /* Hamburger toggle button */
135
+ .panel-toggle {
136
+ width: 32px;
137
+ height: 32px;
138
+ border: none;
139
+ background: transparent;
140
+ cursor: pointer;
141
+ display: flex;
142
+ align-items: center;
143
+ justify-content: center;
144
+ border-radius: 6px;
145
+ transition: all 0.2s ease;
146
+ flex-shrink: 0;
147
+ }
148
+
149
+ .panel-toggle:hover {
150
+ background: #e0e0e0;
151
+ }
152
+
153
+ .panel-toggle-icon {
154
+ width: 20px;
155
+ height: 20px;
156
+ position: relative;
157
+ display: flex;
158
+ flex-direction: column;
159
+ justify-content: center;
160
+ gap: 4px;
161
+ }
162
+
163
+ .panel-toggle-icon span {
164
+ display: block;
165
+ height: 2px;
166
+ background: #333;
167
+ border-radius: 2px;
168
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
169
+ }
170
+
171
+ /* Collapsed state - smooth transitions */
172
+ .container.left-collapsed .blocks-header-content,
173
+ .container.right-collapsed .editor-header-content {
174
+ opacity: 0;
175
+ pointer-events: none;
176
+ width: 0;
177
+ overflow: hidden;
178
+ transition: opacity 0.2s ease, width 0.3s ease;
179
+ }
180
+
181
+ .container.left-collapsed .blocks-list,
182
+ .container.right-collapsed .editor-content {
183
+ opacity: 0;
184
+ pointer-events: none;
185
+ transition: opacity 0.2s ease;
186
+ }
187
+
188
+ .container.left-collapsed .blocks-panel {
189
+ overflow: hidden;
190
+ }
191
+
192
+ .container.right-collapsed .editor-panel {
193
+ overflow: hidden;
194
+ }
195
+
196
+ .container.left-collapsed .blocks-header,
197
+ .container.right-collapsed .editor-header {
198
+ justify-content: center;
199
+ padding: 16px 12px;
200
+ transition: all 0.3s ease;
201
+ }
202
+
203
+ /* Rotate hamburger icon when collapsed */
204
+ .container.left-collapsed .blocks-panel .panel-toggle-icon,
205
+ .container.right-collapsed .editor-panel .panel-toggle-icon {
206
+ transform: rotate(180deg);
207
+ }
208
+
209
+ /* Filters Section */
210
+ .blocks-filters {
211
+ padding: 12px;
212
+ border-bottom: 1px solid #e0e0e0;
213
+ background: #fafafa;
214
+ display: flex;
215
+ flex-direction: column;
216
+ gap: 12px;
217
+ flex-shrink: 0;
218
+ }
219
+
220
+ .container.left-collapsed .blocks-filters {
221
+ opacity: 0;
222
+ pointer-events: none;
223
+ height: 0;
224
+ padding: 0;
225
+ overflow: hidden;
226
+ }
227
+
228
+ .search-input {
229
+ width: 100%;
230
+ padding: 8px 12px;
231
+ border: 1px solid #ddd;
232
+ border-radius: 6px;
233
+ font-size: 13px;
234
+ background: white;
235
+ transition: all 0.2s;
236
+ }
237
+
238
+ .search-input:focus {
239
+ outline: none;
240
+ border-color: #667eea;
241
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
242
+ }
243
+
244
+ .search-input::placeholder {
245
+ color: #999;
246
+ }
247
+
248
+ .filter-tabs {
249
+ display: flex;
250
+ gap: 4px;
251
+ background: #e0e0e0;
252
+ padding: 3px;
253
+ border-radius: 8px;
254
+ }
255
+
256
+ .filter-tab {
257
+ flex: 1;
258
+ padding: 6px 12px;
259
+ border: none;
260
+ background: transparent;
261
+ cursor: pointer;
262
+ font-size: 12px;
263
+ font-weight: 500;
264
+ color: #666;
265
+ border-radius: 6px;
266
+ transition: all 0.2s;
267
+ }
268
+
269
+ .filter-tab:hover {
270
+ color: #333;
271
+ }
272
+
273
+ .filter-tab.active {
274
+ background: white;
275
+ color: #333;
276
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
277
+ }
278
+
279
+ .filter-row {
280
+ display: flex;
281
+ gap: 8px;
282
+ }
283
+
284
+ .filter-select {
285
+ flex: 1;
286
+ padding: 6px 10px;
287
+ border: 1px solid #ddd;
288
+ border-radius: 6px;
289
+ font-size: 12px;
290
+ background: white;
291
+ cursor: pointer;
292
+ color: #333;
293
+ }
294
+
295
+ .filter-select:focus {
296
+ outline: none;
297
+ border-color: #667eea;
298
+ }
299
+
300
+ /* Tags Multi-Select */
301
+ .tags-filter {
302
+ display: flex;
303
+ flex-wrap: wrap;
304
+ gap: 6px;
305
+ max-height: 120px;
306
+ overflow-y: auto;
307
+ padding-right: 4px;
308
+ }
309
+
310
+ .tag-chip {
311
+ display: inline-flex;
312
+ align-items: center;
313
+ padding: 4px 10px;
314
+ border: 1px solid #ddd;
315
+ border-radius: 12px;
316
+ font-size: 11px;
317
+ cursor: pointer;
318
+ background: white;
319
+ color: #666;
320
+ transition: all 0.2s;
321
+ }
322
+
323
+ .tag-chip:hover {
324
+ border-color: #667eea;
325
+ color: #667eea;
326
+ }
327
+
328
+ .tag-chip.active {
329
+ background: #667eea;
330
+ border-color: #667eea;
331
+ color: white;
332
+ }
333
+
334
+ .clear-filters {
335
+ padding: 4px 10px;
336
+ border: 1px dashed #ddd;
337
+ border-radius: 12px;
338
+ font-size: 11px;
339
+ cursor: pointer;
340
+ background: transparent;
341
+ color: #999;
342
+ transition: all 0.2s;
343
+ }
344
+
345
+ .clear-filters:hover {
346
+ border-color: #e53935;
347
+ color: #e53935;
348
+ }
349
+
350
+ .blocks-list {
351
+ padding: 12px;
352
+ overflow-y: auto;
353
+ flex: 1;
354
+ }
355
+
356
+ /* Category Group */
357
+ .block-category {
358
+ margin-bottom: 16px;
359
+ }
360
+
361
+ .block-category:last-child {
362
+ margin-bottom: 0;
363
+ }
364
+
365
+ .category-header {
366
+ font-size: 11px;
367
+ font-weight: 600;
368
+ text-transform: uppercase;
369
+ letter-spacing: 0.5px;
370
+ color: #999;
371
+ padding: 8px 12px 6px;
372
+ margin-bottom: 4px;
373
+ display: flex;
374
+ align-items: center;
375
+ gap: 8px;
376
+ }
377
+
378
+ .category-count {
379
+ font-size: 10px;
380
+ font-weight: 500;
381
+ background: #e0e0e0;
382
+ padding: 2px 6px;
383
+ border-radius: 10px;
384
+ color: #666;
385
+ }
386
+
387
+ /* Template badge */
388
+ .type-badge {
389
+ font-size: 10px;
390
+ padding: 2px 6px;
391
+ border-radius: 4px;
392
+ font-weight: 500;
393
+ margin-left: 8px;
394
+ }
395
+
396
+ .type-badge.template {
397
+ background: #f3e8ff;
398
+ color: #7c3aed;
399
+ }
400
+
401
+ .type-badge.block {
402
+ background: #e8f5e9;
403
+ color: #2e7d32;
404
+ }
405
+
406
+ /* Active filters indicator */
407
+ .active-filters {
408
+ display: flex;
409
+ flex-wrap: wrap;
410
+ gap: 6px;
411
+ padding-top: 4px;
412
+ }
413
+
414
+ .active-filter-chip {
415
+ display: inline-flex;
416
+ align-items: center;
417
+ gap: 4px;
418
+ padding: 2px 8px;
419
+ background: #667eea;
420
+ color: white;
421
+ border-radius: 10px;
422
+ font-size: 11px;
423
+ }
424
+
425
+ .active-filter-chip button {
426
+ background: none;
427
+ border: none;
428
+ color: white;
429
+ cursor: pointer;
430
+ padding: 0;
431
+ font-size: 12px;
432
+ opacity: 0.8;
433
+ }
434
+
435
+ .active-filter-chip button:hover {
436
+ opacity: 1;
437
+ }
438
+
439
+ /* Empty state for filtered results */
440
+ .no-results {
441
+ text-align: center;
442
+ padding: 40px 20px;
443
+ color: #999;
444
+ }
445
+
446
+ .no-results-icon {
447
+ font-size: 32px;
448
+ margin-bottom: 12px;
449
+ opacity: 0.5;
450
+ }
451
+
452
+ .block-item {
453
+ padding: 12px 16px;
454
+ margin-bottom: 4px;
455
+ border-radius: 8px;
456
+ cursor: pointer;
457
+ transition: all 0.2s;
458
+ border: 1px solid transparent;
459
+ }
460
+
461
+ .block-item:hover {
462
+ background: #f5f5f5;
463
+ }
464
+
465
+ .block-item.active {
466
+ background: #667eea;
467
+ color: white;
468
+ border-color: #667eea;
469
+ }
470
+
471
+ .block-item-name {
472
+ font-size: 14px;
473
+ font-weight: 500;
474
+ margin-bottom: 2px;
475
+ }
476
+
477
+ .block-item-type {
478
+ font-size: 12px;
479
+ opacity: 0.7;
480
+ }
481
+
482
+ .block-item-header {
483
+ display: flex;
484
+ justify-content: space-between;
485
+ align-items: center;
486
+ margin-bottom: 4px;
487
+ }
488
+
489
+ .block-item-footer {
490
+ display: flex;
491
+ justify-content: space-between;
492
+ align-items: center;
493
+ gap: 8px;
494
+ }
495
+
496
+ .version-badge {
497
+ font-size: 11px;
498
+ padding: 2px 6px;
499
+ background: #e3f2fd;
500
+ color: #1976d2;
501
+ border-radius: 4px;
502
+ font-weight: 500;
503
+ }
504
+
505
+ .status-badge {
506
+ font-size: 11px;
507
+ padding: 2px 8px;
508
+ border-radius: 10px;
509
+ font-weight: 500;
510
+ }
511
+
512
+ .status-badge.status-local {
513
+ background: #fff3e0;
514
+ color: #e65100;
515
+ }
516
+
517
+ .status-badge.status-published {
518
+ background: #e8f5e9;
519
+ color: #2e7d32;
520
+ }
521
+
522
+ /* Center Panel - Preview */
523
+ .preview-panel {
524
+ background: #fafafa;
525
+ display: flex;
526
+ flex-direction: column;
527
+ overflow: hidden;
528
+ }
529
+
530
+ .preview-header {
531
+ padding: 16px 24px;
532
+ background: white;
533
+ border-bottom: 1px solid #e0e0e0;
534
+ display: flex;
535
+ justify-content: space-between;
536
+ align-items: center;
537
+ }
538
+
539
+ .preview-info {
540
+ display: flex;
541
+ align-items: center;
542
+ gap: 12px;
543
+ }
544
+
545
+ .preview-title {
546
+ font-size: 16px;
547
+ font-weight: 600;
548
+ color: #1a1a1a;
549
+ }
550
+
551
+ .preview-actions {
552
+ display: flex;
553
+ gap: 8px;
554
+ align-items: center;
555
+ }
556
+
557
+ .btn-publish {
558
+ padding: 8px 16px;
559
+ background: #667eea;
560
+ color: white;
561
+ border: none;
562
+ border-radius: 6px;
563
+ font-size: 14px;
564
+ font-weight: 500;
565
+ cursor: pointer;
566
+ transition: background 0.2s;
567
+ }
568
+
569
+ .btn-publish:hover {
570
+ background: #5568d3;
571
+ }
572
+
573
+ .preview-badge {
574
+ font-size: 12px;
575
+ padding: 4px 12px;
576
+ background: #e8f5e9;
577
+ color: #2e7d32;
578
+ border-radius: 12px;
579
+ font-weight: 500;
580
+ }
581
+
582
+ .preview-content {
583
+ flex: 1;
584
+ padding: 24px;
585
+ overflow: auto;
586
+ display: flex;
587
+ align-items: center;
588
+ justify-content: center;
589
+ }
590
+
591
+ .preview-iframe-wrapper {
592
+ width: 100%;
593
+ height: 100%;
594
+ background: white;
595
+ border-radius: 12px;
596
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
597
+ overflow: hidden;
598
+ }
599
+
600
+ .preview-iframe {
601
+ width: 100%;
602
+ height: 100%;
603
+ border: none;
604
+ }
605
+
606
+ .preview-empty {
607
+ text-align: center;
608
+ color: #999;
609
+ padding: 60px 20px;
610
+ }
611
+
612
+ .preview-empty-icon {
613
+ font-size: 48px;
614
+ margin-bottom: 16px;
615
+ opacity: 0.3;
616
+ }
617
+
618
+ /* Right Panel - Editor Drawer */
619
+ .editor-panel {
620
+ background: #ffffff;
621
+ border-left: 1px solid #e0e0e0;
622
+ display: flex;
623
+ flex-direction: column;
624
+ overflow: hidden;
625
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
626
+ }
627
+
628
+ .editor-header {
629
+ padding: 16px;
630
+ border-bottom: 1px solid #e0e0e0;
631
+ background: #fafafa;
632
+ display: flex;
633
+ align-items: center;
634
+ justify-content: space-between;
635
+ min-height: 60px;
636
+ flex-shrink: 0;
637
+ }
638
+
639
+ .editor-header-content {
640
+ flex: 1;
641
+ min-width: 0;
642
+ transition: opacity 0.2s ease;
643
+ }
644
+
645
+ .editor-header h2 {
646
+ font-size: 16px;
647
+ font-weight: 600;
648
+ color: #1a1a1a;
649
+ margin-bottom: 4px;
650
+ white-space: nowrap;
651
+ overflow: hidden;
652
+ text-overflow: ellipsis;
653
+ }
654
+
655
+ .editor-header p {
656
+ font-size: 13px;
657
+ color: #666;
658
+ white-space: nowrap;
659
+ overflow: hidden;
660
+ text-overflow: ellipsis;
661
+ }
662
+
663
+ .editor-content {
664
+ flex: 1;
665
+ overflow-y: auto;
666
+ padding: 20px;
667
+ }
668
+
669
+ .editor-empty {
670
+ text-align: center;
671
+ color: #999;
672
+ padding: 40px 20px;
673
+ }
674
+
675
+ /* Form Fields */
676
+ .field-group {
677
+ margin-bottom: 24px;
678
+ }
679
+
680
+ .field-label {
681
+ display: block;
682
+ font-size: 13px;
683
+ font-weight: 500;
684
+ color: #333;
685
+ margin-bottom: 8px;
686
+ }
687
+
688
+ .field-required {
689
+ color: #e53935;
690
+ margin-left: 2px;
691
+ }
692
+
693
+ .field-help {
694
+ font-size: 12px;
695
+ color: #666;
696
+ margin-top: 4px;
697
+ font-weight: 400;
698
+ }
699
+
700
+ .field-input {
701
+ width: 100%;
702
+ padding: 10px 12px;
703
+ border: 1px solid #ddd;
704
+ border-radius: 6px;
705
+ font-size: 14px;
706
+ font-family: inherit;
707
+ transition: all 0.2s;
708
+ }
709
+
710
+ .field-input:focus {
711
+ outline: none;
712
+ border-color: #667eea;
713
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
714
+ }
715
+
716
+ .field-textarea {
717
+ min-height: 80px;
718
+ resize: vertical;
719
+ }
720
+
721
+ .field-select {
722
+ cursor: pointer;
723
+ }
724
+
725
+ .field-checkbox {
726
+ width: auto;
727
+ margin-right: 8px;
728
+ }
729
+
730
+ /* Repeater Fields */
731
+ .repeater-items {
732
+ border: 1px solid #e0e0e0;
733
+ border-radius: 8px;
734
+ padding: 12px;
735
+ background: #fafafa;
736
+ }
737
+
738
+ .repeater-item {
739
+ background: white;
740
+ border: 1px solid #e0e0e0;
741
+ border-radius: 6px;
742
+ padding: 16px;
743
+ margin-bottom: 12px;
744
+ }
745
+
746
+ .repeater-item:last-child {
747
+ margin-bottom: 0;
748
+ }
749
+
750
+ .repeater-item-header {
751
+ display: flex;
752
+ justify-content: space-between;
753
+ align-items: center;
754
+ margin-bottom: 12px;
755
+ padding-bottom: 12px;
756
+ border-bottom: 1px solid #f0f0f0;
757
+ }
758
+
759
+ .repeater-item-title {
760
+ font-size: 13px;
761
+ font-weight: 500;
762
+ color: #666;
763
+ }
764
+
765
+ .repeater-item-remove {
766
+ background: #ffebee;
767
+ color: #c62828;
768
+ border: none;
769
+ padding: 4px 12px;
770
+ border-radius: 4px;
771
+ font-size: 12px;
772
+ cursor: pointer;
773
+ font-weight: 500;
774
+ transition: all 0.2s;
775
+ }
776
+
777
+ .repeater-item-remove:hover {
778
+ background: #ffcdd2;
779
+ }
780
+
781
+ .repeater-add {
782
+ width: 100%;
783
+ padding: 10px;
784
+ background: white;
785
+ border: 1px dashed #667eea;
786
+ color: #667eea;
787
+ border-radius: 6px;
788
+ font-size: 13px;
789
+ font-weight: 500;
790
+ cursor: pointer;
791
+ transition: all 0.2s;
792
+ margin-top: 8px;
793
+ }
794
+
795
+ .repeater-add:hover {
796
+ background: #f5f7ff;
797
+ border-style: solid;
798
+ }
799
+
800
+ /* Loading State */
801
+ .loading {
802
+ display: flex;
803
+ align-items: center;
804
+ justify-content: center;
805
+ padding: 40px;
806
+ color: #999;
807
+ }
808
+
809
+ .spinner {
810
+ width: 20px;
811
+ height: 20px;
812
+ border: 2px solid #f3f3f3;
813
+ border-top: 2px solid #667eea;
814
+ border-radius: 50%;
815
+ animation: spin 1s linear infinite;
816
+ margin-right: 12px;
817
+ }
818
+
819
+ @keyframes spin {
820
+ 0% {
821
+ transform: rotate(0deg);
822
+ }
823
+ 100% {
824
+ transform: rotate(360deg);
825
+ }
826
+ }
827
+
828
+ /* Media Field */
829
+ .media-field {
830
+ display: flex;
831
+ gap: 12px;
832
+ align-items: flex-start;
833
+ }
834
+
835
+ .media-preview {
836
+ width: 80px;
837
+ height: 80px;
838
+ border: 1px solid #ddd;
839
+ border-radius: 6px;
840
+ overflow: hidden;
841
+ background: #fafafa;
842
+ display: flex;
843
+ align-items: center;
844
+ justify-content: center;
845
+ }
846
+
847
+ .media-preview img {
848
+ width: 100%;
849
+ height: 100%;
850
+ object-fit: cover;
851
+ }
852
+
853
+ .media-placeholder {
854
+ color: #999;
855
+ font-size: 12px;
856
+ }
857
+
858
+ .media-input-group {
859
+ flex: 1;
860
+ }
861
+
862
+ /* Color Field */
863
+ .color-field {
864
+ display: flex;
865
+ gap: 12px;
866
+ align-items: center;
867
+ }
868
+
869
+ .color-preview {
870
+ width: 40px;
871
+ height: 40px;
872
+ border: 1px solid #ddd;
873
+ border-radius: 6px;
874
+ cursor: pointer;
875
+ }
876
+
877
+ .color-input {
878
+ flex: 1;
879
+ }
880
+ /* Publish Modal */
881
+ .modal {
882
+ position: fixed;
883
+ top: 0;
884
+ left: 0;
885
+ right: 0;
886
+ bottom: 0;
887
+ background: rgba(0, 0, 0, 0.5);
888
+ display: none;
889
+ align-items: center;
890
+ justify-content: center;
891
+ z-index: 9999;
892
+ }
893
+
894
+ .modal.active {
895
+ display: flex;
896
+ }
897
+
898
+ .modal-content {
899
+ background: white;
900
+ border-radius: 12px;
901
+ width: 90%;
902
+ max-width: 500px;
903
+ max-height: 80vh;
904
+ overflow: auto;
905
+ }
906
+
907
+ .modal-header {
908
+ padding: 20px 24px;
909
+ border-bottom: 1px solid #e0e0e0;
910
+ }
911
+
912
+ .modal-header h3 {
913
+ font-size: 20px;
914
+ font-weight: 600;
915
+ margin: 0 0 4px 0;
916
+ }
917
+
918
+ .modal-header p {
919
+ font-size: 14px;
920
+ color: #666;
921
+ margin: 0;
922
+ }
923
+
924
+ .modal-body {
925
+ padding: 24px;
926
+ }
927
+
928
+ .form-group {
929
+ margin-bottom: 20px;
930
+ }
931
+
932
+ .form-label {
933
+ display: block;
934
+ font-size: 14px;
935
+ font-weight: 500;
936
+ margin-bottom: 8px;
937
+ color: #333;
938
+ }
939
+
940
+ .radio-group {
941
+ display: flex;
942
+ flex-direction: column;
943
+ gap: 12px;
944
+ }
945
+
946
+ .radio-option {
947
+ display: flex;
948
+ align-items: flex-start;
949
+ padding: 12px;
950
+ border: 2px solid #e0e0e0;
951
+ border-radius: 8px;
952
+ cursor: pointer;
953
+ transition: all 0.2s;
954
+ }
955
+
956
+ .radio-option:hover {
957
+ border-color: #667eea;
958
+ background: #f5f7ff;
959
+ }
960
+
961
+ .radio-option input[type="radio"] {
962
+ margin-right: 12px;
963
+ margin-top: 2px;
964
+ }
965
+
966
+ .radio-option-content {
967
+ flex: 1;
968
+ }
969
+
970
+ .radio-option-title {
971
+ font-weight: 500;
972
+ margin-bottom: 2px;
973
+ }
974
+
975
+ .radio-option-desc {
976
+ font-size: 13px;
977
+ color: #666;
978
+ }
979
+
980
+ .input-field {
981
+ width: 100%;
982
+ padding: 10px 12px;
983
+ border: 1px solid #e0e0e0;
984
+ border-radius: 6px;
985
+ font-size: 14px;
986
+ font-family: inherit;
987
+ }
988
+
989
+ .input-field:focus {
990
+ outline: none;
991
+ border-color: #667eea;
992
+ }
993
+
994
+ .select-field {
995
+ width: 100%;
996
+ padding: 10px 12px;
997
+ border: 1px solid #e0e0e0;
998
+ border-radius: 6px;
999
+ font-size: 14px;
1000
+ font-family: inherit;
1001
+ background: white;
1002
+ }
1003
+
1004
+ .modal-footer {
1005
+ padding: 16px 24px;
1006
+ border-top: 1px solid #e0e0e0;
1007
+ display: flex;
1008
+ justify-content: flex-end;
1009
+ gap: 12px;
1010
+ }
1011
+
1012
+ .btn {
1013
+ padding: 10px 20px;
1014
+ border: none;
1015
+ border-radius: 6px;
1016
+ font-size: 14px;
1017
+ font-weight: 500;
1018
+ cursor: pointer;
1019
+ transition: all 0.2s;
1020
+ }
1021
+
1022
+ .btn-secondary {
1023
+ background: #f5f5f5;
1024
+ color: #333;
1025
+ }
1026
+
1027
+ .btn-secondary:hover {
1028
+ background: #e0e0e0;
1029
+ }
1030
+
1031
+ .btn-primary {
1032
+ background: #667eea;
1033
+ color: white;
1034
+ }
1035
+
1036
+ .btn-primary:hover {
1037
+ background: #5568d3;
1038
+ }
1039
+
1040
+ /* Publish Progress */
1041
+ .publish-progress-container {
1042
+ padding: 24px;
1043
+ }
1044
+
1045
+ .progress-bar-container {
1046
+ margin-bottom: 24px;
1047
+ }
1048
+
1049
+ .progress-bar-bg {
1050
+ height: 8px;
1051
+ background: #e0e0e0;
1052
+ border-radius: 4px;
1053
+ overflow: hidden;
1054
+ margin-bottom: 8px;
1055
+ }
1056
+
1057
+ .progress-bar-fill {
1058
+ height: 100%;
1059
+ background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
1060
+ transition: width 0.3s;
1061
+ border-radius: 4px;
1062
+ }
1063
+
1064
+ .progress-text {
1065
+ font-size: 13px;
1066
+ color: #666;
1067
+ text-align: center;
1068
+ }
1069
+
1070
+ .progress-steps {
1071
+ display: flex;
1072
+ flex-direction: column;
1073
+ gap: 12px;
1074
+ }
1075
+
1076
+ .progress-step {
1077
+ display: flex;
1078
+ align-items: center;
1079
+ gap: 12px;
1080
+ padding: 12px;
1081
+ background: #f5f5f5;
1082
+ border-radius: 8px;
1083
+ }
1084
+
1085
+ .progress-step.completed {
1086
+ background: #e8f5e9;
1087
+ }
1088
+
1089
+ .progress-step.failed {
1090
+ background: #ffebee;
1091
+ }
1092
+
1093
+ .step-icon {
1094
+ font-size: 18px;
1095
+ }
1096
+
1097
+ .step-message {
1098
+ flex: 1;
1099
+ font-size: 14px;
1100
+ }
1101
+
1102
+ .publish-error {
1103
+ text-align: center;
1104
+ padding: 40px 24px;
1105
+ }
1106
+
1107
+ .error-icon {
1108
+ font-size: 48px;
1109
+ margin-bottom: 16px;
1110
+ color: #d32f2f;
1111
+ }
1112
+
1113
+ .error-message {
1114
+ font-size: 14px;
1115
+ color: #666;
1116
+ margin-bottom: 24px;
1117
+ }
1118
+
1119
+ /* Smooth transitions for lists */
1120
+ .blocks-list,
1121
+ .editor-content {
1122
+ transition: opacity 0.2s ease;
1123
+ }
1124
+
1125
+ /* Template Editor Styles */
1126
+ .template-editor {
1127
+ padding: 0;
1128
+ }
1129
+
1130
+ .template-info {
1131
+ padding: 16px;
1132
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
1133
+ color: white;
1134
+ border-radius: 8px;
1135
+ margin-bottom: 20px;
1136
+ }
1137
+
1138
+ .template-info-badge {
1139
+ display: inline-block;
1140
+ background: rgba(255,255,255,0.2);
1141
+ padding: 4px 10px;
1142
+ border-radius: 12px;
1143
+ font-size: 11px;
1144
+ font-weight: 600;
1145
+ text-transform: uppercase;
1146
+ letter-spacing: 0.5px;
1147
+ margin-bottom: 8px;
1148
+ }
1149
+
1150
+ .template-info-desc {
1151
+ margin: 0;
1152
+ font-size: 13px;
1153
+ opacity: 0.9;
1154
+ line-height: 1.5;
1155
+ }
1156
+
1157
+ .template-section {
1158
+ margin-bottom: 24px;
1159
+ }
1160
+
1161
+ .template-section-title {
1162
+ font-size: 12px;
1163
+ font-weight: 600;
1164
+ text-transform: uppercase;
1165
+ letter-spacing: 0.5px;
1166
+ color: #666;
1167
+ margin: 0 0 12px 0;
1168
+ padding-bottom: 8px;
1169
+ border-bottom: 1px solid #eee;
1170
+ }
1171
+
1172
+ .template-pages-list {
1173
+ display: flex;
1174
+ flex-direction: column;
1175
+ gap: 8px;
1176
+ }
1177
+
1178
+ .template-page-item {
1179
+ padding: 12px 16px;
1180
+ background: #f8f9fa;
1181
+ border: 1px solid #e9ecef;
1182
+ border-radius: 8px;
1183
+ cursor: pointer;
1184
+ transition: all 0.2s;
1185
+ }
1186
+
1187
+ .template-page-item:hover {
1188
+ background: #e9ecef;
1189
+ border-color: #667eea;
1190
+ }
1191
+
1192
+ .template-page-header {
1193
+ display: flex;
1194
+ justify-content: space-between;
1195
+ align-items: center;
1196
+ margin-bottom: 4px;
1197
+ }
1198
+
1199
+ .template-page-name {
1200
+ font-weight: 500;
1201
+ font-size: 14px;
1202
+ color: #333;
1203
+ }
1204
+
1205
+ .template-page-blocks {
1206
+ font-size: 11px;
1207
+ color: #666;
1208
+ background: #e9ecef;
1209
+ padding: 2px 8px;
1210
+ border-radius: 10px;
1211
+ }
1212
+
1213
+ .template-page-slug {
1214
+ font-size: 12px;
1215
+ color: #999;
1216
+ font-family: monospace;
1217
+ }
1218
+
1219
+ .template-layout-slot {
1220
+ display: flex;
1221
+ justify-content: space-between;
1222
+ align-items: center;
1223
+ padding: 10px 14px;
1224
+ background: #f8f9fa;
1225
+ border-radius: 6px;
1226
+ margin-bottom: 8px;
1227
+ }
1228
+
1229
+ .slot-type {
1230
+ font-size: 12px;
1231
+ font-weight: 500;
1232
+ text-transform: capitalize;
1233
+ color: #667eea;
1234
+ }
1235
+
1236
+ .slot-block {
1237
+ font-size: 12px;
1238
+ color: #666;
1239
+ font-family: monospace;
1240
+ }
1241
+
1242
+ .template-hint {
1243
+ padding: 12px;
1244
+ background: #fff3cd;
1245
+ border-radius: 6px;
1246
+ margin-top: 20px;
1247
+ }
1248
+
1249
+ .template-hint p {
1250
+ margin: 0;
1251
+ font-size: 12px;
1252
+ color: #856404;
1253
+ }
1254
+
1255
+ /* Template preview style */
1256
+ .template-preview {
1257
+ background: #1a1a2e;
1258
+ }
1259
+ </style>
1260
+ </head>
1261
+ <body>
1262
+ <div class="container" id="container">
1263
+ <!-- Left Panel: Blocks List -->
1264
+ <div class="blocks-panel">
1265
+ <div class="blocks-header">
1266
+ <div class="blocks-header-content">
1267
+ <h1>📦 Blocks</h1>
1268
+ <p id="blocks-count">Loading...</p>
1269
+ </div>
1270
+ <button
1271
+ class="panel-toggle"
1272
+ id="toggle-left"
1273
+ onclick="toggleLeftPanel()"
1274
+ title="Collapse panel (Ctrl+B)"
1275
+ aria-label="Toggle blocks panel"
1276
+ >
1277
+ <div class="panel-toggle-icon">
1278
+ <span></span>
1279
+ <span></span>
1280
+ <span></span>
1281
+ </div>
1282
+ </button>
1283
+ </div>
1284
+
1285
+ <!-- Filters Section -->
1286
+ <div class="blocks-filters" id="blocks-filters">
1287
+ <input
1288
+ type="search"
1289
+ class="search-input"
1290
+ id="search-input"
1291
+ placeholder="Search blocks..."
1292
+ oninput="handleSearchInput(event)"
1293
+ />
1294
+
1295
+ <div class="filter-tabs">
1296
+ <button class="filter-tab active" data-type="all" onclick="setTypeFilter('all')">All</button>
1297
+ <button class="filter-tab" data-type="block" onclick="setTypeFilter('block')">Blocks</button>
1298
+ <button class="filter-tab" data-type="template" onclick="setTypeFilter('template')">Templates</button>
1299
+ </div>
1300
+
1301
+ <div class="filter-row">
1302
+ <select class="filter-select" id="category-filter" onchange="setCategoryFilter(this.value)">
1303
+ <option value="">All Categories</option>
1304
+ </select>
1305
+ </div>
1306
+
1307
+ <div class="tags-filter" id="tags-filter">
1308
+ <!-- Tags will be populated dynamically -->
1309
+ </div>
1310
+ </div>
1311
+
1312
+ <div class="blocks-list" id="blocks-list">
1313
+ <div class="loading">
1314
+ <div class="spinner"></div>
1315
+ <span>Loading blocks...</span>
1316
+ </div>
1317
+ </div>
1318
+ </div>
1319
+
1320
+ <!-- Center Panel: Preview -->
1321
+ <div class="preview-panel">
1322
+ <div class="preview-header">
1323
+ <div class="preview-info">
1324
+ <div class="preview-title" id="preview-title">Preview</div>
1325
+ </div>
1326
+ <div class="preview-actions">
1327
+ <div class="preview-badge" id="preview-status">Ready</div>
1328
+ <button
1329
+ class="btn-publish"
1330
+ onclick="openPublishModal()"
1331
+ style="display: none"
1332
+ id="publish-btn"
1333
+ >
1334
+ 📦 Publish
1335
+ </button>
1336
+ </div>
1337
+ </div>
1338
+ <div class="preview-content" id="preview-content">
1339
+ <div class="preview-empty">
1340
+ <div class="preview-empty-icon">👈</div>
1341
+ <p>Select a block to preview</p>
1342
+ </div>
1343
+ </div>
1344
+ </div>
1345
+
1346
+ <!-- Right Panel: Editor -->
1347
+ <div class="editor-panel">
1348
+ <div class="editor-header">
1349
+ <button
1350
+ class="panel-toggle"
1351
+ id="toggle-right"
1352
+ onclick="toggleRightPanel()"
1353
+ title="Collapse panel (Ctrl+E)"
1354
+ aria-label="Toggle properties panel"
1355
+ >
1356
+ <div class="panel-toggle-icon">
1357
+ <span></span>
1358
+ <span></span>
1359
+ <span></span>
1360
+ </div>
1361
+ </button>
1362
+ <div class="editor-header-content">
1363
+ <h2>⚙️ Properties</h2>
1364
+ <p id="editor-subtitle">No block selected</p>
1365
+ </div>
1366
+ </div>
1367
+ <div class="editor-content" id="editor-content">
1368
+ <div class="editor-empty">Select a block to edit its properties</div>
1369
+ </div>
1370
+ </div>
1371
+ </div>
1372
+
1373
+ <!-- Publish Modal -->
1374
+ <div class="modal" id="publish-modal">
1375
+ <div class="modal-content">
1376
+ <div class="modal-header">
1377
+ <h3>Publish <span id="publish-block-name"></span></h3>
1378
+ <p style="margin: 0;">Local version: <span id="publish-local-version"></span></p>
1379
+ <p id="publish-published-version-row" style="margin: 0; color: #666; font-size: 13px; display: none;">
1380
+ Published: <span id="publish-published-version"></span>
1381
+ </p>
1382
+ </div>
1383
+
1384
+ <!-- Publish Form -->
1385
+ <div id="publish-form">
1386
+ <div class="modal-body">
1387
+ <!-- Target Selection -->
1388
+ <div class="form-group">
1389
+ <label class="form-label">Publish Target</label>
1390
+ <div class="radio-group">
1391
+ <label class="radio-option">
1392
+ <input
1393
+ type="radio"
1394
+ name="publish-target"
1395
+ value="marketplace"
1396
+ id="publish-target-marketplace"
1397
+ onchange="toggleWorkspaceInput()"
1398
+ checked
1399
+ />
1400
+ <div class="radio-option-content">
1401
+ <div class="radio-option-title">
1402
+ 📋 Marketplace (Public)
1403
+ </div>
1404
+ <div class="radio-option-desc">
1405
+ Submit for review, available to everyone after approval
1406
+ </div>
1407
+ </div>
1408
+ </label>
1409
+ <label class="radio-option">
1410
+ <input
1411
+ type="radio"
1412
+ name="publish-target"
1413
+ value="workspace"
1414
+ id="publish-target-workspace"
1415
+ onchange="toggleWorkspaceInput()"
1416
+ />
1417
+ <div class="radio-option-content">
1418
+ <div class="radio-option-title">🏢 Workspace (Private)</div>
1419
+ <div class="radio-option-desc">
1420
+ Publish instantly to your workspace, no review needed
1421
+ </div>
1422
+ </div>
1423
+ </label>
1424
+ </div>
1425
+ </div>
1426
+
1427
+ <!-- Workspace Select (conditional) -->
1428
+ <div
1429
+ class="form-group"
1430
+ id="workspace-id-group"
1431
+ style="display: none"
1432
+ >
1433
+ <label class="form-label" for="publish-workspace-id"
1434
+ >Select Workspace</label
1435
+ >
1436
+ <select class="select-field" id="publish-workspace-id" onchange="handleWorkspaceChange()">
1437
+ <option value="">Loading workspaces...</option>
1438
+ </select>
1439
+ <div
1440
+ id="workspace-error"
1441
+ style="
1442
+ display: none;
1443
+ color: #e53e3e;
1444
+ font-size: 12px;
1445
+ margin-top: 4px;
1446
+ "
1447
+ >
1448
+ Failed to load workspaces. Check your API token configuration.
1449
+ </div>
1450
+ </div>
1451
+
1452
+ <!-- Version Bump -->
1453
+ <div class="form-group">
1454
+ <label class="form-label" for="publish-version-bump"
1455
+ >Version Bump (Optional)</label
1456
+ >
1457
+ <select class="select-field" id="publish-version-bump">
1458
+ <option value="">No change</option>
1459
+ <option value="patch">Patch (1.0.0 → 1.0.1)</option>
1460
+ <option value="minor">Minor (1.0.0 → 1.1.0)</option>
1461
+ <option value="major">Major (1.0.0 → 2.0.0)</option>
1462
+ </select>
1463
+ </div>
1464
+ </div>
1465
+
1466
+ <div class="modal-footer">
1467
+ <button class="btn btn-secondary" onclick="closePublishModal()">
1468
+ Cancel
1469
+ </button>
1470
+ <button class="btn btn-primary" onclick="startPublish()">
1471
+ Publish
1472
+ </button>
1473
+ </div>
1474
+ </div>
1475
+
1476
+ <!-- Publish Progress -->
1477
+ <div id="publish-progress" style="display: none">
1478
+ <div class="publish-progress-container">
1479
+ <div class="progress-bar-container">
1480
+ <div class="progress-bar-bg">
1481
+ <div
1482
+ class="progress-bar-fill"
1483
+ id="publish-progress-bar"
1484
+ style="width: 0%"
1485
+ ></div>
1486
+ </div>
1487
+ <div class="progress-text" id="publish-progress-text">0%</div>
1488
+ </div>
1489
+
1490
+ <div class="progress-steps" id="publish-steps">
1491
+ <!-- Steps will be dynamically added here -->
1492
+ </div>
1493
+
1494
+ <div style="text-align: center; margin-top: 24px">
1495
+ <button
1496
+ class="btn btn-primary"
1497
+ onclick="closePublishModal()"
1498
+ id="publish-close-btn"
1499
+ style="display: none"
1500
+ >
1501
+ Done
1502
+ </button>
1503
+ </div>
1504
+ </div>
1505
+ </div>
1506
+ </div>
1507
+ </div>
1508
+
1509
+ <script src="/dev-ui/app.js"></script>
1510
+ </body>
1511
+ </html>