diff --git a/src/main/index.ts b/src/main/index.ts index 48c57a2..6a5513a 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -7,6 +7,7 @@ import { registerTerminalIpc } from './ipc/terminal' import { registerDatabaseIpc } from './ipc/database' import { registerAddonsIpc } from './ipc/addons' import { registerLogsIpc } from './ipc/logs' +import { registerCreateIpc } from './ipc/create' import { killAllRunningCommands } from './commandRunner' function createWindow(): void { @@ -61,6 +62,7 @@ app.whenReady().then(() => { registerDatabaseIpc() registerAddonsIpc() registerLogsIpc() + registerCreateIpc() createWindow() diff --git a/src/main/ipc/create.ts b/src/main/ipc/create.ts new file mode 100644 index 0000000..cee4613 --- /dev/null +++ b/src/main/ipc/create.ts @@ -0,0 +1,28 @@ +import { dialog, ipcMain } from 'electron' +import { runStreamed } from '../commandRunner' + +export function registerCreateIpc(): void { + ipcMain.handle('create:pickDirectory', async () => { + const result = await dialog.showOpenDialog({ + properties: ['openDirectory', 'createDirectory'] + }) + return result.canceled ? null : result.filePaths[0] + }) + + ipcMain.handle( + 'create:configure', + ( + event, + operationId: string, + directory: string, + projectName: string, + projectType: string, + docroot: string + ) => { + const args = ['config', `--project-name=${projectName}`, '--auto'] + if (projectType) args.push(`--project-type=${projectType}`) + if (docroot.trim()) args.push(`--docroot=${docroot.trim()}`) + return runStreamed(operationId, args, event.sender, { cwd: directory }) + } + ) +} diff --git a/src/preload/index.ts b/src/preload/index.ts index e4dc01f..693022a 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -79,6 +79,24 @@ const api = { ipcRenderer.on('logs:exit', listener) return () => ipcRenderer.removeListener('logs:exit', listener) } + }, + create: { + pickDirectory: (): Promise => ipcRenderer.invoke('create:pickDirectory'), + configure: ( + operationId: string, + directory: string, + projectName: string, + projectType: string, + docroot: string + ): Promise => + ipcRenderer.invoke( + 'create:configure', + operationId, + directory, + projectName, + projectType, + docroot + ) } } diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx index 6222f3a..1a7fb5c 100644 --- a/src/renderer/src/App.tsx +++ b/src/renderer/src/App.tsx @@ -1,21 +1,33 @@ +import { useState } from 'react' +import { Plus } from 'lucide-react' import { ProjectDetail } from './components/projects/ProjectDetail' import { ProjectList } from './components/projects/ProjectList' import { TerminalPanel } from './components/terminal/TerminalPanel' import { StatusBar } from './components/layout/StatusBar' import { Toaster } from './components/ui/Toaster' +import { CreateProjectModal } from './components/create/CreateProjectModal' import { useAppStore } from './stores/appStore' import { useTerminalEvents } from './hooks/useTerminalEvents' function App(): React.JSX.Element { const selectedProjectName = useAppStore((s) => s.selectedProjectName) + const [isCreateOpen, setIsCreateOpen] = useState(false) useTerminalEvents() return (