feat: use native OS folder picker dialog in Electron mode
Electron 环境下改用系统原生文件夹选择对话框替代自定义 FolderPicker 组件, 浏览器环境保留原有 FolderPicker 作为 fallback(浏览器沙箱无法获取绝对路径)。 - electron/main.ts: 新增 `dialog:open-folder` IPC handler,调用 `dialog.showOpenDialog` 并设置 openDirectory + createDirectory 属性, macOS 下支持在对话框内新建文件夹,对话框模态绑定 mainWindow - electron/preload.ts: 在 electronAPI 中暴露 `dialog.openFolder()` 方法 - src/types/electron.d.ts: 新建全局类型声明,统一定义 window.electronAPI 的完整类型,消除代码中散落的 `(window as any)` 类型断言 - src/hooks/useNativeFolderPicker.ts: 新建 hook 封装平台检测和原生对话框 调用逻辑,返回 isElectron 标志和 openNativePicker 方法 - src/components/layout/ChatListPanel.tsx: 新增 openFolderPicker() 统一入口, Electron 走原生对话框、浏览器走 setFolderPickerOpen(true);替换 handleNewChat 中 4 处及文件夹按钮 onClick 共 5 处调用点; handleFolderSelect 改为 useCallback 并调整声明顺序避免引用前使用; 清理 electronAPI 类型断言 - src/app/chat/[id]/page.tsx: 移除 `window as unknown as ...` 类型断言 - src/components/layout/ConnectionStatus.tsx: 移除 `(window as any)` 断言 - src/components/layout/InstallWizard.tsx: getInstallAPI() 简化为直接返回 window.electronAPI?.install,移除 10 行手动类型定义 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
5bace38e47
commit
c6ed594800
8 files changed
+119
-43
No files matched your search
@@ -712,6 +712,17 @@ app.whenReady().then(async () => {
|
||||
return shell.openPath(folderPath);
|
||||
});
|
||||
|
||||
// Native folder picker dialog
|
||||
ipcMain.handle('dialog:open-folder', async (_event, options?: { defaultPath?: string; title?: string }) => {
|
||||
if (!mainWindow) return { canceled: true, filePaths: [] };
|
||||
const result = await dialog.showOpenDialog(mainWindow, {
|
||||
title: options?.title || 'Select a project folder',
|
||||
defaultPath: options?.defaultPath || undefined,
|
||||
properties: ['openDirectory', 'createDirectory'],
|
||||
});
|
||||
return { canceled: result.canceled, filePaths: result.filePaths };
|
||||
});
|
||||
|
||||
try {
|
||||
let port: number;
|
||||
|
||||
|
||||
@@ -10,6 +10,10 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
||||
shell: {
|
||||
openPath: (folderPath: string) => ipcRenderer.invoke('shell:open-path', folderPath),
|
||||
},
|
||||
dialog: {
|
||||
openFolder: (options?: { defaultPath?: string; title?: string }) =>
|
||||
ipcRenderer.invoke('dialog:open-folder', options),
|
||||
},
|
||||
install: {
|
||||
checkPrerequisites: () => ipcRenderer.invoke('install:check-prerequisites'),
|
||||
start: (options?: { includeNode?: boolean }) => ipcRenderer.invoke('install:start', options),
|
||||
|
||||
Reference in new issue
Block a user