vibespot 1.1.1 → 1.3.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 (56) hide show
  1. package/LICENSE +103 -33
  2. package/README.md +55 -6
  3. package/assets/blog-rules.md +251 -0
  4. package/assets/email-rules.md +390 -0
  5. package/assets/humanify-guide.md +300 -101
  6. package/assets/plan-templates/agency-services.md +42 -0
  7. package/assets/plan-templates/blog-content-hub.md +50 -0
  8. package/assets/plan-templates/ecommerce-product.md +42 -0
  9. package/assets/plan-templates/email-announcement.md +41 -0
  10. package/assets/plan-templates/email-event-invite.md +43 -0
  11. package/assets/plan-templates/email-newsletter.md +41 -0
  12. package/assets/plan-templates/email-re-engagement.md +42 -0
  13. package/assets/plan-templates/email-welcome.md +41 -0
  14. package/assets/plan-templates/event-registration.md +42 -0
  15. package/assets/plan-templates/portfolio.md +41 -0
  16. package/assets/plan-templates/restaurant.md +42 -0
  17. package/assets/plan-templates/saas-landing.md +42 -0
  18. package/dist/index.js +1485 -397
  19. package/dist/index.js.map +1 -1
  20. package/package.json +11 -7
  21. package/starters/01-saas-landing.json +43 -0
  22. package/starters/02-portfolio.json +39 -0
  23. package/starters/03-restaurant.json +39 -0
  24. package/starters/04-event.json +39 -0
  25. package/starters/05-coming-soon.json +32 -0
  26. package/starters/06-blog-content-hub.json +75 -0
  27. package/starters/06-email-welcome.json +60 -0
  28. package/starters/07-email-announcement.json +60 -0
  29. package/starters/08-email-newsletter.json +52 -0
  30. package/ui/chat.js +1604 -155
  31. package/ui/code-editor.js +49 -7
  32. package/ui/dashboard.js +551 -83
  33. package/ui/docs/docs.css +29 -0
  34. package/ui/docs/index.html +274 -117
  35. package/ui/docs/screenshots/brand-kit-preview.png +0 -0
  36. package/ui/docs/screenshots/content-type-dropdown.png +0 -0
  37. package/ui/docs/screenshots/editor-full-layout.png +0 -0
  38. package/ui/docs/screenshots/inline-wysiwyg-editing.png +0 -0
  39. package/ui/docs/screenshots/multi-page-tree.png +0 -0
  40. package/ui/docs/screenshots/onboarding-walkthrough.png +0 -0
  41. package/ui/docs/screenshots/split-pane-view.png +0 -0
  42. package/ui/docs/screenshots/visual-controls-toolbar.png +0 -0
  43. package/ui/docs/screenshots/workspace-tabs.png +0 -0
  44. package/ui/email-preview.js +109 -0
  45. package/ui/field-editor.js +71 -0
  46. package/ui/icons.js +120 -0
  47. package/ui/index.html +882 -515
  48. package/ui/inline-edit.js +710 -0
  49. package/ui/marketplace.js +218 -0
  50. package/ui/plan.js +0 -0
  51. package/ui/preview.js +219 -1
  52. package/ui/section-controls.js +628 -0
  53. package/ui/settings.js +84 -28
  54. package/ui/setup.js +1016 -118
  55. package/ui/styles.css +6119 -2456
  56. package/ui/upload-panel.js +47 -20
package/ui/settings.js CHANGED
@@ -24,6 +24,8 @@ const ENGINE_LABELS = {
24
24
  // Open / Close
25
25
  // ---------------------------------------------------------------------------
26
26
 
27
+ let _prevWorkspaceTab = "pages";
28
+
27
29
  function openSettings(tab) {
28
30
  if (typeof closeMenu === "function") closeMenu();
29
31
  if (tab) {
@@ -31,12 +33,24 @@ function openSettings(tab) {
31
33
  const tabs = document.querySelectorAll("#settings-tabs .settings__tab");
32
34
  tabs.forEach((t) => t.classList.toggle("active", t.dataset.tab === tab));
33
35
  }
34
- document.getElementById("settings-overlay").classList.remove("hidden");
36
+ const overlay = document.getElementById("settings-overlay");
37
+ if (overlay) {
38
+ overlay.classList.remove("hidden");
39
+ } else if (typeof switchWorkspaceTab === "function") {
40
+ const activeWs = document.querySelector(".workspace-tab.active");
41
+ if (activeWs && activeWs.dataset.wsTab !== "settings") _prevWorkspaceTab = activeWs.dataset.wsTab;
42
+ switchWorkspaceTab("settings");
43
+ }
35
44
  refreshSettings();
36
45
  }
37
46
 
38
47
  function closeSettings() {
39
- document.getElementById("settings-overlay").classList.add("hidden");
48
+ const overlay = document.getElementById("settings-overlay");
49
+ if (overlay) {
50
+ overlay.classList.add("hidden");
51
+ } else if (typeof switchWorkspaceTab === "function") {
52
+ switchWorkspaceTab(_prevWorkspaceTab || "pages");
53
+ }
40
54
  Object.keys(activePolls).forEach((id) => {
41
55
  clearInterval(activePolls[id]);
42
56
  delete activePolls[id];
@@ -67,15 +81,43 @@ async function refreshSettings() {
67
81
  const body = document.getElementById("settings-body");
68
82
  body.innerHTML = `<div class="settings__loading"><div class="settings__spinner-lg"></div><span>Loading environment...</span></div>`;
69
83
 
84
+ const controller = new AbortController();
85
+ const timeout = setTimeout(() => controller.abort(), 3000);
86
+
70
87
  try {
71
- const res = await fetch("/api/settings/status");
88
+ const res = await fetch("/api/settings/status", { signal: controller.signal });
89
+ clearTimeout(timeout);
72
90
  settingsData = await res.json();
73
91
  renderSettings(settingsData);
74
92
  } catch (err) {
75
- body.innerHTML = `<div class="settings__loading" style="color:var(--error)">Failed to load settings</div>`;
93
+ clearTimeout(timeout);
94
+ const aborted = err && err.name === "AbortError";
95
+ renderSettingsError(body, aborted);
76
96
  }
77
97
  }
78
98
 
99
+ function renderSettingsError(body, timedOut) {
100
+ const message = timedOut
101
+ ? "Settings took too long to load. The server may be busy or unreachable."
102
+ : "Failed to load settings.";
103
+ body.innerHTML = "";
104
+ const wrap = el("div", "settings__empty-state");
105
+ wrap.style.cssText = "padding:32px;text-align:center;color:var(--text-muted);";
106
+ const heading = el("div", "");
107
+ heading.style.cssText = "font-weight:600;color:var(--text);margin-bottom:8px;";
108
+ heading.textContent = timedOut ? "Settings unavailable" : "Couldn't load settings";
109
+ wrap.appendChild(heading);
110
+ const desc = el("p", "");
111
+ desc.style.cssText = "margin:0 0 16px;font-size:13px;";
112
+ desc.textContent = message;
113
+ wrap.appendChild(desc);
114
+ const retry = el("button", "btn btn--sm btn--primary");
115
+ retry.textContent = "Retry";
116
+ retry.addEventListener("click", () => refreshSettings());
117
+ wrap.appendChild(retry);
118
+ body.appendChild(wrap);
119
+ }
120
+
79
121
  function renderSettings(data) {
80
122
  const body = document.getElementById("settings-body");
81
123
  body.innerHTML = "";
@@ -551,7 +593,7 @@ function renderFigmaTab(body, data) {
551
593
 
552
594
  const section = el("section", "settings__section");
553
595
  section.appendChild(sectionTitle("Personal Access Token"));
554
- section.appendChild(desc("Connect your Figma account to import designs directly into HubSpot CMS modules. Tokens are stored locally and only used to call the Figma API."));
596
+ section.appendChild(desc("Connect your Figma account to import designs directly into HubSpot CMS sections. Tokens are stored locally and only used to call the Figma API."));
555
597
 
556
598
  const figmaToken = config.figmaToken;
557
599
  const figmaKeyInfo = {
@@ -1057,12 +1099,16 @@ async function switchHsAccount(portalId, btn) {
1057
1099
  });
1058
1100
  const data = await res.json();
1059
1101
  if (data.jobId) {
1060
- pollJob(data.jobId, () => refreshSettings(), () => {
1102
+ pollJob(data.jobId, () => {
1103
+ refreshSettings();
1104
+ if (typeof refreshPortalIndicator === "function") refreshPortalIndicator();
1105
+ }, () => {
1061
1106
  btn.textContent = "Failed";
1062
1107
  btn.disabled = false;
1063
1108
  });
1064
1109
  } else {
1065
1110
  refreshSettings();
1111
+ if (typeof refreshPortalIndicator === "function") refreshPortalIndicator();
1066
1112
  }
1067
1113
  } catch {
1068
1114
  btn.textContent = "Failed";
@@ -1394,36 +1440,47 @@ function getModelsForEngine(engine) {
1394
1440
  switch (engine) {
1395
1441
  case "claude-code":
1396
1442
  return [
1397
- { id: "sonnet", label: "Claude Sonnet (default)" },
1398
- { id: "opus", label: "Claude Opus" },
1399
- { id: "haiku", label: "Claude Haiku" },
1443
+ { id: "claude-opus-4-7", label: "Claude Opus 4.7" },
1444
+ { id: "claude-opus-4-6", label: "Claude Opus 4.6" },
1445
+ { id: "claude-sonnet-4-6", label: "Claude Sonnet 4.6 (default)" },
1446
+ { id: "claude-sonnet-4-5", label: "Claude Sonnet 4.5" },
1447
+ { id: "claude-haiku-4-5", label: "Claude Haiku 4.5" },
1400
1448
  ];
1401
1449
  case "anthropic-api":
1402
1450
  case "claude-oauth":
1403
1451
  return [
1404
- { id: "claude-sonnet-4-6", label: "Claude Sonnet 4.6" },
1452
+ { id: "claude-opus-4-7", label: "Claude Opus 4.7" },
1405
1453
  { id: "claude-opus-4-6", label: "Claude Opus 4.6" },
1454
+ { id: "claude-sonnet-4-6", label: "Claude Sonnet 4.6 (default)" },
1455
+ { id: "claude-sonnet-4-5", label: "Claude Sonnet 4.5" },
1406
1456
  { id: "claude-haiku-4-5-20251001", label: "Claude Haiku 4.5" },
1407
1457
  ];
1408
1458
  case "openai-api":
1409
1459
  return [
1410
- { id: "gpt-4o", label: "GPT-4o (default)" },
1411
- { id: "gpt-4o-mini", label: "GPT-4o Mini" },
1412
- { id: "o3", label: "o3" },
1413
- { id: "o4-mini", label: "o4 Mini" },
1460
+ { id: "gpt-5.5", label: "GPT-5.5 (default)" },
1461
+ { id: "gpt-5.5-pro", label: "GPT-5.5 Pro" },
1462
+ { id: "gpt-5.4-mini", label: "GPT-5.4 Mini" },
1463
+ { id: "gpt-5.4-nano", label: "GPT-5.4 Nano" },
1464
+ { id: "gpt-5.3-codex", label: "GPT-5.3 Codex" },
1414
1465
  ];
1415
1466
  case "gemini-cli":
1416
1467
  case "gemini-api":
1417
1468
  return [
1418
- { id: "gemini-2.5-flash", label: "Gemini 2.5 Flash (default)" },
1419
- { id: "gemini-2.5-pro", label: "Gemini 2.5 Pro" },
1469
+ { id: "gemini-2.5-pro", label: "Gemini 2.5 Pro (default)" },
1470
+ { id: "gemini-2.5-flash", label: "Gemini 2.5 Flash" },
1420
1471
  { id: "gemini-2.0-flash", label: "Gemini 2.0 Flash" },
1421
1472
  ];
1422
1473
  case "codex-cli":
1423
1474
  return [
1424
- { id: "o4-mini", label: "o4 Mini (default)" },
1425
- { id: "o3", label: "o3" },
1426
- { id: "gpt-4o", label: "GPT-4o" },
1475
+ { id: "gpt-5.5", label: "GPT-5.5 (default)" },
1476
+ { id: "gpt-5.5-pro", label: "GPT-5.5 Pro" },
1477
+ { id: "gpt-5.3-codex", label: "GPT-5.3 Codex" },
1478
+ { id: "gpt-5.2-codex", label: "GPT-5.2 Codex" },
1479
+ { id: "gpt-5.1-codex-max", label: "GPT-5.1 Codex Max" },
1480
+ { id: "gpt-5.1-codex-mini", label: "GPT-5.1 Codex Mini" },
1481
+ { id: "gpt-5.4-mini", label: "GPT-5.4 Mini" },
1482
+ { id: "gpt-5.4-nano", label: "GPT-5.4 Nano" },
1483
+ { id: "codex-mini-latest", label: "Codex Mini (latest)" },
1427
1484
  ];
1428
1485
  default:
1429
1486
  return [];
@@ -1432,10 +1489,13 @@ function getModelsForEngine(engine) {
1432
1489
 
1433
1490
  function getCurrentModel(engine, config) {
1434
1491
  switch (engine) {
1435
- case "claude-code": return config.claudeCodeModel || "sonnet";
1492
+ case "claude-code": return config.claudeCodeModel || "claude-sonnet-4-6";
1436
1493
  case "anthropic-api":
1437
1494
  case "claude-oauth": return config.anthropicApiModel || "claude-sonnet-4-6";
1438
- case "openai-api": return config.openaiApiModel || "gpt-4o";
1495
+ case "openai-api": return config.openaiApiModel || "gpt-5.5";
1496
+ case "codex-cli": return config.codexCliModel || "gpt-5.5";
1497
+ case "gemini-cli": return config.geminiCliModel || "gemini-2.5-pro";
1498
+ case "gemini-api": return config.geminiApiModel || "gemini-2.5-pro";
1439
1499
  default: return null;
1440
1500
  }
1441
1501
  }
@@ -1496,15 +1556,11 @@ function escSettings(str) {
1496
1556
  // Event listeners
1497
1557
  // ---------------------------------------------------------------------------
1498
1558
 
1499
- document.getElementById("settings-close").addEventListener("click", closeSettings);
1500
- document.getElementById("settings-overlay").addEventListener("click", (e) => {
1501
- if (e.target.id === "settings-overlay") closeSettings();
1502
- });
1503
-
1504
- document.getElementById("btn-setup-settings").addEventListener("click", openSettings);
1559
+ document.getElementById("btn-setup-settings")?.addEventListener("click", () => openSettings());
1505
1560
 
1506
1561
  document.addEventListener("keydown", (e) => {
1507
- if (e.key === "Escape" && !document.getElementById("settings-overlay").classList.contains("hidden")) {
1562
+ const settingsTabActive = document.querySelector('.workspace-tab[data-ws-tab="settings"].active');
1563
+ if (e.key === "Escape" && settingsTabActive) {
1508
1564
  closeSettings();
1509
1565
  }
1510
1566
  });