/ electron / menu.ts
menu.ts
  1  import { app, BrowserWindow, Menu, MenuItemConstructorOptions, shell } from 'electron'
  2  import { RuntimePaths } from './paths'
  3  
  4  export function buildAppMenu(paths: RuntimePaths, getWindow: () => BrowserWindow | null): void {
  5    const isMac = process.platform === 'darwin'
  6  
  7    const macAppMenu: MenuItemConstructorOptions = {
  8      label: app.name,
  9      submenu: [
 10        { role: 'about' },
 11        { type: 'separator' },
 12        { role: 'services' },
 13        { type: 'separator' },
 14        { role: 'hide' },
 15        { role: 'hideOthers' },
 16        { role: 'unhide' },
 17        { type: 'separator' },
 18        { role: 'quit' },
 19      ],
 20    }
 21  
 22    const fileMenu: MenuItemConstructorOptions = {
 23      label: 'File',
 24      submenu: [
 25        {
 26          label: 'Open Data Folder',
 27          click: () => void shell.openPath(paths.swarmclawHome),
 28        },
 29        { type: 'separator' },
 30        isMac ? { role: 'close' } : { role: 'quit' },
 31      ],
 32    }
 33  
 34    const editMenu: MenuItemConstructorOptions = {
 35      label: 'Edit',
 36      submenu: [
 37        { role: 'undo' },
 38        { role: 'redo' },
 39        { type: 'separator' },
 40        { role: 'cut' },
 41        { role: 'copy' },
 42        { role: 'paste' },
 43        { role: 'selectAll' },
 44      ],
 45    }
 46  
 47    const viewMenu: MenuItemConstructorOptions = {
 48      label: 'View',
 49      submenu: [
 50        {
 51          label: 'Reload',
 52          accelerator: isMac ? 'Cmd+R' : 'Ctrl+R',
 53          click: () => getWindow()?.webContents.reload(),
 54        },
 55        {
 56          label: 'Force Reload',
 57          accelerator: isMac ? 'Shift+Cmd+R' : 'Ctrl+Shift+R',
 58          click: () => getWindow()?.webContents.reloadIgnoringCache(),
 59        },
 60        { type: 'separator' },
 61        { role: 'resetZoom' },
 62        { role: 'zoomIn' },
 63        { role: 'zoomOut' },
 64        { type: 'separator' },
 65        { role: 'togglefullscreen' },
 66        { role: 'toggleDevTools' },
 67      ],
 68    }
 69  
 70    const windowMenu: MenuItemConstructorOptions = {
 71      label: 'Window',
 72      submenu: isMac
 73        ? [
 74            { role: 'minimize' },
 75            { role: 'zoom' },
 76            { type: 'separator' },
 77            { role: 'front' },
 78          ]
 79        : [{ role: 'minimize' }, { role: 'close' }],
 80    }
 81  
 82    const helpMenu: MenuItemConstructorOptions = {
 83      role: 'help',
 84      submenu: [
 85        {
 86          label: 'SwarmClaw Website',
 87          click: () => void shell.openExternal('https://swarmclaw.ai'),
 88        },
 89        {
 90          label: 'Documentation',
 91          click: () => void shell.openExternal('https://swarmclaw.ai/docs'),
 92        },
 93        {
 94          label: 'Report an Issue',
 95          click: () => void shell.openExternal('https://github.com/swarmclawai/swarmclaw/issues'),
 96        },
 97      ],
 98    }
 99  
100    const template: MenuItemConstructorOptions[] = [
101      ...(isMac ? [macAppMenu] : []),
102      fileMenu,
103      editMenu,
104      viewMenu,
105      windowMenu,
106      helpMenu,
107    ]
108  
109    Menu.setApplicationMenu(Menu.buildFromTemplate(template))
110  }