addds open menu
Some checks failed
CI / check (push) Has been cancelled

This commit is contained in:
2026-06-16 07:41:25 +02:00
parent 66248c4736
commit 6abee5f8b6
3 changed files with 42 additions and 9 deletions

View File

@@ -1,5 +1,5 @@
import { join, sep } from 'node:path' import { join, sep } from 'node:path'
import { app, dialog, shell, BrowserWindow, ipcMain } from 'electron' import { app, dialog, shell, BrowserWindow, ipcMain, Menu } from 'electron'
import { watch, type FSWatcher } from 'chokidar' import { watch, type FSWatcher } from 'chokidar'
import { getName, getRoot, openDialog } from './project' import { getName, getRoot, openDialog } from './project'
import { readAll, readProjectFile, readTree, writeProjectFile } from './fs-service' import { readAll, readProjectFile, readTree, writeProjectFile } from './fs-service'
@@ -34,6 +34,42 @@ function startConfigWatcher(): void {
configWatcher.on('add', reload).on('change', reload).on('unlink', reload) configWatcher.on('add', reload).on('change', reload).on('unlink', reload)
} }
/** Show the folder picker; if a new folder is chosen, switch the project
* (config + watchers). Returns whether the project changed. */
async function openFolderFlow(win: BrowserWindow | null): Promise<boolean> {
const next = await openDialog(win)
if (!next) return false
await resolveConfig(getRoot())
startWatcher()
startConfigWatcher()
return true
}
function buildAppMenu(): Menu {
const template: Electron.MenuItemConstructorOptions[] = [
...(isMac ? [{ role: 'appMenu' as const }] : []),
{
label: 'File',
submenu: [
{
label: 'Open Folder…',
accelerator: 'CmdOrCtrl+O',
click: (_m, win) => {
const bw = win instanceof BrowserWindow ? win : BrowserWindow.getFocusedWindow()
openFolderFlow(bw).then((changed) => { if (changed) broadcast('project:changed') })
},
},
{ type: 'separator' },
isMac ? { role: 'close' } : { role: 'quit' },
],
},
{ role: 'editMenu' },
{ role: 'viewMenu' },
{ role: 'windowMenu' },
]
return Menu.buildFromTemplate(template)
}
function startWatcher(): void { function startWatcher(): void {
if (watcher) { watcher.close(); watcher = null } if (watcher) { watcher.close(); watcher = null }
const root = getRoot() const root = getRoot()
@@ -52,13 +88,7 @@ function startWatcher(): void {
function registerIpc(): void { function registerIpc(): void {
ipcMain.handle('project:current', () => ({ root: getRoot(), name: getName() })) ipcMain.handle('project:current', () => ({ root: getRoot(), name: getName() }))
ipcMain.handle('project:open', async (e) => { ipcMain.handle('project:open', async (e) => {
const win = BrowserWindow.fromWebContents(e.sender) await openFolderFlow(BrowserWindow.fromWebContents(e.sender))
const next = await openDialog(win)
if (next) {
await resolveConfig(getRoot())
startWatcher()
startConfigWatcher()
}
return { root: getRoot(), name: getName() } return { root: getRoot(), name: getName() }
}) })
@@ -134,6 +164,7 @@ function createWindow(): void {
app.whenReady().then(async () => { app.whenReady().then(async () => {
app.setName('Helder') app.setName('Helder')
Menu.setApplicationMenu(buildAppMenu())
registerIpc() registerIpc()
await resolveConfig(getRoot()) await resolveConfig(getRoot())
startWatcher() startWatcher()

View File

@@ -375,7 +375,8 @@ export function App(): React.ReactElement {
</div> </div>
<Splitter onDelta={(dx) => setRightW((w) => clamp(w - dx, 280, 780))} /> <Splitter onDelta={(dx) => setRightW((w) => clamp(w - dx, 280, 780))} />
<RightColumn width={rightW} /> {/* keyed by root so the PTYs respawn in the new cwd when the project switches */}
{proj.ready && <RightColumn key={proj.root ?? 'none'} width={rightW} />}
</div> </div>
{/* status bar */} {/* status bar */}

View File

@@ -278,6 +278,7 @@ export function Editor({ tabs, active, mode, setMode, onActivate, onClose, onCon
<div style={{ opacity: 0.5 }}>{Icon.file({ width: 30, height: 30 })}</div> <div style={{ opacity: 0.5 }}>{Icon.file({ width: 30, height: 30 })}</div>
<div className="big">No file open</div> <div className="big">No file open</div>
<div className="klist"> <div className="klist">
<div><span>Open folder</span><kbd> O</kbd></div>
<div><span>Search files &amp; content</span><kbd> F</kbd></div> <div><span>Search files &amp; content</span><kbd> F</kbd></div>
<div><span>Copy reference</span><kbd>right-click</kbd></div> <div><span>Copy reference</span><kbd>right-click</kbd></div>
<div><span>Pass on to Agent</span><kbd>right-click</kbd></div> <div><span>Pass on to Agent</span><kbd>right-click</kbd></div>