Skip to content

Commit c8e964c

Browse files
committed
Add code export and interactive preview mode
1 parent 8c27d0c commit c8e964c

14 files changed

Lines changed: 3101 additions & 622 deletions

File tree

apps/desktop/src/main/index.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
*/
1010

1111
import { app, BrowserWindow, ipcMain, dialog, shell, nativeTheme, Menu } from 'electron';
12-
import { join } from 'node:path';
13-
import { readFile, writeFile } from 'node:fs/promises';
12+
import { dirname, join } from 'node:path';
13+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
1414
import { watch, type FSWatcher } from 'node:fs';
1515
import { is } from '@electron-toolkit/utils';
1616
import { setupMCPIPC } from './mcp-client';
@@ -82,6 +82,13 @@ function setupIPC(): void {
8282
return result.canceled ? null : result.filePaths[0];
8383
});
8484

85+
ipcMain.handle('fs:pick-directory', async () => {
86+
const result = await dialog.showOpenDialog(mainWindow!, {
87+
properties: ['openDirectory', 'createDirectory'],
88+
});
89+
return result.canceled ? null : result.filePaths[0];
90+
});
91+
8592
ipcMain.handle('fs:save-dialog', async (_event) => {
8693
const result = await dialog.showSaveDialog(mainWindow!, {
8794
filters: [
@@ -92,6 +99,14 @@ function setupIPC(): void {
9299
return result.canceled ? null : result.filePath;
93100
});
94101

102+
ipcMain.handle('fs:write-batch', async (_event, basePath: string, files: Array<{ path: string; content: string }>) => {
103+
for (const file of files) {
104+
const targetPath = join(basePath, file.path);
105+
await mkdir(dirname(targetPath), { recursive: true });
106+
await writeFile(targetPath, file.content, 'utf-8');
107+
}
108+
});
109+
95110
// Theme
96111
ipcMain.handle('theme:get', () => {
97112
return nativeTheme.shouldUseDarkColors ? 'dark' : 'light';

apps/desktop/src/main/mcp-client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ interface LiveMutationOperation {
5757

5858
type LiveMutation =
5959
| { kind: 'applyOperations'; operations: LiveMutationOperation[] }
60-
| { kind: 'replaceSpec'; spec: unknown }
60+
| { kind: 'replaceSpec'; spec: unknown; filePath?: string | null }
6161
| { kind: 'undo' }
6262
| { kind: 'redo' }
6363
| { kind: 'setSelection'; selectedIds: string[] };

apps/desktop/src/preload/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ export interface DesignForgeAPI {
1212
read(path: string): Promise<string>;
1313
write(path: string, content: string): Promise<void>;
1414
pick(filters?: string[]): Promise<string | null>;
15+
pickDirectory(): Promise<string | null>;
1516
saveDialog(): Promise<string | null>;
17+
writeBatch(basePath: string, files: Array<{ path: string; content: string }>): Promise<void>;
1618
};
1719
theme: {
1820
get(): Promise<'light' | 'dark'>;
@@ -85,7 +87,10 @@ const api: DesignForgeAPI = {
8587
read: (path: string) => ipcRenderer.invoke('fs:read', path),
8688
write: (path: string, content: string) => ipcRenderer.invoke('fs:write', path, content),
8789
pick: (filters?: string[]) => ipcRenderer.invoke('fs:pick', filters),
90+
pickDirectory: () => ipcRenderer.invoke('fs:pick-directory'),
8891
saveDialog: () => ipcRenderer.invoke('fs:save-dialog'),
92+
writeBatch: (basePath: string, files: Array<{ path: string; content: string }>) =>
93+
ipcRenderer.invoke('fs:write-batch', basePath, files),
8994
},
9095
theme: {
9196
get: () => ipcRenderer.invoke('theme:get'),

0 commit comments

Comments
 (0)