macOS application menu

Standard menus (App: hide/quit; Edit: clipboard roles enabling Cmd+C/V/X/Z;
View: Refresh Cmd+R + fullscreen; Window: minimize/zoom/cycle) plus File with
New/Close Tab (Cmd+T/W), New Folder/File, and a Connect submenu built from
saved connections (folders as nested submenus, Connection Manager entry).
Custom actions forward to the webview as menuAction messages; the menu rebuilds
whenever connections change. macOS-only per electrobun support.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Jokin
2026-07-11 19:17:25 +02:00
co-authored by Claude Fable 5
parent 20e5703d29
commit 2d7e7b44cd
6 changed files with 165 additions and 5 deletions
+13 -2
View File
@@ -1,7 +1,8 @@
import { BrowserWindow, Updater } from "electrobun/bun";
import { ApplicationMenu, BrowserWindow, Updater } from "electrobun/bun";
import { BRANDING } from "../shared/branding";
import { effectiveConcurrency } from "../shared/types";
import { SessionRegistry } from "./fs/registry";
import { applyApplicationMenu } from "./menu";
import { createAppRPC } from "./rpc-handlers";
import { ConnectionStore } from "./store/connections";
import { SettingsStore } from "./store/settings";
@@ -31,7 +32,10 @@ const registry = new SessionRegistry();
const engine = new TransferEngine(registry);
const store = new ConnectionStore();
const settings = new SettingsStore();
const events = { sessionClosed: (_info: { sessionId: string; reason: string }) => {} };
const events = {
sessionClosed: (_info: { sessionId: string; reason: string }) => {},
connectionsChanged: () => {},
};
const rpc = createAppRPC({ registry, engine, store, settings, events });
const url = await getMainViewUrl();
@@ -59,6 +63,13 @@ new BrowserWindow({
engine.onUpdate = (snapshot) => rpc.send.transferUpdate(snapshot);
events.sessionClosed = (info) => rpc.send.sessionClosed(info);
events.connectionsChanged = () => void applyApplicationMenu(store);
void settings.load().then((s) => engine.setConcurrency(effectiveConcurrency(s)));
void applyApplicationMenu(store);
ApplicationMenu.on("application-menu-clicked", (event) => {
const action = (event as { data?: { action?: string } }).data?.action;
if (action) rpc.send.menuAction({ action });
});
console.log(`${BRANDING.appName} started (${url})`);