diff --git a/app/package.json b/app/package.json index 30980e12..7b8a1137 100644 --- a/app/package.json +++ b/app/package.json @@ -14,6 +14,7 @@ "dev": "tsc -w & vite build --watch & electron .", "dev:vite": "vite", "preview": "npm run build && METALSHARP_PREVIEW=1 METALSHARP_HOME=\"$HOME/.metalsharp\" electron .", + "preview:dev": "npm run build && METALSHARP_PREVIEW=1 METALSHARP_DEV_LIBRARY=1 METALSHARP_HOME=\"$HOME/.metalsharp\" electron .", "rust:build": "cd src-rust && cargo build --release", "rust:dev": "cd src-rust && cargo build", "build:all": "npm run rust:build && npm run build", diff --git a/app/src/main/index.ts b/app/src/main/index.ts index aec82bce..2a8f8508 100644 --- a/app/src/main/index.ts +++ b/app/src/main/index.ts @@ -608,8 +608,10 @@ async function createWindow(migrating = false) { }, }); + const query: Record = uiOnly ? { theme: "developer" } : {}; + if (process.env.METALSHARP_DEV_LIBRARY === "1") query["skip-to"] = "library"; mainWindow.loadFile(path.join(__dirname, "..", "renderer", "index.html"), { - query: isUiOnlyRuntime() ? { theme: "developer" } : {}, + query, }); } diff --git a/app/src/main/rust-bridge.ts b/app/src/main/rust-bridge.ts index a1f3e277..06b1fc4e 100644 --- a/app/src/main/rust-bridge.ts +++ b/app/src/main/rust-bridge.ts @@ -169,7 +169,9 @@ export class RustBridge { resolve(true); }); req.on("error", () => resolve(false)); - req.setTimeout(1500, () => { + // Dev backends can be busy with a first-run bottle scan; don't treat a + // slow /status as dead or ensureRunning will kill and restart it forever. + req.setTimeout(this.devMode ? 10000 : 1500, () => { req.destroy(); resolve(false); }); diff --git a/app/src/renderer/App.vue b/app/src/renderer/App.vue index 47ed5aba..eca78f2d 100644 --- a/app/src/renderer/App.vue +++ b/app/src/renderer/App.vue @@ -60,7 +60,7 @@ const updateDismissed = ref(false); let updatePollTimer: ReturnType | null = null; let installPollTimer: ReturnType | null = null; -const { theme, toggle: toggleTheme } = useTheme(); +const { theme, setTheme } = useTheme(); const toast = useToast(); const viewMap: Record = { @@ -319,6 +319,17 @@ watch(lowPerformanceMode, (enabled) => { onMounted(async () => { applyLowPerformanceMode(lowPerformanceMode.value); await checkBackend(); + if (new URLSearchParams(window.location.search).get("skip-to") === "library") { + // The dev backend may still be starting (first-run bottle scan); wait for + // it before loading the library instead of racing a dead window. + for (let i = 0; i < 60 && !backendConnected.value; i++) { + await new Promise((r) => setTimeout(r, 1000)); + await checkBackend(); + } + await initApp(); + checkForUpdates(); + return; + } const migrationMode = await getAPI().isMigrationMode?.(); if (migrationMode) { showMigration.value = true; @@ -345,7 +356,7 @@ onMounted(async () => { :current-view="currentView" :theme="theme" @navigate="currentView = $event" - @toggle-theme="toggleTheme()" + @select-theme="setTheme($event)" />
{ } :root[data-theme="developer"] .content { background: - linear-gradient(118deg, rgba(185, 255, 77, 0.025), transparent 36%, rgba(0, 245, 255, 0.03) 72%, transparent), - radial-gradient(circle at 24% 16%, rgba(255, 46, 247, 0.14), transparent 34%), - radial-gradient(circle at 84% 10%, rgba(0, 245, 255, 0.11), transparent 30%), var(--bg-deep); + linear-gradient(118deg, rgba(185, 255, 77, 0.02), transparent 36%, rgba(0, 245, 255, 0.024) 72%, transparent), + radial-gradient(circle at 24% 16%, rgba(255, 46, 247, 0.11), transparent 34%), + radial-gradient(circle at 84% 10%, rgba(0, 245, 255, 0.09), transparent 30%), var(--bg-deep); } .content.content-glass-header { background: transparent; diff --git a/app/src/renderer/components/Sidebar.vue b/app/src/renderer/components/Sidebar.vue index 52f9017b..b968443b 100644 --- a/app/src/renderer/components/Sidebar.vue +++ b/app/src/renderer/components/Sidebar.vue @@ -1,14 +1,15 @@