vibespot 0.9.0 → 0.9.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibespot",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
4
4
  "description": "AI-powered HubSpot CMS landing page builder — vibe coding & React converter",
5
5
  "type": "module",
6
6
  "bin": {
package/ui/setup.js CHANGED
@@ -293,9 +293,10 @@ function updateRailActive() {
293
293
  });
294
294
  }
295
295
 
296
- // "+" button → go to setup
296
+ // "+" button → open New Theme panel (show setup first if needed)
297
297
  document.getElementById("project-rail-add")?.addEventListener("click", () => {
298
- showSetup();
298
+ if (setupScreen.classList.contains("hidden")) showSetup();
299
+ togglePanel("new");
299
300
  });
300
301
 
301
302
  // ---------------------------------------------------------------------------
@@ -691,26 +692,35 @@ async function fetchTheme() {
691
692
  }
692
693
  }
693
694
 
695
+ let _openThemePromise = null;
694
696
  async function openTheme(pathOrName) {
697
+ // Deduplicate concurrent calls for the same theme
698
+ if (_openThemePromise) return _openThemePromise;
695
699
  showLoading("Opening theme...");
696
700
 
697
- try {
698
- const res = await fetch("/api/setup/open", {
699
- method: "POST",
700
- headers: { "Content-Type": "application/json" },
701
- body: JSON.stringify({ path: pathOrName }),
702
- });
703
- const data = await res.json();
701
+ _openThemePromise = (async () => {
702
+ try {
703
+ const res = await fetch("/api/setup/open", {
704
+ method: "POST",
705
+ headers: { "Content-Type": "application/json" },
706
+ body: JSON.stringify({ path: pathOrName }),
707
+ });
708
+ const data = await res.json();
704
709
 
705
- if (data.error) {
706
- showError(data.error);
707
- return;
710
+ if (data.error) {
711
+ showError(data.error);
712
+ return;
713
+ }
714
+
715
+ showApp(data.themeName);
716
+ } catch (err) {
717
+ showError("Failed to open theme: " + err.message);
718
+ } finally {
719
+ _openThemePromise = null;
708
720
  }
721
+ })();
709
722
 
710
- showApp(data.themeName);
711
- } catch (err) {
712
- showError("Failed to open theme: " + err.message);
713
- }
723
+ return _openThemePromise;
714
724
  }
715
725
 
716
726
  async function resumeSession(sessionId) {
@@ -1190,14 +1200,18 @@ function handleRoute() {
1190
1200
  }
1191
1201
  }
1192
1202
 
1193
- window.addEventListener("popstate", handleRoute);
1194
-
1195
1203
  // ---------------------------------------------------------------------------
1196
1204
  // Initialize — check URL hash first, fall back to setup screen
1197
1205
  // ---------------------------------------------------------------------------
1198
1206
 
1199
- if (location.hash && (location.hash.startsWith("#/app/") || location.hash.startsWith("#/dashboard/"))) {
1200
- handleRoute();
1201
- } else {
1202
- initSetup();
1203
- }
1207
+ let _initialized = false;
1208
+ window.addEventListener("popstate", () => { if (_initialized) handleRoute(); });
1209
+
1210
+ // Always initialize setup (loads project rail, engine status, etc.)
1211
+ // then handle the hash route if present.
1212
+ initSetup().then(() => {
1213
+ _initialized = true;
1214
+ if (location.hash && (location.hash.startsWith("#/app/") || location.hash.startsWith("#/dashboard/"))) {
1215
+ handleRoute();
1216
+ }
1217
+ });