diff --git a/ui-electrobun/src/bun/index.ts b/ui-electrobun/src/bun/index.ts index b2c1df8..92903ec 100644 --- a/ui-electrobun/src/bun/index.ts +++ b/ui-electrobun/src/bun/index.ts @@ -6,7 +6,7 @@ */ import fs from "fs"; -import { BrowserWindow, BrowserView, Updater } from "electrobun/bun"; +import { BrowserWindow, BrowserView, Updater, Utils } from "electrobun/bun"; import { PtyClient } from "./pty-client.ts"; import { settingsDb } from "./settings-db.ts"; import { sessionDb } from "./session-db.ts"; @@ -128,6 +128,24 @@ const rpc = BrowserView.defineRPC({ // Git ...gitHandlers, + // Native folder picker dialog + "files.pickDirectory": async ({ startingFolder }) => { + try { + const paths = await Utils.openFileDialog({ + startingFolder: startingFolder || "~/", + canChooseFiles: false, + canChooseDirectory: true, + allowsMultipleSelection: false, + }); + return { path: paths?.[0] ?? null }; + } catch { return { path: null }; } + }, + + // Home directory + "files.homeDir": async () => { + return { path: process.env.HOME || "/home" }; + }, + // Project templates (hardcoded list) "project.templates": async () => ({ templates: [ diff --git a/ui-electrobun/src/mainview/ProjectWizard.svelte b/ui-electrobun/src/mainview/ProjectWizard.svelte index da099c6..7008787 100644 --- a/ui-electrobun/src/mainview/ProjectWizard.svelte +++ b/ui-electrobun/src/mainview/ProjectWizard.svelte @@ -210,10 +210,22 @@ function handleBrowserSelect(path: string) { localPath = path; - showBrowser = false; validatePath(path); } + async function handleNativeBrowse() { + try { + const result = await appRpc.request['files.pickDirectory']({ startingFolder: localPath || '~/' }); + if (result?.path) { + localPath = result.path; + validatePath(result.path); + } + } catch { + // Fallback: native dialog not available, user types path manually + console.warn('[wizard] Native folder picker not available'); + } + } + // Validation indicator function validationIcon(state: typeof pathValid): string { switch (state) { @@ -280,16 +292,13 @@ placeholder={t('wizard.step1.pathPlaceholder' as any)} bind:value={localPath} oninput={() => validatePath(localPath)} /> - + {#if pathValid !== 'idle'} {validationIcon(pathValid)} {/if} - {#if showBrowser} - showBrowser = false} /> - {/if} {#if pathValid === 'valid' && isGitRepo} {t('wizard.step1.gitDetected' as any)} ({gitBranch}) diff --git a/ui-electrobun/src/shared/pty-rpc-schema.ts b/ui-electrobun/src/shared/pty-rpc-schema.ts index 8fd7fad..ccc9b2a 100644 --- a/ui-electrobun/src/shared/pty-rpc-schema.ts +++ b/ui-electrobun/src/shared/pty-rpc-schema.ts @@ -146,6 +146,16 @@ export type PtyRPCRequests = { error?: string; }; }; + /** Native folder picker dialog */ + "files.pickDirectory": { + params: { startingFolder?: string }; + response: { path: string | null }; + }; + /** Get home directory path */ + "files.homeDir": { + params: {}; + response: { path: string }; + }; /** Write text content to a file (atomic temp+rename). */ "files.write": { params: { path: string; content: string };