vibespot 1.1.1 → 1.2.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.
- package/LICENSE +103 -33
- package/README.md +11 -1
- package/assets/plan-templates/agency-services.md +42 -0
- package/assets/plan-templates/blog-content-hub.md +41 -0
- package/assets/plan-templates/ecommerce-product.md +42 -0
- package/assets/plan-templates/event-registration.md +42 -0
- package/assets/plan-templates/portfolio.md +41 -0
- package/assets/plan-templates/restaurant.md +42 -0
- package/assets/plan-templates/saas-landing.md +42 -0
- package/dist/index.js +240 -225
- package/dist/index.js.map +1 -1
- package/package.json +8 -4
- package/starters/01-saas-landing.json +43 -0
- package/starters/02-portfolio.json +39 -0
- package/starters/03-restaurant.json +39 -0
- package/starters/04-event.json +39 -0
- package/starters/05-coming-soon.json +32 -0
- package/ui/chat.js +865 -130
- package/ui/dashboard.js +194 -12
- package/ui/docs/index.html +89 -10
- package/ui/field-editor.js +1 -1
- package/ui/index.html +156 -37
- package/ui/marketplace.js +218 -0
- package/ui/plan.js +0 -0
- package/ui/preview.js +316 -1
- package/ui/settings.js +35 -21
- package/ui/setup.js +291 -3
- package/ui/styles.css +1305 -120
package/ui/index.html
CHANGED
|
@@ -83,32 +83,110 @@
|
|
|
83
83
|
|
|
84
84
|
<!-- Main action buttons -->
|
|
85
85
|
<div class="setup__options" id="setup-options">
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
86
|
+
|
|
87
|
+
<!-- Returning users: recent projects (auto-shown when projects exist) -->
|
|
88
|
+
<div class="setup__recent hidden" id="setup-recent">
|
|
89
|
+
<div class="setup__recent-header">
|
|
90
|
+
<span class="setup__recent-title">Continue where you left off</span>
|
|
91
|
+
<button type="button" class="setup__recent-all hidden" id="setup-recent-all">View all</button>
|
|
92
|
+
</div>
|
|
93
|
+
<div class="setup__recent-list" id="setup-recent-list"></div>
|
|
94
|
+
</div>
|
|
95
|
+
|
|
96
|
+
<!-- Primary path: describe-it prompt -->
|
|
97
|
+
<div class="setup__prompt-card" id="setup-prompt-card">
|
|
98
|
+
<textarea
|
|
99
|
+
class="setup__prompt-input"
|
|
100
|
+
id="setup-prompt-input"
|
|
101
|
+
rows="3"
|
|
102
|
+
placeholder="Describe the landing page you want to build..."
|
|
103
|
+
></textarea>
|
|
104
|
+
<div class="setup__prompt-row">
|
|
105
|
+
<span class="setup__prompt-hint" id="setup-prompt-hint">Press <span id="setup-prompt-shortcut">⌘↵</span> or click Build to start</span>
|
|
106
|
+
<button class="btn btn--primary setup__prompt-submit" id="setup-prompt-submit" disabled>
|
|
107
|
+
<span class="setup__prompt-submit-icon">▲</span>
|
|
108
|
+
<span>Build</span>
|
|
109
|
+
</button>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
<!-- Secondary path: pick a template -->
|
|
114
|
+
<div class="setup__secondary">
|
|
115
|
+
<button class="setup__secondary-btn" data-action="starter">
|
|
116
|
+
<span class="setup__secondary-icon">★</span>
|
|
117
|
+
<span class="setup__secondary-label">Start from Template</span>
|
|
118
|
+
<span class="setup__secondary-meta">Browse pre-built starters</span>
|
|
103
119
|
</button>
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
<!-- Starter template panel — sits directly under the "Start from Template" button -->
|
|
123
|
+
<div class="setup__panel" id="panel-starter">
|
|
124
|
+
<div class="starter-grid" id="starter-grid">
|
|
125
|
+
<div class="starter-card" data-starter-id="saas-landing">
|
|
126
|
+
<span class="starter-card__name">SaaS Landing Page</span>
|
|
127
|
+
<span class="starter-card__desc">Modern SaaS landing page with hero, features, pricing, and CTA</span>
|
|
128
|
+
<span class="starter-card__meta">4 modules</span>
|
|
129
|
+
</div>
|
|
130
|
+
<div class="starter-card" data-starter-id="portfolio">
|
|
131
|
+
<span class="starter-card__name">Portfolio</span>
|
|
132
|
+
<span class="starter-card__desc">Creative portfolio with project gallery, about section, and contact form</span>
|
|
133
|
+
<span class="starter-card__meta">4 modules</span>
|
|
134
|
+
</div>
|
|
135
|
+
<div class="starter-card" data-starter-id="restaurant">
|
|
136
|
+
<span class="starter-card__name">Restaurant</span>
|
|
137
|
+
<span class="starter-card__desc">Restaurant landing page with menu, reservations, and location info</span>
|
|
138
|
+
<span class="starter-card__meta">4 modules</span>
|
|
139
|
+
</div>
|
|
140
|
+
<div class="starter-card" data-starter-id="event">
|
|
141
|
+
<span class="starter-card__name">Event / Conference</span>
|
|
142
|
+
<span class="starter-card__desc">Event landing page with speakers, schedule, and registration</span>
|
|
143
|
+
<span class="starter-card__meta">4 modules</span>
|
|
144
|
+
</div>
|
|
145
|
+
<div class="starter-card" data-starter-id="coming-soon">
|
|
146
|
+
<span class="starter-card__name">Coming Soon</span>
|
|
147
|
+
<span class="starter-card__desc">Pre-launch page with signup form and feature preview</span>
|
|
148
|
+
<span class="starter-card__meta">3 modules</span>
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
151
|
+
<div class="starter-create hidden" id="starter-create">
|
|
152
|
+
<p class="starter-create__label" id="starter-create-label"></p>
|
|
153
|
+
<div class="setup__row">
|
|
154
|
+
<input type="text" class="setup__input setup__input--wide" id="starter-theme-name" placeholder="my-landing-page" />
|
|
155
|
+
<button class="btn btn--primary" id="btn-create-from-starter">Create</button>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
|
|
160
|
+
<!-- More ways to start: collapsible advanced options -->
|
|
161
|
+
<div class="setup__more">
|
|
162
|
+
<button type="button" class="setup__more-toggle" id="setup-more-toggle" aria-expanded="false" aria-controls="setup-more-panel">
|
|
163
|
+
<span>More ways to start</span>
|
|
164
|
+
<span class="setup__more-chevron" aria-hidden="true">▾</span>
|
|
108
165
|
</button>
|
|
166
|
+
<div class="setup__more-panel hidden" id="setup-more-panel">
|
|
167
|
+
<div class="setup__actions">
|
|
168
|
+
<button class="setup__action-btn" data-action="new">
|
|
169
|
+
<span class="setup__action-icon">+</span>
|
|
170
|
+
<span>Blank Theme</span>
|
|
171
|
+
</button>
|
|
172
|
+
<button class="setup__action-btn" data-action="download">
|
|
173
|
+
<span class="setup__action-icon">↓</span>
|
|
174
|
+
<span>From HubSpot</span>
|
|
175
|
+
</button>
|
|
176
|
+
<button class="setup__action-btn" data-action="figma">
|
|
177
|
+
<span class="setup__action-icon">◆</span>
|
|
178
|
+
<span>From Figma</span>
|
|
179
|
+
<span class="setup__action-badge">Beta</span>
|
|
180
|
+
</button>
|
|
181
|
+
<button class="setup__action-btn" data-action="convert">
|
|
182
|
+
<span class="setup__action-icon">↺</span>
|
|
183
|
+
<span>From React</span>
|
|
184
|
+
<span class="setup__action-badge">Beta</span>
|
|
185
|
+
</button>
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
109
188
|
</div>
|
|
110
189
|
|
|
111
|
-
<!-- Expandable panels (one visible at a time) -->
|
|
112
190
|
<div class="setup__panel hidden" id="panel-new">
|
|
113
191
|
<div class="setup__row">
|
|
114
192
|
<input type="text" class="setup__input setup__input--wide" id="new-theme-name" placeholder="my-landing-page" />
|
|
@@ -233,6 +311,16 @@
|
|
|
233
311
|
</button>
|
|
234
312
|
</div>
|
|
235
313
|
|
|
314
|
+
<!-- Import Analysis -->
|
|
315
|
+
<section class="dashboard__section dashboard__section--inverse hidden" id="dashboard-inverse-section">
|
|
316
|
+
<div class="dashboard__section-header">
|
|
317
|
+
<h2 class="dashboard__section-title">Import Analysis</h2>
|
|
318
|
+
<span class="dashboard__section-hint" id="inverse-status">Analyzing theme...</span>
|
|
319
|
+
<button class="btn btn--sm btn--outline hidden" id="btn-inverse-apply-tokens" title="Seed shared CSS from inferred tokens">Apply Tokens</button>
|
|
320
|
+
</div>
|
|
321
|
+
<div class="inverse-summary" id="inverse-summary"></div>
|
|
322
|
+
</section>
|
|
323
|
+
|
|
236
324
|
<!-- Brand Assets -->
|
|
237
325
|
<section class="dashboard__section">
|
|
238
326
|
<div class="dashboard__section-header">
|
|
@@ -326,8 +414,8 @@
|
|
|
326
414
|
<div class="page-type-card__icon">
|
|
327
415
|
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg>
|
|
328
416
|
</div>
|
|
329
|
-
<span class="page-type-card__label">
|
|
330
|
-
<span class="page-type-card__desc">Standalone
|
|
417
|
+
<span class="page-type-card__label">Section Only</span>
|
|
418
|
+
<span class="page-type-card__desc">Standalone section, no template</span>
|
|
331
419
|
</button>
|
|
332
420
|
</div>
|
|
333
421
|
</section>
|
|
@@ -346,16 +434,16 @@
|
|
|
346
434
|
<!-- Module Library -->
|
|
347
435
|
<section class="dashboard__section">
|
|
348
436
|
<div class="dashboard__section-header">
|
|
349
|
-
<h2 class="dashboard__section-title">
|
|
437
|
+
<h2 class="dashboard__section-title">Section Library</h2>
|
|
350
438
|
</div>
|
|
351
439
|
<div class="dashboard__module-library" id="dashboard-module-library">
|
|
352
|
-
<p class="dashboard__empty-state">
|
|
440
|
+
<p class="dashboard__empty-state">Sections will appear here as you build pages.</p>
|
|
353
441
|
</div>
|
|
354
442
|
<div class="dashboard__module-preview hidden" id="dashboard-module-preview">
|
|
355
443
|
<div class="dashboard__module-preview-header">
|
|
356
444
|
<span class="dashboard__module-preview-name" id="dashboard-preview-name"></span>
|
|
357
445
|
<span class="dashboard__module-preview-used" id="dashboard-preview-used"></span>
|
|
358
|
-
<button class="btn btn--danger btn--sm dashboard__module-preview-delete" id="dashboard-preview-delete">Delete
|
|
446
|
+
<button class="btn btn--danger btn--sm dashboard__module-preview-delete" id="dashboard-preview-delete">Delete section</button>
|
|
359
447
|
<button class="dashboard__module-preview-close" id="dashboard-preview-close">×</button>
|
|
360
448
|
</div>
|
|
361
449
|
<iframe class="dashboard__module-preview-frame" id="dashboard-preview-frame" sandbox="allow-scripts allow-same-origin"></iframe>
|
|
@@ -389,6 +477,10 @@
|
|
|
389
477
|
<svg width="10" height="18" viewBox="0 0 10 18" fill="none"><rect x="1" y="1" width="8" height="16" rx="1.5" stroke="currentColor" stroke-width="1.5"/><circle cx="5" cy="15" r="0.75" fill="currentColor"/></svg>
|
|
390
478
|
</button>
|
|
391
479
|
</div>
|
|
480
|
+
<button class="select-mode-toggle" id="select-mode-toggle" title="Select an element in the preview to reference it in chat" aria-pressed="false">
|
|
481
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 3l7 17 2-7 7-2z"/></svg>
|
|
482
|
+
<span>Select</span>
|
|
483
|
+
</button>
|
|
392
484
|
</div>
|
|
393
485
|
<div class="topbar__right">
|
|
394
486
|
<button class="topbar__icon-btn" title="Submit feedback" onclick="vibeFeedback()">
|
|
@@ -401,6 +493,9 @@
|
|
|
401
493
|
<button class="topbar__icon-btn" id="btn-history" title="Version History" style="display:none">
|
|
402
494
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
|
|
403
495
|
</button>
|
|
496
|
+
<button class="topbar__icon-btn" id="btn-marketplace" title="Marketplace publication check">
|
|
497
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M3 9l1-5h16l1 5"/><path d="M5 9v11a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V9"/><path d="M9 22V12h6v10"/></svg>
|
|
498
|
+
</button>
|
|
404
499
|
<button class="btn btn--primary" id="btn-upload" title="Deploy theme to HubSpot">
|
|
405
500
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="margin-right:4px;vertical-align:-2px"><path d="M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z"/></svg>
|
|
406
501
|
Deploy
|
|
@@ -413,7 +508,7 @@
|
|
|
413
508
|
<div class="module-bar" id="module-bar">
|
|
414
509
|
<button class="module-bar__btn" id="btn-modules">
|
|
415
510
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg>
|
|
416
|
-
<span>
|
|
511
|
+
<span>Sections</span>
|
|
417
512
|
<span class="module-bar__count" id="module-count">0</span>
|
|
418
513
|
</button>
|
|
419
514
|
</div>
|
|
@@ -421,9 +516,9 @@
|
|
|
421
516
|
<div class="module-slideout" id="module-slideout">
|
|
422
517
|
<div class="module-slideout__view" id="module-list-view">
|
|
423
518
|
<div class="module-slideout__header">
|
|
424
|
-
<span class="module-slideout__title">
|
|
519
|
+
<span class="module-slideout__title">Sections</span>
|
|
425
520
|
<span class="module-slideout__count" id="slideout-module-count">0</span>
|
|
426
|
-
<button class="module-slideout__add" id="btn-add-module" title="Add
|
|
521
|
+
<button class="module-slideout__add" id="btn-add-module" title="Add section from library">+</button>
|
|
427
522
|
<button class="module-slideout__close" id="module-slideout-close">×</button>
|
|
428
523
|
</div>
|
|
429
524
|
<div class="module-library-dropdown hidden" id="module-library-dropdown"></div>
|
|
@@ -449,14 +544,36 @@
|
|
|
449
544
|
<p>Describe what you want or pick a template to get started.</p>
|
|
450
545
|
|
|
451
546
|
<div class="chat__section-label">Templates</div>
|
|
452
|
-
<div class="chat__starters" id="starter-templates">
|
|
453
|
-
<button class="starter-btn" data-prompt="Create a modern SaaS landing page with a hero section featuring a gradient background, a features grid with icons, a testimonials carousel, a pricing table with 3 tiers, and a CTA section.">
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
547
|
+
<div class="chat__starters chat__starters--rich" id="starter-templates">
|
|
548
|
+
<button class="starter-btn starter-btn--rich" data-prompt="Create a modern SaaS landing page with a hero section featuring a gradient background, a features grid with icons, a testimonials carousel, a pricing table with 3 tiers, and a CTA section.">
|
|
549
|
+
<span class="starter-btn__label">SaaS Landing Page</span>
|
|
550
|
+
<span class="starter-btn__desc">Hero, features, testimonials, pricing & CTA</span>
|
|
551
|
+
</button>
|
|
552
|
+
<button class="starter-btn starter-btn--rich" data-prompt="Create a portfolio landing page with a hero section, a project gallery grid, an about/bio section, a skills section, and a contact form section.">
|
|
553
|
+
<span class="starter-btn__label">Portfolio</span>
|
|
554
|
+
<span class="starter-btn__desc">Hero, project gallery, about, skills & contact</span>
|
|
555
|
+
</button>
|
|
556
|
+
<button class="starter-btn starter-btn--rich" data-prompt="Create a restaurant landing page with a hero section featuring a food image background, a menu section with categories, a reservations section, a reviews section, and a location/hours section.">
|
|
557
|
+
<span class="starter-btn__label">Restaurant</span>
|
|
558
|
+
<span class="starter-btn__desc">Hero, menu, reservations, reviews & hours</span>
|
|
559
|
+
</button>
|
|
560
|
+
<button class="starter-btn starter-btn--rich" data-prompt="Create an event landing page with a countdown hero, a speakers section with photos and bios, a schedule/agenda section, a sponsors section with logos, and a registration CTA section.">
|
|
561
|
+
<span class="starter-btn__label">Event / Conference</span>
|
|
562
|
+
<span class="starter-btn__desc">Countdown hero, speakers, schedule & sponsors</span>
|
|
563
|
+
</button>
|
|
457
564
|
</div>
|
|
458
565
|
</div>
|
|
459
566
|
</div>
|
|
567
|
+
<div class="history-timeline hidden" id="history-timeline" aria-label="Version history">
|
|
568
|
+
<button class="history-timeline__nav" id="history-timeline-undo" title="Undo (Ctrl+Z)" aria-label="Undo">
|
|
569
|
+
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
|
|
570
|
+
</button>
|
|
571
|
+
<div class="history-timeline__track" id="history-timeline-track"></div>
|
|
572
|
+
<button class="history-timeline__nav" id="history-timeline-redo" title="Redo (Ctrl+Shift+Z)" aria-label="Redo">
|
|
573
|
+
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>
|
|
574
|
+
</button>
|
|
575
|
+
<div class="history-timeline__tooltip hidden" id="history-timeline-tooltip" role="tooltip"></div>
|
|
576
|
+
</div>
|
|
460
577
|
<div class="chat__input-area">
|
|
461
578
|
<div class="chat__mode-bar">
|
|
462
579
|
<button class="plan-toggle" id="plan-mode-toggle" title="Plan mode — deliberate before generating" aria-pressed="false">
|
|
@@ -467,6 +584,7 @@
|
|
|
467
584
|
<span class="plan-toggle__state">Off</span>
|
|
468
585
|
</button>
|
|
469
586
|
</div>
|
|
587
|
+
<div class="chat__suggestions hidden" id="chat-suggestions" aria-label="Suggested next steps"></div>
|
|
470
588
|
<div class="chat__file-chips" id="file-chips"></div>
|
|
471
589
|
<div class="chat__input-wrapper">
|
|
472
590
|
<textarea class="chat__input" id="chat-input" placeholder="Describe your landing page..." rows="1"></textarea>
|
|
@@ -622,11 +740,12 @@
|
|
|
622
740
|
<script src="/vendor/marked.umd.js"></script>
|
|
623
741
|
<script src="/vendor/codemirror-bundle.global.js"></script>
|
|
624
742
|
<script src="/dialog.js"></script>
|
|
625
|
-
<script src="/setup.js"></script>
|
|
743
|
+
<script src="/setup.js?v=110"></script>
|
|
626
744
|
<script src="/dashboard.js"></script>
|
|
627
745
|
<script src="/settings.js"></script>
|
|
628
746
|
<script src="/upload-panel.js"></script>
|
|
629
|
-
<script src="/
|
|
747
|
+
<script src="/marketplace.js"></script>
|
|
748
|
+
<script src="/chat.js?v=108"></script>
|
|
630
749
|
<script src="/plan.js"></script>
|
|
631
750
|
<script src="/preview.js"></script>
|
|
632
751
|
<script src="/field-editor.js"></script>
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Marketplace publication panel — runs the Marketplace check against the
|
|
3
|
+
* active theme, lets users browse findings, fix the auto-fixable ones, and
|
|
4
|
+
* edit the marketplace.json listing sidecar.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
async function openMarketplacePanel() {
|
|
8
|
+
const overlay = document.createElement("div");
|
|
9
|
+
overlay.className = "confirm-overlay marketplace-overlay";
|
|
10
|
+
overlay.innerHTML = `
|
|
11
|
+
<div class="confirm-dialog marketplace-dialog">
|
|
12
|
+
<div class="confirm-dialog__title">HubSpot Marketplace check</div>
|
|
13
|
+
<div class="marketplace-body" id="marketplace-body">
|
|
14
|
+
<p class="confirm-dialog__detail">Running check…</p>
|
|
15
|
+
</div>
|
|
16
|
+
<div class="confirm-dialog__actions">
|
|
17
|
+
<button class="btn btn--ghost" data-action="close">Close</button>
|
|
18
|
+
<button class="btn btn--ghost" data-action="edit">Edit listing</button>
|
|
19
|
+
<button class="btn btn--ghost" data-action="fix" disabled>Apply fixes</button>
|
|
20
|
+
<button class="btn btn--primary" data-action="recheck">Re-check</button>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
`;
|
|
24
|
+
document.body.appendChild(overlay);
|
|
25
|
+
|
|
26
|
+
const body = overlay.querySelector("#marketplace-body");
|
|
27
|
+
const fixBtn = overlay.querySelector('[data-action="fix"]');
|
|
28
|
+
const editBtn = overlay.querySelector('[data-action="edit"]');
|
|
29
|
+
const recheckBtn = overlay.querySelector('[data-action="recheck"]');
|
|
30
|
+
const closeBtn = overlay.querySelector('[data-action="close"]');
|
|
31
|
+
|
|
32
|
+
let lastCategories = [];
|
|
33
|
+
|
|
34
|
+
async function refresh() {
|
|
35
|
+
body.innerHTML = `<p class="confirm-dialog__detail">Running check…</p>`;
|
|
36
|
+
try {
|
|
37
|
+
const res = await fetch("/api/marketplace/check");
|
|
38
|
+
const data = await res.json();
|
|
39
|
+
if (!res.ok) throw new Error(data.error || "Check failed");
|
|
40
|
+
lastCategories = data.categories || [];
|
|
41
|
+
renderReport(body, data.report);
|
|
42
|
+
const autoFixable = (data.report.findings || []).some((f) => f.autoFixable);
|
|
43
|
+
fixBtn.disabled = !autoFixable;
|
|
44
|
+
} catch (err) {
|
|
45
|
+
body.innerHTML = `<p class="confirm-dialog__detail">${esc(err.message)}</p>`;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
recheckBtn.addEventListener("click", refresh);
|
|
50
|
+
closeBtn.addEventListener("click", () => overlay.remove());
|
|
51
|
+
overlay.addEventListener("click", (e) => { if (e.target === overlay) overlay.remove(); });
|
|
52
|
+
|
|
53
|
+
fixBtn.addEventListener("click", async () => {
|
|
54
|
+
fixBtn.disabled = true;
|
|
55
|
+
try {
|
|
56
|
+
const res = await fetch("/api/marketplace/fix", { method: "POST" });
|
|
57
|
+
const data = await res.json();
|
|
58
|
+
if (!res.ok) throw new Error(data.error || "Fix failed");
|
|
59
|
+
renderReport(body, data.report, data.fix);
|
|
60
|
+
const stillFixable = (data.report.findings || []).some((f) => f.autoFixable);
|
|
61
|
+
fixBtn.disabled = !stillFixable;
|
|
62
|
+
} catch (err) {
|
|
63
|
+
await vibeAlert(err.message, "Fix failed");
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
editBtn.addEventListener("click", async () => {
|
|
68
|
+
try {
|
|
69
|
+
const res = await fetch("/api/marketplace/listing");
|
|
70
|
+
const data = await res.json();
|
|
71
|
+
if (!res.ok) throw new Error(data.error || "Could not load listing");
|
|
72
|
+
lastCategories = data.categories || lastCategories;
|
|
73
|
+
const next = await openListingEditor(data.metadata, lastCategories);
|
|
74
|
+
if (!next) return;
|
|
75
|
+
const save = await fetch("/api/marketplace/listing", {
|
|
76
|
+
method: "POST",
|
|
77
|
+
headers: { "Content-Type": "application/json" },
|
|
78
|
+
body: JSON.stringify(next),
|
|
79
|
+
});
|
|
80
|
+
const result = await save.json();
|
|
81
|
+
if (!save.ok) throw new Error(result.error || "Save failed");
|
|
82
|
+
await refresh();
|
|
83
|
+
} catch (err) {
|
|
84
|
+
await vibeAlert(err.message, "Listing");
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
refresh();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function renderReport(container, report, fix) {
|
|
92
|
+
if (!report) {
|
|
93
|
+
container.innerHTML = `<p class="confirm-dialog__detail">No report available.</p>`;
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const errors = report.findings.filter((f) => f.severity === "error");
|
|
98
|
+
const warnings = report.findings.filter((f) => f.severity === "warning");
|
|
99
|
+
const info = report.findings.filter((f) => f.severity === "info");
|
|
100
|
+
|
|
101
|
+
const summaryClass = report.passed ? "marketplace-summary--ok" : "marketplace-summary--fail";
|
|
102
|
+
const summaryText = report.passed
|
|
103
|
+
? `Theme passes Marketplace checks.`
|
|
104
|
+
: `Theme is not yet ready.`;
|
|
105
|
+
|
|
106
|
+
let html = `
|
|
107
|
+
<div class="marketplace-summary ${summaryClass}">
|
|
108
|
+
<strong>${esc(summaryText)}</strong>
|
|
109
|
+
<div class="marketplace-summary__counts">
|
|
110
|
+
<span class="marketplace-pill marketplace-pill--error">${errors.length} errors</span>
|
|
111
|
+
<span class="marketplace-pill marketplace-pill--warn">${warnings.length} warnings</span>
|
|
112
|
+
<span class="marketplace-pill marketplace-pill--info">${info.length} notes</span>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
`;
|
|
116
|
+
|
|
117
|
+
if (fix && (fix.applied?.length || fix.skipped?.length)) {
|
|
118
|
+
html += `<div class="marketplace-fix-result">`;
|
|
119
|
+
if (fix.applied?.length) {
|
|
120
|
+
html += `<strong>Applied:</strong><ul>${fix.applied.map((s) => `<li>${esc(s)}</li>`).join("")}</ul>`;
|
|
121
|
+
}
|
|
122
|
+
if (fix.skipped?.length) {
|
|
123
|
+
html += `<strong>Skipped:</strong><ul>${fix.skipped.map((s) => `<li>${esc(s)}</li>`).join("")}</ul>`;
|
|
124
|
+
}
|
|
125
|
+
html += `</div>`;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
html += renderFindingGroup("Errors", errors);
|
|
129
|
+
html += renderFindingGroup("Warnings", warnings);
|
|
130
|
+
html += renderFindingGroup("Notes", info);
|
|
131
|
+
|
|
132
|
+
if (report.findings.length === 0) {
|
|
133
|
+
html += `<p class="confirm-dialog__detail">Nothing to flag — submit when ready.</p>`;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
container.innerHTML = html;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function renderFindingGroup(title, findings) {
|
|
140
|
+
if (findings.length === 0) return "";
|
|
141
|
+
const items = findings.map((f) => `
|
|
142
|
+
<li class="marketplace-finding marketplace-finding--${f.severity}">
|
|
143
|
+
${f.file ? `<code class="marketplace-finding__file">${esc(f.file)}</code>` : ""}
|
|
144
|
+
<span class="marketplace-finding__msg">${esc(f.message)}</span>
|
|
145
|
+
${f.fix ? `<div class="marketplace-finding__fix">${esc(f.fix)}</div>` : ""}
|
|
146
|
+
</li>
|
|
147
|
+
`).join("");
|
|
148
|
+
return `<section class="marketplace-section"><h4>${esc(title)}</h4><ul class="marketplace-findings">${items}</ul></section>`;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function openListingEditor(existing, categories) {
|
|
152
|
+
const meta = existing || {};
|
|
153
|
+
return new Promise((resolve) => {
|
|
154
|
+
const overlay = document.createElement("div");
|
|
155
|
+
overlay.className = "confirm-overlay";
|
|
156
|
+
const catOptions = (categories || []).map(
|
|
157
|
+
(c) => `<option value="${esc(c)}" ${c === meta.category ? "selected" : ""}>${esc(c)}</option>`
|
|
158
|
+
).join("");
|
|
159
|
+
overlay.innerHTML = `
|
|
160
|
+
<div class="confirm-dialog marketplace-dialog">
|
|
161
|
+
<div class="confirm-dialog__title">Marketplace listing</div>
|
|
162
|
+
<form id="marketplace-listing-form" class="marketplace-listing-form">
|
|
163
|
+
<label>Category
|
|
164
|
+
<select name="category"><option value="">Select…</option>${catOptions}</select>
|
|
165
|
+
</label>
|
|
166
|
+
<label>Description
|
|
167
|
+
<textarea name="description" rows="3" placeholder="A 1–2 sentence summary for the Marketplace listing.">${esc(meta.description || "")}</textarea>
|
|
168
|
+
</label>
|
|
169
|
+
<label>Features (comma-separated, 2–5 items)
|
|
170
|
+
<input name="features" value="${esc((meta.features || []).join(", "))}" placeholder="Hero, Pricing, Testimonials, Footer" />
|
|
171
|
+
</label>
|
|
172
|
+
<label>Support URL
|
|
173
|
+
<input type="url" name="supportUrl" value="${esc(meta.supportUrl || "")}" placeholder="https://example.com/support" />
|
|
174
|
+
</label>
|
|
175
|
+
<label>Documentation URL (optional)
|
|
176
|
+
<input type="url" name="documentationUrl" value="${esc(meta.documentationUrl || "")}" placeholder="https://example.com/docs" />
|
|
177
|
+
</label>
|
|
178
|
+
<label>Pricing tier
|
|
179
|
+
<select name="pricingTier">
|
|
180
|
+
<option value="free" ${meta.pricingTier === "free" ? "selected" : ""}>Free</option>
|
|
181
|
+
<option value="paid" ${meta.pricingTier === "paid" ? "selected" : ""}>Paid</option>
|
|
182
|
+
</select>
|
|
183
|
+
</label>
|
|
184
|
+
</form>
|
|
185
|
+
<div class="confirm-dialog__actions">
|
|
186
|
+
<button class="btn btn--ghost" data-action="cancel">Cancel</button>
|
|
187
|
+
<button class="btn btn--primary" data-action="save">Save</button>
|
|
188
|
+
</div>
|
|
189
|
+
</div>
|
|
190
|
+
`;
|
|
191
|
+
document.body.appendChild(overlay);
|
|
192
|
+
const form = overlay.querySelector("form");
|
|
193
|
+
|
|
194
|
+
const cleanup = () => overlay.remove();
|
|
195
|
+
overlay.querySelector('[data-action="cancel"]').addEventListener("click", () => { cleanup(); resolve(null); });
|
|
196
|
+
overlay.addEventListener("click", (e) => { if (e.target === overlay) { cleanup(); resolve(null); } });
|
|
197
|
+
overlay.querySelector('[data-action="save"]').addEventListener("click", () => {
|
|
198
|
+
const fd = new FormData(form);
|
|
199
|
+
const features = String(fd.get("features") || "")
|
|
200
|
+
.split(",").map((s) => s.trim()).filter(Boolean);
|
|
201
|
+
const result = {
|
|
202
|
+
category: String(fd.get("category") || "") || undefined,
|
|
203
|
+
description: String(fd.get("description") || "") || undefined,
|
|
204
|
+
features: features.length ? features : undefined,
|
|
205
|
+
supportUrl: String(fd.get("supportUrl") || "") || undefined,
|
|
206
|
+
documentationUrl: String(fd.get("documentationUrl") || "") || undefined,
|
|
207
|
+
pricingTier: String(fd.get("pricingTier") || "") || undefined,
|
|
208
|
+
};
|
|
209
|
+
cleanup();
|
|
210
|
+
resolve(result);
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
document.addEventListener("DOMContentLoaded", () => {
|
|
216
|
+
const btn = document.getElementById("btn-marketplace");
|
|
217
|
+
if (btn) btn.addEventListener("click", openMarketplacePanel);
|
|
218
|
+
});
|
package/ui/plan.js
CHANGED
|
Binary file
|